ccdserver.cpp 994 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047170481704917050170511705217053170541705517056170571705817059170601706117062170631706417065170661706717068170691707017071170721707317074170751707617077170781707917080170811708217083170841708517086170871708817089170901709117092170931709417095170961709717098170991710017101171021710317104171051710617107171081710917110171111711217113171141711517116171171711817119171201712117122171231712417125171261712717128171291713017131171321713317134171351713617137171381713917140171411714217143171441714517146171471714817149171501715117152171531715417155171561715717158171591716017161171621716317164171651716617167171681716917170171711717217173171741717517176171771717817179171801718117182171831718417185171861718717188171891719017191171921719317194171951719617197171981719917200172011720217203172041720517206172071720817209172101721117212172131721417215172161721717218172191722017221172221722317224172251722617227172281722917230172311723217233172341723517236172371723817239172401724117242172431724417245172461724717248172491725017251172521725317254172551725617257172581725917260172611726217263172641726517266172671726817269172701727117272172731727417275172761727717278172791728017281172821728317284172851728617287172881728917290172911729217293172941729517296172971729817299173001730117302173031730417305173061730717308173091731017311173121731317314173151731617317173181731917320173211732217323173241732517326173271732817329173301733117332173331733417335173361733717338173391734017341173421734317344173451734617347173481734917350173511735217353173541735517356173571735817359173601736117362173631736417365173661736717368173691737017371173721737317374173751737617377173781737917380173811738217383173841738517386173871738817389173901739117392173931739417395173961739717398173991740017401174021740317404174051740617407174081740917410174111741217413174141741517416174171741817419174201742117422174231742417425174261742717428174291743017431174321743317434174351743617437174381743917440174411744217443174441744517446174471744817449174501745117452174531745417455174561745717458174591746017461174621746317464174651746617467174681746917470174711747217473174741747517476174771747817479174801748117482174831748417485174861748717488174891749017491174921749317494174951749617497174981749917500175011750217503175041750517506175071750817509175101751117512175131751417515175161751717518175191752017521175221752317524175251752617527175281752917530175311753217533175341753517536175371753817539175401754117542175431754417545175461754717548175491755017551175521755317554175551755617557175581755917560175611756217563175641756517566175671756817569175701757117572175731757417575175761757717578175791758017581175821758317584175851758617587175881758917590175911759217593175941759517596175971759817599176001760117602176031760417605176061760717608176091761017611176121761317614176151761617617176181761917620176211762217623176241762517626176271762817629176301763117632176331763417635176361763717638176391764017641176421764317644176451764617647176481764917650176511765217653176541765517656176571765817659176601766117662176631766417665176661766717668176691767017671176721767317674176751767617677176781767917680176811768217683176841768517686176871768817689176901769117692176931769417695176961769717698176991770017701177021770317704177051770617707177081770917710177111771217713177141771517716177171771817719177201772117722177231772417725177261772717728177291773017731177321773317734177351773617737177381773917740177411774217743177441774517746177471774817749177501775117752177531775417755177561775717758177591776017761177621776317764177651776617767177681776917770177711777217773177741777517776177771777817779177801778117782177831778417785177861778717788177891779017791177921779317794177951779617797177981779917800178011780217803178041780517806178071780817809178101781117812178131781417815178161781717818178191782017821178221782317824178251782617827178281782917830178311783217833178341783517836178371783817839178401784117842178431784417845178461784717848178491785017851178521785317854178551785617857178581785917860178611786217863178641786517866178671786817869178701787117872178731787417875178761787717878178791788017881178821788317884178851788617887178881788917890178911789217893178941789517896178971789817899179001790117902179031790417905179061790717908179091791017911179121791317914179151791617917179181791917920179211792217923179241792517926179271792817929179301793117932179331793417935179361793717938179391794017941179421794317944179451794617947179481794917950179511795217953179541795517956179571795817959179601796117962179631796417965179661796717968179691797017971179721797317974179751797617977179781797917980179811798217983179841798517986179871798817989179901799117992179931799417995179961799717998179991800018001180021800318004180051800618007180081800918010180111801218013180141801518016180171801818019180201802118022180231802418025180261802718028180291803018031180321803318034180351803618037180381803918040180411804218043180441804518046180471804818049180501805118052180531805418055180561805718058180591806018061180621806318064180651806618067180681806918070180711807218073180741807518076180771807818079180801808118082180831808418085180861808718088180891809018091180921809318094180951809618097180981809918100181011810218103181041810518106181071810818109181101811118112181131811418115181161811718118181191812018121181221812318124181251812618127181281812918130181311813218133181341813518136181371813818139181401814118142181431814418145181461814718148181491815018151181521815318154181551815618157181581815918160181611816218163181641816518166181671816818169181701817118172181731817418175181761817718178181791818018181181821818318184181851818618187181881818918190181911819218193181941819518196181971819818199182001820118202182031820418205182061820718208182091821018211182121821318214182151821618217182181821918220182211822218223182241822518226182271822818229182301823118232182331823418235182361823718238182391824018241182421824318244182451824618247182481824918250182511825218253182541825518256182571825818259182601826118262182631826418265182661826718268182691827018271182721827318274182751827618277182781827918280182811828218283182841828518286182871828818289182901829118292182931829418295182961829718298182991830018301183021830318304183051830618307183081830918310183111831218313183141831518316183171831818319183201832118322183231832418325183261832718328183291833018331183321833318334183351833618337183381833918340183411834218343183441834518346183471834818349183501835118352183531835418355183561835718358183591836018361183621836318364183651836618367183681836918370183711837218373183741837518376183771837818379183801838118382183831838418385183861838718388183891839018391183921839318394183951839618397183981839918400184011840218403184041840518406184071840818409184101841118412184131841418415184161841718418184191842018421184221842318424184251842618427184281842918430184311843218433184341843518436184371843818439184401844118442184431844418445184461844718448184491845018451184521845318454184551845618457184581845918460184611846218463184641846518466184671846818469184701847118472184731847418475184761847718478184791848018481184821848318484184851848618487184881848918490184911849218493184941849518496184971849818499185001850118502185031850418505185061850718508185091851018511185121851318514185151851618517185181851918520185211852218523185241852518526185271852818529185301853118532185331853418535185361853718538185391854018541185421854318544185451854618547185481854918550185511855218553185541855518556185571855818559185601856118562185631856418565185661856718568185691857018571185721857318574185751857618577185781857918580185811858218583185841858518586185871858818589185901859118592185931859418595185961859718598185991860018601186021860318604186051860618607186081860918610186111861218613186141861518616186171861818619186201862118622186231862418625186261862718628186291863018631186321863318634186351863618637186381863918640186411864218643186441864518646186471864818649186501865118652186531865418655186561865718658186591866018661186621866318664186651866618667186681866918670186711867218673186741867518676186771867818679186801868118682186831868418685186861868718688186891869018691186921869318694186951869618697186981869918700187011870218703187041870518706187071870818709187101871118712187131871418715187161871718718187191872018721187221872318724187251872618727187281872918730187311873218733187341873518736187371873818739187401874118742187431874418745187461874718748187491875018751187521875318754187551875618757187581875918760187611876218763187641876518766187671876818769187701877118772187731877418775187761877718778187791878018781187821878318784187851878618787187881878918790187911879218793187941879518796187971879818799188001880118802188031880418805188061880718808188091881018811188121881318814188151881618817188181881918820188211882218823188241882518826188271882818829188301883118832188331883418835188361883718838188391884018841188421884318844188451884618847188481884918850188511885218853188541885518856188571885818859188601886118862188631886418865188661886718868188691887018871188721887318874188751887618877188781887918880188811888218883188841888518886188871888818889188901889118892188931889418895188961889718898188991890018901189021890318904189051890618907189081890918910189111891218913189141891518916189171891818919189201892118922189231892418925189261892718928189291893018931189321893318934189351893618937189381893918940189411894218943189441894518946189471894818949189501895118952189531895418955189561895718958189591896018961189621896318964189651896618967189681896918970189711897218973189741897518976189771897818979189801898118982189831898418985189861898718988189891899018991189921899318994189951899618997189981899919000190011900219003190041900519006190071900819009190101901119012190131901419015190161901719018190191902019021190221902319024190251902619027190281902919030190311903219033190341903519036190371903819039190401904119042190431904419045190461904719048190491905019051190521905319054190551905619057190581905919060190611906219063190641906519066190671906819069190701907119072190731907419075190761907719078190791908019081190821908319084190851908619087190881908919090190911909219093190941909519096190971909819099191001910119102191031910419105191061910719108191091911019111191121911319114191151911619117191181911919120191211912219123191241912519126191271912819129191301913119132191331913419135191361913719138191391914019141191421914319144191451914619147191481914919150191511915219153191541915519156191571915819159191601916119162191631916419165191661916719168191691917019171191721917319174191751917619177191781917919180191811918219183191841918519186191871918819189191901919119192191931919419195191961919719198191991920019201192021920319204192051920619207192081920919210192111921219213192141921519216192171921819219192201922119222192231922419225192261922719228192291923019231192321923319234192351923619237192381923919240192411924219243192441924519246192471924819249192501925119252192531925419255192561925719258192591926019261192621926319264192651926619267192681926919270192711927219273192741927519276192771927819279192801928119282192831928419285192861928719288192891929019291192921929319294192951929619297192981929919300193011930219303193041930519306193071930819309193101931119312193131931419315193161931719318193191932019321193221932319324193251932619327193281932919330193311933219333193341933519336193371933819339193401934119342193431934419345193461934719348193491935019351193521935319354193551935619357193581935919360193611936219363193641936519366193671936819369193701937119372193731937419375193761937719378193791938019381193821938319384193851938619387193881938919390193911939219393193941939519396193971939819399194001940119402194031940419405194061940719408194091941019411194121941319414194151941619417194181941919420194211942219423194241942519426194271942819429194301943119432194331943419435194361943719438194391944019441194421944319444194451944619447194481944919450194511945219453194541945519456194571945819459194601946119462194631946419465194661946719468194691947019471194721947319474194751947619477194781947919480194811948219483194841948519486194871948819489194901949119492194931949419495194961949719498194991950019501195021950319504195051950619507195081950919510195111951219513195141951519516195171951819519195201952119522195231952419525195261952719528195291953019531195321953319534195351953619537195381953919540195411954219543195441954519546195471954819549195501955119552195531955419555195561955719558195591956019561195621956319564195651956619567195681956919570195711957219573195741957519576195771957819579195801958119582195831958419585195861958719588195891959019591195921959319594195951959619597195981959919600196011960219603196041960519606196071960819609196101961119612196131961419615196161961719618196191962019621196221962319624196251962619627196281962919630196311963219633196341963519636196371963819639196401964119642196431964419645196461964719648196491965019651196521965319654196551965619657196581965919660196611966219663196641966519666196671966819669196701967119672196731967419675196761967719678196791968019681196821968319684196851968619687196881968919690196911969219693196941969519696196971969819699197001970119702197031970419705197061970719708197091971019711197121971319714197151971619717197181971919720197211972219723197241972519726197271972819729197301973119732197331973419735197361973719738197391974019741197421974319744197451974619747197481974919750197511975219753197541975519756197571975819759197601976119762197631976419765197661976719768197691977019771197721977319774197751977619777197781977919780197811978219783197841978519786197871978819789197901979119792197931979419795197961979719798197991980019801198021980319804198051980619807198081980919810198111981219813198141981519816198171981819819198201982119822198231982419825198261982719828198291983019831198321983319834198351983619837198381983919840198411984219843198441984519846198471984819849198501985119852198531985419855198561985719858198591986019861198621986319864198651986619867198681986919870198711987219873198741987519876198771987819879198801988119882198831988419885198861988719888198891989019891198921989319894198951989619897198981989919900199011990219903199041990519906199071990819909199101991119912199131991419915199161991719918199191992019921199221992319924199251992619927199281992919930199311993219933199341993519936199371993819939199401994119942199431994419945199461994719948199491995019951199521995319954199551995619957199581995919960199611996219963199641996519966199671996819969199701997119972199731997419975199761997719978199791998019981199821998319984199851998619987199881998919990199911999219993199941999519996199971999819999200002000120002200032000420005200062000720008200092001020011200122001320014200152001620017200182001920020200212002220023200242002520026200272002820029200302003120032200332003420035200362003720038200392004020041200422004320044200452004620047200482004920050200512005220053200542005520056200572005820059200602006120062200632006420065200662006720068200692007020071200722007320074200752007620077200782007920080200812008220083200842008520086200872008820089200902009120092200932009420095200962009720098200992010020101201022010320104201052010620107201082010920110201112011220113201142011520116201172011820119201202012120122201232012420125201262012720128201292013020131201322013320134201352013620137201382013920140201412014220143201442014520146201472014820149201502015120152201532015420155201562015720158201592016020161201622016320164201652016620167201682016920170201712017220173201742017520176201772017820179201802018120182201832018420185201862018720188201892019020191201922019320194201952019620197201982019920200202012020220203202042020520206202072020820209202102021120212202132021420215202162021720218202192022020221202222022320224202252022620227202282022920230202312023220233202342023520236202372023820239202402024120242202432024420245202462024720248202492025020251202522025320254202552025620257202582025920260202612026220263202642026520266202672026820269202702027120272202732027420275202762027720278202792028020281202822028320284202852028620287202882028920290202912029220293202942029520296202972029820299203002030120302203032030420305203062030720308203092031020311203122031320314203152031620317203182031920320203212032220323203242032520326203272032820329203302033120332203332033420335203362033720338203392034020341203422034320344203452034620347203482034920350203512035220353203542035520356203572035820359203602036120362203632036420365203662036720368203692037020371203722037320374203752037620377203782037920380203812038220383203842038520386203872038820389203902039120392203932039420395203962039720398203992040020401204022040320404204052040620407204082040920410204112041220413204142041520416204172041820419204202042120422204232042420425204262042720428204292043020431204322043320434204352043620437204382043920440204412044220443204442044520446204472044820449204502045120452204532045420455204562045720458204592046020461204622046320464204652046620467204682046920470204712047220473204742047520476204772047820479204802048120482204832048420485204862048720488204892049020491204922049320494204952049620497204982049920500205012050220503205042050520506205072050820509205102051120512205132051420515205162051720518205192052020521205222052320524205252052620527205282052920530205312053220533205342053520536205372053820539205402054120542205432054420545205462054720548205492055020551205522055320554205552055620557205582055920560205612056220563205642056520566205672056820569205702057120572205732057420575205762057720578205792058020581205822058320584205852058620587205882058920590205912059220593205942059520596205972059820599206002060120602206032060420605206062060720608206092061020611206122061320614206152061620617206182061920620206212062220623206242062520626206272062820629206302063120632206332063420635206362063720638206392064020641206422064320644206452064620647206482064920650206512065220653206542065520656206572065820659206602066120662206632066420665206662066720668206692067020671206722067320674206752067620677206782067920680206812068220683206842068520686206872068820689206902069120692206932069420695206962069720698206992070020701207022070320704207052070620707207082070920710207112071220713207142071520716207172071820719207202072120722207232072420725207262072720728207292073020731207322073320734207352073620737207382073920740207412074220743207442074520746207472074820749207502075120752207532075420755207562075720758207592076020761207622076320764207652076620767207682076920770207712077220773207742077520776207772077820779207802078120782207832078420785207862078720788207892079020791207922079320794207952079620797207982079920800208012080220803208042080520806208072080820809208102081120812208132081420815208162081720818208192082020821208222082320824208252082620827208282082920830208312083220833208342083520836208372083820839208402084120842208432084420845208462084720848208492085020851208522085320854208552085620857208582085920860208612086220863208642086520866208672086820869208702087120872208732087420875208762087720878208792088020881208822088320884208852088620887208882088920890208912089220893208942089520896208972089820899209002090120902209032090420905209062090720908209092091020911209122091320914209152091620917209182091920920209212092220923209242092520926209272092820929209302093120932209332093420935209362093720938209392094020941209422094320944209452094620947209482094920950209512095220953209542095520956209572095820959209602096120962209632096420965209662096720968209692097020971209722097320974209752097620977209782097920980209812098220983209842098520986209872098820989209902099120992209932099420995209962099720998209992100021001210022100321004210052100621007210082100921010210112101221013210142101521016210172101821019210202102121022210232102421025210262102721028210292103021031210322103321034210352103621037210382103921040210412104221043210442104521046210472104821049210502105121052210532105421055210562105721058210592106021061210622106321064210652106621067210682106921070210712107221073210742107521076210772107821079210802108121082210832108421085210862108721088210892109021091210922109321094210952109621097210982109921100211012110221103211042110521106211072110821109211102111121112211132111421115211162111721118211192112021121211222112321124211252112621127211282112921130211312113221133211342113521136211372113821139211402114121142211432114421145211462114721148211492115021151211522115321154211552115621157211582115921160211612116221163211642116521166211672116821169211702117121172211732117421175211762117721178211792118021181211822118321184211852118621187211882118921190211912119221193211942119521196211972119821199212002120121202212032120421205212062120721208212092121021211212122121321214212152121621217212182121921220212212122221223212242122521226212272122821229212302123121232212332123421235212362123721238212392124021241212422124321244212452124621247212482124921250212512125221253212542125521256212572125821259212602126121262212632126421265212662126721268212692127021271212722127321274212752127621277212782127921280212812128221283212842128521286212872128821289212902129121292212932129421295212962129721298212992130021301213022130321304213052130621307213082130921310213112131221313213142131521316213172131821319213202132121322213232132421325213262132721328213292133021331213322133321334213352133621337213382133921340213412134221343213442134521346213472134821349213502135121352213532135421355213562135721358213592136021361213622136321364213652136621367213682136921370213712137221373213742137521376213772137821379213802138121382213832138421385213862138721388213892139021391213922139321394213952139621397213982139921400214012140221403214042140521406214072140821409214102141121412214132141421415214162141721418214192142021421214222142321424214252142621427214282142921430214312143221433214342143521436214372143821439214402144121442214432144421445214462144721448214492145021451214522145321454214552145621457214582145921460214612146221463214642146521466214672146821469214702147121472214732147421475214762147721478214792148021481214822148321484214852148621487214882148921490214912149221493214942149521496214972149821499215002150121502215032150421505215062150721508215092151021511215122151321514215152151621517215182151921520215212152221523215242152521526215272152821529215302153121532215332153421535215362153721538215392154021541215422154321544215452154621547215482154921550215512155221553215542155521556215572155821559215602156121562215632156421565215662156721568215692157021571215722157321574215752157621577215782157921580215812158221583215842158521586215872158821589215902159121592215932159421595215962159721598215992160021601216022160321604216052160621607216082160921610216112161221613216142161521616216172161821619216202162121622216232162421625216262162721628216292163021631216322163321634216352163621637216382163921640216412164221643216442164521646216472164821649216502165121652216532165421655216562165721658216592166021661216622166321664216652166621667216682166921670216712167221673216742167521676216772167821679216802168121682216832168421685216862168721688216892169021691216922169321694216952169621697216982169921700217012170221703217042170521706217072170821709217102171121712217132171421715217162171721718217192172021721217222172321724217252172621727217282172921730217312173221733217342173521736217372173821739217402174121742217432174421745217462174721748217492175021751217522175321754217552175621757217582175921760217612176221763217642176521766217672176821769217702177121772217732177421775217762177721778217792178021781217822178321784217852178621787217882178921790217912179221793217942179521796217972179821799218002180121802218032180421805218062180721808218092181021811218122181321814218152181621817218182181921820218212182221823218242182521826218272182821829218302183121832218332183421835218362183721838218392184021841218422184321844218452184621847218482184921850218512185221853218542185521856218572185821859218602186121862218632186421865218662186721868218692187021871218722187321874218752187621877218782187921880218812188221883218842188521886218872188821889218902189121892218932189421895218962189721898218992190021901219022190321904219052190621907219082190921910219112191221913219142191521916219172191821919219202192121922219232192421925219262192721928219292193021931219322193321934219352193621937219382193921940219412194221943219442194521946219472194821949219502195121952219532195421955219562195721958219592196021961219622196321964219652196621967219682196921970219712197221973219742197521976219772197821979219802198121982219832198421985219862198721988219892199021991219922199321994219952199621997219982199922000220012200222003220042200522006220072200822009220102201122012220132201422015220162201722018220192202022021220222202322024220252202622027220282202922030220312203222033220342203522036220372203822039220402204122042220432204422045220462204722048220492205022051220522205322054220552205622057220582205922060220612206222063220642206522066220672206822069220702207122072220732207422075220762207722078220792208022081220822208322084220852208622087220882208922090220912209222093220942209522096220972209822099221002210122102221032210422105221062210722108221092211022111221122211322114221152211622117221182211922120221212212222123221242212522126221272212822129221302213122132221332213422135221362213722138221392214022141221422214322144221452214622147221482214922150221512215222153221542215522156221572215822159221602216122162221632216422165221662216722168221692217022171221722217322174221752217622177221782217922180221812218222183221842218522186221872218822189221902219122192221932219422195221962219722198221992220022201222022220322204222052220622207222082220922210222112221222213222142221522216222172221822219222202222122222222232222422225222262222722228222292223022231222322223322234222352223622237222382223922240222412224222243222442224522246222472224822249222502225122252222532225422255222562225722258222592226022261222622226322264222652226622267222682226922270222712227222273222742227522276222772227822279222802228122282222832228422285222862228722288222892229022291222922229322294222952229622297222982229922300223012230222303223042230522306223072230822309223102231122312223132231422315223162231722318223192232022321223222232322324223252232622327223282232922330223312233222333223342233522336223372233822339223402234122342223432234422345223462234722348223492235022351223522235322354223552235622357223582235922360223612236222363223642236522366223672236822369223702237122372223732237422375223762237722378223792238022381223822238322384223852238622387223882238922390223912239222393223942239522396223972239822399224002240122402224032240422405224062240722408224092241022411224122241322414224152241622417224182241922420224212242222423224242242522426224272242822429224302243122432224332243422435224362243722438224392244022441224422244322444224452244622447224482244922450224512245222453224542245522456224572245822459224602246122462224632246422465224662246722468224692247022471224722247322474224752247622477224782247922480224812248222483224842248522486224872248822489224902249122492224932249422495224962249722498224992250022501225022250322504225052250622507225082250922510225112251222513225142251522516225172251822519225202252122522225232252422525225262252722528225292253022531225322253322534225352253622537225382253922540225412254222543225442254522546225472254822549225502255122552225532255422555225562255722558225592256022561225622256322564225652256622567225682256922570225712257222573225742257522576225772257822579225802258122582225832258422585225862258722588225892259022591225922259322594225952259622597225982259922600226012260222603226042260522606226072260822609226102261122612226132261422615226162261722618226192262022621226222262322624226252262622627226282262922630226312263222633226342263522636226372263822639226402264122642226432264422645226462264722648226492265022651226522265322654226552265622657226582265922660226612266222663226642266522666226672266822669226702267122672226732267422675226762267722678226792268022681226822268322684226852268622687226882268922690226912269222693226942269522696226972269822699227002270122702227032270422705227062270722708227092271022711227122271322714227152271622717227182271922720227212272222723227242272522726227272272822729227302273122732227332273422735227362273722738227392274022741227422274322744227452274622747227482274922750227512275222753227542275522756227572275822759227602276122762227632276422765227662276722768227692277022771227722277322774227752277622777227782277922780227812278222783227842278522786227872278822789227902279122792227932279422795227962279722798227992280022801228022280322804228052280622807228082280922810228112281222813228142281522816228172281822819228202282122822228232282422825228262282722828228292283022831228322283322834228352283622837228382283922840228412284222843228442284522846228472284822849228502285122852228532285422855228562285722858228592286022861228622286322864228652286622867228682286922870228712287222873228742287522876228772287822879228802288122882228832288422885228862288722888228892289022891228922289322894228952289622897228982289922900229012290222903229042290522906229072290822909229102291122912229132291422915229162291722918229192292022921229222292322924229252292622927229282292922930229312293222933229342293522936229372293822939229402294122942229432294422945229462294722948229492295022951229522295322954229552295622957229582295922960229612296222963229642296522966229672296822969229702297122972229732297422975229762297722978229792298022981229822298322984229852298622987229882298922990229912299222993229942299522996229972299822999230002300123002230032300423005230062300723008230092301023011230122301323014230152301623017230182301923020230212302223023230242302523026230272302823029230302303123032230332303423035230362303723038230392304023041230422304323044230452304623047230482304923050230512305223053230542305523056230572305823059230602306123062230632306423065230662306723068230692307023071230722307323074230752307623077230782307923080230812308223083230842308523086230872308823089230902309123092230932309423095230962309723098230992310023101231022310323104231052310623107231082310923110231112311223113231142311523116231172311823119231202312123122231232312423125231262312723128231292313023131231322313323134231352313623137231382313923140231412314223143231442314523146231472314823149231502315123152231532315423155231562315723158231592316023161231622316323164231652316623167231682316923170231712317223173231742317523176231772317823179231802318123182231832318423185231862318723188231892319023191231922319323194231952319623197231982319923200232012320223203232042320523206232072320823209232102321123212232132321423215232162321723218232192322023221232222322323224232252322623227232282322923230232312323223233232342323523236232372323823239232402324123242232432324423245232462324723248232492325023251232522325323254232552325623257232582325923260232612326223263232642326523266232672326823269232702327123272232732327423275232762327723278232792328023281232822328323284232852328623287232882328923290232912329223293232942329523296232972329823299233002330123302233032330423305233062330723308233092331023311233122331323314233152331623317233182331923320233212332223323233242332523326233272332823329233302333123332233332333423335233362333723338233392334023341233422334323344233452334623347233482334923350233512335223353233542335523356233572335823359233602336123362233632336423365233662336723368233692337023371233722337323374233752337623377233782337923380233812338223383233842338523386233872338823389233902339123392233932339423395233962339723398233992340023401234022340323404234052340623407234082340923410234112341223413234142341523416234172341823419234202342123422234232342423425234262342723428234292343023431234322343323434234352343623437234382343923440234412344223443234442344523446234472344823449234502345123452234532345423455234562345723458234592346023461234622346323464234652346623467234682346923470234712347223473234742347523476234772347823479234802348123482234832348423485234862348723488234892349023491234922349323494234952349623497234982349923500235012350223503235042350523506235072350823509235102351123512235132351423515235162351723518235192352023521235222352323524235252352623527235282352923530235312353223533235342353523536235372353823539235402354123542235432354423545235462354723548235492355023551235522355323554235552355623557235582355923560235612356223563235642356523566235672356823569235702357123572235732357423575235762357723578235792358023581235822358323584235852358623587235882358923590235912359223593235942359523596235972359823599236002360123602236032360423605236062360723608236092361023611236122361323614236152361623617236182361923620236212362223623236242362523626236272362823629236302363123632236332363423635236362363723638236392364023641236422364323644236452364623647236482364923650236512365223653236542365523656236572365823659236602366123662236632366423665236662366723668236692367023671236722367323674236752367623677236782367923680236812368223683236842368523686236872368823689236902369123692236932369423695236962369723698236992370023701237022370323704237052370623707237082370923710237112371223713237142371523716237172371823719237202372123722237232372423725237262372723728237292373023731237322373323734237352373623737237382373923740237412374223743237442374523746237472374823749237502375123752237532375423755237562375723758237592376023761237622376323764237652376623767237682376923770237712377223773237742377523776237772377823779237802378123782237832378423785237862378723788237892379023791237922379323794237952379623797237982379923800238012380223803238042380523806238072380823809238102381123812238132381423815238162381723818238192382023821238222382323824238252382623827238282382923830238312383223833238342383523836238372383823839238402384123842238432384423845238462384723848238492385023851238522385323854238552385623857238582385923860238612386223863238642386523866238672386823869238702387123872238732387423875238762387723878238792388023881238822388323884238852388623887238882388923890238912389223893238942389523896238972389823899239002390123902239032390423905239062390723908239092391023911239122391323914239152391623917239182391923920239212392223923239242392523926239272392823929239302393123932239332393423935239362393723938239392394023941239422394323944239452394623947239482394923950239512395223953239542395523956239572395823959239602396123962239632396423965239662396723968239692397023971239722397323974239752397623977239782397923980239812398223983239842398523986239872398823989239902399123992239932399423995239962399723998239992400024001240022400324004240052400624007240082400924010240112401224013240142401524016240172401824019240202402124022240232402424025240262402724028240292403024031240322403324034240352403624037240382403924040240412404224043240442404524046240472404824049240502405124052240532405424055240562405724058240592406024061240622406324064240652406624067240682406924070240712407224073240742407524076240772407824079240802408124082240832408424085240862408724088240892409024091240922409324094240952409624097240982409924100241012410224103241042410524106241072410824109241102411124112241132411424115241162411724118241192412024121241222412324124241252412624127241282412924130241312413224133241342413524136241372413824139241402414124142241432414424145241462414724148241492415024151241522415324154241552415624157241582415924160241612416224163241642416524166241672416824169241702417124172241732417424175241762417724178241792418024181241822418324184241852418624187241882418924190241912419224193241942419524196241972419824199242002420124202242032420424205242062420724208242092421024211242122421324214242152421624217242182421924220242212422224223242242422524226242272422824229242302423124232242332423424235242362423724238242392424024241242422424324244242452424624247242482424924250242512425224253242542425524256242572425824259242602426124262242632426424265242662426724268242692427024271242722427324274242752427624277242782427924280242812428224283242842428524286242872428824289242902429124292242932429424295242962429724298242992430024301243022430324304243052430624307243082430924310243112431224313243142431524316243172431824319243202432124322243232432424325243262432724328243292433024331243322433324334243352433624337243382433924340243412434224343243442434524346243472434824349243502435124352243532435424355243562435724358243592436024361243622436324364243652436624367243682436924370243712437224373243742437524376243772437824379243802438124382243832438424385243862438724388243892439024391243922439324394243952439624397243982439924400244012440224403244042440524406244072440824409244102441124412244132441424415244162441724418244192442024421244222442324424244252442624427244282442924430244312443224433244342443524436244372443824439244402444124442244432444424445244462444724448244492445024451244522445324454244552445624457244582445924460244612446224463244642446524466244672446824469244702447124472244732447424475244762447724478244792448024481244822448324484244852448624487244882448924490244912449224493244942449524496244972449824499245002450124502245032450424505245062450724508245092451024511245122451324514245152451624517245182451924520245212452224523245242452524526245272452824529245302453124532245332453424535245362453724538245392454024541245422454324544245452454624547245482454924550245512455224553245542455524556245572455824559245602456124562245632456424565245662456724568245692457024571245722457324574245752457624577245782457924580245812458224583245842458524586245872458824589245902459124592245932459424595245962459724598245992460024601246022460324604246052460624607246082460924610246112461224613246142461524616246172461824619246202462124622246232462424625246262462724628246292463024631246322463324634246352463624637246382463924640246412464224643246442464524646246472464824649246502465124652246532465424655246562465724658246592466024661246622466324664246652466624667246682466924670246712467224673246742467524676246772467824679246802468124682246832468424685246862468724688246892469024691246922469324694246952469624697246982469924700247012470224703247042470524706247072470824709247102471124712247132471424715247162471724718247192472024721247222472324724247252472624727247282472924730247312473224733247342473524736247372473824739247402474124742247432474424745247462474724748247492475024751247522475324754247552475624757247582475924760247612476224763247642476524766247672476824769247702477124772247732477424775247762477724778247792478024781247822478324784247852478624787247882478924790247912479224793247942479524796247972479824799248002480124802248032480424805248062480724808248092481024811248122481324814248152481624817248182481924820248212482224823248242482524826248272482824829248302483124832248332483424835248362483724838248392484024841248422484324844248452484624847248482484924850248512485224853248542485524856248572485824859248602486124862248632486424865248662486724868248692487024871248722487324874248752487624877248782487924880248812488224883248842488524886248872488824889248902489124892248932489424895248962489724898248992490024901249022490324904249052490624907249082490924910249112491224913249142491524916249172491824919249202492124922249232492424925249262492724928249292493024931249322493324934249352493624937249382493924940249412494224943249442494524946249472494824949249502495124952249532495424955249562495724958249592496024961249622496324964249652496624967249682496924970249712497224973249742497524976249772497824979249802498124982249832498424985249862498724988249892499024991249922499324994249952499624997249982499925000250012500225003250042500525006250072500825009250102501125012250132501425015250162501725018250192502025021250222502325024250252502625027250282502925030250312503225033250342503525036250372503825039250402504125042250432504425045250462504725048250492505025051250522505325054250552505625057250582505925060250612506225063250642506525066250672506825069250702507125072250732507425075250762507725078250792508025081250822508325084250852508625087250882508925090250912509225093250942509525096250972509825099251002510125102251032510425105251062510725108251092511025111251122511325114251152511625117251182511925120251212512225123251242512525126251272512825129251302513125132251332513425135251362513725138251392514025141251422514325144251452514625147251482514925150251512515225153251542515525156251572515825159251602516125162251632516425165251662516725168251692517025171251722517325174251752517625177251782517925180251812518225183251842518525186251872518825189251902519125192251932519425195251962519725198251992520025201252022520325204252052520625207252082520925210252112521225213252142521525216252172521825219252202522125222252232522425225252262522725228252292523025231252322523325234252352523625237252382523925240252412524225243252442524525246252472524825249252502525125252252532525425255252562525725258252592526025261252622526325264252652526625267252682526925270252712527225273252742527525276252772527825279252802528125282252832528425285252862528725288252892529025291252922529325294252952529625297252982529925300253012530225303253042530525306253072530825309253102531125312253132531425315253162531725318253192532025321253222532325324253252532625327253282532925330253312533225333253342533525336253372533825339253402534125342253432534425345253462534725348253492535025351253522535325354253552535625357253582535925360253612536225363253642536525366253672536825369253702537125372253732537425375253762537725378253792538025381253822538325384253852538625387253882538925390253912539225393253942539525396253972539825399254002540125402254032540425405254062540725408254092541025411254122541325414254152541625417254182541925420254212542225423254242542525426254272542825429254302543125432254332543425435254362543725438254392544025441254422544325444254452544625447254482544925450254512545225453254542545525456254572545825459254602546125462254632546425465254662546725468254692547025471254722547325474254752547625477254782547925480254812548225483254842548525486254872548825489254902549125492254932549425495254962549725498254992550025501255022550325504255052550625507255082550925510255112551225513255142551525516255172551825519255202552125522255232552425525255262552725528255292553025531255322553325534255352553625537255382553925540255412554225543255442554525546255472554825549255502555125552255532555425555255562555725558255592556025561255622556325564255652556625567255682556925570255712557225573255742557525576255772557825579255802558125582255832558425585255862558725588255892559025591255922559325594255952559625597255982559925600256012560225603256042560525606256072560825609256102561125612256132561425615256162561725618256192562025621256222562325624256252562625627256282562925630256312563225633256342563525636256372563825639256402564125642256432564425645256462564725648256492565025651256522565325654256552565625657256582565925660256612566225663256642566525666256672566825669256702567125672256732567425675256762567725678256792568025681256822568325684256852568625687256882568925690256912569225693256942569525696256972569825699257002570125702257032570425705257062570725708257092571025711257122571325714257152571625717257182571925720257212572225723257242572525726257272572825729257302573125732257332573425735257362573725738257392574025741257422574325744257452574625747257482574925750257512575225753257542575525756257572575825759257602576125762257632576425765257662576725768257692577025771257722577325774257752577625777257782577925780257812578225783257842578525786257872578825789257902579125792257932579425795257962579725798257992580025801258022580325804258052580625807258082580925810258112581225813258142581525816258172581825819258202582125822258232582425825258262582725828258292583025831258322583325834258352583625837258382583925840258412584225843258442584525846258472584825849258502585125852258532585425855258562585725858258592586025861258622586325864258652586625867258682586925870258712587225873258742587525876258772587825879258802588125882258832588425885258862588725888258892589025891258922589325894258952589625897258982589925900259012590225903259042590525906259072590825909259102591125912259132591425915259162591725918259192592025921259222592325924259252592625927259282592925930259312593225933259342593525936259372593825939259402594125942259432594425945259462594725948259492595025951259522595325954259552595625957259582595925960259612596225963259642596525966259672596825969259702597125972259732597425975259762597725978259792598025981259822598325984259852598625987259882598925990259912599225993259942599525996259972599825999260002600126002260032600426005260062600726008260092601026011260122601326014260152601626017260182601926020260212602226023260242602526026260272602826029260302603126032260332603426035260362603726038260392604026041260422604326044260452604626047260482604926050260512605226053260542605526056260572605826059260602606126062260632606426065260662606726068260692607026071260722607326074260752607626077260782607926080260812608226083260842608526086260872608826089260902609126092260932609426095260962609726098260992610026101261022610326104261052610626107261082610926110261112611226113261142611526116261172611826119261202612126122261232612426125261262612726128261292613026131261322613326134261352613626137261382613926140261412614226143261442614526146261472614826149261502615126152261532615426155261562615726158261592616026161261622616326164261652616626167261682616926170261712617226173261742617526176261772617826179261802618126182261832618426185261862618726188261892619026191261922619326194261952619626197261982619926200262012620226203262042620526206262072620826209262102621126212262132621426215262162621726218262192622026221262222622326224262252622626227262282622926230262312623226233262342623526236262372623826239262402624126242262432624426245262462624726248262492625026251262522625326254262552625626257262582625926260262612626226263262642626526266262672626826269262702627126272262732627426275262762627726278262792628026281262822628326284262852628626287262882628926290262912629226293262942629526296262972629826299263002630126302263032630426305263062630726308263092631026311263122631326314263152631626317263182631926320263212632226323263242632526326263272632826329263302633126332263332633426335263362633726338263392634026341263422634326344263452634626347263482634926350263512635226353263542635526356263572635826359263602636126362263632636426365263662636726368263692637026371263722637326374263752637626377263782637926380263812638226383263842638526386263872638826389263902639126392263932639426395263962639726398263992640026401264022640326404264052640626407264082640926410264112641226413264142641526416264172641826419264202642126422264232642426425264262642726428264292643026431264322643326434264352643626437264382643926440264412644226443264442644526446264472644826449264502645126452264532645426455264562645726458264592646026461264622646326464264652646626467264682646926470264712647226473264742647526476264772647826479264802648126482264832648426485264862648726488264892649026491264922649326494264952649626497264982649926500265012650226503265042650526506265072650826509265102651126512265132651426515265162651726518265192652026521265222652326524265252652626527265282652926530265312653226533265342653526536265372653826539265402654126542265432654426545265462654726548265492655026551265522655326554265552655626557265582655926560265612656226563265642656526566265672656826569265702657126572265732657426575265762657726578265792658026581265822658326584265852658626587265882658926590265912659226593265942659526596265972659826599266002660126602266032660426605266062660726608266092661026611266122661326614266152661626617266182661926620266212662226623266242662526626266272662826629266302663126632266332663426635266362663726638266392664026641266422664326644266452664626647266482664926650266512665226653266542665526656266572665826659266602666126662266632666426665266662666726668266692667026671266722667326674266752667626677266782667926680266812668226683266842668526686266872668826689266902669126692266932669426695266962669726698266992670026701267022670326704267052670626707267082670926710267112671226713267142671526716267172671826719267202672126722267232672426725267262672726728267292673026731267322673326734267352673626737267382673926740267412674226743267442674526746267472674826749267502675126752267532675426755267562675726758267592676026761267622676326764267652676626767267682676926770267712677226773267742677526776267772677826779267802678126782267832678426785267862678726788267892679026791267922679326794267952679626797267982679926800268012680226803268042680526806268072680826809268102681126812268132681426815268162681726818268192682026821268222682326824268252682626827268282682926830268312683226833268342683526836268372683826839268402684126842268432684426845268462684726848268492685026851268522685326854268552685626857268582685926860268612686226863268642686526866268672686826869268702687126872268732687426875268762687726878268792688026881268822688326884268852688626887268882688926890268912689226893268942689526896268972689826899269002690126902269032690426905269062690726908269092691026911269122691326914269152691626917269182691926920269212692226923269242692526926269272692826929269302693126932269332693426935269362693726938269392694026941269422694326944269452694626947269482694926950269512695226953269542695526956269572695826959269602696126962269632696426965269662696726968269692697026971269722697326974269752697626977269782697926980269812698226983269842698526986269872698826989269902699126992269932699426995269962699726998269992700027001270022700327004270052700627007270082700927010270112701227013270142701527016270172701827019270202702127022270232702427025270262702727028270292703027031270322703327034270352703627037270382703927040270412704227043270442704527046270472704827049270502705127052270532705427055270562705727058270592706027061270622706327064270652706627067270682706927070270712707227073270742707527076270772707827079270802708127082270832708427085270862708727088270892709027091270922709327094270952709627097270982709927100271012710227103271042710527106271072710827109271102711127112271132711427115271162711727118271192712027121271222712327124271252712627127271282712927130271312713227133271342713527136271372713827139271402714127142271432714427145271462714727148271492715027151271522715327154271552715627157271582715927160271612716227163271642716527166271672716827169271702717127172271732717427175271762717727178271792718027181271822718327184271852718627187271882718927190271912719227193271942719527196271972719827199272002720127202272032720427205272062720727208272092721027211272122721327214272152721627217272182721927220272212722227223272242722527226272272722827229272302723127232272332723427235272362723727238272392724027241272422724327244272452724627247272482724927250272512725227253272542725527256272572725827259272602726127262272632726427265272662726727268272692727027271272722727327274272752727627277272782727927280272812728227283272842728527286272872728827289272902729127292272932729427295272962729727298272992730027301273022730327304273052730627307273082730927310273112731227313273142731527316273172731827319273202732127322273232732427325273262732727328273292733027331273322733327334273352733627337273382733927340273412734227343273442734527346273472734827349273502735127352273532735427355273562735727358273592736027361273622736327364273652736627367273682736927370273712737227373273742737527376273772737827379273802738127382273832738427385273862738727388273892739027391273922739327394273952739627397273982739927400274012740227403274042740527406274072740827409274102741127412274132741427415274162741727418274192742027421274222742327424274252742627427274282742927430274312743227433274342743527436274372743827439274402744127442274432744427445274462744727448274492745027451274522745327454274552745627457274582745927460274612746227463274642746527466274672746827469274702747127472274732747427475274762747727478274792748027481274822748327484274852748627487274882748927490274912749227493274942749527496274972749827499275002750127502275032750427505275062750727508275092751027511275122751327514275152751627517275182751927520275212752227523275242752527526275272752827529275302753127532275332753427535275362753727538275392754027541275422754327544275452754627547275482754927550275512755227553275542755527556275572755827559275602756127562275632756427565275662756727568275692757027571275722757327574275752757627577275782757927580275812758227583275842758527586275872758827589275902759127592275932759427595275962759727598275992760027601276022760327604276052760627607276082760927610276112761227613276142761527616276172761827619276202762127622276232762427625276262762727628276292763027631276322763327634276352763627637276382763927640276412764227643276442764527646276472764827649276502765127652276532765427655276562765727658276592766027661276622766327664276652766627667276682766927670276712767227673276742767527676276772767827679276802768127682276832768427685276862768727688276892769027691276922769327694276952769627697276982769927700277012770227703277042770527706277072770827709277102771127712277132771427715277162771727718277192772027721277222772327724277252772627727277282772927730277312773227733277342773527736277372773827739277402774127742277432774427745277462774727748277492775027751277522775327754277552775627757277582775927760277612776227763277642776527766277672776827769277702777127772277732777427775277762777727778277792778027781277822778327784277852778627787277882778927790277912779227793277942779527796277972779827799278002780127802278032780427805278062780727808278092781027811278122781327814278152781627817278182781927820278212782227823278242782527826278272782827829278302783127832278332783427835278362783727838278392784027841278422784327844278452784627847278482784927850278512785227853278542785527856278572785827859278602786127862278632786427865278662786727868278692787027871278722787327874278752787627877278782787927880278812788227883278842788527886278872788827889278902789127892278932789427895278962789727898278992790027901279022790327904279052790627907279082790927910279112791227913279142791527916279172791827919279202792127922279232792427925279262792727928279292793027931279322793327934279352793627937279382793927940279412794227943279442794527946279472794827949279502795127952279532795427955279562795727958279592796027961279622796327964279652796627967279682796927970279712797227973279742797527976279772797827979279802798127982279832798427985279862798727988279892799027991279922799327994279952799627997279982799928000280012800228003280042800528006280072800828009280102801128012280132801428015280162801728018280192802028021280222802328024280252802628027280282802928030280312803228033280342803528036280372803828039280402804128042280432804428045280462804728048280492805028051280522805328054280552805628057280582805928060280612806228063280642806528066280672806828069280702807128072280732807428075280762807728078280792808028081280822808328084280852808628087280882808928090280912809228093280942809528096280972809828099281002810128102281032810428105281062810728108281092811028111281122811328114281152811628117281182811928120281212812228123281242812528126281272812828129281302813128132281332813428135281362813728138281392814028141281422814328144281452814628147281482814928150281512815228153281542815528156281572815828159281602816128162281632816428165281662816728168281692817028171281722817328174281752817628177281782817928180281812818228183281842818528186281872818828189281902819128192281932819428195281962819728198281992820028201282022820328204282052820628207282082820928210282112821228213282142821528216282172821828219282202822128222282232822428225282262822728228282292823028231282322823328234282352823628237282382823928240282412824228243282442824528246282472824828249282502825128252282532825428255282562825728258282592826028261282622826328264282652826628267282682826928270282712827228273282742827528276282772827828279282802828128282282832828428285282862828728288282892829028291282922829328294282952829628297282982829928300283012830228303283042830528306283072830828309283102831128312283132831428315283162831728318283192832028321283222832328324283252832628327283282832928330283312833228333283342833528336283372833828339283402834128342283432834428345283462834728348283492835028351283522835328354283552835628357283582835928360283612836228363283642836528366283672836828369283702837128372283732837428375283762837728378283792838028381283822838328384283852838628387283882838928390
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "jmisc.hpp"
  14. #include "jdebug.hpp"
  15. #include "jptree.hpp"
  16. #include "rtlkey.hpp"
  17. #include "jsort.hpp"
  18. #include "jhtree.hpp"
  19. #include "jqueue.tpp"
  20. #include "jisem.hpp"
  21. #include "thorxmlread.hpp"
  22. #include "thorrparse.ipp"
  23. #include "thorxmlwrite.hpp"
  24. #include "thorsoapcall.hpp"
  25. #include "thorcommon.ipp"
  26. #include "thorsort.hpp"
  27. #include "thorstats.hpp"
  28. #include "jlzw.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.hpp"
  37. #include "rtlds_imp.hpp"
  38. #include "rtlread_imp.hpp"
  39. #include "rtlcommon.hpp"
  40. #include <algorithm>
  41. #include "dafdesc.hpp"
  42. #include "dautils.hpp"
  43. #include "ftbase.ipp"
  44. #include "eclhelper_base.hpp"
  45. #include "ccd.hpp"
  46. #include "ccdserver.hpp"
  47. #include "ccdcontext.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 "roxiemem.hpp"
  58. #include "roxierowbuff.hpp"
  59. #include "roxiehelper.hpp"
  60. #include "roxielmj.hpp"
  61. #include "roxierow.hpp"
  62. #include "thorplugin.hpp"
  63. #include "keybuild.hpp"
  64. #include "thorstrand.hpp"
  65. #include "rtldynfield.hpp"
  66. #define MAX_HTTP_HEADERSIZE 8000
  67. #define MIN_PAYLOAD_SIZE 800
  68. #pragma warning(disable : 4355)
  69. #define DEFAULT_PARALLEL_LOOP_THREADS 1
  70. #define PROBE
  71. #ifdef _DEBUG
  72. //#define FAKE_EXCEPTIONS
  73. //#define TRACE_JOINGROUPS
  74. //#define TRACE_SPLIT
  75. //#define _CHECK_HEAPSORT
  76. //#undef PARALLEL_EXECUTE
  77. //#define TRACE_SEEK_REQUESTS
  78. #endif
  79. using roxiemem::OwnedRoxieRow;
  80. using roxiemem::OwnedRoxieString;
  81. using roxiemem::OwnedConstRoxieRow;
  82. using roxiemem::IRowManager;
  83. using roxiemem::ReleaseRoxieRows;
  84. // 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...
  85. #if _MSC_VER==1200
  86. #define protected public
  87. #endif
  88. #define TRACE_STARTSTOP // This determines if it is available - it is enabled/disabled by a configuration option
  89. #define TRACE_STRANDS
  90. #define MAX_SENSIBLE_STRANDS 1024 // Architecture dependent...
  91. static const SmartStepExtra dummySmartStepExtra(SSEFreadAhead, NULL);
  92. //=================================================================================
  93. class RestartableThread : public CInterface
  94. {
  95. class MyThread : public Thread
  96. {
  97. Linked<RestartableThread> owner;
  98. public:
  99. MyThread(RestartableThread *_owner, const char *name) : Thread(name), owner(_owner)
  100. {
  101. }
  102. virtual int run()
  103. {
  104. owner->started.signal();
  105. return owner->run();
  106. }
  107. };
  108. friend class MyThread;
  109. Semaphore started;
  110. Owned<MyThread> thread;
  111. CriticalSection crit;
  112. StringAttr name;
  113. public:
  114. RestartableThread(const char *_name) : name(_name)
  115. {
  116. }
  117. virtual void start(const char *namePrefix)
  118. {
  119. StringBuffer s(namePrefix);
  120. s.append(name);
  121. {
  122. CriticalBlock b(crit);
  123. assertex(!thread);
  124. thread.setown(new MyThread(this, s));
  125. thread->start();
  126. }
  127. started.wait();
  128. }
  129. virtual void join()
  130. {
  131. {
  132. Owned<Thread> tthread;
  133. {
  134. CriticalBlock b(crit);
  135. tthread.setown(thread.getClear());
  136. }
  137. if (tthread)
  138. tthread->join();
  139. }
  140. }
  141. virtual int run() = 0;
  142. };
  143. //================================================================================
  144. //The following don't link their arguments because that creates a circular reference
  145. //But I wish there was a better way
  146. class IndirectSlaveContext : implements IRoxieSlaveContext, public CInterface
  147. {
  148. public:
  149. IndirectSlaveContext(IRoxieSlaveContext * _ctx) : ctx(_ctx) {}
  150. IMPLEMENT_IINTERFACE
  151. // void set(IRoxieSlaveContext * _ctx) { ctx = _ctx; }
  152. virtual ICodeContext *queryCodeContext()
  153. {
  154. return ctx->queryCodeContext();
  155. }
  156. virtual void checkAbort()
  157. {
  158. ctx->checkAbort();
  159. }
  160. virtual void notifyAbort(IException *E)
  161. {
  162. ctx->notifyAbort(E);
  163. }
  164. virtual IActivityGraph * queryChildGraph(unsigned id)
  165. {
  166. return ctx->queryChildGraph(id);
  167. }
  168. virtual void noteChildGraph(unsigned id, IActivityGraph *childGraph)
  169. {
  170. ctx->noteChildGraph(id, childGraph) ;
  171. }
  172. virtual IRowManager &queryRowManager()
  173. {
  174. return ctx->queryRowManager();
  175. }
  176. virtual void noteStatistic(StatisticKind kind, unsigned __int64 value) const
  177. {
  178. ctx->noteStatistic(kind, value);
  179. }
  180. virtual void mergeStats(const CRuntimeStatisticCollection &from) const
  181. {
  182. ctx->mergeStats(from);
  183. }
  184. virtual void gatherStats(CRuntimeStatisticCollection & merged) const override
  185. {
  186. ctx->gatherStats(merged);
  187. }
  188. virtual void CTXLOGva(const char *format, va_list args) const __attribute__((format(printf,2,0)))
  189. {
  190. ctx->CTXLOGva(format, args);
  191. }
  192. virtual void CTXLOGa(TracingCategory category, const char *prefix, const char *text) const
  193. {
  194. ctx->CTXLOGa(category, prefix, text);
  195. }
  196. virtual void logOperatorExceptionVA(IException *E, const char *file, unsigned line, const char *format, va_list args) const __attribute__((format(printf,5,0)))
  197. {
  198. ctx->logOperatorExceptionVA(E, file, line, format, args);
  199. }
  200. virtual void CTXLOGaeva(IException *E, const char *file, unsigned line, const char *prefix, const char *format, va_list args) const __attribute__((format(printf,6,0)))
  201. {
  202. ctx->CTXLOGaeva(E, file, line, prefix, format, args);
  203. }
  204. virtual void CTXLOGl(LogItem *log) const
  205. {
  206. ctx->CTXLOGl(log);
  207. }
  208. virtual StringBuffer &getLogPrefix(StringBuffer &ret) const
  209. {
  210. return ctx->getLogPrefix(ret);
  211. }
  212. virtual unsigned queryTraceLevel() const
  213. {
  214. return ctx->queryTraceLevel();
  215. }
  216. virtual bool isIntercepted() const
  217. {
  218. return ctx->isIntercepted();
  219. }
  220. virtual bool isBlind() const
  221. {
  222. return ctx->isBlind();
  223. }
  224. virtual const QueryOptions &queryOptions() const
  225. {
  226. return ctx->queryOptions();
  227. }
  228. virtual void addSlavesReplyLen(unsigned len)
  229. {
  230. ctx->addSlavesReplyLen(len);
  231. }
  232. virtual const char *queryAuthToken()
  233. {
  234. return ctx->queryAuthToken();
  235. }
  236. virtual const IResolvedFile *resolveLFN(const char *filename, bool isOpt)
  237. {
  238. return ctx->resolveLFN(filename, isOpt);
  239. }
  240. virtual IRoxieWriteHandler *createLFN(const char *filename, bool overwrite, bool extend, const StringArray &clusters)
  241. {
  242. return ctx->createLFN(filename, overwrite, extend, clusters);
  243. }
  244. virtual void onFileCallback(const RoxiePacketHeader &header, const char *lfn, bool isOpt, bool isLocal)
  245. {
  246. ctx->onFileCallback(header, lfn, isOpt, isLocal);
  247. }
  248. virtual IActivityGraph *getLibraryGraph(const LibraryCallFactoryExtra &extra, IRoxieServerActivity *parentActivity)
  249. {
  250. return ctx->getLibraryGraph(extra, parentActivity);
  251. }
  252. virtual void noteProcessed(unsigned subgraphId, unsigned activityId, unsigned _idx, unsigned _processed, unsigned _strands) const
  253. {
  254. ctx->noteProcessed(subgraphId, activityId, _idx, _processed, _strands);
  255. }
  256. virtual void mergeActivityStats(const CRuntimeStatisticCollection &fromStats, unsigned subgraphId, unsigned activityId) const
  257. {
  258. ctx->mergeActivityStats(fromStats, subgraphId, activityId);
  259. }
  260. virtual IProbeManager *queryProbeManager() const
  261. {
  262. return ctx->queryProbeManager();
  263. }
  264. virtual IDebuggableContext *queryDebugContext() const
  265. {
  266. return ctx->queryDebugContext();
  267. }
  268. virtual void printResults(IXmlWriter *output, const char *name, unsigned sequence)
  269. {
  270. ctx->printResults(output, name, sequence);
  271. }
  272. virtual void setWUState(WUState state)
  273. {
  274. ctx->setWUState(state);
  275. }
  276. virtual bool checkWuAborted()
  277. {
  278. return ctx->checkWuAborted();
  279. }
  280. virtual IWorkUnit *updateWorkUnit() const
  281. {
  282. return ctx->updateWorkUnit();
  283. }
  284. virtual IConstWorkUnit *queryWorkUnit() const
  285. {
  286. return ctx->queryWorkUnit();
  287. }
  288. virtual IRoxieServerContext *queryServerContext()
  289. {
  290. return ctx->queryServerContext();
  291. }
  292. virtual IWorkUnitRowReader *getWorkunitRowReader(const char *wuid, const char * name, unsigned sequence, IXmlToRowTransformer * xmlTransformer, IEngineRowAllocator *rowAllocator, bool isGrouped)
  293. {
  294. return ctx->getWorkunitRowReader(wuid, name, sequence, xmlTransformer, rowAllocator, isGrouped);
  295. }
  296. virtual IEngineRowAllocator *getRowAllocatorEx(IOutputMetaData * meta, unsigned activityId, roxiemem::RoxieHeapFlags flags) const
  297. {
  298. return ctx->getRowAllocatorEx(meta, activityId, flags);
  299. }
  300. protected:
  301. IRoxieSlaveContext * ctx;
  302. };
  303. //=================================================================================
  304. #define RESULT_FLUSH_THRESHOLD 10000u
  305. #ifdef _DEBUG
  306. #define SOAP_SPLIT_THRESHOLD 100u
  307. #define SOAP_SPLIT_RESERVE 200u
  308. #else
  309. #define SOAP_SPLIT_THRESHOLD 64000u
  310. #define SOAP_SPLIT_RESERVE 65535u
  311. #endif
  312. //=================================================================================
  313. // General activity statistics
  314. static const StatisticsMapping actStatistics({StWhenFirstRow, StTimeElapsed, StTimeLocalExecute, StTimeTotalExecute, StSizeMaxRowSize,
  315. StNumRowsProcessed, StNumSlaves, StNumStarts, StNumStops, StNumStrands,
  316. StNumScansPerRow, StNumAllocations, StNumAllocationScans,
  317. StTimeFirstExecute, StCycleLocalExecuteCycles, StCycleTotalExecuteCycles});
  318. static const StatisticsMapping joinStatistics(&actStatistics, {StNumAtmostTriggered});
  319. static const StatisticsMapping keyedJoinStatistics(&joinStatistics, { StNumServerCacheHits, StNumIndexSeeks, StNumIndexScans, StNumIndexWildSeeks,
  320. StNumIndexSkips, StNumIndexNullSkips, StNumIndexMerges, StNumIndexMergeCompares,
  321. StNumPreFiltered, StNumPostFiltered, StNumIndexAccepted, StNumIndexRejected,
  322. StNumIndexRowsRead, StNumDiskRowsRead, StNumDiskSeeks, StNumDiskAccepted,
  323. StNumBlobCacheHits, StNumLeafCacheHits, StNumNodeCacheHits,
  324. StNumBlobCacheAdds, StNumLeafCacheAdds, StNumNodeCacheAdds,
  325. StNumDiskRejected});
  326. static const StatisticsMapping indexStatistics(&actStatistics, {StNumServerCacheHits, StNumIndexSeeks, StNumIndexScans, StNumIndexWildSeeks,
  327. StNumIndexSkips, StNumIndexNullSkips, StNumIndexMerges, StNumIndexMergeCompares,
  328. StNumPreFiltered, StNumPostFiltered, StNumIndexAccepted, StNumIndexRejected,
  329. StNumBlobCacheHits, StNumLeafCacheHits, StNumNodeCacheHits,
  330. StNumBlobCacheAdds, StNumLeafCacheAdds, StNumNodeCacheAdds,
  331. StNumIndexRowsRead});
  332. static const StatisticsMapping diskStatistics(&actStatistics, {StNumServerCacheHits, StNumDiskRowsRead, StNumDiskSeeks, StNumDiskAccepted,
  333. StNumDiskRejected });
  334. static const StatisticsMapping soapStatistics(&actStatistics, { StTimeSoapcall });
  335. static const StatisticsMapping groupStatistics(&actStatistics, { StNumGroups, StNumGroupMax });
  336. static const StatisticsMapping sortStatistics(&actStatistics, { StTimeSortElapsed });
  337. //=================================================================================
  338. const static unsigned minus1U = (0U-1U);
  339. class CRoxieServerActivityFactoryBase : public CActivityFactory, implements IRoxieServerActivityFactory
  340. {
  341. protected:
  342. IntArray dependencies; // things I am dependent on
  343. IntArray dependencyIndexes; // things I am dependent on
  344. IntArray dependencyControlIds; // things I am dependent on
  345. StringArray dependencyEdgeIds; // How to describe them to the debugger
  346. unsigned dependentCount; // things dependent on me
  347. unsigned optParallel = 0; // -1=enable,0=not specified,1=single-threaded,n=<num threads>
  348. bool optStableInput = true; // is the input forced to ordered?
  349. bool optUnstableInput = false; // is the input forced to unordered?
  350. bool optUnordered = false; // is the output specified as unordered?
  351. unsigned heapFlags;
  352. mutable RelaxedAtomic<__int64> processed = {0};
  353. mutable RelaxedAtomic<__int64> started = {0};
  354. public:
  355. IMPLEMENT_IINTERFACE;
  356. CRoxieServerActivityFactoryBase(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  357. : CActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  358. {
  359. dependentCount = 0;
  360. optParallel = _graphNode.getPropInt("att[@name='parallel']/@value", 0);
  361. optUnordered = !_graphNode.getPropBool("att[@name='ordered']/@value", true);
  362. heapFlags = _graphNode.getPropInt("hint[@name='heapflags']/@value", _queryFactory.queryOptions().heapFlags);
  363. }
  364. ~CRoxieServerActivityFactoryBase()
  365. {
  366. }
  367. StringBuffer &toString(StringBuffer &ret) const
  368. {
  369. return ret.appendf("%p", this);
  370. }
  371. virtual void addDependency(unsigned _source, ThorActivityKind _kind, unsigned _sourceIdx, int controlId, const char *edgeId)
  372. {
  373. dependencies.append(_source);
  374. dependencyIndexes.append(_sourceIdx);
  375. dependencyControlIds.append(controlId);
  376. dependencyEdgeIds.append(edgeId);
  377. }
  378. virtual bool isInputOrdered(bool consumerOrdered, unsigned idx) const
  379. {
  380. if (optStableInput)
  381. return true;
  382. if (optUnstableInput)
  383. return false;
  384. if (optUnordered)
  385. return false;
  386. return consumerOrdered;
  387. }
  388. virtual void noteDependent(unsigned target)
  389. {
  390. dependentCount++;
  391. }
  392. virtual IntArray &queryDependencies() { return dependencies; }
  393. virtual IntArray &queryDependencyIndexes() { return dependencyIndexes; }
  394. virtual IntArray &queryDependencyControlIds() { return dependencyControlIds; }
  395. virtual StringArray &queryDependencyEdgeIds() { return dependencyEdgeIds; }
  396. virtual unsigned queryId() const { return id; }
  397. virtual unsigned querySubgraphId() const { return subgraphId; }
  398. virtual ThorActivityKind getKind() const { return kind; }
  399. virtual IOutputMetaData * queryOutputMeta() const
  400. {
  401. return meta;
  402. }
  403. virtual bool isSink() const
  404. {
  405. return false;
  406. }
  407. virtual bool isFunction() const
  408. {
  409. return false;
  410. }
  411. virtual bool isGraphInvariant() const
  412. {
  413. return false;
  414. }
  415. virtual IHThorArg &getHelper() const
  416. {
  417. return *helperFactory();
  418. }
  419. virtual IRoxieServerActivity *createFunction(IHThorArg &arg, IProbeManager *_probeManager) const
  420. {
  421. arg.Release();
  422. throwUnexpected();
  423. }
  424. virtual void mergeStats(const CRuntimeStatisticCollection &from) const
  425. {
  426. CActivityFactory::mergeStats(from);
  427. }
  428. virtual void noteProcessed(unsigned _idx, unsigned _processed) const
  429. {
  430. dbgassertex(!_idx);
  431. if (_processed)
  432. processed += _processed;
  433. }
  434. virtual void noteStarted() const
  435. {
  436. started++;
  437. }
  438. virtual void noteStarted(unsigned idx) const
  439. {
  440. throwUnexpected(); // should be implemented/required by multiOutput cases only
  441. }
  442. virtual void getEdgeProgressInfo(unsigned output, IPropertyTree &edge) const
  443. {
  444. if (output == 0)
  445. {
  446. putStatsValue(&edge, "count", "sum", processed);
  447. auto _started = started.load();
  448. if (_started)
  449. putStatsValue(&edge, "started", "sum", _started);
  450. }
  451. else
  452. ERRLOG("unexpected call to getEdgeProcessInfo for output %d in activity %d", output, queryId());
  453. }
  454. virtual void getNodeProgressInfo(IPropertyTree &node) const
  455. {
  456. CActivityFactory::getNodeProgressInfo(node);
  457. auto _started = started.load();
  458. if (_started)
  459. putStatsValue(&node, "_roxieStarted", "sum", _started);
  460. }
  461. virtual void resetNodeProgressInfo()
  462. {
  463. CActivityFactory::resetNodeProgressInfo();
  464. processed = 0;
  465. started = 0;
  466. }
  467. virtual void getActivityMetrics(StringBuffer &reply) const
  468. {
  469. CActivityFactory::getActivityMetrics(reply);
  470. putStatsValue(reply, "_roxieStarted", "sum", started);
  471. CriticalBlock b(statsCrit);
  472. putStatsValue(reply, "totalTime", "sum", (unsigned) (mystats.getSerialStatisticValue(StTimeTotalExecute)/1000));
  473. putStatsValue(reply, "localTime", "sum", (unsigned) (mystats.getSerialStatisticValue(StTimeLocalExecute)/1000));
  474. }
  475. virtual unsigned __int64 queryLocalTimeNs() const
  476. {
  477. return mystats.getSerialStatisticValue(StTimeLocalExecute);
  478. }
  479. virtual IQueryFactory &queryQueryFactory() const
  480. {
  481. return CActivityFactory::queryQueryFactory();
  482. }
  483. virtual ActivityArray *queryChildQuery(unsigned idx, unsigned &id)
  484. {
  485. return CActivityFactory::queryChildQuery(idx, id);
  486. }
  487. virtual void addChildQuery(unsigned id, ActivityArray *childQuery)
  488. {
  489. CActivityFactory::addChildQuery(id, childQuery);
  490. }
  491. virtual void onCreateChildQueries(IRoxieSlaveContext *ctx, IHThorArg *colocalArg, IArrayOf<IActivityGraph> &childGraphs, IRoxieServerActivity *parentActivity, IProbeManager *_probeManager, const IRoxieContextLogger &_logctx, unsigned numParallel) const
  492. {
  493. ForEachItemIn(idx, childQueries)
  494. {
  495. childGraphs.append(*createActivityGraph(ctx, NULL, childQueryIndexes.item(idx), childQueries.item(idx), parentActivity, _probeManager, _logctx, numParallel));
  496. ctx->noteChildGraph(childQueryIndexes.item(idx), &childGraphs.item(idx));
  497. childGraphs.item(idx).onCreate(colocalArg);
  498. }
  499. }
  500. IActivityGraph * createChildGraph(IRoxieSlaveContext * ctx, IHThorArg *colocalArg, unsigned childId, IRoxieServerActivity *parentActivity, IProbeManager * _probeManager, const IRoxieContextLogger &_logctx) const
  501. {
  502. unsigned match = childQueryIndexes.find(childId);
  503. assertex(match != NotFound);
  504. Owned<IActivityGraph> graph = createActivityGraph(ctx, NULL, childQueryIndexes.item(match), childQueries.item(match), parentActivity, _probeManager, _logctx, 1);
  505. graph->onCreate(colocalArg);
  506. return graph.getClear();
  507. }
  508. virtual IRoxieServerSideCache *queryServerSideCache() const
  509. {
  510. return NULL; // Activities that wish to support server-side caching will need to do better....
  511. }
  512. virtual bool getEnableFieldTranslation() const
  513. {
  514. throwUnexpected(); // only implemented by index-related subclasses
  515. }
  516. virtual IDefRecordMeta *queryActivityMeta() const
  517. {
  518. throwUnexpected(); // only implemented by index-related subclasses
  519. }
  520. virtual void getXrefInfo(IPropertyTree &reply, const IRoxieContextLogger &logctx) const
  521. {
  522. // Most activities have nothing to say...
  523. }
  524. virtual const StatisticsMapping &queryStatsMapping() const
  525. {
  526. return actStatistics; // Overridden by anyone that needs more
  527. }
  528. virtual roxiemem::RoxieHeapFlags getHeapFlags() const
  529. {
  530. return (roxiemem::RoxieHeapFlags)heapFlags;
  531. }
  532. };
  533. class CRoxieServerMultiInputInfo
  534. {
  535. private:
  536. UnsignedArray inputs;
  537. UnsignedArray inputIndexes;
  538. public:
  539. void set(unsigned idx, unsigned source, unsigned sourceidx)
  540. {
  541. if (idx==inputs.length())
  542. {
  543. inputs.append(source);
  544. inputIndexes.append(sourceidx);
  545. }
  546. else
  547. {
  548. while (!inputs.isItem(idx))
  549. {
  550. inputs.append(0);
  551. inputIndexes.append(0);
  552. }
  553. inputs.replace(source, idx);
  554. inputIndexes.replace(sourceidx, idx);
  555. }
  556. }
  557. unsigned get(unsigned idx, unsigned &sourceidx) const
  558. {
  559. if (inputs.isItem(idx))
  560. {
  561. sourceidx = inputIndexes.item(idx);
  562. return inputs.item(idx);
  563. }
  564. else
  565. return (unsigned) -1;
  566. }
  567. inline unsigned ordinality() const { return inputs.ordinality(); }
  568. };
  569. class CRoxieServerMultiInputFactory : public CRoxieServerActivityFactoryBase
  570. {
  571. private:
  572. CRoxieServerMultiInputInfo inputs;
  573. public:
  574. CRoxieServerMultiInputFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  575. : CRoxieServerActivityFactoryBase(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  576. {
  577. }
  578. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  579. {
  580. inputs.set(idx, source, sourceidx);
  581. }
  582. virtual unsigned getInput(unsigned idx, unsigned &sourceidx) const
  583. {
  584. return inputs.get(idx, sourceidx);
  585. }
  586. virtual unsigned numInputs() const { return inputs.ordinality(); }
  587. };
  588. class DECL_EXCEPTION CWrappedException : implements IException, public CInterface
  589. {
  590. Owned<IException> wrapped;
  591. ThorActivityKind kind;
  592. unsigned queryId;
  593. public:
  594. IMPLEMENT_IINTERFACE;
  595. CWrappedException(IException *_wrapped, ThorActivityKind _kind, unsigned _queryId)
  596. : wrapped(_wrapped), kind(_kind), queryId(_queryId)
  597. {
  598. }
  599. virtual int errorCode() const { return wrapped->errorCode(); }
  600. virtual StringBuffer & errorMessage(StringBuffer &msg) const { return wrapped->errorMessage(msg).appendf(" (in %s %d)", getActivityText(kind), queryId); }
  601. virtual MessageAudience errorAudience() const { return wrapped->errorAudience(); }
  602. };
  603. class CRoxieServerActivityFactory : public CRoxieServerActivityFactoryBase
  604. {
  605. protected:
  606. unsigned input;
  607. unsigned inputidx;
  608. public:
  609. CRoxieServerActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  610. : CRoxieServerActivityFactoryBase(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  611. {
  612. input = (unsigned) -1;
  613. inputidx = 0;
  614. }
  615. inline void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  616. {
  617. if (idx != 0)
  618. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: id = %d : setInput() parameter out of bounds idx = %d at %s(%d)", id, idx, sanitizeSourceFile(__FILE__), __LINE__);
  619. if (input != -1)
  620. 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, sanitizeSourceFile(__FILE__), __LINE__);
  621. input = source;
  622. inputidx = sourceidx;
  623. }
  624. virtual unsigned getInput(unsigned idx, unsigned &sourceidx) const
  625. {
  626. if (!idx)
  627. {
  628. sourceidx = inputidx;
  629. return input;
  630. }
  631. return (unsigned) -1;
  632. }
  633. virtual unsigned numInputs() const { return (input == (unsigned)-1) ? 0 : 1; }
  634. };
  635. class CRoxieServerMultiOutputFactory : public CRoxieServerActivityFactory
  636. {
  637. protected:
  638. unsigned numOutputs = 0;
  639. RelaxedAtomic<__int64> *processedArray = nullptr;
  640. RelaxedAtomic<__int64> *startedArray = nullptr;
  641. CRoxieServerMultiOutputFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  642. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  643. {
  644. }
  645. ~CRoxieServerMultiOutputFactory()
  646. {
  647. delete [] processedArray;
  648. delete [] startedArray;
  649. }
  650. void setNumOutputs(unsigned num)
  651. {
  652. numOutputs = num;
  653. if (!num)
  654. num = 1; // Even sink activities like to track how many records they process
  655. processedArray = new RelaxedAtomic<__int64>[num];
  656. startedArray = new RelaxedAtomic<__int64>[num];
  657. for (unsigned i = 0; i < num; i++)
  658. {
  659. processedArray[i] = 0;
  660. startedArray[i] = 0;
  661. }
  662. }
  663. virtual void getEdgeProgressInfo(unsigned idx, IPropertyTree &edge) const
  664. {
  665. assertex(numOutputs ? idx < numOutputs : idx==0);
  666. putStatsValue(&edge, "count", "sum", processedArray[idx]);
  667. putStatsValue(&edge, "started", "sum", startedArray[idx]);
  668. }
  669. virtual void resetNodeProgressInfo()
  670. {
  671. CRoxieServerActivityFactory::resetNodeProgressInfo();
  672. for (unsigned i = 0; i < numOutputs; i++)
  673. {
  674. processedArray[i] = 0;
  675. startedArray[i] = 0;
  676. }
  677. }
  678. virtual void noteProcessed(unsigned idx, unsigned _processed) const
  679. {
  680. assertex(numOutputs ? idx < numOutputs : idx==0);
  681. processedArray[idx] += _processed;
  682. }
  683. virtual void noteStarted(unsigned idx) const
  684. {
  685. assertex(numOutputs ? idx < numOutputs : idx==0);
  686. startedArray[idx]++;
  687. }
  688. };
  689. class CRoxieServerInternalSinkFactory : public CRoxieServerActivityFactory
  690. {
  691. protected:
  692. bool isInternal;
  693. bool isRoot;
  694. unsigned usageCount;
  695. public:
  696. CRoxieServerInternalSinkFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned _usageCount, bool _isRoot)
  697. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  698. {
  699. usageCount = _usageCount;
  700. isRoot = _isRoot;
  701. isInternal = false; // filled in by derived class constructor
  702. }
  703. virtual bool isSink() const
  704. {
  705. //only a sink if a root activity
  706. 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?
  707. }
  708. virtual void getEdgeProgressInfo(unsigned idx, IPropertyTree &edge) const
  709. {
  710. // 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
  711. // Just leave it blank is safest.
  712. }
  713. };
  714. typedef enum { STATEreset, STATEstarted, STATEstopped, STATEstarting } activityState;
  715. const char *queryStateText(activityState state)
  716. {
  717. switch (state)
  718. {
  719. case STATEreset: return "reset";
  720. case STATEstarted: return "started";
  721. case STATEstopped: return "stopped";
  722. case STATEstarting: return "starting";
  723. default: return "unknown";
  724. }
  725. }
  726. typedef ICopyArrayOf<IRoxieServerActivity> IRoxieServerActivityCopyArray;
  727. class CParallelActivityExecutor : public CAsyncFor
  728. {
  729. public:
  730. unsigned parentExtractSize;
  731. const byte * parentExtract;
  732. CParallelActivityExecutor(IRoxieServerActivityCopyArray & _activities, unsigned _parentExtractSize, const byte * _parentExtract) :
  733. activities(_activities), parentExtractSize(_parentExtractSize), parentExtract(_parentExtract) { }
  734. void Do(unsigned i)
  735. {
  736. activities.item(i).execute(parentExtractSize, parentExtract);
  737. }
  738. private:
  739. IRoxieServerActivityCopyArray & activities;
  740. };
  741. extern IEngineRowStream * ensureSingleStream(IRoxieSlaveContext *ctx, PointerArrayOf<IEngineRowStream> & instreams, Owned<IStrandJunction> &junction)
  742. {
  743. if (instreams.length() != 1)
  744. {
  745. assertex(instreams.length());
  746. if (!junction)
  747. junction.setown(createStrandJunction(ctx->queryRowManager(), instreams.length(), 1, ctx->queryOptions().strandBlockSize, false));
  748. ForEachItemIn(stream, instreams)
  749. {
  750. junction->setInput(stream, instreams.item(stream));
  751. }
  752. return junction->queryOutput(0);
  753. }
  754. else
  755. return instreams.item(0);
  756. }
  757. extern IEngineRowStream *connectSingleStream(IRoxieSlaveContext *ctx, IFinalRoxieInput *input, unsigned idx, Owned<IStrandJunction> &junction, bool consumerOrdered)
  758. {
  759. if (input)
  760. {
  761. PointerArrayOf<IEngineRowStream> instreams;
  762. junction.setown(input->getOutputStreams(ctx, idx, instreams, NULL, consumerOrdered, nullptr));
  763. return ensureSingleStream(ctx, instreams, junction);
  764. }
  765. else
  766. return NULL;
  767. }
  768. extern IEngineRowStream *connectSingleStream(IRoxieSlaveContext *ctx, IFinalRoxieInput *input, unsigned idx, bool consumerOrdered)
  769. {
  770. Owned<IStrandJunction> junction;
  771. IEngineRowStream * result = connectSingleStream(ctx, input, idx, junction, consumerOrdered);
  772. assertex(!junction);
  773. return result;
  774. }
  775. class CRoxieServerActivity : implements CInterfaceOf<IRoxieServerActivity>, implements IFinalRoxieInput, implements IEngineRowStream, implements IRoxieContextLogger
  776. {
  777. friend class StrandProcessor;
  778. protected:
  779. IFinalRoxieInput *input;
  780. unsigned sourceIdx;
  781. IEngineRowStream *inputStream;
  782. Owned<IStrandJunction> junction;
  783. IHThorArg &basehelper;
  784. IRoxieSlaveContext *ctx;
  785. class InterceptRegisterTimer : public IndirectCodeContext
  786. {
  787. public:
  788. InterceptRegisterTimer(CRoxieServerActivity &_activity) : activity(_activity) {}
  789. virtual ISectionTimer *registerTimer(unsigned activityId, const char * name)
  790. {
  791. if (activityId == activity.queryId())
  792. return activity.registerTimer(activityId, name);
  793. else
  794. return ctx->registerTimer(activityId, name);
  795. }
  796. private:
  797. CRoxieServerActivity &activity;
  798. } interceptedCtx;
  799. const IRoxieServerActivityFactory *factory;
  800. IRoxieServerActivityCopyArray dependencies;
  801. IntArray dependencyIndexes;
  802. IntArray dependencyControlIds;
  803. IArrayOf<IActivityGraph> childGraphs;
  804. CachedOutputMetaData meta;
  805. IHThorArg *colocalParent;
  806. IEngineRowAllocator *rowAllocator;
  807. CriticalSection statecrit;
  808. CriticalSection statscrit;
  809. mutable CRuntimeStatisticCollection stats;
  810. MapStringToMyClass<ThorSectionTimer> functionTimers;
  811. unsigned processed;
  812. ActivityTimeAccumulator totalCycles;
  813. unsigned activityId;
  814. activityState state;
  815. bool createPending;
  816. bool debugging;
  817. bool timeActivities;
  818. bool aborted;
  819. bool connected = false;
  820. IProbeManager *probeManager = NULL;
  821. public:
  822. IMPLEMENT_IINTERFACE_USING(CInterfaceOf<IRoxieServerActivity>)
  823. CRoxieServerActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  824. : ctx(_ctx),
  825. interceptedCtx(*this),
  826. factory(_factory),
  827. basehelper(_factory->getHelper()),
  828. activityId(_factory->queryId()),
  829. stats(_factory->queryStatsMapping()),
  830. probeManager(_probeManager)
  831. {
  832. input = NULL;
  833. sourceIdx = 0;
  834. inputStream = NULL;
  835. meta.set(basehelper.queryOutputMeta());
  836. processed = 0;
  837. state=STATEreset;
  838. rowAllocator = NULL;
  839. debugging = _probeManager != NULL; // Don't want to collect timing stats from debug sessions
  840. colocalParent = NULL;
  841. createPending = true;
  842. timeActivities = defaultTimeActivities;
  843. aborted = false;
  844. }
  845. CRoxieServerActivity(IRoxieSlaveContext *_ctx, IHThorArg & _helper)
  846. : ctx(_ctx),
  847. interceptedCtx(*this),
  848. factory(NULL), basehelper(_helper), stats(allStatistics)
  849. {
  850. activityId = 0;
  851. input = NULL;
  852. sourceIdx = 0;
  853. inputStream = NULL;
  854. ctx = NULL;
  855. meta.set(basehelper.queryOutputMeta());
  856. processed = 0;
  857. state=STATEreset;
  858. rowAllocator = NULL;
  859. debugging = false;
  860. colocalParent = NULL;
  861. createPending = true;
  862. timeActivities = defaultTimeActivities;
  863. aborted = false;
  864. }
  865. ~CRoxieServerActivity()
  866. {
  867. basehelper.Release();
  868. ::Release(rowAllocator);
  869. }
  870. virtual void beforeDispose() override
  871. {
  872. if (traceStartStop)
  873. {
  874. // There was an old comment here stating // Note- CTXLOG may not be safe
  875. // There were problems in the destruction order of graphs that might mean an IndirectSlaveContext
  876. // was released while activities still referenced it.
  877. // However these should now all be fixed
  878. DBGLOG("%p destroy %d state=%s", this, activityId, queryStateText(state));
  879. if (watchActivityId && watchActivityId==activityId)
  880. {
  881. DBGLOG("WATCH: %p destroy %d state=%s", this, activityId, queryStateText(state));
  882. }
  883. }
  884. if (state!=STATEreset)
  885. {
  886. DBGLOG("STATE: Activity %d destroyed but not reset", activityId);
  887. state = STATEreset; // bit pointless but there you go...
  888. }
  889. }
  890. virtual void updateFactoryStatistics() const override
  891. {
  892. CRuntimeStatisticCollection mergedStats(stats.queryMapping());
  893. gatherStats(mergedStats);
  894. if (factory && !debugging)
  895. {
  896. if (processed)
  897. factory->noteProcessed(0, processed);
  898. factory->mergeStats(mergedStats);
  899. }
  900. if (ctx && factory)
  901. {
  902. if (processed)
  903. ctx->noteProcessed(factory->querySubgraphId(), activityId, 0, processed, 0);
  904. ctx->mergeActivityStats(mergedStats, factory->querySubgraphId(), activityId);
  905. }
  906. ForEachItemIn(i, childGraphs)
  907. childGraphs.item(i).updateFactoryStatistics();
  908. }
  909. virtual const IRoxieContextLogger &queryLogCtx()const
  910. {
  911. return *this;
  912. }
  913. inline const StatisticsMapping & queryStatsMapping() const
  914. {
  915. return factory ? factory->queryStatsMapping() : actStatistics;
  916. }
  917. virtual void mergeStats(MemoryBuffer &buf)
  918. {
  919. stats.deserializeMerge(buf);
  920. }
  921. virtual ISectionTimer *registerTimer(unsigned _activityId, const char * name)
  922. {
  923. CriticalBlock b(statscrit); // reuse statscrit to protect functionTimers - it will not be held concurrently
  924. ISectionTimer *timer = functionTimers.getValue(name);
  925. if (!timer)
  926. {
  927. timer = ThorSectionTimer::createTimer(stats, name);
  928. functionTimers.setValue(name, timer);
  929. timer->Release(); // Value returned is not linked
  930. }
  931. return timer;
  932. }
  933. void mergeStrandStats(unsigned strandProcessed, const ActivityTimeAccumulator & strandCycles)
  934. {
  935. CriticalBlock cb(statscrit);
  936. processed += strandProcessed;
  937. totalCycles.merge(strandCycles);
  938. }
  939. inline void ensureRowAllocator()
  940. {
  941. if (!rowAllocator)
  942. rowAllocator = createRowAllocator(meta.queryOriginal());
  943. }
  944. virtual IEngineRowAllocator * createRowAllocator(IOutputMetaData * metadata)
  945. {
  946. return ctx->getRowAllocatorEx(metadata, activityId, factory->getHeapFlags());
  947. }
  948. virtual IEngineRowAllocator * createRowAllocatorEx(IOutputMetaData * metadata, roxiemem::RoxieHeapFlags extraFlags)
  949. {
  950. return ctx->getRowAllocatorEx(metadata, activityId, (roxiemem::RoxieHeapFlags)(factory->getHeapFlags()|extraFlags));
  951. }
  952. inline ICodeContext *queryCodeContext()
  953. {
  954. return ctx->queryCodeContext();
  955. }
  956. // MORE - most of this is copied from ccd.hpp - can't we refactor?
  957. virtual void CTXLOGa(TracingCategory category, const char *prefix, const char *text) const
  958. {
  959. if (ctx)
  960. ctx->CTXLOGa(category, prefix, text);
  961. else
  962. DBGLOG("[%s] %s", prefix, text);
  963. }
  964. virtual void CTXLOGaeva(IException *E, const char *file, unsigned line, const char *prefix, const char *format, va_list args) const __attribute__((format(printf,6,0)))
  965. {
  966. if (ctx)
  967. ctx->CTXLOGaeva(E, file, line, prefix, format, args);
  968. else
  969. {
  970. StringBuffer ss;
  971. ss.appendf("[%s] ERROR", prefix);
  972. if (E)
  973. ss.append(": ").append(E->errorCode());
  974. if (file)
  975. ss.appendf(": %s(%d) ", file, line);
  976. if (E)
  977. E->errorMessage(ss.append(": "));
  978. if (format)
  979. {
  980. ss.append(": ").valist_appendf(format, args);
  981. }
  982. LOG(MCoperatorProgress, unknownJob, "%s", ss.str());
  983. }
  984. }
  985. virtual void CTXLOGl(LogItem *log) const
  986. {
  987. if (ctx)
  988. ctx->CTXLOGl(log);
  989. else
  990. {
  991. assert(ctx);
  992. log->Release(); // Should never happen
  993. }
  994. }
  995. virtual void noteStatistic(StatisticKind kind, unsigned __int64 value) const
  996. {
  997. stats.addStatistic(kind, value);
  998. }
  999. virtual void mergeStats(const CRuntimeStatisticCollection &from) const
  1000. {
  1001. stats.merge(from);
  1002. }
  1003. virtual void gatherStats(CRuntimeStatisticCollection & merged) const override
  1004. {
  1005. merged.merge(stats);
  1006. if (rowAllocator)
  1007. rowAllocator->gatherStats(merged);
  1008. totalCycles.addStatistics(merged);
  1009. merged.mergeStatistic(StCycleLocalExecuteCycles, queryLocalCycles());
  1010. }
  1011. virtual StringBuffer &getLogPrefix(StringBuffer &ret) const
  1012. {
  1013. if (ctx)
  1014. ctx->getLogPrefix(ret);
  1015. return ret.append('@').append(activityId);
  1016. }
  1017. virtual bool isIntercepted() const
  1018. {
  1019. return ctx ? ctx->isIntercepted() : false;
  1020. }
  1021. virtual bool isBlind() const
  1022. {
  1023. return ctx ? ctx->isBlind() : blindLogging;
  1024. }
  1025. virtual unsigned queryTraceLevel() const
  1026. {
  1027. if (ctx)
  1028. return ctx->queryTraceLevel();
  1029. else
  1030. return traceLevel;
  1031. }
  1032. virtual bool isPassThrough()
  1033. {
  1034. return false;
  1035. }
  1036. virtual const IResolvedFile *resolveLFN(const char *filename, bool isOpt)
  1037. {
  1038. return ctx->resolveLFN(filename, isOpt);
  1039. }
  1040. virtual const IResolvedFile *queryVarFileInfo() const
  1041. {
  1042. throwUnexpected(); // should be implemented in more derived class by anyone that has a remote adaptor
  1043. return NULL;
  1044. }
  1045. virtual void serializeSkipInfo(MemoryBuffer &out, unsigned seekLen, const void *rawSeek, unsigned numFields, const void * seek, const SmartStepExtra &stepExtra) const
  1046. {
  1047. throwUnexpected(); // should be implemented in more derived class wherever needed
  1048. }
  1049. virtual IRoxieSlaveContext *queryContext()
  1050. {
  1051. return ctx;
  1052. }
  1053. virtual IEngineRowStream *queryConcreteOutputStream(unsigned whichInput) { assertex(whichInput==0); return this; }
  1054. virtual IStrandJunction *queryConcreteOutputJunction(unsigned idx) const { assertex(idx==0); return junction; }
  1055. virtual IRoxieServerActivity *queryActivity() { return this; }
  1056. virtual IIndexReadActivityInfo *queryIndexReadActivity() { return NULL; }
  1057. virtual bool needsAllocator() const { return false; }
  1058. void _onCreate(IHThorArg *_colocalParent, unsigned _numParallel)
  1059. {
  1060. colocalParent = _colocalParent;
  1061. createPending = true;
  1062. if (needsAllocator())
  1063. ensureRowAllocator();
  1064. processed = 0;
  1065. if (factory)
  1066. factory->onCreateChildQueries(ctx, &basehelper, childGraphs, this, probeManager, *this, _numParallel);
  1067. if (ctx)
  1068. timeActivities = ctx->queryOptions().timeActivities;
  1069. }
  1070. virtual void onCreate(IHThorArg *_colocalParent)
  1071. {
  1072. _onCreate(_colocalParent, 1);
  1073. }
  1074. virtual void serializeCreateStartContext(MemoryBuffer &out)
  1075. {
  1076. //This should only be called after onStart has been called on the helper
  1077. assertex(!createPending);
  1078. assertex(state==STATEstarted);
  1079. unsigned startlen = out.length();
  1080. basehelper.serializeCreateContext(out);
  1081. basehelper.serializeStartContext(out);
  1082. if (queryTraceLevel() > 10)
  1083. CTXLOG("serializeCreateStartContext for %d added %d bytes", activityId, out.length()-startlen);
  1084. }
  1085. virtual void serializeExtra(MemoryBuffer &out) {}
  1086. inline void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  1087. {
  1088. CriticalBlock cb(statecrit);
  1089. if (state != STATEreset && state != STATEstarting)
  1090. {
  1091. CTXLOG("STATE: Expected state to be reset, but was %s, in activity %d", queryStateText(state), activityId);
  1092. }
  1093. state=STATEstarted;
  1094. #ifdef TRACE_STARTSTOP
  1095. if (traceStartStop)
  1096. {
  1097. CTXLOG("start %p %d", this, activityId);
  1098. if (watchActivityId && watchActivityId==activityId)
  1099. {
  1100. CTXLOG("WATCH: start %p %d", this, activityId);
  1101. }
  1102. }
  1103. #endif
  1104. executeDependencies(parentExtractSize, parentExtract, 0);
  1105. if (input)
  1106. input->start(parentExtractSize, parentExtract, paused);
  1107. ensureCreated();
  1108. basehelper.onStart(parentExtract, NULL);
  1109. if (factory)
  1110. factory->noteStarted();
  1111. startJunction(junction);
  1112. }
  1113. void executeDependencies(unsigned parentExtractSize, const byte *parentExtract, unsigned controlId)
  1114. {
  1115. //MORE: Create a filtered list and then use asyncfor
  1116. ForEachItemIn(idx, dependencies)
  1117. {
  1118. if (dependencyControlIds.item(idx) == controlId)
  1119. dependencies.item(idx).execute(parentExtractSize, parentExtract);
  1120. }
  1121. }
  1122. void stopDependencies(unsigned parentExtractSize, const byte *parentExtract, unsigned controlId)
  1123. {
  1124. ForEachItemIn(idx, dependencies)
  1125. {
  1126. if (dependencyControlIds.item(idx) == controlId)
  1127. dependencies.item(idx).stop();
  1128. }
  1129. }
  1130. virtual unsigned __int64 queryTotalCycles() const
  1131. {
  1132. return totalCycles.totalCycles;
  1133. }
  1134. virtual unsigned __int64 queryLocalCycles() const
  1135. {
  1136. __int64 ret = totalCycles.totalCycles;
  1137. if (input) ret -= input->queryTotalCycles();
  1138. if (ret < 0)
  1139. ret = 0;
  1140. return ret;
  1141. }
  1142. virtual IFinalRoxieInput *queryInput(unsigned idx) const
  1143. {
  1144. if (idx==0)
  1145. return input;
  1146. else
  1147. return NULL;
  1148. }
  1149. inline void ensureCreated()
  1150. {
  1151. if (createPending)
  1152. {
  1153. createPending = false;
  1154. interceptedCtx.set(ctx->queryCodeContext());
  1155. basehelper.onCreate(&interceptedCtx, colocalParent, NULL);
  1156. }
  1157. }
  1158. virtual void stop()
  1159. {
  1160. // NOTE - don't be tempted to skip the stop for activities that are reset - splitters need to see the stops
  1161. if (state != STATEstopped)
  1162. {
  1163. CriticalBlock cb(statecrit);
  1164. if (state != STATEstopped)
  1165. {
  1166. #ifdef TRACE_STARTSTOP
  1167. if (traceStartStop)
  1168. {
  1169. CTXLOG("stop %p %d (state currently %s)", this, activityId, queryStateText(state));
  1170. if (watchActivityId && watchActivityId==activityId)
  1171. {
  1172. CTXLOG("WATCH: stop %p %d", this, activityId);
  1173. }
  1174. }
  1175. #endif
  1176. state=STATEstopped;
  1177. // NOTE - this is needed to ensure that dependencies which were not used are properly stopped
  1178. ForEachItemIn(idx, dependencies)
  1179. {
  1180. if (dependencyControlIds.item(idx) == 0)
  1181. dependencies.item(idx).stopSink(dependencyIndexes.item(idx));
  1182. }
  1183. if (inputStream)
  1184. inputStream->stop();
  1185. }
  1186. }
  1187. }
  1188. virtual void abort()
  1189. {
  1190. aborted = true;
  1191. // MORE - should abort dependencies here?
  1192. stop();
  1193. }
  1194. inline void reset()
  1195. {
  1196. if (state != STATEreset)
  1197. {
  1198. CriticalBlock cb(statecrit);
  1199. if (state != STATEreset)
  1200. {
  1201. if (state==STATEstarted || state==STATEstarting)
  1202. {
  1203. if (ctx->queryOptions().failOnLeaks)
  1204. throw makeStringExceptionV(ROXIE_INTERNAL_ERROR, "STATE: activity %d reset without stop", activityId);
  1205. if (traceStartStop || traceLevel > 2)
  1206. CTXLOG("STATE: activity %d reset without stop", activityId);
  1207. stop();
  1208. }
  1209. state = STATEreset;
  1210. #ifdef TRACE_STARTSTOP
  1211. if (traceStartStop)
  1212. {
  1213. CTXLOG("reset %p %d", this, activityId);
  1214. if (watchActivityId && watchActivityId==activityId)
  1215. {
  1216. CTXLOG("WATCH: reset %p %d", this, activityId);
  1217. }
  1218. }
  1219. #endif
  1220. resetJunction(junction);
  1221. ForEachItemIn(idx, dependencies)
  1222. dependencies.item(idx).reset();
  1223. if (input)
  1224. input->reset();
  1225. }
  1226. }
  1227. aborted = false;
  1228. }
  1229. virtual void addDependency(IRoxieServerActivity &source, unsigned sourceIdx, int controlId)
  1230. {
  1231. dependencies.append(source);
  1232. dependencyIndexes.append(sourceIdx);
  1233. dependencyControlIds.append(controlId);
  1234. }
  1235. virtual void resetEOF()
  1236. {
  1237. //would make more sense if the default implementation (and eof member) were in the base class
  1238. }
  1239. // Sink activities should override this....
  1240. virtual void execute(unsigned parentExtractSize, const byte * parentExtract)
  1241. {
  1242. throw MakeStringException(ROXIE_SINK, "Internal error: execute() requires a sink");
  1243. }
  1244. virtual void executeChild(size32_t & retSize, void * & ret, unsigned parentExtractSize, const byte * parentExtract)
  1245. {
  1246. throw MakeStringException(ROXIE_SINK, "Internal error: executeChild() requires a suitable sink");
  1247. }
  1248. virtual void stopSink(unsigned idx)
  1249. {
  1250. throw MakeStringException(ROXIE_SINK, "Internal error: stopSink() requires a suitable sink");
  1251. }
  1252. virtual void connectInputStreams(bool consumerOrdered)
  1253. {
  1254. if (input && !inputStream)
  1255. inputStream = connectSingleStream(ctx, input, sourceIdx, junction, isInputOrdered(consumerOrdered, 0));
  1256. if (!connected)
  1257. {
  1258. connectDependencies();
  1259. connected = true;
  1260. }
  1261. }
  1262. void connectDependencies()
  1263. {
  1264. ForEachItemIn(i, dependencies)
  1265. dependencies.item(i).connectInputStreams(true);
  1266. }
  1267. virtual __int64 evaluate()
  1268. {
  1269. throw MakeStringException(ROXIE_SINK, "Internal error: evaluate() requires a function");
  1270. }
  1271. virtual IFinalRoxieInput * querySelectOutput(unsigned id)
  1272. {
  1273. return NULL;
  1274. }
  1275. virtual bool querySetStreamInput(unsigned id, unsigned _sourceIdx, IFinalRoxieInput * _input)
  1276. {
  1277. return false;
  1278. }
  1279. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  1280. {
  1281. assertex(!idx);
  1282. input = _in;
  1283. sourceIdx = _sourceIdx;
  1284. inputStream = NULL;
  1285. }
  1286. bool isInputOrdered(bool consumerOrdered, unsigned idx) const
  1287. {
  1288. if (!factory)
  1289. return true;
  1290. //Grouping implies the stream processing must be ordered - I think this always applies
  1291. IFinalRoxieInput * curInput = queryInput(idx);
  1292. if (curInput && curInput->queryOutputMeta()->isGrouped())
  1293. return true;
  1294. return factory->isInputOrdered(consumerOrdered, idx);
  1295. }
  1296. virtual IStrandJunction *getOutputStreams(IRoxieSlaveContext *ctx, unsigned idx, PointerArrayOf<IEngineRowStream> &streams, const StrandOptions * consumerOptions, bool consumerOrdered, IOrderedCallbackCollection * orderedCallbacks)
  1297. {
  1298. assertex(!idx);
  1299. // By default, activities are assumed NOT to support streams
  1300. bool inputOrdered = isInputOrdered(consumerOrdered, 0);
  1301. connectInputStreams(inputOrdered);
  1302. // Return a single stream
  1303. streams.append(this);
  1304. return NULL;
  1305. }
  1306. virtual IFinalRoxieInput *queryOutput(unsigned idx)
  1307. {
  1308. if (idx == (unsigned) -1)
  1309. idx = 0;
  1310. return idx ? NULL : this;
  1311. }
  1312. virtual IOutputMetaData *queryOutputMeta() const
  1313. {
  1314. return meta.queryOriginal();
  1315. }
  1316. virtual unsigned queryId() const
  1317. {
  1318. return activityId;
  1319. }
  1320. virtual unsigned querySubgraphId() const
  1321. {
  1322. return factory->querySubgraphId();
  1323. }
  1324. virtual void checkAbort()
  1325. {
  1326. ctx->checkAbort();
  1327. }
  1328. IException *makeWrappedException(IException *e)
  1329. {
  1330. StringBuffer msg;
  1331. ThorActivityKind activityKind = factory ? factory->getKind() : TAKnone;
  1332. CTXLOG("makeWrappedException - %s (in %s %d)", e->errorMessage(msg).str(), getActivityText(activityKind), activityId);
  1333. if (QUERYINTERFACE(e, CWrappedException) || QUERYINTERFACE(e, IUserException))
  1334. return e;
  1335. else
  1336. return new CWrappedException(e, activityKind, activityId);
  1337. }
  1338. virtual void gatherIterationUsage(IRoxieServerLoopResultProcessor & processor, unsigned parentExtractSize, const byte * parentExtract)
  1339. {
  1340. }
  1341. virtual void associateIterationOutputs(IRoxieServerLoopResultProcessor & processor, unsigned parentExtractSize, const byte * parentExtract, IProbeManager *probeManager, IArrayOf<IRoxieProbe> &probes)
  1342. {
  1343. }
  1344. virtual void resetOutputsUsed()
  1345. {
  1346. }
  1347. virtual void noteOutputUsed()
  1348. {
  1349. }
  1350. virtual IRoxieServerSideCache *queryServerSideCache() const
  1351. {
  1352. return factory->queryServerSideCache();
  1353. }
  1354. virtual const IRoxieServerActivityFactory *queryFactory() const
  1355. {
  1356. return factory;
  1357. }
  1358. inline ThorActivityKind getKind() const
  1359. {
  1360. return factory->getKind();
  1361. }
  1362. inline bool isSink() const
  1363. {
  1364. return (factory != NULL) && factory->isSink();
  1365. }
  1366. };
  1367. //=====================================================================================================
  1368. class CRoxieServerLateStartActivity : public CRoxieServerActivity
  1369. {
  1370. protected:
  1371. bool prefiltered;
  1372. bool eof;
  1373. void lateStart(unsigned parentExtractSize, const byte *parentExtract, bool any)
  1374. {
  1375. prefiltered = !any;
  1376. eof = prefiltered;
  1377. if (!prefiltered)
  1378. {
  1379. input->start(parentExtractSize, parentExtract, false);
  1380. startJunction(junction);
  1381. }
  1382. else
  1383. {
  1384. if (traceStartStop)
  1385. CTXLOG("lateStart activity stopping input early as prefiltered");
  1386. inputStream->stop();
  1387. }
  1388. }
  1389. public:
  1390. CRoxieServerLateStartActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  1391. : CRoxieServerActivity(_ctx, _factory, _probeManager)
  1392. {
  1393. prefiltered = false;
  1394. eof = false;
  1395. }
  1396. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  1397. {
  1398. IFinalRoxieInput *saveInput = input;
  1399. Owned<IStrandJunction> saveJunction = junction.getClear();
  1400. input = NULL; // Make sure parent does not start the chain yet
  1401. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  1402. input = saveInput;
  1403. junction.setown(saveJunction.getClear());
  1404. }
  1405. virtual void stop()
  1406. {
  1407. if (!prefiltered)
  1408. {
  1409. inputStream->stop();
  1410. }
  1411. else if (traceStartStop)
  1412. CTXLOG("lateStart activity NOT stopping input late as prefiltered");
  1413. IEngineRowStream *save = inputStream;
  1414. inputStream = NULL; // We already stopped inputStream - prevent parent from doing so again
  1415. CRoxieServerActivity::stop();
  1416. inputStream = save;
  1417. }
  1418. virtual void reset()
  1419. {
  1420. CRoxieServerActivity::reset();
  1421. prefiltered = false;
  1422. }
  1423. };
  1424. //=================================================================================
  1425. class StrandOptions
  1426. {
  1427. // Typically set from hints, common to many stranded activities
  1428. public:
  1429. explicit StrandOptions(IPropertyTree &_graphNode)
  1430. {
  1431. //PARALLEL(1) can be used to explicitly disable parallel processing.
  1432. numStrands = _graphNode.getPropInt("att[@name='parallel']/@value", 0);
  1433. if ((numStrands == minus1U) || (numStrands > MAX_SENSIBLE_STRANDS))
  1434. numStrands = getAffinityCpus();
  1435. blockSize = _graphNode.getPropInt("hint[@name='strandblocksize']/@value", 0);
  1436. }
  1437. StrandOptions(const StrandOptions &from, IRoxieSlaveContext *ctx)
  1438. {
  1439. numStrands = from.numStrands;
  1440. blockSize = from.blockSize;
  1441. if (!blockSize)
  1442. blockSize = ctx->queryOptions().strandBlockSize;
  1443. if (numStrands == 0)
  1444. numStrands = ctx->queryOptions().forceNumStrands;
  1445. }
  1446. public:
  1447. unsigned numStrands = 0; // if 1 it forces single-stranded operations. (Useful for testing.)
  1448. unsigned blockSize = 0;
  1449. };
  1450. class StrandProcessor : public CInterfaceOf<IEngineRowStream>
  1451. {
  1452. protected:
  1453. CRoxieServerActivity &parent;
  1454. IEngineRowAllocator *rowAllocator;
  1455. IEngineRowStream *inputStream;
  1456. ActivityTimeAccumulator totalCycles;
  1457. mutable CRuntimeStatisticCollection stats;
  1458. unsigned processed = 0;
  1459. unsigned numProcessedLastGroup = 0;
  1460. const bool timeActivities;
  1461. bool stopped = false;
  1462. std::atomic<bool> abortRequested;
  1463. public:
  1464. explicit StrandProcessor(CRoxieServerActivity &_parent, IEngineRowStream *_inputStream, bool needsAllocator)
  1465. : parent(_parent), inputStream(_inputStream), stats(parent.queryStatsMapping()), timeActivities(_parent.timeActivities), abortRequested(false)
  1466. {
  1467. if (needsAllocator)
  1468. {
  1469. rowAllocator = parent.createRowAllocatorEx(parent.queryOutputMeta(), roxiemem::RHFunique);
  1470. }
  1471. else
  1472. rowAllocator = NULL;
  1473. }
  1474. ~StrandProcessor()
  1475. {
  1476. ::Release(rowAllocator);
  1477. }
  1478. virtual void start()
  1479. {
  1480. processed = 0;
  1481. numProcessedLastGroup = 0;
  1482. totalCycles.reset();
  1483. }
  1484. virtual void stop()
  1485. {
  1486. if (!stopped)
  1487. {
  1488. if (inputStream)
  1489. inputStream->stop();
  1490. parent.stop();
  1491. //It would be preferrable to move totalCycles (+processed?) to gatherStats(), but because of
  1492. //the way firstRow is associated with startCycles it would require an extra parameter
  1493. //which is not consistent with the other gatherStats() calls, or extra logic in the stats classes.
  1494. parent.mergeStrandStats(processed, totalCycles);
  1495. }
  1496. stopped = true;
  1497. }
  1498. virtual void reset()
  1499. {
  1500. stopped = false;
  1501. abortRequested.store(false, std::memory_order_relaxed);
  1502. }
  1503. virtual void resetEOF()
  1504. {
  1505. inputStream->resetEOF();
  1506. }
  1507. inline void requestAbort() { abortRequested.store(true, std::memory_order_relaxed); }
  1508. inline bool isAborting() { return abortRequested.load(std::memory_order_relaxed); }
  1509. void gatherStats(CRuntimeStatisticCollection & mergedStats) const
  1510. {
  1511. mergedStats.merge(stats);
  1512. if (rowAllocator)
  1513. rowAllocator->gatherStats(mergedStats);
  1514. }
  1515. };
  1516. class CRoxieServerStrandedActivity : public CRoxieServerActivity
  1517. {
  1518. protected:
  1519. StrandOptions strandOptions;
  1520. IArrayOf<StrandProcessor> strands;
  1521. Owned<IStrandBranch> branch;
  1522. Owned<IStrandJunction> splitter;
  1523. Owned<IStrandJunction> sourceJunction; // A junction applied to the output of a source activity
  1524. std::atomic<unsigned> active;
  1525. public:
  1526. CRoxieServerStrandedActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const StrandOptions &_strandOptions)
  1527. : CRoxieServerActivity(_ctx, _factory, _probeManager),
  1528. strandOptions(_strandOptions, ctx)
  1529. {
  1530. active = 0;
  1531. }
  1532. ~CRoxieServerStrandedActivity()
  1533. {
  1534. if (strands.ordinality() > 1)
  1535. {
  1536. if (factory && !debugging)
  1537. factory->noteProcessed(0, processed);
  1538. if (ctx && factory)
  1539. ctx->noteProcessed(factory->querySubgraphId(), activityId, 0, processed, strands.ordinality());
  1540. processed = 0; // To avoid reprocessing in base destructor
  1541. }
  1542. }
  1543. virtual void gatherStats(CRuntimeStatisticCollection & merged) const override
  1544. {
  1545. CRoxieServerActivity::gatherStats(merged);
  1546. ForEachItemIn(i, strands)
  1547. strands.item(i).gatherStats(merged);
  1548. }
  1549. virtual void onCreate(IHThorArg *_colocalArg)
  1550. {
  1551. CRoxieServerActivity::_onCreate(_colocalArg, strands.ordinality());
  1552. }
  1553. //This function is pure (But also implemented out of line) to force the derived classes to implement it.
  1554. //After calling the base class start method, and initialising any values from the helper they must call onStartStrands(),
  1555. //this must also happen before any rows are read from the strands (e.g., by a source junction)
  1556. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused) = 0;
  1557. virtual void reset()
  1558. {
  1559. assertex(active==0);
  1560. ForEachItemIn(idx, strands)
  1561. strands.item(idx).reset();
  1562. resetJunction(splitter);
  1563. CRoxieServerActivity::reset();
  1564. resetJunction(sourceJunction);
  1565. }
  1566. virtual void stop()
  1567. {
  1568. // Called from the strands... which should ensure that stop is not called more than once per strand
  1569. //The first strand to call
  1570. if (active)
  1571. --active;
  1572. if (!active)
  1573. CRoxieServerActivity::stop();
  1574. }
  1575. void requestAbort()
  1576. {
  1577. ForEachItemIn(idx, strands)
  1578. strands.item(idx).requestAbort();
  1579. }
  1580. virtual IStrandJunction *getOutputStreams(IRoxieSlaveContext *ctx, unsigned idx, PointerArrayOf<IEngineRowStream> &streams, const StrandOptions * consumerOptions, bool consumerOrdered, IOrderedCallbackCollection * orderedCallbacks) override
  1581. {
  1582. assertex(idx == 0);
  1583. assertex(strands.empty());
  1584. CRoxieServerActivity::connectDependencies();
  1585. bool inputOrdered = isInputOrdered(consumerOrdered, idx);
  1586. //Note, numStrands == 1 is an explicit request to disable threading
  1587. if (consumerOptions && (consumerOptions->numStrands != 1) && (strandOptions.numStrands != 1))
  1588. {
  1589. //Check to see if the consumer's settings should override
  1590. if (strandOptions.numStrands == 0)
  1591. {
  1592. strandOptions.numStrands = consumerOptions->numStrands;
  1593. strandOptions.blockSize = consumerOptions->blockSize;
  1594. }
  1595. else if (consumerOptions->numStrands > strandOptions.numStrands)
  1596. {
  1597. strandOptions.numStrands = consumerOptions->numStrands;
  1598. }
  1599. }
  1600. Owned <IStrandJunction> recombiner;
  1601. if (input)
  1602. {
  1603. if (strandOptions.numStrands == 1)
  1604. {
  1605. // 1 means explicitly requested single-strand.
  1606. IEngineRowStream *instream = connectSingleStream(ctx, input, sourceIdx, junction, inputOrdered);
  1607. strands.append(*createStrandProcessor(instream));
  1608. }
  1609. else
  1610. {
  1611. PointerArrayOf<IEngineRowStream> instreams;
  1612. recombiner.setown(input->getOutputStreams(ctx, sourceIdx, instreams, &strandOptions, inputOrdered, orderedCallbacks));
  1613. if ((instreams.length() == 1) && (strandOptions.numStrands != 0)) // 0 means did not specify - we should use the strands that our upstream provides
  1614. {
  1615. assertex(recombiner == NULL);
  1616. // Create a splitter to split the input into n... and a recombiner if need to preserve sorting
  1617. if (inputOrdered)
  1618. {
  1619. branch.setown(createStrandBranch(ctx->queryRowManager(), strandOptions.numStrands, strandOptions.blockSize, true, input->queryOutputMeta()->isGrouped(), false, orderedCallbacks));
  1620. splitter.set(branch->queryInputJunction());
  1621. recombiner.set(branch->queryOutputJunction());
  1622. }
  1623. else
  1624. {
  1625. splitter.setown(createStrandJunction(ctx->queryRowManager(), 1, strandOptions.numStrands, strandOptions.blockSize, false));
  1626. }
  1627. splitter->setInput(0, instreams.item(0));
  1628. for (unsigned strandNo = 0; strandNo < strandOptions.numStrands; strandNo++)
  1629. strands.append(*createStrandProcessor(splitter->queryOutput(strandNo)));
  1630. }
  1631. else
  1632. {
  1633. // Ignore my hint and just use the width already split into...
  1634. ForEachItemIn(strandNo, instreams)
  1635. strands.append(*createStrandProcessor(instreams.item(strandNo)));
  1636. }
  1637. }
  1638. }
  1639. else
  1640. {
  1641. unsigned numStrands = strandOptions.numStrands ? strandOptions.numStrands : 1;
  1642. for (unsigned i=0; i < numStrands; i++)
  1643. strands.append(*createStrandSourceProcessor(inputOrdered));
  1644. if (inputOrdered && (numStrands > 1))
  1645. {
  1646. if (consumerOptions)
  1647. {
  1648. //If the output activities are also stranded then need to create a version of the branch
  1649. bool isGrouped = queryOutputMeta()->isGrouped();
  1650. branch.setown(createStrandBranch(ctx->queryRowManager(), strandOptions.numStrands, strandOptions.blockSize, true, isGrouped, true, orderedCallbacks));
  1651. sourceJunction.set(branch->queryInputJunction());
  1652. recombiner.set(branch->queryOutputJunction());
  1653. assertex((orderedCallbacks && !recombiner) || (!orderedCallbacks && recombiner));
  1654. //This is different from the branch above. The first "junction" has the source activity as the input, and the outputs as the result of the activity
  1655. for (unsigned strandNo = 0; strandNo < strandOptions.numStrands; strandNo++)
  1656. {
  1657. sourceJunction->setInput(strandNo, &strands.item(strandNo));
  1658. streams.append(sourceJunction->queryOutput(strandNo));
  1659. }
  1660. #ifdef TRACE_STRANDS
  1661. if (traceLevel > 2)
  1662. DBGLOG("Executing activity %u with %u strands", activityId, strands.ordinality());
  1663. #endif
  1664. return recombiner.getClear();
  1665. }
  1666. else
  1667. {
  1668. //Feeding into a non threaded activity, so create a M:1 junction to combine the source strands
  1669. recombiner.setown(createStrandJunction(ctx->queryRowManager(), numStrands, 1, strandOptions.blockSize, inputOrdered));
  1670. }
  1671. }
  1672. }
  1673. ForEachItemIn(i, strands)
  1674. streams.append(&strands.item(i));
  1675. #ifdef TRACE_STRANDS
  1676. if (traceLevel > 2)
  1677. DBGLOG("Executing activity %u with %u strands", activityId, strands.ordinality());
  1678. #endif
  1679. return recombiner.getClear();
  1680. }
  1681. virtual StrandProcessor *createStrandProcessor(IEngineRowStream *instream) = 0;
  1682. //MORE: Possibly this class should be split into two for sinks and non sinks...
  1683. virtual StrandProcessor *createStrandSourceProcessor(bool inputOrdered) = 0;
  1684. virtual const void * nextRow()
  1685. {
  1686. throwUnexpected();
  1687. }
  1688. inline unsigned numStrands() const { return strands.ordinality(); }
  1689. protected:
  1690. void onStartStrands()
  1691. {
  1692. ForEachItemIn(idx, strands)
  1693. {
  1694. strands.item(idx).start();
  1695. active++;
  1696. }
  1697. }
  1698. };
  1699. //For some reason gcc doesn't let you specify a function as pure virtual and define it at the same time.
  1700. void CRoxieServerStrandedActivity::start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  1701. {
  1702. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  1703. startJunction(splitter);
  1704. }
  1705. class CRoxieServerStrandedLateStartActivity : public CRoxieServerStrandedActivity
  1706. {
  1707. protected:
  1708. bool prefiltered;
  1709. bool eof;
  1710. void lateStart(unsigned parentExtractSize, const byte *parentExtract, bool any)
  1711. {
  1712. prefiltered = !any;
  1713. eof = prefiltered;
  1714. if (!prefiltered)
  1715. {
  1716. //At this point
  1717. input->start(parentExtractSize, parentExtract, false);
  1718. startJunction(splitter);
  1719. onStartStrands(); // Initialise the strands - the helper will have been correctly initialized by this point.
  1720. startJunction(sourceJunction);
  1721. }
  1722. else
  1723. {
  1724. if (traceStartStop)
  1725. CTXLOG("strandedLateStart activity stopping input early as prefiltered");
  1726. ForEachItemIn(idx, strands)
  1727. strands.item(idx).stop();
  1728. }
  1729. }
  1730. public:
  1731. CRoxieServerStrandedLateStartActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const StrandOptions &_strandOptions)
  1732. : CRoxieServerStrandedActivity(_ctx, _factory, _probeManager, _strandOptions)
  1733. {
  1734. prefiltered = false;
  1735. eof = false;
  1736. }
  1737. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  1738. {
  1739. IFinalRoxieInput *save = input;
  1740. input = NULL; // Make sure parent does not start the chain yet - but we do want to do the dependencies (because the decision about whether to start may depend on them)
  1741. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  1742. input = save;
  1743. }
  1744. virtual void reset()
  1745. {
  1746. CRoxieServerStrandedActivity::reset();
  1747. prefiltered = false;
  1748. }
  1749. };
  1750. //=====================================================================================================
  1751. atomic_t nextInstanceId;
  1752. extern unsigned getNextInstanceId()
  1753. {
  1754. return atomic_add_exchange(&nextInstanceId, 1)+1;
  1755. }
  1756. atomic_t nextRuid;
  1757. ruid_t getNextRuid()
  1758. {
  1759. ruid_t ret = atomic_add_exchange(&nextRuid, 1)+1;
  1760. while (ret < RUID_FIRST)
  1761. ret = atomic_add_exchange(&nextRuid, 1)+1; // ruids 0 and 1 are reserved for pings/unwanted discarder.
  1762. return ret;
  1763. }
  1764. void setStartRuid(unsigned restarts)
  1765. {
  1766. atomic_set(&nextRuid, restarts * 0x10000);
  1767. atomic_set(&nextInstanceId, restarts * 10000);
  1768. }
  1769. enum { LimitSkipErrorCode = 0, KeyedLimitSkipErrorCode = 1 };
  1770. class DECL_EXCEPTION LimitSkipException : public IException, public CInterface
  1771. {
  1772. int code;
  1773. public:
  1774. LimitSkipException(int _code) { code = _code; }
  1775. IMPLEMENT_IINTERFACE;
  1776. virtual int errorCode() const { return code; }
  1777. virtual StringBuffer & errorMessage(StringBuffer &msg) const { return msg.append("LimitSkipException"); }
  1778. virtual MessageAudience errorAudience() const { return MSGAUD_internal; }
  1779. };
  1780. IException *makeLimitSkipException(bool isKeyed)
  1781. {
  1782. // We need to make sure what we throw is IException not something derived from it....
  1783. return new LimitSkipException(isKeyed ? KeyedLimitSkipErrorCode : LimitSkipErrorCode);
  1784. }
  1785. //=================================================================================
  1786. interface IRecordPullerCallback : extends IExceptionHandler
  1787. {
  1788. virtual void processRow(const void *row) = 0;
  1789. virtual void processEOG() = 0;
  1790. virtual void processGroup(const ConstPointerArray &rows) = 0;
  1791. virtual void processDone() = 0;
  1792. };
  1793. class RecordPullerThread : public RestartableThread
  1794. {
  1795. protected:
  1796. IFinalRoxieInput *input;
  1797. Owned<IStrandJunction> junction;
  1798. unsigned sourceIdx = 0;
  1799. IEngineRowStream *inputStream;
  1800. IRecordPullerCallback *helper;
  1801. Semaphore started; // MORE: GH->RKC I'm pretty sure this can be deleted, since handled by RestartableThread
  1802. bool groupAtOnce, eof, eog;
  1803. CriticalSection crit;
  1804. public:
  1805. RecordPullerThread(bool _groupAtOnce)
  1806. : RestartableThread("RecordPullerThread"), groupAtOnce(_groupAtOnce)
  1807. {
  1808. input = NULL;
  1809. inputStream = NULL;
  1810. helper = NULL;
  1811. eof = eog = FALSE;
  1812. }
  1813. inline unsigned __int64 queryTotalCycles() const
  1814. {
  1815. return input->queryTotalCycles();
  1816. }
  1817. void setInput(IRecordPullerCallback *_helper, unsigned _sourceIdx, IFinalRoxieInput *_input)
  1818. {
  1819. helper = _helper;
  1820. input = _input;
  1821. sourceIdx = _sourceIdx;
  1822. }
  1823. IFinalRoxieInput *queryInput() const
  1824. {
  1825. return input;
  1826. }
  1827. virtual void connectInputStreams(IRoxieSlaveContext *ctx, bool consumerOrdered)
  1828. {
  1829. inputStream = connectSingleStream(ctx, input, sourceIdx, junction, consumerOrdered);
  1830. }
  1831. IEngineRowStream *queryStream() const
  1832. {
  1833. return inputStream;
  1834. }
  1835. void start(unsigned parentExtractSize, const byte *parentExtract, bool paused, unsigned preload, bool noThread, IRoxieSlaveContext *ctx)
  1836. {
  1837. eof = false;
  1838. eog = false;
  1839. input->start(parentExtractSize, parentExtract, paused);
  1840. startJunction(junction);
  1841. try
  1842. {
  1843. if (preload && !paused)
  1844. {
  1845. if (traceLevel > 4)
  1846. DBGLOG("Preload fetching first %d records", preload);
  1847. if (groupAtOnce)
  1848. pullGroups(preload);
  1849. else
  1850. pullRecords(preload);
  1851. }
  1852. if (eof)
  1853. {
  1854. if (traceLevel > 4)
  1855. DBGLOG("No need to start puller after preload");
  1856. helper->processDone();
  1857. }
  1858. else
  1859. {
  1860. if (!noThread)
  1861. {
  1862. StringBuffer logPrefix("[");
  1863. if (ctx) ctx->getLogPrefix(logPrefix);
  1864. logPrefix.append("] ");
  1865. RestartableThread::start(logPrefix);
  1866. started.wait();
  1867. }
  1868. }
  1869. }
  1870. catch (IException *e)
  1871. {
  1872. helper->fireException(e);
  1873. }
  1874. catch (...)
  1875. {
  1876. helper->fireException(MakeStringException(ROXIE_INTERNAL_ERROR, "Unexpected exception caught in RecordPullerThread::start"));
  1877. }
  1878. }
  1879. void stop()
  1880. {
  1881. if (traceStartStop)
  1882. DBGLOG("RecordPullerThread::stop");
  1883. {
  1884. 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-nextRow etc etc.
  1885. if (inputStream)
  1886. inputStream->stop();
  1887. }
  1888. RestartableThread::join();
  1889. }
  1890. void reset()
  1891. {
  1892. input->reset();
  1893. resetJunction(junction);
  1894. }
  1895. virtual int run()
  1896. {
  1897. started.signal();
  1898. try
  1899. {
  1900. if (groupAtOnce)
  1901. pullGroups((unsigned) -1);
  1902. else
  1903. pullRecords((unsigned) -1);
  1904. helper->processDone();
  1905. }
  1906. catch (IException *e)
  1907. {
  1908. helper->fireException(e);
  1909. }
  1910. catch (...)
  1911. {
  1912. helper->fireException(MakeStringException(ROXIE_INTERNAL_ERROR, "Unexpected exception caught in RecordPullerThread::run"));
  1913. }
  1914. return 0;
  1915. }
  1916. void done()
  1917. {
  1918. helper->processDone();
  1919. }
  1920. bool pullRecords(unsigned preload)
  1921. {
  1922. if (eof)
  1923. return false;
  1924. while (preload)
  1925. {
  1926. const void * row;
  1927. {
  1928. CriticalBlock c(crit); // See comments in stop for why this is needed
  1929. row = inputStream->nextRow();
  1930. }
  1931. if (row)
  1932. {
  1933. eog = false;
  1934. helper->processRow(row);
  1935. }
  1936. else if (!eog)
  1937. {
  1938. helper->processEOG();
  1939. eog = true;
  1940. }
  1941. else
  1942. {
  1943. eof = true;
  1944. return false;
  1945. }
  1946. if (preload != (unsigned) -1)
  1947. preload--;
  1948. }
  1949. return true;
  1950. }
  1951. void pullGroups(unsigned preload)
  1952. {
  1953. ConstPointerArray thisGroup;
  1954. unsigned rowsDone = 0;
  1955. while (preload && !eof)
  1956. {
  1957. const void *row;
  1958. {
  1959. CriticalBlock c(crit);
  1960. row = inputStream->nextRow();
  1961. }
  1962. if (row)
  1963. {
  1964. thisGroup.append(row);
  1965. rowsDone++;
  1966. }
  1967. else if (thisGroup.length())
  1968. {
  1969. helper->processGroup(thisGroup);
  1970. thisGroup.kill();
  1971. if (preload != (unsigned) -1)
  1972. {
  1973. if (preload > rowsDone)
  1974. preload -= rowsDone;
  1975. else
  1976. break;
  1977. }
  1978. rowsDone = 0;
  1979. }
  1980. else
  1981. {
  1982. eof = true;
  1983. break;
  1984. }
  1985. }
  1986. }
  1987. };
  1988. //=================================================================================
  1989. #define READAHEAD_SIZE 1000
  1990. // MORE - this code copied from ThreadedConcat code - may be able to common up some.
  1991. class CRoxieServerReadAheadInput : implements IEngineRowStream, implements IFinalRoxieInput, implements IRecordPullerCallback, public CInterface
  1992. {
  1993. QueueOf<const void, true> buffer;
  1994. InterruptableSemaphore ready;
  1995. InterruptableSemaphore space;
  1996. CriticalSection crit;
  1997. bool eof;
  1998. bool disabled;
  1999. IRoxieSlaveContext *ctx;
  2000. RecordPullerThread puller;
  2001. unsigned preload;
  2002. cycle_t totalCycles;
  2003. bool timeActivities;
  2004. public:
  2005. IMPLEMENT_IINTERFACE;
  2006. CRoxieServerReadAheadInput(IRoxieSlaveContext *_ctx, unsigned _preload) : ctx(_ctx), puller(true), preload(_preload)
  2007. {
  2008. eof = false;
  2009. disabled = (ctx->queryDebugContext() != NULL);
  2010. totalCycles = 0;
  2011. timeActivities = ctx->queryOptions().timeActivities;
  2012. }
  2013. virtual IRoxieServerActivity *queryActivity()
  2014. {
  2015. return puller.queryInput()->queryActivity();
  2016. }
  2017. virtual IStrandJunction *getOutputStreams(IRoxieSlaveContext *ctx, unsigned idx, PointerArrayOf<IEngineRowStream> &streams, const StrandOptions * consumerOptions, bool consumerOrdered, IOrderedCallbackCollection * orderedCallbacks) override
  2018. {
  2019. assertex(!idx);
  2020. puller.connectInputStreams(ctx, consumerOrdered);
  2021. streams.append(this);
  2022. return NULL;
  2023. }
  2024. virtual IEngineRowStream *queryConcreteOutputStream(unsigned whichInput) { return this; }
  2025. virtual IStrandJunction *queryConcreteOutputJunction(unsigned idx) const { return nullptr; }
  2026. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  2027. {
  2028. return puller.queryInput()->queryIndexReadActivity();
  2029. }
  2030. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  2031. {
  2032. eof = false;
  2033. if (disabled)
  2034. puller.queryInput()->start(parentExtractSize, parentExtract, paused);
  2035. else
  2036. {
  2037. space.reinit(READAHEAD_SIZE);
  2038. ready.reinit();
  2039. puller.start(parentExtractSize, parentExtract, paused, preload, false, ctx);
  2040. }
  2041. }
  2042. virtual void stop()
  2043. {
  2044. if (disabled)
  2045. puller.queryStream()->stop();
  2046. else
  2047. {
  2048. space.interrupt();
  2049. ready.interrupt();
  2050. puller.stop();
  2051. }
  2052. }
  2053. virtual void reset()
  2054. {
  2055. if (disabled)
  2056. puller.queryInput()->reset();
  2057. else
  2058. {
  2059. puller.reset();
  2060. ForEachItemIn(idx1, buffer)
  2061. ReleaseRoxieRow(buffer.item(idx1));
  2062. buffer.clear();
  2063. }
  2064. }
  2065. virtual void resetEOF()
  2066. {
  2067. throwUnexpected();
  2068. }
  2069. virtual IOutputMetaData * queryOutputMeta() const
  2070. {
  2071. return puller.queryInput()->queryOutputMeta();
  2072. }
  2073. void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  2074. {
  2075. assertex(!idx);
  2076. puller.setInput(this, _sourceIdx, _in);
  2077. }
  2078. virtual IFinalRoxieInput *queryInput(unsigned idx) const
  2079. {
  2080. if (idx==0)
  2081. return puller.queryInput();
  2082. else
  2083. return NULL;
  2084. }
  2085. virtual unsigned __int64 queryTotalCycles() const
  2086. {
  2087. return totalCycles;
  2088. }
  2089. virtual const void * nextRow()
  2090. {
  2091. SimpleActivityTimer t(totalCycles, timeActivities);
  2092. if (disabled)
  2093. return puller.queryStream()->nextRow();
  2094. else
  2095. {
  2096. for (;;)
  2097. {
  2098. {
  2099. CriticalBlock b(crit);
  2100. if (eof && !buffer.ordinality())
  2101. return NULL; // eof
  2102. }
  2103. ready.wait();
  2104. const void *ret;
  2105. {
  2106. CriticalBlock b(crit);
  2107. ret = buffer.dequeue();
  2108. }
  2109. space.signal();
  2110. return ret;
  2111. }
  2112. }
  2113. }
  2114. virtual bool fireException(IException *e)
  2115. {
  2116. // called from puller thread on failure
  2117. ready.interrupt(LINK(e));
  2118. space.interrupt(e);
  2119. return true;
  2120. }
  2121. virtual void processRow(const void *row)
  2122. {
  2123. {
  2124. CriticalBlock b(crit);
  2125. buffer.enqueue(row);
  2126. }
  2127. ready.signal();
  2128. space.wait();
  2129. }
  2130. virtual void processGroup(const ConstPointerArray &rows)
  2131. {
  2132. // NOTE - a bit bizarre in that it waits for the space AFTER using it.
  2133. // But the space semaphore is only there to stop infinite readahead. And otherwise it would deadlock
  2134. // if group was larger than max(space)
  2135. {
  2136. CriticalBlock b(crit);
  2137. ForEachItemIn(idx, rows)
  2138. buffer.enqueue(rows.item(idx));
  2139. buffer.enqueue(NULL);
  2140. }
  2141. for (unsigned i2 = 0; i2 <= rows.length(); i2++) // note - does 1 extra for the null
  2142. {
  2143. ready.signal();
  2144. space.wait();
  2145. }
  2146. }
  2147. virtual void processEOG()
  2148. {
  2149. // Used when output is not grouped - just ignore
  2150. }
  2151. virtual void processDone()
  2152. {
  2153. CriticalBlock b(crit);
  2154. eof = true;
  2155. ready.signal();
  2156. }
  2157. };
  2158. //=================================================================================
  2159. class CRoxieServerTwoInputActivity : public CRoxieServerActivity
  2160. {
  2161. protected:
  2162. IFinalRoxieInput *input1;
  2163. IEngineRowStream *inputStream1;
  2164. Owned<IStrandJunction> junction1;
  2165. unsigned sourceIdx1 = 0;
  2166. Owned<CRoxieServerReadAheadInput> puller;
  2167. public:
  2168. CRoxieServerTwoInputActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  2169. : CRoxieServerActivity(_ctx, _factory, _probeManager)
  2170. {
  2171. input1 = NULL;
  2172. inputStream1 = NULL;
  2173. }
  2174. ~CRoxieServerTwoInputActivity()
  2175. {
  2176. }
  2177. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  2178. {
  2179. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  2180. input1->start(parentExtractSize, parentExtract, paused);
  2181. startJunction(junction1);
  2182. }
  2183. virtual void stop()
  2184. {
  2185. inputStream1->stop();
  2186. CRoxieServerActivity::stop();
  2187. }
  2188. virtual unsigned __int64 queryLocalCycles() const
  2189. {
  2190. __int64 ret;
  2191. __int64 inputCycles = input->queryTotalCycles();
  2192. __int64 input1Cycles = input1->queryTotalCycles();
  2193. if (puller)
  2194. ret = totalCycles.totalCycles - (inputCycles > input1Cycles ? inputCycles : input1Cycles);
  2195. else
  2196. ret = totalCycles.totalCycles - (inputCycles + input1Cycles);
  2197. if (ret < 0)
  2198. ret = 0;
  2199. return ret;
  2200. }
  2201. virtual IFinalRoxieInput *queryInput(unsigned idx) const
  2202. {
  2203. switch (idx)
  2204. {
  2205. case 0:
  2206. return input;
  2207. case 1:
  2208. return input1;
  2209. default:
  2210. return NULL;
  2211. }
  2212. }
  2213. virtual void reset()
  2214. {
  2215. CRoxieServerActivity::reset();
  2216. if (input1)
  2217. input1->reset();
  2218. resetJunction(junction1);
  2219. }
  2220. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  2221. {
  2222. switch(idx)
  2223. {
  2224. case 0:
  2225. CRoxieServerActivity::setInput(idx, _sourceIdx, _in);
  2226. break;
  2227. case 1:
  2228. input1 = _in;
  2229. sourceIdx1 = _sourceIdx;
  2230. break;
  2231. default:
  2232. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", sanitizeSourceFile(__FILE__), __LINE__);
  2233. }
  2234. }
  2235. virtual IStrandJunction *getOutputStreams(IRoxieSlaveContext *ctx, unsigned idx, PointerArrayOf<IEngineRowStream> &streams, const StrandOptions * consumerOptions, bool consumerOrdered, IOrderedCallbackCollection * orderedCallbacks) override
  2236. {
  2237. inputStream1 = connectSingleStream(ctx, input1, sourceIdx1, junction1, isInputOrdered(consumerOrdered, 1));
  2238. //Assumes input1 will be stranded if any.
  2239. return CRoxieServerActivity::getOutputStreams(ctx, idx, streams, consumerOptions, consumerOrdered, orderedCallbacks);
  2240. }
  2241. };
  2242. //=================================================================================
  2243. class CRoxieServerMultiInputBaseActivity : public CRoxieServerActivity
  2244. {
  2245. protected:
  2246. unsigned numInputs;
  2247. unsigned numStreams;
  2248. IFinalRoxieInput **inputArray;
  2249. unsigned *sourceIdxArray;
  2250. IEngineRowStream **streamArray;
  2251. Owned<IStrandJunction> *junctionArray;
  2252. public:
  2253. CRoxieServerMultiInputBaseActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  2254. : CRoxieServerActivity(_ctx, _factory, _probeManager), numInputs(_numInputs)
  2255. {
  2256. numStreams = numInputs;
  2257. inputArray = new IFinalRoxieInput*[numInputs];
  2258. sourceIdxArray = new unsigned[numInputs];
  2259. streamArray = new IEngineRowStream*[numStreams];
  2260. junctionArray = new Owned<IStrandJunction>[numStreams];
  2261. for (unsigned i1 = 0; i1 < numInputs; i1++)
  2262. {
  2263. inputArray[i1] = NULL;
  2264. sourceIdxArray[i1] = 0;
  2265. }
  2266. for (unsigned i2 = 0; i2 < numStreams; i2++)
  2267. streamArray[i2] = NULL;
  2268. }
  2269. ~CRoxieServerMultiInputBaseActivity()
  2270. {
  2271. delete [] inputArray;
  2272. delete [] sourceIdxArray;
  2273. delete [] streamArray;
  2274. delete [] junctionArray;
  2275. }
  2276. virtual unsigned __int64 queryLocalCycles() const
  2277. {
  2278. __int64 localCycles = totalCycles.totalCycles;
  2279. for (unsigned i = 0; i < numInputs; i++)
  2280. localCycles -= inputArray[i]->queryTotalCycles();
  2281. if (localCycles < 0)
  2282. localCycles = 0;
  2283. return localCycles;
  2284. }
  2285. virtual IFinalRoxieInput *queryInput(unsigned idx) const
  2286. {
  2287. if (idx < numInputs)
  2288. return inputArray[idx];
  2289. else
  2290. return NULL;
  2291. }
  2292. virtual IFinalRoxieInput * queryConcreteInput(unsigned idx)
  2293. {
  2294. return queryInput(idx);
  2295. }
  2296. virtual IEngineRowStream *queryConcreteOutputStream(unsigned whichInput)
  2297. {
  2298. if (whichInput < numInputs)
  2299. return streamArray[whichInput];
  2300. else
  2301. return NULL;
  2302. }
  2303. virtual IStrandJunction *queryConcreteOutputJunction(unsigned idx) const
  2304. {
  2305. if (idx < numInputs)
  2306. return junctionArray[idx];
  2307. else
  2308. return NULL;
  2309. }
  2310. virtual void reset()
  2311. {
  2312. for (unsigned i = 0; i < numInputs; i++)
  2313. inputArray[i]->reset();
  2314. for (unsigned iS = 0; iS < numStreams; iS++)
  2315. {
  2316. resetJunction(junctionArray[iS]);
  2317. }
  2318. CRoxieServerActivity::reset();
  2319. }
  2320. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  2321. {
  2322. assertex(idx < numInputs && idx < numStreams);
  2323. inputArray[idx] = _in;
  2324. sourceIdxArray[idx] = _sourceIdx;
  2325. }
  2326. virtual IStrandJunction *getOutputStreams(IRoxieSlaveContext *ctx, unsigned idx, PointerArrayOf<IEngineRowStream> &streams, const StrandOptions * consumerOptions, bool consumerOrdered, IOrderedCallbackCollection * orderedCallbacks) override
  2327. {
  2328. //There could be situations (e.g., NONEMPTY), where you might want to strand the activity.
  2329. for (unsigned i = 0; i < numInputs; i++)
  2330. streamArray[i] = connectSingleStream(ctx, inputArray[i], sourceIdxArray[i], junctionArray[i], consumerOrdered);
  2331. return CRoxieServerActivity::getOutputStreams(ctx, idx, streams, NULL, consumerOrdered, nullptr); // The input basesclass does not have an input
  2332. }
  2333. };
  2334. //=================================================================================
  2335. class CRoxieServerMultiInputActivity : public CRoxieServerMultiInputBaseActivity
  2336. {
  2337. public:
  2338. CRoxieServerMultiInputActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  2339. : CRoxieServerMultiInputBaseActivity(_ctx, _factory, _probeManager, _numInputs)
  2340. {
  2341. }
  2342. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  2343. {
  2344. CRoxieServerMultiInputBaseActivity::start(parentExtractSize, parentExtract, paused);
  2345. for (unsigned i = 0; i < numInputs; i++)
  2346. {
  2347. inputArray[i]->start(parentExtractSize, parentExtract, paused);
  2348. }
  2349. for (unsigned iS = 0; iS < numStreams; iS++)
  2350. {
  2351. startJunction(junctionArray[iS]);
  2352. }
  2353. }
  2354. virtual void stop()
  2355. {
  2356. for (unsigned i = 0; i < numStreams; i++)
  2357. {
  2358. streamArray[i]->stop();
  2359. }
  2360. CRoxieServerMultiInputBaseActivity::stop();
  2361. }
  2362. };
  2363. //=====================================================================================================
  2364. class CRoxieServerInternalSinkActivity : public CRoxieServerActivity
  2365. {
  2366. protected:
  2367. unsigned numOutputs;
  2368. bool executed;
  2369. bool *stopped;
  2370. CriticalSection ecrit;
  2371. Owned<IException> exception;
  2372. public:
  2373. CRoxieServerInternalSinkActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numOutputs)
  2374. : CRoxieServerActivity(_ctx, _factory, _probeManager), numOutputs(_numOutputs)
  2375. {
  2376. executed = false;
  2377. stopped = new bool[numOutputs];
  2378. for (unsigned s = 0; s < numOutputs; s++)
  2379. stopped[s] = false;
  2380. }
  2381. ~CRoxieServerInternalSinkActivity()
  2382. {
  2383. delete [] stopped;
  2384. }
  2385. virtual void reset()
  2386. {
  2387. for (unsigned s = 0; s < numOutputs; s++)
  2388. stopped[s] = false;
  2389. executed = false;
  2390. exception.clear();
  2391. CRoxieServerActivity::reset();
  2392. }
  2393. virtual IFinalRoxieInput *queryOutput(unsigned idx)
  2394. {
  2395. return NULL;
  2396. }
  2397. virtual void stopSink(unsigned outputIdx)
  2398. {
  2399. if (outputIdx < numOutputs && !stopped[outputIdx]) // Implicit dependencies on DiskWrite activities do not count as outputs
  2400. {
  2401. stopped[outputIdx] = true;
  2402. for (unsigned s = 0; s < numOutputs; s++)
  2403. if (!stopped[s])
  2404. return;
  2405. stop(); // all outputs stopped - stop parent.
  2406. }
  2407. }
  2408. virtual const void *nextRow()
  2409. {
  2410. throwUnexpected(); // I am nobody's input
  2411. }
  2412. virtual void onExecute() = 0;
  2413. virtual void execute(unsigned parentExtractSize, const byte * parentExtract)
  2414. {
  2415. CriticalBlock b(ecrit);
  2416. if (exception)
  2417. throw exception.getLink();
  2418. if (!executed)
  2419. {
  2420. try
  2421. {
  2422. start(parentExtractSize, parentExtract, false);
  2423. {
  2424. ActivityTimer t(totalCycles, timeActivities); // unfortunately this is not really best place for seeing in debugger.
  2425. onExecute();
  2426. }
  2427. stop();
  2428. executed = true;
  2429. }
  2430. catch (IException *E)
  2431. {
  2432. exception.set(E); // (or maybe makeWrappedException?)
  2433. abort();
  2434. throw;
  2435. }
  2436. catch (...)
  2437. {
  2438. exception.set(MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught at %s:%d", sanitizeSourceFile(__FILE__), __LINE__));
  2439. abort();
  2440. throw;
  2441. }
  2442. }
  2443. }
  2444. };
  2445. //=================================================================================
  2446. class CRoxieServerQueryPacket : implements IRoxieServerQueryPacket, public CInterface
  2447. {
  2448. protected:
  2449. Owned<IMessageResult> result;
  2450. Owned<IRoxieQueryPacket> packet;
  2451. Linked<IRoxieServerQueryPacket> continuation;
  2452. unsigned hash;
  2453. unsigned seq;
  2454. unsigned lastDebugSequence;
  2455. Owned<IRoxieQueryPacket> lastDebugResponse;
  2456. ILRUChain *prev;
  2457. ILRUChain *next;
  2458. bool delayed;
  2459. public:
  2460. IMPLEMENT_IINTERFACE;
  2461. CRoxieServerQueryPacket(IRoxieQueryPacket *p) : packet(p)
  2462. {
  2463. hash = 0;
  2464. seq = 0;
  2465. prev = NULL;
  2466. next = NULL;
  2467. delayed = false;
  2468. lastDebugSequence = 0;
  2469. }
  2470. virtual IRoxieQueryPacket *queryPacket() const
  2471. {
  2472. return packet;
  2473. }
  2474. virtual bool isContinuation() const
  2475. {
  2476. return packet && (packet->queryHeader().continueSequence & ~CONTINUE_SEQUENCE_SKIPTO) != 0;
  2477. }
  2478. virtual bool isDelayed() const
  2479. {
  2480. return delayed;
  2481. }
  2482. virtual bool isEnd() const
  2483. {
  2484. return false;
  2485. }
  2486. virtual bool isLimit(unsigned __int64 &_rowLimit, unsigned __int64 &_keyedLimit, unsigned __int64 &_stopAfter) const
  2487. {
  2488. return false;
  2489. }
  2490. virtual bool hasResult() const
  2491. {
  2492. return result != NULL;
  2493. }
  2494. virtual bool hasContinuation() const
  2495. {
  2496. return continuation != NULL;
  2497. }
  2498. virtual void setDelayed(bool _delayed)
  2499. {
  2500. delayed = _delayed;
  2501. }
  2502. virtual void setPacket(IRoxieQueryPacket *_packet)
  2503. {
  2504. packet.setown(_packet);
  2505. }
  2506. virtual void setSequence(unsigned _seq)
  2507. {
  2508. assertex(!IsShared());
  2509. seq = _seq;
  2510. }
  2511. virtual unsigned getSequence() const
  2512. {
  2513. return seq;
  2514. }
  2515. IMessageResult *getResult()
  2516. {
  2517. return result.getLink();
  2518. }
  2519. IMessageResult *queryResult()
  2520. {
  2521. return result;
  2522. }
  2523. void setResult(IMessageResult *r)
  2524. {
  2525. result.setown(r);
  2526. }
  2527. IRoxieServerQueryPacket *queryContinuation()
  2528. {
  2529. return continuation;
  2530. }
  2531. void setContinuation(IRoxieServerQueryPacket *c)
  2532. {
  2533. continuation.setown(c);
  2534. }
  2535. virtual unsigned queryHash() const
  2536. {
  2537. return hash;
  2538. }
  2539. virtual void setHash(unsigned _hash)
  2540. {
  2541. hash = _hash;
  2542. }
  2543. virtual ILRUChain *queryPrev() const { return prev; }
  2544. virtual ILRUChain *queryNext() const { return next; }
  2545. virtual void setPrev(ILRUChain *p) { prev = p; }
  2546. virtual void setNext(ILRUChain *n) { next = n; }
  2547. virtual void unchain()
  2548. {
  2549. if (prev && next)
  2550. {
  2551. prev->setNext(next);
  2552. next->setPrev(prev);
  2553. }
  2554. next = NULL;
  2555. prev = NULL;
  2556. }
  2557. virtual IRoxieQueryPacket *getDebugResponse(unsigned sequence)
  2558. {
  2559. if (sequence == lastDebugSequence)
  2560. return lastDebugResponse.getLink();
  2561. else if (sequence > lastDebugSequence)
  2562. {
  2563. lastDebugResponse.clear();
  2564. return NULL;
  2565. }
  2566. else
  2567. throwUnexpected();
  2568. }
  2569. virtual void setDebugResponse(unsigned sequence, IRoxieQueryPacket *response)
  2570. {
  2571. lastDebugSequence = sequence;
  2572. lastDebugResponse.set(response);
  2573. }
  2574. };
  2575. class CRoxieServerQueryPacketEndMarker : public CRoxieServerQueryPacket
  2576. {
  2577. public:
  2578. CRoxieServerQueryPacketEndMarker() : CRoxieServerQueryPacket(NULL)
  2579. {
  2580. }
  2581. virtual bool isEnd() const
  2582. {
  2583. return true;
  2584. }
  2585. };
  2586. class CRoxieServerQueryPacketLimitMarker : public CRoxieServerQueryPacket
  2587. {
  2588. unsigned __int64 rowLimit;
  2589. unsigned __int64 keyedLimit;
  2590. unsigned __int64 stopAfter;
  2591. public:
  2592. CRoxieServerQueryPacketLimitMarker(unsigned __int64 _rowLimit, unsigned __int64 _keyedLimit, unsigned __int64 _stopAfter) : CRoxieServerQueryPacket(NULL)
  2593. {
  2594. rowLimit = _rowLimit;
  2595. keyedLimit = _keyedLimit;
  2596. stopAfter = _stopAfter;
  2597. }
  2598. virtual bool isLimit(unsigned __int64 &_rowLimit, unsigned __int64 &_keyedLimit, unsigned __int64 &_stopAfter) const
  2599. {
  2600. _rowLimit = rowLimit;
  2601. _keyedLimit = keyedLimit;
  2602. _stopAfter = stopAfter;
  2603. return true;
  2604. }
  2605. };
  2606. class CRoxieServerSideCache : implements IRoxieServerSideCache, implements ILRUChain
  2607. {
  2608. protected:
  2609. unsigned cacheTableSize;
  2610. unsigned cacheTableSpace;
  2611. IRoxieServerQueryPacket **cacheTable;
  2612. mutable ILRUChain *prev;
  2613. mutable ILRUChain *next;
  2614. mutable CriticalSection crit;
  2615. virtual ILRUChain *queryPrev() const { return prev; }
  2616. virtual ILRUChain *queryNext() const { return next; }
  2617. virtual void setPrev(ILRUChain *p) { prev = p; }
  2618. virtual void setNext(ILRUChain *n) { next = n; }
  2619. virtual void unchain()
  2620. {
  2621. prev->setNext(next);
  2622. next->setPrev(prev);
  2623. next = NULL;
  2624. prev = NULL;
  2625. }
  2626. void moveToHead(IRoxieServerQueryPacket *mru)
  2627. {
  2628. mru->unchain();
  2629. mru->setNext(next);
  2630. next->setPrev(mru);
  2631. mru->setPrev(this);
  2632. next = mru;
  2633. }
  2634. IRoxieServerQueryPacket *removeLRU()
  2635. {
  2636. if (next==this)
  2637. assertex(next != this);
  2638. IRoxieServerQueryPacket *goer = (IRoxieServerQueryPacket *) next;
  2639. goer->unchain(); // NOTE - this will modify the value of next
  2640. return goer;
  2641. }
  2642. void removeEntry(IRoxieServerQueryPacket *goer)
  2643. {
  2644. unsigned v = goer->queryHash() % cacheTableSize;
  2645. for (;;)
  2646. {
  2647. IRoxieServerQueryPacket *found = cacheTable[v];
  2648. assertex(found);
  2649. if (found == goer)
  2650. {
  2651. cacheTable[v] = NULL;
  2652. unsigned vn = v;
  2653. for (;;)
  2654. {
  2655. vn++;
  2656. if (vn==cacheTableSize) vn = 0;
  2657. IRoxieServerQueryPacket *found2 = cacheTable[vn];
  2658. if (!found2)
  2659. break;
  2660. unsigned vm = found2->queryHash() % cacheTableSize;
  2661. if (((vn+cacheTableSize-vm) % cacheTableSize)>=((vn+cacheTableSize-v) % cacheTableSize)) // diff(vn,vm)>=diff(vn,v)
  2662. {
  2663. cacheTable[v] = found2;
  2664. v = vn;
  2665. cacheTable[v] = NULL;
  2666. }
  2667. }
  2668. cacheTableSpace++;
  2669. break;
  2670. }
  2671. v++;
  2672. if (v==cacheTableSize)
  2673. v = 0;
  2674. }
  2675. goer->Release();
  2676. }
  2677. public:
  2678. CRoxieServerSideCache(unsigned _cacheSize)
  2679. {
  2680. cacheTableSize = (_cacheSize*4)/3;
  2681. cacheTable = new IRoxieServerQueryPacket *[cacheTableSize];
  2682. memset(cacheTable, 0, cacheTableSize * sizeof(IRoxieServerQueryPacket *));
  2683. cacheTableSpace = _cacheSize;
  2684. prev = this;
  2685. next = this;
  2686. }
  2687. ~CRoxieServerSideCache()
  2688. {
  2689. for (unsigned i = 0; i < cacheTableSize; i++)
  2690. {
  2691. ::Release(cacheTable[i]);
  2692. }
  2693. delete [] cacheTable;
  2694. }
  2695. virtual IRoxieServerQueryPacket *findCachedResult(const IRoxieContextLogger &logctx, IRoxieQueryPacket *p) const
  2696. {
  2697. unsigned hash = p->hash();
  2698. unsigned et = hash % cacheTableSize;
  2699. if (traceServerSideCache)
  2700. {
  2701. StringBuffer s;
  2702. logctx.CTXLOG("CRoxieServerSideCache::findCachedResult hash %x slot %d %s", hash, et, p->queryHeader().toString(s).str());
  2703. }
  2704. CriticalBlock b(crit);
  2705. for (;;)
  2706. {
  2707. IRoxieServerQueryPacket *found = cacheTable[et];
  2708. if (!found)
  2709. return NULL;
  2710. if (found->queryHash() == hash && found->queryPacket()->cacheMatch(p))
  2711. {
  2712. const_cast<CRoxieServerSideCache *>(this)->moveToHead(found);
  2713. if (traceServerSideCache)
  2714. logctx.CTXLOG("CRoxieServerSideCache::findCachedResult cache hit");
  2715. logctx.noteStatistic(StNumServerCacheHits, 1);
  2716. return NULL;
  2717. // Because IMessageResult cannot be replayed, this scheme is flawed. I'm leaving the code here just as a stats gatherer to see how useful it would have been....
  2718. //IRoxieServerQueryPacket *ret = new CRoxieServerQueryPacket(p);
  2719. //ret->setResult(found->getResult());
  2720. //return ret;
  2721. }
  2722. et++;
  2723. if (et == cacheTableSize)
  2724. et = 0;
  2725. }
  2726. }
  2727. virtual void noteCachedResult(IRoxieServerQueryPacket *out, IMessageResult *in)
  2728. {
  2729. if (true) //!in->getLength()) // MORE - separate caches for hits and nohits
  2730. {
  2731. unsigned hash = out->queryPacket()->hash();
  2732. out->setHash(hash);
  2733. unsigned et = hash % cacheTableSize;
  2734. if (traceServerSideCache)
  2735. {
  2736. StringBuffer s;
  2737. DBGLOG("CRoxieServerSideCache::noteCachedResult hash %x slot %d %s", hash, et, out->queryPacket()->queryHeader().toString(s).str());
  2738. }
  2739. CriticalBlock b(crit);
  2740. for (;;)
  2741. {
  2742. IRoxieServerQueryPacket *found = cacheTable[et];
  2743. if (!found)
  2744. {
  2745. if (cacheTableSpace)
  2746. {
  2747. out->setResult(LINK(in));
  2748. cacheTable[et] = LINK(out);
  2749. cacheTableSpace--;
  2750. moveToHead(out);
  2751. break;
  2752. }
  2753. else
  2754. {
  2755. IRoxieServerQueryPacket *goer = removeLRU();
  2756. removeEntry(goer);
  2757. et = hash % cacheTableSize;
  2758. continue;
  2759. }
  2760. }
  2761. else if (found->queryHash()==hash && found->queryPacket()->cacheMatch(out->queryPacket()))
  2762. {
  2763. moveToHead(found);
  2764. return; // already in the cache. Because we don't cache until we have result, this can happen where
  2765. // multiple copies of a slave query are in-flight at once.
  2766. }
  2767. et++;
  2768. if (et == cacheTableSize)
  2769. et = 0;
  2770. }
  2771. }
  2772. // MORE - do we need to worry about the attachment between the MessageUnpacker and the current row manager. May all fall out ok...
  2773. // Can I easily spot a null result? Do I want to cache null results separately? only?
  2774. }
  2775. // Note that this caching mechanism (unlike the old keyed-join specific one) does not common up cases where multiple
  2776. // identical queries are in-flight at the same time. But if we can make it persistent between queries that will
  2777. // more than make up for it
  2778. };
  2779. class CRowArrayMessageUnpackCursor : implements IMessageUnpackCursor, public CInterface
  2780. {
  2781. ConstPointerArray &data;
  2782. Linked<IMessageResult> result;
  2783. public:
  2784. IMPLEMENT_IINTERFACE;
  2785. CRowArrayMessageUnpackCursor(ConstPointerArray &_data, IMessageResult *_result)
  2786. : data(_data), result(_result)
  2787. {
  2788. }
  2789. virtual bool atEOF() const
  2790. {
  2791. return data.length()==0;
  2792. }
  2793. virtual bool isSerialized() const
  2794. {
  2795. return false;
  2796. }
  2797. virtual const void * getNext(int length)
  2798. {
  2799. if (!data.length())
  2800. return NULL;
  2801. const void *ret = data.item(0);
  2802. data.remove(0);
  2803. return ret;
  2804. }
  2805. };
  2806. // MORE - should possibly move more over to the lazy version used in indexread?
  2807. class CRowArrayMessageResult : implements IMessageResult, public CInterface
  2808. {
  2809. ConstPointerArray data;
  2810. IRowManager &rowManager;
  2811. bool variableSize;
  2812. public:
  2813. IMPLEMENT_IINTERFACE;
  2814. CRowArrayMessageResult(IRowManager &_rowManager, bool _variableSize) : rowManager(_rowManager), variableSize(_variableSize)
  2815. {
  2816. }
  2817. ~CRowArrayMessageResult()
  2818. {
  2819. ReleaseRoxieRows(data);
  2820. }
  2821. virtual IMessageUnpackCursor *getCursor(IRowManager *rowMgr) const
  2822. {
  2823. CRowArrayMessageResult *_this = (CRowArrayMessageResult *) this;
  2824. return new CRowArrayMessageUnpackCursor(_this->data, _this);
  2825. }
  2826. virtual const void *getMessageHeader(unsigned &length) const
  2827. {
  2828. throwUnexpected(); // should never get called - I don't have a header available
  2829. }
  2830. virtual const void *getMessageMetadata(unsigned &length) const
  2831. {
  2832. length = 0;
  2833. return NULL;
  2834. }
  2835. virtual void discard() const
  2836. {
  2837. throwUnexpected();
  2838. }
  2839. void append(const void *row)
  2840. {
  2841. data.append(row);
  2842. }
  2843. };
  2844. void throwRemoteException(IMessageUnpackCursor *extra)
  2845. {
  2846. RecordLengthType *rowlen = (RecordLengthType *) extra->getNext(sizeof(RecordLengthType));
  2847. if (rowlen)
  2848. {
  2849. char *xml = (char *) extra->getNext(*rowlen);
  2850. ReleaseRoxieRow(rowlen);
  2851. Owned<IPropertyTree> p = createPTreeFromXMLString(xml, ipt_fast);
  2852. ReleaseRoxieRow(xml);
  2853. unsigned code = p->getPropInt("Code", 0);
  2854. const char *msg = p->queryProp("Message");
  2855. if (!msg)
  2856. msg = xml;
  2857. throw MakeStringException(code, "%s", msg);
  2858. }
  2859. throwUnexpected();
  2860. }
  2861. class CRemoteResultAdaptor : implements IEngineRowStream, implements IFinalRoxieInput, implements IExceptionHandler, public CInterface
  2862. {
  2863. friend class CRemoteResultMerger;
  2864. class CRemoteResultMerger
  2865. {
  2866. class HeapEntry : public CInterface
  2867. {
  2868. private:
  2869. CRemoteResultAdaptor &adaptor;
  2870. IMessageUnpackCursor *cursor;
  2871. public:
  2872. const void *current;
  2873. bool isLast;
  2874. bool lastIsComplete;
  2875. IRoxieServerQueryPacket *packet;
  2876. unsigned seq;
  2877. public:
  2878. inline const void *noteResult(IMessageUnpackCursor *_cursor, bool _lastIsComplete)
  2879. {
  2880. cursor = _cursor;
  2881. lastIsComplete = _lastIsComplete;
  2882. return next();
  2883. }
  2884. public:
  2885. HeapEntry(CRemoteResultAdaptor &_adaptor, IRoxieServerQueryPacket *_packet, unsigned _seq) : adaptor(_adaptor), packet(_packet), seq(_seq)
  2886. {
  2887. cursor = NULL;
  2888. current = NULL;
  2889. isLast = false;
  2890. lastIsComplete = true;
  2891. }
  2892. ~HeapEntry()
  2893. {
  2894. ::Release(packet);
  2895. ::Release(cursor);
  2896. ReleaseRoxieRow(current);
  2897. }
  2898. bool isCompleteMatch() const
  2899. {
  2900. if (!isLast || lastIsComplete)
  2901. return true;
  2902. else
  2903. return false;
  2904. }
  2905. const void *next()
  2906. {
  2907. if (cursor)
  2908. {
  2909. ReleaseClearRoxieRow(current);
  2910. current = adaptor.getRow(cursor);
  2911. isLast = cursor->atEOF();
  2912. if (!current)
  2913. {
  2914. cursor->Release();
  2915. cursor = NULL;
  2916. }
  2917. }
  2918. return current;
  2919. }
  2920. unsigned skipTo(IRangeCompare *compare, const void *seek, unsigned numFields, bool requireExactMatch)
  2921. {
  2922. // MORE - This loop should possibly be a binchop... though it's not absolutely clear that is true (depends on term frequencies)
  2923. unsigned skipped = 0;
  2924. for (;;)
  2925. {
  2926. int c = compare->docompare(current, seek, numFields);
  2927. //If larger than the seek values, then we may be allowed to return an inexact match,
  2928. //if equal then it is required to be an exact match,
  2929. if (c > 0)
  2930. {
  2931. if (!requireExactMatch || isCompleteMatch())
  2932. break;
  2933. }
  2934. else if ((c == 0) && isCompleteMatch())
  2935. break;
  2936. skipped++;
  2937. if (!next())
  2938. break;
  2939. }
  2940. return skipped;
  2941. }
  2942. };
  2943. CRemoteResultAdaptor &adaptor;
  2944. CIArrayOf<HeapEntry> heapEntries;
  2945. UnsignedArray heap;
  2946. IRowManager *rowManager;
  2947. unsigned numPending;
  2948. unsigned numFields;
  2949. bool endSeen;
  2950. bool remakePending;
  2951. IRangeCompare *compare;
  2952. bool deferredContinuation;
  2953. inline int doCompare(unsigned l, unsigned r)
  2954. {
  2955. int ret = compare->docompare(heapEntries.item(l).current, heapEntries.item(r).current, numFields);
  2956. if (!ret) ret = heapEntries.item(l).seq - heapEntries.item(r).seq;
  2957. return ret;
  2958. }
  2959. void makeHeap()
  2960. {
  2961. /* Permute blocks to establish the heap property
  2962. For each element p, the children are p*2+1 and p*2+2 (provided these are in range)
  2963. The children of p must both be greater than or equal to p
  2964. The parent of a child c is given by p = (c-1)/2
  2965. */
  2966. unsigned i;
  2967. unsigned n = heap.length();
  2968. unsigned *s = heap.getArray();
  2969. for (i=1; i<n; i++)
  2970. {
  2971. unsigned r = s[i];
  2972. int c = i; /* child */
  2973. while (c > 0)
  2974. {
  2975. int p = (c-1)/2; /* parent */
  2976. if ( doCompare( s[c], s[p] ) >= 0 )
  2977. break;
  2978. s[c] = s[p];
  2979. s[p] = r;
  2980. c = p;
  2981. }
  2982. }
  2983. remakePending = false;
  2984. }
  2985. void remakeHeap()
  2986. {
  2987. /* The row associated with block[0] will have changed
  2988. This code restores the heap property
  2989. */
  2990. unsigned p = 0; /* parent */
  2991. unsigned n = heap.length();
  2992. unsigned *s = heap.getArray();
  2993. while (1)
  2994. {
  2995. unsigned c = p*2 + 1; /* child */
  2996. if ( c >= n )
  2997. break;
  2998. /* Select smaller child */
  2999. if ( c+1 < n && doCompare( s[c+1], s[c] ) < 0 ) c += 1;
  3000. /* If child is greater or equal than parent then we are done */
  3001. if ( doCompare( s[c], s[p] ) >= 0 )
  3002. break;
  3003. /* Swap parent and child */
  3004. unsigned r = s[c];
  3005. s[c] = s[p];
  3006. s[p] = r;
  3007. /* child becomes parent */
  3008. p = c;
  3009. }
  3010. remakePending = false;
  3011. }
  3012. void append(IRoxieServerQueryPacket *p, unsigned seq)
  3013. {
  3014. HeapEntry &h = *new HeapEntry(adaptor, LINK(p), seq);
  3015. IMessageResult *result = p->queryResult();
  3016. assertex(result);
  3017. if (h.noteResult(result->getCursor(rowManager), isCompleteMatchFlag(result)))
  3018. {
  3019. heapEntries.append(h);
  3020. heap.append(heap.ordinality());
  3021. }
  3022. else
  3023. h.Release();
  3024. }
  3025. void removeHeap(unsigned idx)
  3026. {
  3027. heapEntries.remove(idx);
  3028. ForEachItemIn(i, heap)
  3029. {
  3030. unsigned v = heap.item(i);
  3031. assertex(v != idx);
  3032. if (v > idx)
  3033. heap.replace(v-1, i);
  3034. }
  3035. }
  3036. bool isCompleteMatchFlag(IMessageResult *result)
  3037. {
  3038. unsigned metaLen;
  3039. const byte *metaInfo = (const byte *) result->getMessageMetadata(metaLen);
  3040. if (metaLen)
  3041. {
  3042. unsigned short continuationLen = *(unsigned short *) metaInfo;
  3043. if (continuationLen >= sizeof(bool))
  3044. {
  3045. metaInfo += sizeof(unsigned short);
  3046. return *(bool *) metaInfo;
  3047. }
  3048. }
  3049. return true; // if no continuation info, last row was complete.
  3050. }
  3051. public:
  3052. CRemoteResultMerger(CRemoteResultAdaptor &_adaptor) : adaptor(_adaptor)
  3053. {
  3054. init(NULL, NULL);
  3055. }
  3056. void init(ISteppingMeta *meta, IRowManager *_rowManager)
  3057. {
  3058. if (meta)
  3059. {
  3060. numFields = meta->getNumFields();
  3061. compare = meta->queryCompare();
  3062. }
  3063. else
  3064. {
  3065. numFields = 0;
  3066. compare = NULL;
  3067. }
  3068. rowManager = _rowManager;
  3069. numPending = 0;
  3070. endSeen = false;
  3071. remakePending = false;
  3072. deferredContinuation = false;
  3073. }
  3074. void reset()
  3075. {
  3076. heapEntries.kill();
  3077. heap.kill();
  3078. numPending = 0;
  3079. endSeen = false;
  3080. remakePending = false;
  3081. deferredContinuation = false;
  3082. }
  3083. inline bool noteEndSeen()
  3084. {
  3085. bool hadSeen = endSeen;
  3086. if (!endSeen)
  3087. makeHeap();
  3088. endSeen = true;
  3089. return !hadSeen;
  3090. }
  3091. void noteResult(IRoxieServerQueryPacket *p, unsigned seq)
  3092. {
  3093. if (!p->isContinuation())
  3094. append(p, seq);
  3095. else
  3096. {
  3097. ForEachItemIn(idx, heapEntries)
  3098. {
  3099. HeapEntry &h = heapEntries.item(idx);
  3100. if (h.packet == p)
  3101. {
  3102. IMessageResult *result = p->queryResult();
  3103. if (!h.noteResult(result->getCursor(rowManager), isCompleteMatchFlag(result)))
  3104. {
  3105. heap.zap(idx);
  3106. removeHeap(idx);
  3107. }
  3108. numPending--;
  3109. if (!numPending)
  3110. makeHeap();
  3111. return;
  3112. }
  3113. }
  3114. }
  3115. // If we get here it must be a continuation for one that I have not yet consumed... we don't need to do anything.
  3116. return;
  3117. }
  3118. unsigned skipRows(unsigned &idx, const void *seek, const void *rawSeek, unsigned numFields, unsigned seekLen, const SmartStepExtra & stepExtra)
  3119. {
  3120. HeapEntry &entry = heapEntries.item(idx);
  3121. unsigned skipped = entry.current ? entry.skipTo(compare, seek, numFields, !stepExtra.returnMismatches()) : 0;
  3122. if (!entry.current)
  3123. {
  3124. IRoxieServerQueryPacket *continuation = entry.packet->queryContinuation();
  3125. if (continuation)
  3126. {
  3127. continuation->Link();
  3128. entry.packet->Release();
  3129. entry.packet = continuation;
  3130. if (continuation->hasResult())
  3131. {
  3132. IMessageResult *result = continuation->queryResult();
  3133. bool lastIsCompleteMatch = isCompleteMatchFlag(result);
  3134. entry.noteResult(result->getCursor(rowManager), lastIsCompleteMatch);
  3135. }
  3136. else
  3137. {
  3138. if (continuation->isDelayed())
  3139. {
  3140. continuation->setDelayed(false);
  3141. MemoryBuffer serializedSkip;
  3142. adaptor.activity.serializeSkipInfo(serializedSkip, seekLen, rawSeek, numFields, seek, stepExtra);
  3143. continuation->setPacket(continuation->queryPacket()->insertSkipData(serializedSkip.length(), serializedSkip.toByteArray()));
  3144. ROQ->sendPacket(continuation->queryPacket(), adaptor.activity.queryLogCtx());
  3145. adaptor.sentsome.signal();
  3146. }
  3147. numPending++;
  3148. }
  3149. }
  3150. else
  3151. {
  3152. heap.zap(idx);
  3153. removeHeap(idx);
  3154. idx--;
  3155. }
  3156. }
  3157. return skipped;
  3158. }
  3159. const void * nextRowGE(const void * seek, const void *rawSeek, unsigned numFields, unsigned seeklen, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  3160. {
  3161. // We discard all rows < seekval from all entries in heap
  3162. // If this results in additional slave requests, we return NULL so that we can wait for them
  3163. // If not, we rebuild the heap (if any were skipped) and return the first row
  3164. deferredContinuation = false;
  3165. if (heap.length())
  3166. {
  3167. unsigned skipped = 0;
  3168. unsigned idx = 0;
  3169. while(heapEntries.isItem(idx))
  3170. {
  3171. skipped += skipRows(idx, seek, rawSeek, numFields, seeklen, stepExtra);
  3172. idx++;
  3173. }
  3174. if (numPending)
  3175. return NULL; // can't answer yet, need more results from slaves
  3176. else
  3177. {
  3178. if (skipped)
  3179. makeHeap();
  3180. return next(wasCompleteMatch, stepExtra);
  3181. }
  3182. }
  3183. else
  3184. return NULL;
  3185. }
  3186. bool doContinuation(HeapEntry &topEntry, bool canDefer)
  3187. {
  3188. IRoxieServerQueryPacket *continuation = topEntry.packet->queryContinuation();
  3189. if (continuation)
  3190. {
  3191. if (continuation->isDelayed() && canDefer)
  3192. {
  3193. if (adaptor.activity.queryLogCtx().queryTraceLevel() > 10)
  3194. adaptor.activity.queryLogCtx().CTXLOG("Deferring continuation");
  3195. deferredContinuation = true;
  3196. }
  3197. else
  3198. {
  3199. deferredContinuation = false;
  3200. continuation->Link();
  3201. topEntry.packet->Release();
  3202. topEntry.packet = continuation;
  3203. if (continuation->hasResult())
  3204. {
  3205. IMessageResult *result = continuation->queryResult();
  3206. bool lastIsCompleteMatch = isCompleteMatchFlag(result);
  3207. topEntry.noteResult(result->getCursor(rowManager), lastIsCompleteMatch);
  3208. }
  3209. else
  3210. {
  3211. if (continuation->isDelayed()) // has the continuation been requested yet?
  3212. {
  3213. continuation->Link();
  3214. topEntry.packet->Release();
  3215. topEntry.packet = continuation;
  3216. continuation->setDelayed(false);
  3217. if (adaptor.activity.queryLogCtx().queryTraceLevel() > 10)
  3218. adaptor.activity.queryLogCtx().CTXLOG("About to send continuation, from doContinuation");
  3219. ROQ->sendPacket(continuation->queryPacket(), adaptor.activity.queryLogCtx());
  3220. adaptor.sentsome.signal();
  3221. }
  3222. numPending++; // we are waiting for one that is already in flight
  3223. }
  3224. }
  3225. return true; // next not known yet
  3226. }
  3227. else
  3228. return false;
  3229. }
  3230. const void *next(bool & wasCompleteMatch, const SmartStepExtra & stepExtra)
  3231. {
  3232. OwnedConstRoxieRow ret;
  3233. if (heap.length())
  3234. {
  3235. if (deferredContinuation)
  3236. {
  3237. unsigned top = heap.item(0);
  3238. HeapEntry &topEntry = heapEntries.item(top);
  3239. doContinuation(topEntry, false);
  3240. return NULL;
  3241. }
  3242. if (remakePending)
  3243. remakeHeap();
  3244. unsigned top = heap.item(0);
  3245. HeapEntry &topEntry = heapEntries.item(top);
  3246. ret.set(topEntry.current);
  3247. wasCompleteMatch = topEntry.isCompleteMatch();
  3248. const void *next = topEntry.next();
  3249. if (!next)
  3250. {
  3251. if (!doContinuation(topEntry, stepExtra.returnMismatches()))
  3252. {
  3253. unsigned last = heap.popGet();
  3254. if (heap.length())
  3255. heap.replace(last, 0);
  3256. removeHeap(top);
  3257. }
  3258. }
  3259. remakePending = true;
  3260. }
  3261. return ret.getClear();
  3262. }
  3263. bool ready()
  3264. {
  3265. return endSeen && numPending == 0;
  3266. }
  3267. };
  3268. IRoxieServerQueryPacket *createRoxieServerQueryPacket(IRoxieQueryPacket *p, bool &cached)
  3269. {
  3270. if (serverSideCache && !debugContext)
  3271. {
  3272. IRoxieServerQueryPacket *ret = serverSideCache->findCachedResult(activity.queryLogCtx(), p);
  3273. if (ret)
  3274. {
  3275. p->Release();
  3276. cached = true;
  3277. return ret;
  3278. }
  3279. }
  3280. cached = false;
  3281. return new CRoxieServerQueryPacket(p);
  3282. }
  3283. #ifdef _DEBUG
  3284. void dumpPending()
  3285. {
  3286. CriticalBlock b(pendingCrit);
  3287. ForEachItemIn(idx, pending)
  3288. {
  3289. IRoxieServerQueryPacket &p = pending.item(idx);
  3290. StringBuffer s;
  3291. unsigned __int64 dummy;
  3292. if (p.isEnd())
  3293. s.append("END");
  3294. else if (p.isLimit(dummy, dummy, dummy))
  3295. s.append("LIMIT");
  3296. else
  3297. {
  3298. IRoxieQueryPacket *i = p.queryPacket();
  3299. s.appendf("%s", p.hasResult() ? "COMPLETE " : "PENDING ");
  3300. if (i)
  3301. {
  3302. RoxiePacketHeader &header = i->queryHeader();
  3303. header.toString(s);
  3304. }
  3305. }
  3306. DBGLOG("Pending %d %s", idx, s.str());
  3307. }
  3308. }
  3309. #endif
  3310. void abortPending()
  3311. {
  3312. CriticalBlock b(pendingCrit);
  3313. ForEachItemIn(idx, pending)
  3314. {
  3315. IRoxieServerQueryPacket &p = pending.item(idx);
  3316. if (!p.hasResult())
  3317. {
  3318. IRoxieQueryPacket *i = p.queryPacket();
  3319. if (i)
  3320. {
  3321. RoxiePacketHeader &header = i->queryHeader();
  3322. ROQ->sendAbort(header, activity.queryLogCtx());
  3323. }
  3324. }
  3325. }
  3326. pending.kill();
  3327. }
  3328. void checkDelayed()
  3329. {
  3330. if (ctx->queryDebugContext() && ctx->queryDebugContext()->getExecuteSequentially())
  3331. {
  3332. bool allDelayed = true;
  3333. CriticalBlock b(pendingCrit);
  3334. unsigned sendIdx = (unsigned) -1;
  3335. ForEachItemIn(idx, pending)
  3336. {
  3337. IRoxieServerQueryPacket &p = pending.item(idx);
  3338. if (p.queryPacket())
  3339. {
  3340. if (p.isDelayed())
  3341. {
  3342. if (sendIdx == (unsigned) -1)
  3343. sendIdx = idx;
  3344. }
  3345. else if (!p.hasResult())
  3346. {
  3347. allDelayed = false;
  3348. break;
  3349. }
  3350. }
  3351. }
  3352. if (allDelayed && sendIdx != (unsigned) -1)
  3353. {
  3354. if (activity.queryLogCtx().queryTraceLevel() > 10)
  3355. activity.queryLogCtx().CTXLOG("About to send debug-deferred from next");
  3356. pending.item(sendIdx).setDelayed(false);
  3357. ROQ->sendPacket(pending.item(sendIdx).queryPacket(), activity.queryLogCtx());
  3358. sentsome.signal();
  3359. }
  3360. }
  3361. else if (deferredStart)
  3362. {
  3363. CriticalBlock b(pendingCrit);
  3364. ForEachItemIn(idx, pending)
  3365. {
  3366. IRoxieServerQueryPacket &p = pending.item(idx);
  3367. if (p.isDelayed())
  3368. {
  3369. if (activity.queryLogCtx().queryTraceLevel() > 10)
  3370. activity.queryLogCtx().CTXLOG("About to send deferred start from next");
  3371. p.setDelayed(false);
  3372. ROQ->sendPacket(p.queryPacket(), activity.queryLogCtx());
  3373. sentsome.signal();
  3374. }
  3375. }
  3376. deferredStart = false;
  3377. }
  3378. }
  3379. void retryPending()
  3380. {
  3381. CriticalBlock b(pendingCrit);
  3382. checkDelayed();
  3383. ForEachItemIn(idx, pending)
  3384. {
  3385. IRoxieServerQueryPacket &p = pending.item(idx);
  3386. if (!p.hasResult() && !p.isDelayed())
  3387. {
  3388. IRoxieQueryPacket *i = p.queryPacket();
  3389. if (i)
  3390. {
  3391. if (!i->queryHeader().retry())
  3392. {
  3393. StringBuffer s;
  3394. IException *E = MakeStringException(ROXIE_MULTICAST_ERROR, "Failed to get response from slave(s) for %s in activity %d", i->queryHeader().toString(s).str(), activity.queryId());
  3395. activity.queryLogCtx().logOperatorException(E, __FILE__, __LINE__, "CRemoteResultAdaptor::retry");
  3396. throw E;
  3397. }
  3398. if (!localSlave)
  3399. {
  3400. ROQ->sendPacket(i, activity.queryLogCtx());
  3401. atomic_inc(&retriesSent);
  3402. }
  3403. }
  3404. }
  3405. }
  3406. }
  3407. class ChannelBuffer
  3408. {
  3409. protected:
  3410. unsigned bufferLeft;
  3411. MemoryBuffer buffer;
  3412. char *nextBuf;
  3413. unsigned overflowSequence;
  3414. unsigned channel; // == bonded channel
  3415. bool needsFlush;
  3416. InterruptableSemaphore flowController;
  3417. const CRemoteResultAdaptor &owner;
  3418. CriticalSection crit;
  3419. public:
  3420. ChannelBuffer(const CRemoteResultAdaptor &_owner, unsigned _channel) : owner(_owner), channel(_channel), flowController(perChannelFlowLimit)
  3421. {
  3422. overflowSequence = 0;
  3423. needsFlush = false;
  3424. bufferLeft = 0;
  3425. nextBuf = NULL;
  3426. }
  3427. void init(unsigned minSize)
  3428. {
  3429. assertex(!buffer.length());
  3430. if (minSize < MIN_PAYLOAD_SIZE)
  3431. minSize = MIN_PAYLOAD_SIZE;
  3432. unsigned headerSize = sizeof(RoxiePacketHeader)+owner.headerLength();
  3433. unsigned bufferSize = headerSize+minSize;
  3434. if (bufferSize < mtu_size)
  3435. bufferSize = mtu_size;
  3436. buffer.reserveTruncate(bufferSize);
  3437. bufferLeft = bufferSize - headerSize;
  3438. assertex(buffer.toByteArray());
  3439. nextBuf = (char *) buffer.toByteArray() + headerSize;
  3440. needsFlush = false;
  3441. }
  3442. inline IRoxieQueryPacket *flush()
  3443. {
  3444. CriticalBlock cb(crit);
  3445. Owned<IRoxieQueryPacket> ret;
  3446. if (needsFlush)
  3447. {
  3448. buffer.setLength(nextBuf - buffer.toByteArray());
  3449. RoxiePacketHeader *h = (RoxiePacketHeader *) buffer.toByteArray();
  3450. h->init(owner.remoteId, owner.ruid, channel, overflowSequence);
  3451. //patch logPrefix, cachedContext and parent extract into the place reserved in the message buffer
  3452. byte * tgt = (byte*)(h+1);
  3453. owner.copyHeader(tgt, channel);
  3454. ret.setown(createRoxiePacket(buffer));
  3455. if (overflowSequence == OVERFLOWSEQUENCE_MAX)
  3456. overflowSequence = 1; // don't wrap to 0 - that is a bit special
  3457. else
  3458. overflowSequence++;
  3459. needsFlush = false;
  3460. bufferLeft = 0;
  3461. if (owner.flowControlled)
  3462. {
  3463. CriticalUnblock cub(crit);
  3464. while (!flowController.wait(1000))
  3465. {
  3466. StringBuffer s;
  3467. owner.activity.queryLogCtx().CTXLOG("Channel %d blocked by flow control: %s", channel, h->toString(s).str());
  3468. }
  3469. }
  3470. }
  3471. return ret.getClear();
  3472. }
  3473. inline void signal()
  3474. {
  3475. if (owner.flowControlled)
  3476. flowController.signal();
  3477. }
  3478. inline void interrupt(IException *e)
  3479. {
  3480. flowController.interrupt(e);
  3481. }
  3482. inline void *getBuffer(unsigned size)
  3483. {
  3484. CriticalBlock cb(crit);
  3485. if (bufferLeft >= size)
  3486. {
  3487. needsFlush = true;
  3488. void * ret = nextBuf;
  3489. nextBuf += size;
  3490. bufferLeft -= size;
  3491. return ret;
  3492. }
  3493. else if (!needsFlush)
  3494. {
  3495. init(size);
  3496. return getBuffer(size);
  3497. }
  3498. else if (owner.mergeOrder)
  3499. {
  3500. return buffer.reserve(size); // whole query needs to go as single packet if we are to merge
  3501. }
  3502. else
  3503. return NULL; // will force it to flush and start a new packet
  3504. }
  3505. };
  3506. private:
  3507. friend class CRemoteResultMerger;
  3508. bool allread;
  3509. bool contextCached;
  3510. bool preserveOrder;
  3511. bool eogSent = false;
  3512. InterruptableSemaphore sentsome;
  3513. Owned <IMessageCollator> mc;
  3514. Owned<IMessageUnpackCursor> mu;
  3515. Owned<IMessageResult> mr;
  3516. ChannelBuffer **buffers;
  3517. IHThorArg &helper;
  3518. unsigned __int64 stopAfter;
  3519. unsigned resendSequence;
  3520. IHThorArg *colocalArg;
  3521. IArrayOf<IRoxieServerQueryPacket> pending;
  3522. CriticalSection pendingCrit;
  3523. IRoxieServerSideCache *serverSideCache;
  3524. unsigned sentSequence;
  3525. Owned<IOutputRowDeserializer> deserializer;
  3526. Owned<IEngineRowAllocator> rowAllocator;
  3527. CRemoteResultMerger merger;
  3528. // this is only used to avoid recreating a bufferStream for each row. A better solution may be needed
  3529. MemoryBuffer tempRowBuffer;
  3530. Owned<ISerialStream> bufferStream;
  3531. CThorStreamDeserializerSource rowSource;
  3532. protected:
  3533. IRowManager *rowManager;
  3534. unsigned __int64 rowLimit;
  3535. unsigned __int64 keyedLimit;
  3536. IRoxieServerErrorHandler *errorHandler;
  3537. CachedOutputMetaData meta;
  3538. public:
  3539. ISteppingMeta *mergeOrder;
  3540. IRoxieSlaveContext *ctx;
  3541. IDebuggableContext *debugContext;
  3542. IRoxieServerActivity &activity;
  3543. unsigned parentExtractSize;
  3544. const byte * parentExtract;
  3545. bool flowControlled;
  3546. bool deferredStart;
  3547. MemoryBuffer logInfo;
  3548. MemoryBuffer cachedContext;
  3549. const RemoteActivityId &remoteId;
  3550. ruid_t ruid;
  3551. mutable CriticalSection buffersCrit;
  3552. unsigned processed;
  3553. cycle_t totalCycles;
  3554. bool timeActivities;
  3555. //private: //vc6 doesn't like this being private yet accessed by nested class...
  3556. const void *getRow(IMessageUnpackCursor *mu)
  3557. {
  3558. if (!mu->isSerialized() || (meta.isFixedSize() && !deserializer))
  3559. return mu->getNext(meta.getFixedSize());
  3560. else
  3561. {
  3562. RecordLengthType *rowlen = (RecordLengthType *) mu->getNext(sizeof(RecordLengthType));
  3563. if (rowlen)
  3564. {
  3565. RecordLengthType len = *rowlen;
  3566. ReleaseRoxieRow(rowlen);
  3567. const void *slaveRec = mu->getNext(len);
  3568. if (deserializer && mu->isSerialized())
  3569. {
  3570. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  3571. tempRowBuffer.setBuffer(len, const_cast<void *>(slaveRec), false);
  3572. size_t outsize = deserializer->deserialize(rowBuilder, rowSource);
  3573. ReleaseRoxieRow(slaveRec);
  3574. return rowBuilder.finalizeRowClear(outsize);
  3575. }
  3576. else
  3577. return slaveRec;
  3578. }
  3579. else
  3580. return NULL;
  3581. }
  3582. }
  3583. private:
  3584. ChannelBuffer *queryChannelBuffer(unsigned channel, bool force=false)
  3585. {
  3586. CriticalBlock cb(buffersCrit);
  3587. ChannelBuffer *b = buffers[channel];
  3588. if (!b && force)
  3589. {
  3590. if (!contextCached)
  3591. {
  3592. logInfo.clear();
  3593. unsigned char loggingFlags = LOGGING_FLAGSPRESENT | LOGGING_TRACELEVELSET;
  3594. unsigned char ctxTraceLevel = activity.queryLogCtx().queryTraceLevel() + 1; // Avoid passing a 0
  3595. const QueryOptions &options = ctx->queryOptions();
  3596. if (activity.queryLogCtx().isIntercepted())
  3597. loggingFlags |= LOGGING_INTERCEPTED;
  3598. if (options.timeActivities)
  3599. loggingFlags |= LOGGING_TIMEACTIVITIES;
  3600. if (activity.queryLogCtx().isBlind())
  3601. loggingFlags |= LOGGING_BLIND;
  3602. if (options.checkingHeap)
  3603. loggingFlags |= LOGGING_CHECKINGHEAP;
  3604. if (ctx->queryWorkUnit())
  3605. loggingFlags |= LOGGING_WUID;
  3606. if (debugContext)
  3607. {
  3608. loggingFlags |= LOGGING_DEBUGGERACTIVE;
  3609. logInfo.append(loggingFlags).append(ctxTraceLevel);
  3610. MemoryBuffer bpInfo;
  3611. debugContext->serialize(bpInfo);
  3612. bpInfo.append((__uint64)(memsize_t) &activity);
  3613. logInfo.append((unsigned short) bpInfo.length());
  3614. logInfo.append(bpInfo.length(), bpInfo.toByteArray());
  3615. }
  3616. else
  3617. logInfo.append(loggingFlags).append(ctxTraceLevel);
  3618. StringBuffer logPrefix;
  3619. activity.queryLogCtx().getLogPrefix(logPrefix);
  3620. logInfo.append(logPrefix);
  3621. activity.serializeCreateStartContext(cachedContext.clear());
  3622. activity.serializeExtra(cachedContext);
  3623. if (activity.queryVarFileInfo())
  3624. {
  3625. activity.queryVarFileInfo()->queryTimeStamp().serialize(cachedContext);
  3626. cachedContext.append(activity.queryVarFileInfo()->queryCheckSum());
  3627. }
  3628. contextCached = true;
  3629. }
  3630. b = buffers[channel] = new ChannelBuffer(*this, channel);
  3631. }
  3632. return b;
  3633. }
  3634. void processRow(const void *got)
  3635. {
  3636. processed++;
  3637. if (processed > rowLimit)
  3638. {
  3639. ReleaseRoxieRow(got);
  3640. errorHandler->onLimitExceeded(false); // NOTE - should throw exception
  3641. throwUnexpected();
  3642. }
  3643. else if (processed > keyedLimit)
  3644. {
  3645. ReleaseRoxieRow(got);
  3646. errorHandler->onLimitExceeded(true); // NOTE - should throw exception
  3647. throwUnexpected();
  3648. }
  3649. }
  3650. public:
  3651. IMPLEMENT_IINTERFACE;
  3652. CRemoteResultAdaptor(IRoxieSlaveContext *_ctx, IRoxieServerErrorHandler *_errorHandler, const RemoteActivityId &_remoteId, IOutputMetaData *_meta, IHThorArg &_helper, IRoxieServerActivity &_activity, bool _preserveOrder, bool _flowControlled)
  3653. : remoteId(_remoteId), meta(_meta), activity(_activity), helper(_helper), preserveOrder(_preserveOrder), flowControlled(_flowControlled), merger(*this)
  3654. {
  3655. ctx = _ctx;
  3656. errorHandler = _errorHandler;
  3657. colocalArg = NULL;
  3658. allread = false;
  3659. ruid = 0;
  3660. rowLimit = (unsigned __int64) -1;
  3661. keyedLimit = (unsigned __int64) -1;
  3662. contextCached = false;
  3663. stopAfter = I64C(0x7FFFFFFFFFFFFFFF);
  3664. buffers = new ChannelBuffer*[numChannels+1];
  3665. memset(buffers, 0, (numChannels+1)*sizeof(ChannelBuffer *));
  3666. parentExtractSize = 0;
  3667. rowManager = NULL;
  3668. parentExtract = NULL;
  3669. debugContext = NULL;
  3670. mergeOrder = NULL;
  3671. deferredStart = false;
  3672. processed = 0;
  3673. sentSequence = 0;
  3674. resendSequence = 0;
  3675. totalCycles = 0;
  3676. serverSideCache = activity.queryServerSideCache();
  3677. bufferStream.setown(createMemoryBufferSerialStream(tempRowBuffer));
  3678. rowSource.setStream(bufferStream);
  3679. timeActivities = defaultTimeActivities;
  3680. }
  3681. ~CRemoteResultAdaptor()
  3682. {
  3683. if (mc)
  3684. {
  3685. ROQ->queryReceiveManager()->detachCollator(mc);
  3686. mc.clear();
  3687. }
  3688. for (unsigned channel = 0; channel <= numChannels; channel++)
  3689. {
  3690. delete(buffers[channel]);
  3691. }
  3692. delete [] buffers;
  3693. }
  3694. void setMeta(IOutputMetaData *newmeta)
  3695. {
  3696. meta.set(newmeta);
  3697. }
  3698. virtual IEngineRowStream *queryConcreteOutputStream(unsigned whichInput) { assertex(whichInput==0); return this; }
  3699. virtual IStrandJunction *queryConcreteOutputJunction(unsigned idx) const { assertex(idx==0); return nullptr; }
  3700. virtual IRoxieServerActivity *queryActivity()
  3701. {
  3702. return &activity;
  3703. }
  3704. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  3705. {
  3706. return NULL;
  3707. }
  3708. void setMergeInfo(ISteppingMeta *_mergeOrder)
  3709. {
  3710. mergeOrder = _mergeOrder;
  3711. deferredStart = true;
  3712. }
  3713. void send(IRoxieQueryPacket *p)
  3714. {
  3715. if (p)
  3716. {
  3717. Linked<IRoxieQueryPacket> saver(p); // avoids a race with abortPending, without keeping pendingCrit locked over the send which we might prefer not to
  3718. assertex(p->queryHeader().uid==ruid);
  3719. // MORE: Maybe we should base the fastlane flag on some other
  3720. // criteria !! (i.e A Roxie server prediction based on the
  3721. // activity type/activity behaviour/expected reply size .. etc).
  3722. //
  3723. // Currently (code below) based on high priority, seq=0, and none-child activity.
  3724. // But this could still cause too many reply packets on the fatlane
  3725. // (higher priority output Q), which may cause the activities on the
  3726. // low priority output Q to not get service on time.
  3727. if ((colocalArg == 0) && // not a child query activity??
  3728. (p->queryHeader().activityId & (ROXIE_SLA_PRIORITY | ROXIE_HIGH_PRIORITY)) &&
  3729. (p->queryHeader().overflowSequence == 0) &&
  3730. (p->queryHeader().continueSequence & ~CONTINUE_SEQUENCE_SKIPTO)==0)
  3731. p->queryHeader().retries |= ROXIE_FASTLANE;
  3732. if (p->queryHeader().channel)
  3733. {
  3734. bool cached = false;
  3735. IRoxieServerQueryPacket *rsqp = createRoxieServerQueryPacket(p, cached);
  3736. if (deferredStart)
  3737. rsqp->setDelayed(true);
  3738. rsqp->setSequence(sentSequence++);
  3739. {
  3740. CriticalBlock b(pendingCrit);
  3741. pending.append(*rsqp);
  3742. }
  3743. if (!deferredStart)
  3744. {
  3745. if (!cached)
  3746. ROQ->sendPacket(p, activity.queryLogCtx());
  3747. sentsome.signal();
  3748. }
  3749. }
  3750. else
  3751. {
  3752. // 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
  3753. // Need to add first, then send
  3754. unsigned i;
  3755. bool allCached = true;
  3756. for (i = 1; i <= numChannels; i++)
  3757. {
  3758. IRoxieQueryPacket *q = p->clonePacket(i);
  3759. bool thisChannelCached;
  3760. IRoxieServerQueryPacket *rsqp = createRoxieServerQueryPacket(q, thisChannelCached);
  3761. if (!thisChannelCached)
  3762. allCached = false;
  3763. rsqp->setSequence(sentSequence++);
  3764. if (deferredStart)
  3765. {
  3766. rsqp->setDelayed(true);
  3767. }
  3768. {
  3769. CriticalBlock b(pendingCrit);
  3770. pending.append(*rsqp);
  3771. }
  3772. if (!deferredStart)
  3773. sentsome.signal();
  3774. }
  3775. if (!allCached && !deferredStart)
  3776. ROQ->sendPacket(p, activity.queryLogCtx());
  3777. buffers[0]->signal(); // since replies won't come back on that channel...
  3778. p->Release();
  3779. }
  3780. }
  3781. }
  3782. void *getMem(unsigned partNo, unsigned fileNo, unsigned size)
  3783. {
  3784. unsigned channel = partNo ? getBondedChannel(partNo) : 0;
  3785. size += sizeof(PartNoType);
  3786. ChannelBuffer *b = queryChannelBuffer(channel, true);
  3787. char *buffer = (char *) b->getBuffer(size);
  3788. if (!buffer)
  3789. {
  3790. send(b->flush());
  3791. buffer = (char *) b->getBuffer(size);
  3792. }
  3793. PartNoType sp;
  3794. sp.partNo = partNo;
  3795. sp.fileNo = fileNo;
  3796. memcpy(buffer, &sp, sizeof(sp));
  3797. buffer += sizeof(sp);
  3798. return buffer;
  3799. }
  3800. void injectResult(IMessageResult *result)
  3801. {
  3802. IRoxieServerQueryPacket *f = new CRoxieServerQueryPacket(NULL);
  3803. f->setSequence(sentSequence++);
  3804. f->setResult(result);
  3805. CriticalBlock b(pendingCrit);
  3806. pending.append(*f);
  3807. sentsome.signal(); // MORE - arguably should only send if there is any point waking up the listener thread, to save context swicth
  3808. }
  3809. void flush()
  3810. {
  3811. for (unsigned channel = 0; channel <= numChannels; channel++)
  3812. {
  3813. ChannelBuffer *b = queryChannelBuffer(channel, false);
  3814. if (b)
  3815. send(b->flush());
  3816. }
  3817. }
  3818. void interruptBuffers(IException *e)
  3819. {
  3820. for (unsigned channel = 0; channel <= numChannels; channel++)
  3821. {
  3822. ChannelBuffer *b = queryChannelBuffer(channel, false);
  3823. if (b)
  3824. b->interrupt(LINK(e));
  3825. }
  3826. }
  3827. void senddone()
  3828. {
  3829. CriticalBlock b(pendingCrit);
  3830. pending.append(*new CRoxieServerQueryPacketEndMarker);
  3831. sentsome.signal();
  3832. }
  3833. bool fireException(IException *e)
  3834. {
  3835. {
  3836. CriticalBlock b(pendingCrit);
  3837. pending.append(*new CRoxieServerQueryPacketEndMarker);
  3838. }
  3839. interruptBuffers(e);
  3840. if (mc)
  3841. mc->interrupt(LINK(e));
  3842. sentsome.interrupt(e);
  3843. return true;
  3844. }
  3845. virtual void onCreate(IHThorArg *_colocalArg)
  3846. {
  3847. debugContext = ctx->queryDebugContext();
  3848. colocalArg = _colocalArg;
  3849. if (meta.needsSerializeDisk())
  3850. {
  3851. deserializer.setown(meta.createDiskDeserializer(ctx->queryCodeContext(), activity.queryId()));
  3852. rowAllocator.setown(activity.createRowAllocator(meta.queryOriginal()));
  3853. }
  3854. if (ctx->queryDebugContext() && ctx->queryDebugContext()->getExecuteSequentially())
  3855. deferredStart = true;
  3856. timeActivities = ctx->queryOptions().timeActivities;
  3857. }
  3858. virtual void onStart(unsigned _parentExtractSize, const byte * _parentExtract)
  3859. {
  3860. #ifdef TRACE_STARTSTOP
  3861. if (traceStartStop)
  3862. activity.queryLogCtx().CTXLOG("RRAonstart");
  3863. #endif
  3864. sentsome.reinit();
  3865. ruid = getNextRuid();
  3866. rowManager = &ctx->queryRowManager();
  3867. if (mergeOrder)
  3868. merger.init(mergeOrder, rowManager);
  3869. if (mc)
  3870. {
  3871. ROQ->queryReceiveManager()->detachCollator(mc); // Should never happen - implies someone forgot to call onReset!
  3872. }
  3873. mc.setown(ROQ->queryReceiveManager()->createMessageCollator(rowManager, ruid));
  3874. allread = false;
  3875. mu.clear();
  3876. contextCached = false;
  3877. processed = 0;
  3878. resendSequence = 0;
  3879. sentSequence = 0;
  3880. for (unsigned channel = 0; channel <= numChannels; channel++)
  3881. {
  3882. delete(buffers[channel]);
  3883. buffers[channel] = NULL;
  3884. }
  3885. flush();
  3886. parentExtractSize = _parentExtractSize;
  3887. parentExtract = _parentExtract;
  3888. }
  3889. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  3890. {
  3891. #ifdef TRACE_STARTSTOP
  3892. if (traceStartStop)
  3893. activity.queryLogCtx().CTXLOG("RRAstart");
  3894. #endif
  3895. activity.start(parentExtractSize, parentExtract, paused);
  3896. }
  3897. void setLimits(unsigned __int64 _rowLimit, unsigned __int64 _keyedLimit, unsigned __int64 _stopAfter)
  3898. {
  3899. if (ctx->queryProbeManager())
  3900. {
  3901. if (_rowLimit != (unsigned __int64) -1) ctx->queryProbeManager()->setNodePropertyInt(&activity, "rowLimit", _rowLimit);
  3902. if (_keyedLimit != (unsigned __int64) -1) ctx->queryProbeManager()->setNodePropertyInt(&activity, "keyedLimit", _keyedLimit);
  3903. if (_stopAfter != I64C(0x7FFFFFFFFFFFFFFF)) ctx->queryProbeManager()->setNodePropertyInt(&activity, "choosenLimit", _stopAfter);
  3904. }
  3905. {
  3906. CriticalBlock b(pendingCrit);
  3907. if (pending.length())
  3908. {
  3909. #ifdef _DEBUG
  3910. dumpPending(); // MORE - only defined in debug build - could have put the ifdef inside the dumpPending method
  3911. #endif
  3912. assertex(pending.length()==0);
  3913. }
  3914. pending.append(*new CRoxieServerQueryPacketLimitMarker(_rowLimit, _keyedLimit, _stopAfter));
  3915. }
  3916. sentsome.signal();
  3917. rowLimit = _rowLimit;
  3918. keyedLimit = _keyedLimit;
  3919. stopAfter = _stopAfter;
  3920. }
  3921. virtual void stop()
  3922. {
  3923. #ifdef TRACE_STARTSTOP
  3924. if (traceStartStop)
  3925. activity.queryLogCtx().CTXLOG("RRAstop");
  3926. #endif
  3927. onStop();
  3928. activity.stop();
  3929. }
  3930. void onStop()
  3931. {
  3932. #ifdef TRACE_STARTSTOP
  3933. if (traceStartStop)
  3934. activity.queryLogCtx().CTXLOG("RRAonstop");
  3935. #endif
  3936. abortPending();
  3937. interruptBuffers(NULL);
  3938. sentsome.interrupt();
  3939. if (mc) // May not be set if start() chain threw exception
  3940. mc->interrupt();
  3941. }
  3942. virtual void reset()
  3943. {
  3944. #ifdef TRACE_STARTSTOP
  3945. if (traceStartStop)
  3946. activity.queryLogCtx().CTXLOG("RRAreset");
  3947. #endif
  3948. activity.reset();
  3949. onReset();
  3950. }
  3951. virtual IStrandJunction *getOutputStreams(IRoxieSlaveContext *ctx, unsigned idx, PointerArrayOf<IEngineRowStream> &streams, const StrandOptions * consumerOptions, bool consumerOrdered, IOrderedCallbackCollection * orderedCallbacks)
  3952. {
  3953. // Make sure parent activity calls up the tree
  3954. PointerArrayOf<IEngineRowStream> instreams;
  3955. IStrandJunction *junction = activity.getOutputStreams(ctx, idx, instreams, consumerOptions, consumerOrdered, orderedCallbacks);
  3956. assertex (junction == NULL);
  3957. // I return a single strand (we could change that sometime I guess...)
  3958. streams.append(this);
  3959. return NULL;
  3960. }
  3961. virtual void resetEOF()
  3962. {
  3963. throwUnexpected();
  3964. }
  3965. virtual void onReset()
  3966. {
  3967. #ifdef TRACE_STARTSTOP
  3968. if (traceStartStop)
  3969. activity.queryLogCtx().CTXLOG("RRAonreset");
  3970. #endif
  3971. if (mc)
  3972. ROQ->queryReceiveManager()->detachCollator(mc);
  3973. merger.reset();
  3974. pending.kill();
  3975. if (mc && ctx)
  3976. ctx->addSlavesReplyLen(mc->queryBytesReceived());
  3977. mc.clear(); // Or we won't free memory for graphs that get recreated
  3978. mu.clear(); //ditto
  3979. deferredStart = false;
  3980. // NOTE: do NOT clear mergeOrder - this is set at create time not per child query
  3981. }
  3982. virtual IOutputMetaData * queryOutputMeta() const
  3983. {
  3984. return helper.queryOutputMeta();
  3985. }
  3986. virtual unsigned __int64 queryTotalCycles() const
  3987. {
  3988. return totalCycles;
  3989. }
  3990. void gatherStats(CRuntimeStatisticCollection & merged) const
  3991. {
  3992. if (rowAllocator)
  3993. rowAllocator->gatherStats(merged);
  3994. }
  3995. const void * nextRowGE(const void *seek, const void *rawSeek, unsigned numFields, unsigned seekLen, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  3996. {
  3997. if (activity.queryLogCtx().queryTraceLevel() > 20)
  3998. {
  3999. StringBuffer recstr;
  4000. unsigned i;
  4001. for (i = 0; i < seekLen; i++)
  4002. {
  4003. recstr.appendf("%02x ", ((unsigned char *) rawSeek)[i]);
  4004. }
  4005. activity.queryLogCtx().CTXLOG("CRemoteResultAdaptor::nextRowGE(rawSeek=%s numFields=%d, seeklen=%d, returnMismatches=%d)", recstr.str(), numFields, seekLen, stepExtra.returnMismatches());
  4006. }
  4007. assertex(mergeOrder);
  4008. if (deferredStart)
  4009. {
  4010. CriticalBlock b(pendingCrit);
  4011. ForEachItemIn(idx, pending)
  4012. {
  4013. IRoxieServerQueryPacket &p = pending.item(idx);
  4014. if (p.isDelayed())
  4015. {
  4016. p.setDelayed(false);
  4017. if (activity.queryLogCtx().queryTraceLevel() > 10)
  4018. activity.queryLogCtx().CTXLOG("About to send deferred start from nextRowGE, setting requireExact to %d", !stepExtra.returnMismatches());
  4019. MemoryBuffer serializedSkip;
  4020. activity.serializeSkipInfo(serializedSkip, seekLen, rawSeek, numFields, seek, stepExtra);
  4021. p.setPacket(p.queryPacket()->insertSkipData(serializedSkip.length(), serializedSkip.toByteArray()));
  4022. ROQ->sendPacket(p.queryPacket(), activity.queryLogCtx());
  4023. sentsome.signal();
  4024. }
  4025. }
  4026. deferredStart = false;
  4027. }
  4028. SimpleActivityTimer t(totalCycles, timeActivities);
  4029. if (processed==stopAfter)
  4030. return NULL;
  4031. if (allread)
  4032. return NULL;
  4033. for (;;)
  4034. {
  4035. if (merger.ready())
  4036. {
  4037. const void *got = merger.nextRowGE(seek, rawSeek, numFields, seekLen, wasCompleteMatch, stepExtra);
  4038. if (got)
  4039. {
  4040. processRow(got);
  4041. return got;
  4042. }
  4043. }
  4044. if (!reload()) // MORE - should pass the seek info here...
  4045. return NULL;
  4046. }
  4047. }
  4048. virtual const void *nextRow()
  4049. {
  4050. // If we are merging then we need to do a heapsort on all
  4051. SimpleActivityTimer t(totalCycles, timeActivities);
  4052. if (activity.queryLogCtx().queryTraceLevel() > 10)
  4053. {
  4054. activity.queryLogCtx().CTXLOG("CRemoteResultAdaptor::nextRow()");
  4055. }
  4056. for (;;)
  4057. {
  4058. checkDelayed();
  4059. if (processed==stopAfter)
  4060. return NULL;
  4061. if (allread)
  4062. return NULL;
  4063. // If we can still consume from the merger or the most recently retrieved mu, do so.
  4064. const void *got = NULL;
  4065. if (mergeOrder && merger.ready())
  4066. {
  4067. bool matched = true;
  4068. got = merger.next(matched, dummySmartStepExtra);
  4069. }
  4070. else if (mu)
  4071. {
  4072. got = getRow(mu);
  4073. if (!got && meta.isGrouped() && !eogSent)
  4074. {
  4075. eogSent = true;
  4076. return NULL;
  4077. }
  4078. }
  4079. if (got)
  4080. {
  4081. processRow(got);
  4082. return got;
  4083. }
  4084. eogSent = false;
  4085. if (!reload())
  4086. return NULL;
  4087. }
  4088. }
  4089. bool reload()
  4090. {
  4091. // Wait for something to be returned from a slave....
  4092. mu.clear();
  4093. sentsome.wait();
  4094. // must be at least an endMarker on the queue since sentsome was signalled
  4095. {
  4096. CriticalBlock b(pendingCrit);
  4097. IRoxieServerQueryPacket &top = pending.item(0);
  4098. if (top.isLimit(rowLimit, keyedLimit, stopAfter)) // This is really a start marker...
  4099. {
  4100. pending.remove(0);
  4101. return true;
  4102. }
  4103. else if (top.isEnd())
  4104. {
  4105. pending.remove(0);
  4106. allread = true;
  4107. if (activity.queryLogCtx().queryTraceLevel() > 5)
  4108. activity.queryLogCtx().CTXLOG("All read on ruid %x", ruid);
  4109. return false;
  4110. }
  4111. else if (mergeOrder)
  4112. {
  4113. unsigned idx = 0;
  4114. bool added = false;
  4115. while (pending.isItem(idx))
  4116. {
  4117. IRoxieServerQueryPacket &item = pending.item(idx);
  4118. if (item.isEnd())
  4119. {
  4120. if (merger.noteEndSeen())
  4121. {
  4122. sentsome.signal(); // Because we waited, yet didn't actually consume anything
  4123. added = true;
  4124. }
  4125. break;
  4126. }
  4127. else if (item.hasResult())
  4128. {
  4129. merger.noteResult(&item, item.getSequence());
  4130. pending.remove(idx);
  4131. added = true;
  4132. }
  4133. else if (item.isContinuation())
  4134. idx++;
  4135. else
  4136. break;
  4137. }
  4138. if (added)
  4139. return true;
  4140. }
  4141. else if (top.hasResult())
  4142. {
  4143. mr.setown(pending.item(0).getResult());
  4144. mu.setown(mr->getCursor(rowManager));
  4145. pending.remove(0);
  4146. return true;
  4147. }
  4148. }
  4149. getNextUnpacker();
  4150. return true;
  4151. }
  4152. void getNextUnpacker()
  4153. {
  4154. mu.clear();
  4155. unsigned ctxTraceLevel = activity.queryLogCtx().queryTraceLevel();
  4156. for (;;)
  4157. {
  4158. checkDelayed();
  4159. unsigned timeout = remoteId.isSLAPriority() ? slaTimeout : (remoteId.isHighPriority() ? highTimeout : lowTimeout);
  4160. activity.queryContext()->checkAbort();
  4161. bool anyActivity;
  4162. if (ctxTraceLevel > 5)
  4163. activity.queryLogCtx().CTXLOG("Calling getNextUnpacker(%d)", timeout);
  4164. mr.setown(mc->getNextResult(timeout, anyActivity));
  4165. if (ctxTraceLevel > 6)
  4166. activity.queryLogCtx().CTXLOG("Called getNextUnpacker(%d), activity=%d", timeout, anyActivity);
  4167. activity.queryContext()->checkAbort();
  4168. if (mr)
  4169. {
  4170. unsigned roxieHeaderLen;
  4171. const RoxiePacketHeader &header = *(const RoxiePacketHeader *) mr->getMessageHeader(roxieHeaderLen);
  4172. #ifdef _DEBUG
  4173. assertex(roxieHeaderLen == sizeof(RoxiePacketHeader));
  4174. #endif
  4175. if (ctxTraceLevel > 5)
  4176. {
  4177. StringBuffer s;
  4178. activity.queryLogCtx().CTXLOG("getNextUnpacker got packet %s", header.toString(s).str());
  4179. }
  4180. CriticalBlock b(pendingCrit);
  4181. unsigned idx = 0;
  4182. IRoxieServerQueryPacket *original = NULL;
  4183. IRoxieQueryPacket *op;
  4184. while (pending.isItem(idx))
  4185. {
  4186. original = &pending.item(idx);
  4187. op = original->queryPacket();
  4188. if (op && header.matchPacket(op->queryHeader()))
  4189. break;
  4190. original = NULL;
  4191. idx++;
  4192. }
  4193. if (!original || original->hasResult())
  4194. {
  4195. switch (header.activityId)
  4196. {
  4197. case ROXIE_FILECALLBACK:
  4198. {
  4199. // tell slave to abort
  4200. //if (ctxTraceLevel > 5)
  4201. {
  4202. StringBuffer s;
  4203. activity.queryLogCtx().CTXLOG("Redundant callback on query %s", header.toString(s).str());
  4204. }
  4205. Owned<IMessageUnpackCursor> callbackData = mr->getCursor(rowManager);
  4206. OwnedConstRoxieRow len = callbackData->getNext(sizeof(RecordLengthType));
  4207. if (len)
  4208. {
  4209. RecordLengthType *rowlen = (RecordLengthType *) len.get();
  4210. OwnedConstRoxieRow row = callbackData->getNext(*rowlen);
  4211. const char *rowdata = (const char *) row.get();
  4212. // bool isOpt = * (bool *) rowdata;
  4213. // bool isLocal = * (bool *) (rowdata+1);
  4214. ROQ->sendAbortCallback(header, rowdata+2, activity.queryLogCtx());
  4215. }
  4216. else
  4217. throwUnexpected();
  4218. break;
  4219. }
  4220. // MORE - ROXIE_ALIVE perhaps should go here too
  4221. default:
  4222. if (ctxTraceLevel > 3)
  4223. activity.queryLogCtx().CTXLOG("Discarding packet %p - original %p is NULL or has result already", mr.get(), original);
  4224. mr->discard();
  4225. break;
  4226. }
  4227. mr.clear();
  4228. }
  4229. else
  4230. {
  4231. atomic_inc(&resultsReceived);
  4232. switch (header.activityId)
  4233. {
  4234. case ROXIE_DEBUGCALLBACK:
  4235. {
  4236. Owned<IMessageUnpackCursor> callbackData = mr->getCursor(rowManager);
  4237. OwnedConstRoxieRow len = callbackData->getNext(sizeof(RecordLengthType));
  4238. if (len)
  4239. {
  4240. RecordLengthType *rowlen = (RecordLengthType *) len.get();
  4241. OwnedConstRoxieRow row = callbackData->getNext(*rowlen);
  4242. char *rowdata = (char *) row.get();
  4243. if (ctxTraceLevel > 5)
  4244. {
  4245. StringBuffer s;
  4246. activity.queryLogCtx().CTXLOG("Callback on query %s for debug", header.toString(s).str());
  4247. }
  4248. MemoryBuffer slaveInfo;
  4249. slaveInfo.setBuffer(*rowlen, rowdata, false);
  4250. unsigned debugSequence;
  4251. slaveInfo.read(debugSequence);
  4252. Owned<IRoxieQueryPacket> reply = original->getDebugResponse(debugSequence);
  4253. if (!reply)
  4254. reply.setown(activity.queryContext()->queryDebugContext()->onDebugCallback(header, *rowlen, rowdata));
  4255. if (reply)
  4256. {
  4257. original->setDebugResponse(debugSequence, reply);
  4258. ROQ->sendPacket(reply, activity.queryLogCtx());
  4259. }
  4260. }
  4261. else
  4262. throwUnexpected();
  4263. // MORE - somehow we need to make sure slave gets a reply even if I'm not waiting (in udp layer)
  4264. // Leave original message on pending queue in original location - this is not a reply to it.
  4265. break;
  4266. }
  4267. case ROXIE_FILECALLBACK:
  4268. {
  4269. // we need to send back to the slave a message containing the file info requested.
  4270. Owned<IMessageUnpackCursor> callbackData = mr->getCursor(rowManager);
  4271. OwnedConstRoxieRow len = callbackData->getNext(sizeof(RecordLengthType));
  4272. if (len)
  4273. {
  4274. RecordLengthType *rowlen = (RecordLengthType *) len.get();
  4275. OwnedConstRoxieRow row = callbackData->getNext(*rowlen);
  4276. const char *rowdata = (const char *) row.get();
  4277. bool isOpt = * (bool *) rowdata;
  4278. bool isLocal = * (bool *) (rowdata+1);
  4279. const char *lfn = rowdata+2;
  4280. if (ctxTraceLevel > 5)
  4281. {
  4282. StringBuffer s;
  4283. activity.queryLogCtx().CTXLOG("Callback on query %s file %s", header.toString(s).str(),(const char *) lfn);
  4284. }
  4285. activity.queryContext()->onFileCallback(header, lfn, isOpt, isLocal);
  4286. }
  4287. else
  4288. throwUnexpected();
  4289. // MORE - somehow we need to make sure slave gets a reply even if I'm not waiting (in udp layer)
  4290. // Leave original message on pending queue in original location - this is not a reply to it.
  4291. break;
  4292. }
  4293. case ROXIE_KEYEDLIMIT_EXCEEDED:
  4294. activity.queryLogCtx().CTXLOG("ROXIE_KEYEDLIMIT_EXCEEDED");
  4295. errorHandler->onLimitExceeded(true); // NOTE - should throw exception!
  4296. throwUnexpected();
  4297. case ROXIE_LIMIT_EXCEEDED:
  4298. activity.queryLogCtx().CTXLOG("ROXIE_LIMIT_EXCEEDED");
  4299. errorHandler->onLimitExceeded(false); // NOTE - should throw exception!
  4300. throwUnexpected();
  4301. case ROXIE_TRACEINFO:
  4302. {
  4303. Owned<IMessageUnpackCursor> extra = mr->getCursor(rowManager);
  4304. for (;;)
  4305. {
  4306. RecordLengthType *rowlen = (RecordLengthType *) extra->getNext(sizeof(RecordLengthType));
  4307. if (rowlen)
  4308. {
  4309. char *logInfo = (char *) extra->getNext(*rowlen);
  4310. MemoryBuffer buf;
  4311. buf.setBuffer(*rowlen, logInfo, false);
  4312. switch ((TracingCategory) *logInfo)
  4313. {
  4314. case LOG_TRACING:
  4315. case LOG_ERROR:
  4316. activity.queryLogCtx().CTXLOGl(new LogItem(buf));
  4317. break;
  4318. case LOG_STATVALUES:
  4319. buf.skip(1);
  4320. activity.mergeStats(buf);
  4321. break;
  4322. case LOG_CHILDCOUNT:
  4323. case LOG_CHILDSTATS:
  4324. unsigned graphId, childId;
  4325. buf.skip(1);
  4326. buf.read(graphId);
  4327. buf.read(childId);
  4328. if (*logInfo == LOG_CHILDCOUNT)
  4329. {
  4330. unsigned idx;
  4331. unsigned childProcessed;
  4332. unsigned childStrands;
  4333. buf.read(idx);
  4334. buf.read(childProcessed);
  4335. buf.read(childStrands);
  4336. if (traceLevel > 5)
  4337. activity.queryLogCtx().CTXLOG("Processing ChildCount %d idx %d strands %d for child %d subgraph %d", childProcessed, idx, childStrands, childId, graphId);
  4338. activity.queryContext()->noteProcessed(graphId, childId, idx, childProcessed, childStrands);
  4339. }
  4340. else
  4341. {
  4342. CRuntimeStatisticCollection childStats(allStatistics);
  4343. childStats.deserialize(buf);
  4344. if (traceLevel > 5)
  4345. {
  4346. StringBuffer s;
  4347. activity.queryLogCtx().CTXLOG("Processing ChildStats for child %d subgraph %d: %s", childId, graphId, childStats.toStr(s).str());
  4348. }
  4349. activity.queryContext()->mergeActivityStats(childStats, graphId, childId);
  4350. }
  4351. }
  4352. ReleaseRoxieRow(rowlen);
  4353. ReleaseRoxieRow(logInfo);
  4354. }
  4355. else
  4356. break;
  4357. }
  4358. break;
  4359. }
  4360. case ROXIE_EXCEPTION:
  4361. if (ctxTraceLevel > 1)
  4362. {
  4363. StringBuffer s;
  4364. activity.queryLogCtx().CTXLOG("Exception on query %s", header.toString(s).str());
  4365. }
  4366. op->queryHeader().noteException(header.retries);
  4367. if (op->queryHeader().allChannelsFailed())
  4368. {
  4369. activity.queryLogCtx().CTXLOG("Multiple exceptions on query - aborting");
  4370. Owned<IMessageUnpackCursor> exceptionData = mr->getCursor(rowManager);
  4371. throwRemoteException(exceptionData);
  4372. }
  4373. // Leave it on pending queue in original location
  4374. break;
  4375. case ROXIE_ALIVE:
  4376. if (ctxTraceLevel > 4)
  4377. {
  4378. StringBuffer s;
  4379. activity.queryLogCtx().CTXLOG("ROXIE_ALIVE: %s", header.toString(s).str());
  4380. }
  4381. op->queryHeader().noteAlive(header.retries & ROXIE_RETRIES_MASK);
  4382. // Leave it on pending queue in original location
  4383. break;
  4384. default:
  4385. if (header.retries & ROXIE_RETRIES_MASK)
  4386. atomic_inc(&retriesNeeded);
  4387. unsigned metaLen;
  4388. const void *metaData = mr->getMessageMetadata(metaLen);
  4389. if (metaLen)
  4390. {
  4391. // We got back first chunk but there is more.
  4392. // resend the packet, with the cursor info provided.
  4393. // MORE - if smart-stepping, we don't want to send the continuation immediately. Other cases it's not clear that we do.
  4394. if (ctxTraceLevel > 1)
  4395. {
  4396. StringBuffer s;
  4397. activity.queryLogCtx().CTXLOG("Additional data size %d on query %s mergeOrder %p", metaLen, header.toString(s).str(), mergeOrder);
  4398. }
  4399. if (*((unsigned short *) metaData) + sizeof(unsigned short) != metaLen)
  4400. {
  4401. StringBuffer s;
  4402. activity.queryLogCtx().CTXLOG("Additional data size %d on query %s mergeOrder %p", metaLen, header.toString(s).str(), mergeOrder);
  4403. activity.queryLogCtx().CTXLOG("Additional data is corrupt");
  4404. throwUnexpected();
  4405. }
  4406. MemoryBuffer nextQuery;
  4407. nextQuery.append(sizeof(RoxiePacketHeader), &header);
  4408. nextQuery.append(metaLen, metaData);
  4409. nextQuery.append(op->getTraceLength(), op->queryTraceInfo());
  4410. nextQuery.append(op->getContextLength(), op->queryContextData());
  4411. if (resendSequence == CONTINUESEQUENCE_MAX)
  4412. {
  4413. activity.queryLogCtx().CTXLOG("ERROR: Continuation sequence wrapped"); // shouldn't actually matter.... but suggests a very iffy query!
  4414. resendSequence = 1;
  4415. }
  4416. else
  4417. resendSequence++;
  4418. RoxiePacketHeader *newHeader = (RoxiePacketHeader *) nextQuery.toByteArray();
  4419. newHeader->continueSequence = resendSequence; // NOTE - we clear the skipTo flag since continuation of a skip is NOT a skip...
  4420. newHeader->retries &= ~ROXIE_RETRIES_MASK;
  4421. IRoxieQueryPacket *resend = createRoxiePacket(nextQuery);
  4422. CRoxieServerQueryPacket *fqp = new CRoxieServerQueryPacket(resend);
  4423. fqp->setSequence(original->getSequence());
  4424. pending.add(*fqp, idx+1); // note that pending takes ownership. sendPacket does not release.
  4425. original->setContinuation(LINK(fqp));
  4426. if (mergeOrder)
  4427. fqp->setDelayed(true);
  4428. else
  4429. {
  4430. ROQ->sendPacket(resend, activity.queryLogCtx());
  4431. sentsome.signal();
  4432. }
  4433. // Note that we don't attempt to cache results that have continuation records - too tricky !
  4434. }
  4435. else
  4436. {
  4437. if (serverSideCache)
  4438. serverSideCache->noteCachedResult(original, mr);
  4439. }
  4440. unsigned channel = header.channel;
  4441. {
  4442. ChannelBuffer *b = queryChannelBuffer(channel); // If not something is wrong, or we sent out on channel 0?
  4443. if (b)
  4444. b->signal();
  4445. }
  4446. original->setResult(mr.getClear());
  4447. sentsome.signal();
  4448. return;
  4449. }
  4450. }
  4451. }
  4452. else
  4453. {
  4454. if (!anyActivity && !localSlave)
  4455. {
  4456. activity.queryLogCtx().CTXLOG("Input has stalled - retry required?");
  4457. retryPending();
  4458. }
  4459. }
  4460. }
  4461. }
  4462. inline unsigned headerLength() const
  4463. {
  4464. return logInfo.length() + cachedContext.length() + sizeof(unsigned) + parentExtractSize;
  4465. }
  4466. void copyHeader(byte *tgt, unsigned channel) const
  4467. {
  4468. unsigned len = logInfo.length();
  4469. memcpy(tgt, logInfo.toByteArray(), len);
  4470. tgt += len;
  4471. *(unsigned *) tgt = parentExtractSize;
  4472. tgt += sizeof(unsigned);
  4473. memcpy(tgt, parentExtract, parentExtractSize);
  4474. tgt += parentExtractSize;
  4475. memcpy(tgt, cachedContext.toByteArray(), cachedContext.length());
  4476. tgt += cachedContext.length();
  4477. }
  4478. };
  4479. class CSkippableRemoteResultAdaptor : public CRemoteResultAdaptor
  4480. {
  4481. Owned <IException> exception;
  4482. bool skipping;
  4483. ConstPointerArray buff;
  4484. unsigned index;
  4485. bool pulled;
  4486. void pullInput()
  4487. {
  4488. try
  4489. {
  4490. if (exception)
  4491. throw exception.getClear();
  4492. unsigned __int64 count = 0;
  4493. for (;;)
  4494. {
  4495. const void * next = CRemoteResultAdaptor::nextRow();
  4496. if (next == NULL)
  4497. {
  4498. next = CRemoteResultAdaptor::nextRow();
  4499. if(next == NULL)
  4500. break;
  4501. buff.append(NULL);
  4502. }
  4503. count++;
  4504. if (count > rowLimit)
  4505. {
  4506. ReleaseRoxieRow(next);
  4507. ReleaseRoxieRows(buff);
  4508. errorHandler->onLimitExceeded(false); // throws an exception - user or LimitSkipException
  4509. throwUnexpected();
  4510. }
  4511. else if (count > keyedLimit)
  4512. {
  4513. ReleaseRoxieRow(next);
  4514. ReleaseRoxieRows(buff);
  4515. errorHandler->onLimitExceeded(true); // throws an exception - user or LimitSkipException
  4516. throwUnexpected();
  4517. }
  4518. buff.append(next);
  4519. }
  4520. }
  4521. catch (IException *E)
  4522. {
  4523. if (QUERYINTERFACE(E, LimitSkipException))
  4524. {
  4525. Owned<IException> cleanup = E;
  4526. ReleaseRoxieRows(buff);
  4527. const void *onfail = errorHandler->createLimitFailRow(E->errorCode() == KeyedLimitSkipErrorCode);
  4528. if (onfail)
  4529. buff.append(onfail);
  4530. }
  4531. else
  4532. throw;
  4533. }
  4534. pulled = true;
  4535. }
  4536. public:
  4537. CSkippableRemoteResultAdaptor(IRoxieSlaveContext *_ctx, IRoxieServerErrorHandler *_errorHandler, const RemoteActivityId &_remoteId, IOutputMetaData *_meta, IHThorArg &_helper, IRoxieServerActivity &_activity, bool _preserveOrder, bool _flowControlled, bool _skipping) :
  4538. CRemoteResultAdaptor(_ctx, _errorHandler, _remoteId, _meta, _helper, _activity, _preserveOrder, _flowControlled)
  4539. {
  4540. skipping = _skipping;
  4541. index = 0;
  4542. pulled = false;
  4543. }
  4544. void setException(IException *E)
  4545. {
  4546. exception.setown(E);
  4547. }
  4548. virtual void onReset()
  4549. {
  4550. roxiemem::ReleaseRoxieRowRange(buff.getArray(), index, buff.ordinality());
  4551. buff.kill();
  4552. index = 0;
  4553. pulled = false;
  4554. exception.clear();
  4555. CRemoteResultAdaptor::onReset();
  4556. }
  4557. void onStart(unsigned _parentExtractSize, const byte * _parentExtract)
  4558. {
  4559. index = 0;
  4560. pulled = false;
  4561. CRemoteResultAdaptor::onStart(_parentExtractSize, _parentExtract);
  4562. }
  4563. virtual const void * nextRowGE(const void *seek, const void *rawSeek, unsigned numFields, unsigned seeklen, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  4564. {
  4565. // 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
  4566. if (exception)
  4567. throw exception.getClear();
  4568. return CRemoteResultAdaptor::nextRowGE(seek, rawSeek, numFields, seeklen, wasCompleteMatch, stepExtra);
  4569. }
  4570. virtual const void *nextRow()
  4571. {
  4572. if (skipping)
  4573. {
  4574. if(!pulled)
  4575. pullInput();
  4576. if(buff.isItem(index))
  4577. {
  4578. const void * next = buff.item(index++);
  4579. if(next)
  4580. processed++;
  4581. return next;
  4582. }
  4583. return NULL;
  4584. }
  4585. else
  4586. {
  4587. if (exception)
  4588. throw exception.getClear();
  4589. return CRemoteResultAdaptor::nextRow();
  4590. }
  4591. }
  4592. };
  4593. //=================================================================================
  4594. class CRoxieServerApplyActivity : public CRoxieServerInternalSinkActivity
  4595. {
  4596. IHThorApplyArg &helper;
  4597. public:
  4598. CRoxieServerApplyActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4599. : CRoxieServerInternalSinkActivity(_ctx, _factory, _probeManager, 0), helper((IHThorApplyArg &) basehelper)
  4600. {
  4601. }
  4602. virtual void onExecute()
  4603. {
  4604. helper.start();
  4605. for (;;)
  4606. {
  4607. const void * next = inputStream->ungroupedNextRow();
  4608. if (!next)
  4609. break;
  4610. helper.apply(next);
  4611. ReleaseRoxieRow(next);
  4612. }
  4613. helper.end();
  4614. }
  4615. };
  4616. class CRoxieServerApplyActivityFactory : public CRoxieServerActivityFactory
  4617. {
  4618. bool isRoot;
  4619. public:
  4620. CRoxieServerApplyActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _isRoot)
  4621. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode), isRoot(_isRoot)
  4622. {
  4623. }
  4624. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  4625. {
  4626. return new CRoxieServerApplyActivity(_ctx, this, _probeManager);
  4627. }
  4628. virtual bool isSink() const
  4629. {
  4630. return isRoot;
  4631. }
  4632. };
  4633. IRoxieServerActivityFactory *createRoxieServerApplyActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _isRoot)
  4634. {
  4635. return new CRoxieServerApplyActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _isRoot);
  4636. }
  4637. //=================================================================================
  4638. class CRoxieServerNullActivity : public CRoxieServerActivity
  4639. {
  4640. public:
  4641. CRoxieServerNullActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4642. : CRoxieServerActivity(_ctx, _factory, _probeManager)
  4643. {
  4644. }
  4645. virtual const void *nextRow()
  4646. {
  4647. return NULL;
  4648. }
  4649. };
  4650. IRoxieServerActivity * createRoxieServerNullActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4651. {
  4652. return new CRoxieServerNullActivity(_ctx, _factory, _probeManager);
  4653. }
  4654. class CRoxieServerNullActivityFactory : public CRoxieServerActivityFactory
  4655. {
  4656. public:
  4657. CRoxieServerNullActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  4658. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  4659. {
  4660. }
  4661. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  4662. {
  4663. return new CRoxieServerNullActivity(_ctx, this, _probeManager);
  4664. }
  4665. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  4666. {
  4667. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for null activity");
  4668. }
  4669. };
  4670. IRoxieServerActivityFactory *createRoxieServerNullActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  4671. {
  4672. return new CRoxieServerNullActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  4673. }
  4674. //=================================================================================
  4675. class CRoxieServerPassThroughActivity : public CRoxieServerActivity
  4676. {
  4677. public:
  4678. CRoxieServerPassThroughActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4679. : CRoxieServerActivity(_ctx, _factory, _probeManager)
  4680. {
  4681. }
  4682. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  4683. {
  4684. return input->gatherConjunctions(collector);
  4685. }
  4686. virtual void resetEOF()
  4687. {
  4688. inputStream->resetEOF();
  4689. }
  4690. virtual const void *nextRow()
  4691. {
  4692. const void * next = inputStream->nextRow();
  4693. if (next)
  4694. processed++;
  4695. return next;
  4696. }
  4697. virtual bool isPassThrough()
  4698. {
  4699. return true;
  4700. }
  4701. virtual const void * nextRowGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  4702. {
  4703. ActivityTimer t(totalCycles, timeActivities);
  4704. const void * next = inputStream->nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);
  4705. if (next)
  4706. processed++;
  4707. return next;
  4708. }
  4709. IInputSteppingMeta * querySteppingMeta()
  4710. {
  4711. return input->querySteppingMeta();
  4712. }
  4713. };
  4714. IRoxieServerActivity * createRoxieServerPassThroughActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4715. {
  4716. return new CRoxieServerPassThroughActivity(_ctx, _factory, _probeManager);
  4717. }
  4718. //=================================================================================
  4719. class CRoxieServerChildBaseActivity : public CRoxieServerActivity
  4720. {
  4721. protected:
  4722. bool eof;
  4723. bool first;
  4724. public:
  4725. CRoxieServerChildBaseActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4726. : CRoxieServerActivity(_ctx, _factory, _probeManager)
  4727. {
  4728. eof = false;
  4729. first = true;
  4730. }
  4731. ~CRoxieServerChildBaseActivity()
  4732. {
  4733. }
  4734. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  4735. {
  4736. eof = false;
  4737. first = true;
  4738. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  4739. }
  4740. };
  4741. class CRoxieServerChildBaseActivityFactory : public CRoxieServerActivityFactory
  4742. {
  4743. public:
  4744. CRoxieServerChildBaseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  4745. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  4746. {
  4747. }
  4748. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  4749. {
  4750. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for %s activity", getActivityText(kind));
  4751. }
  4752. };
  4753. //=================================================================================
  4754. class CRoxieServerChildIteratorActivity : public CRoxieServerChildBaseActivity
  4755. {
  4756. IHThorChildIteratorArg &helper;
  4757. public:
  4758. CRoxieServerChildIteratorActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4759. : CRoxieServerChildBaseActivity(_ctx, _factory, _probeManager), helper((IHThorChildIteratorArg &) basehelper)
  4760. {
  4761. }
  4762. virtual bool needsAllocator() const { return true; }
  4763. virtual const void *nextRow()
  4764. {
  4765. ActivityTimer t(totalCycles, timeActivities);
  4766. if (eof)
  4767. return NULL;
  4768. bool ok;
  4769. if (first)
  4770. {
  4771. ok = helper.first();
  4772. first = false;
  4773. }
  4774. else
  4775. ok = helper.next();
  4776. try
  4777. {
  4778. while (ok)
  4779. {
  4780. processed++;
  4781. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  4782. unsigned outSize = helper.transform(rowBuilder);
  4783. if (outSize)
  4784. return rowBuilder.finalizeRowClear(outSize);
  4785. ok = helper.next();
  4786. }
  4787. }
  4788. catch (IException *E)
  4789. {
  4790. throw makeWrappedException(E);
  4791. }
  4792. eof = true;
  4793. return NULL;
  4794. }
  4795. };
  4796. class CRoxieServerChildIteratorActivityFactory : public CRoxieServerChildBaseActivityFactory
  4797. {
  4798. public:
  4799. CRoxieServerChildIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  4800. : CRoxieServerChildBaseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  4801. {
  4802. }
  4803. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  4804. {
  4805. return new CRoxieServerChildIteratorActivity(_ctx, this, _probeManager);
  4806. }
  4807. };
  4808. IRoxieServerActivityFactory *createRoxieServerChildIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  4809. {
  4810. return new CRoxieServerChildIteratorActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  4811. }
  4812. //=================================================================================
  4813. class CRoxieServerChildNormalizeActivity : public CRoxieServerChildBaseActivity
  4814. {
  4815. IHThorChildNormalizeArg &helper;
  4816. public:
  4817. CRoxieServerChildNormalizeActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4818. : CRoxieServerChildBaseActivity(_ctx, _factory, _probeManager), helper((IHThorChildNormalizeArg &) basehelper)
  4819. {
  4820. }
  4821. virtual bool needsAllocator() const { return true; }
  4822. virtual const void *nextRow()
  4823. {
  4824. ActivityTimer t(totalCycles, timeActivities);
  4825. if (eof)
  4826. return NULL;
  4827. bool ok;
  4828. if (first)
  4829. {
  4830. ok = helper.first();
  4831. first = false;
  4832. }
  4833. else
  4834. ok = helper.next();
  4835. if (ok)
  4836. {
  4837. try
  4838. {
  4839. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  4840. do {
  4841. unsigned outSize = helper.transform(rowBuilder);
  4842. if (outSize)
  4843. {
  4844. processed++;
  4845. return rowBuilder.finalizeRowClear(outSize);
  4846. }
  4847. ok = helper.next();
  4848. }
  4849. while (ok);
  4850. }
  4851. catch (IException *E)
  4852. {
  4853. throw makeWrappedException(E);
  4854. }
  4855. }
  4856. eof = true;
  4857. return NULL;
  4858. }
  4859. };
  4860. class CRoxieServerChildNormalizeActivityFactory : public CRoxieServerChildBaseActivityFactory
  4861. {
  4862. public:
  4863. CRoxieServerChildNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  4864. : CRoxieServerChildBaseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  4865. {
  4866. }
  4867. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  4868. {
  4869. return new CRoxieServerChildNormalizeActivity(_ctx, this, _probeManager);
  4870. }
  4871. };
  4872. IRoxieServerActivityFactory *createRoxieServerNewChildNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  4873. {
  4874. return new CRoxieServerChildNormalizeActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  4875. }
  4876. //=================================================================================
  4877. class CRoxieServerChildAggregateActivity : public CRoxieServerChildBaseActivity
  4878. {
  4879. IHThorChildAggregateArg &helper;
  4880. public:
  4881. CRoxieServerChildAggregateActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4882. : CRoxieServerChildBaseActivity(_ctx, _factory, _probeManager), helper((IHThorChildAggregateArg &) basehelper)
  4883. {
  4884. }
  4885. virtual bool needsAllocator() const { return true; }
  4886. virtual const void *nextRow()
  4887. {
  4888. ActivityTimer t(totalCycles, timeActivities);
  4889. if (eof)
  4890. return NULL;
  4891. eof = true;
  4892. processed++;
  4893. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  4894. helper.clearAggregate(rowBuilder);
  4895. helper.processRows(rowBuilder);
  4896. size32_t finalSize = meta.getRecordSize(rowBuilder.getSelf());
  4897. return rowBuilder.finalizeRowClear(finalSize);
  4898. }
  4899. };
  4900. class CRoxieServerChildAggregateActivityFactory : public CRoxieServerChildBaseActivityFactory
  4901. {
  4902. public:
  4903. CRoxieServerChildAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  4904. : CRoxieServerChildBaseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  4905. {
  4906. }
  4907. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  4908. {
  4909. return new CRoxieServerChildAggregateActivity(_ctx, this, _probeManager);
  4910. }
  4911. };
  4912. IRoxieServerActivityFactory *createRoxieServerNewChildAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  4913. {
  4914. return new CRoxieServerChildAggregateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  4915. }
  4916. //=================================================================================
  4917. class CRoxieServerChildGroupAggregateActivity : public CRoxieServerChildBaseActivity, public IHThorGroupAggregateCallback
  4918. {
  4919. IHThorChildGroupAggregateArg &helper;
  4920. RowAggregator aggregated;
  4921. public:
  4922. IMPLEMENT_IINTERFACE_USING(CRoxieServerChildBaseActivity)
  4923. CRoxieServerChildGroupAggregateActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4924. : CRoxieServerChildBaseActivity(_ctx, _factory, _probeManager), helper((IHThorChildGroupAggregateArg &) basehelper),
  4925. aggregated(helper, helper)
  4926. {
  4927. }
  4928. void processRow(const void * next)
  4929. {
  4930. aggregated.addRow(next);
  4931. }
  4932. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  4933. {
  4934. CRoxieServerChildBaseActivity::start(parentExtractSize, parentExtract, paused);
  4935. aggregated.start(rowAllocator);
  4936. }
  4937. virtual void reset()
  4938. {
  4939. aggregated.reset();
  4940. CRoxieServerChildBaseActivity::reset();
  4941. }
  4942. virtual bool needsAllocator() const { return true; }
  4943. virtual const void *nextRow()
  4944. {
  4945. ActivityTimer t(totalCycles, timeActivities);
  4946. if (eof)
  4947. return NULL;
  4948. if (first)
  4949. {
  4950. helper.processRows(this);
  4951. first = false;
  4952. }
  4953. Owned<AggregateRowBuilder> next = aggregated.nextResult();
  4954. if (next)
  4955. {
  4956. processed++;
  4957. return next->finalizeRowClear();
  4958. }
  4959. eof = true;
  4960. return NULL;
  4961. }
  4962. };
  4963. class CRoxieServerChildGroupAggregateActivityFactory : public CRoxieServerChildBaseActivityFactory
  4964. {
  4965. public:
  4966. CRoxieServerChildGroupAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  4967. : CRoxieServerChildBaseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  4968. {
  4969. }
  4970. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  4971. {
  4972. return new CRoxieServerChildGroupAggregateActivity(_ctx, this, _probeManager);
  4973. }
  4974. };
  4975. IRoxieServerActivityFactory *createRoxieServerNewChildGroupAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  4976. {
  4977. return new CRoxieServerChildGroupAggregateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  4978. }
  4979. //=================================================================================
  4980. class CRoxieServerChildThroughNormalizeActivity : public CRoxieServerChildBaseActivity
  4981. {
  4982. IHThorChildThroughNormalizeArg &helper;
  4983. const void * lastInput;
  4984. unsigned numProcessedLastGroup;
  4985. bool ok;
  4986. public:
  4987. CRoxieServerChildThroughNormalizeActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4988. : CRoxieServerChildBaseActivity(_ctx, _factory, _probeManager), helper((IHThorChildThroughNormalizeArg &) basehelper)
  4989. {
  4990. lastInput = NULL;
  4991. numProcessedLastGroup = 0;
  4992. ok = false;
  4993. }
  4994. virtual void stop()
  4995. {
  4996. CRoxieServerChildBaseActivity::stop();
  4997. ReleaseRoxieRow(lastInput);
  4998. lastInput = NULL;
  4999. }
  5000. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5001. {
  5002. CRoxieServerChildBaseActivity::start(parentExtractSize, parentExtract, paused);
  5003. numProcessedLastGroup = processed;
  5004. ok = false;
  5005. }
  5006. virtual bool needsAllocator() const { return true; }
  5007. virtual const void *nextRow()
  5008. {
  5009. ActivityTimer t(totalCycles, timeActivities);
  5010. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  5011. for (;;)
  5012. {
  5013. if (ok)
  5014. ok = helper.next();
  5015. while (!ok)
  5016. {
  5017. ReleaseRoxieRow(lastInput);
  5018. lastInput = inputStream->nextRow();
  5019. if (!lastInput)
  5020. {
  5021. if (numProcessedLastGroup != processed)
  5022. {
  5023. numProcessedLastGroup = processed;
  5024. return NULL;
  5025. }
  5026. lastInput = inputStream->nextRow();
  5027. if (!lastInput)
  5028. return NULL;
  5029. }
  5030. ok = helper.first(lastInput);
  5031. }
  5032. try
  5033. {
  5034. do
  5035. {
  5036. unsigned outSize = helper.transform(rowBuilder);
  5037. if (outSize)
  5038. {
  5039. processed++;
  5040. return rowBuilder.finalizeRowClear(outSize);
  5041. }
  5042. ok = helper.next();
  5043. } while (ok);
  5044. }
  5045. catch (IException *E)
  5046. {
  5047. throw makeWrappedException(E);
  5048. }
  5049. }
  5050. }
  5051. };
  5052. class CRoxieServerChildThroughNormalizeActivityFactory : public CRoxieServerActivityFactory
  5053. {
  5054. public:
  5055. CRoxieServerChildThroughNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  5056. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  5057. {
  5058. }
  5059. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  5060. {
  5061. return new CRoxieServerChildThroughNormalizeActivity(_ctx, this, _probeManager);
  5062. }
  5063. };
  5064. IRoxieServerActivityFactory *createRoxieServerNewChildThroughNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  5065. {
  5066. return new CRoxieServerChildThroughNormalizeActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  5067. }
  5068. //=================================================================================
  5069. class CRoxieServerDistributionActivity : public CRoxieServerInternalSinkActivity
  5070. {
  5071. IHThorDistributionArg &helper;
  5072. public:
  5073. CRoxieServerDistributionActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  5074. : CRoxieServerInternalSinkActivity(_ctx, _factory, _probeManager, 0), helper((IHThorDistributionArg &)basehelper)
  5075. {
  5076. }
  5077. virtual void onExecute()
  5078. {
  5079. MemoryAttr ma;
  5080. IDistributionTable * * accumulator = (IDistributionTable * *)ma.allocate(helper.queryInternalRecordSize()->getMinRecordSize());
  5081. helper.clearAggregate(accumulator);
  5082. OwnedConstRoxieRow nextrec(inputStream->nextRow());
  5083. for (;;)
  5084. {
  5085. if (!nextrec)
  5086. {
  5087. nextrec.setown(inputStream->nextRow());
  5088. if (!nextrec)
  5089. break;
  5090. }
  5091. helper.process(accumulator, nextrec);
  5092. nextrec.setown(inputStream->nextRow());
  5093. }
  5094. StringBuffer result;
  5095. result.append("<XML>");
  5096. helper.gatherResult(accumulator, result);
  5097. result.append("</XML>");
  5098. helper.sendResult(result.length(), result.str());
  5099. helper.destruct(accumulator);
  5100. }
  5101. };
  5102. class CRoxieServerDistributionActivityFactory : public CRoxieServerActivityFactory
  5103. {
  5104. bool isRoot;
  5105. public:
  5106. CRoxieServerDistributionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _isRoot)
  5107. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode), isRoot(_isRoot)
  5108. {
  5109. }
  5110. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  5111. {
  5112. return new CRoxieServerDistributionActivity(_ctx, this, _probeManager);
  5113. }
  5114. virtual bool isSink() const
  5115. {
  5116. return isRoot;
  5117. }
  5118. };
  5119. IRoxieServerActivityFactory *createRoxieServerDistributionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _isRoot)
  5120. {
  5121. return new CRoxieServerDistributionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _isRoot);
  5122. }
  5123. //=================================================================================
  5124. class CRoxieServerLinkedRawIteratorActivity : public CRoxieServerActivity
  5125. {
  5126. IHThorLinkedRawIteratorArg &helper;
  5127. public:
  5128. CRoxieServerLinkedRawIteratorActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  5129. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorLinkedRawIteratorArg &) basehelper)
  5130. {
  5131. }
  5132. virtual const void *nextRow()
  5133. {
  5134. ActivityTimer t(totalCycles, timeActivities);
  5135. const void *ret =helper.next();
  5136. if (ret)
  5137. {
  5138. LinkRoxieRow(ret);
  5139. processed++;
  5140. }
  5141. return ret;
  5142. }
  5143. };
  5144. class CRoxieServerLinkedRawIteratorActivityFactory : public CRoxieServerActivityFactory
  5145. {
  5146. public:
  5147. CRoxieServerLinkedRawIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  5148. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  5149. {
  5150. }
  5151. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  5152. {
  5153. return new CRoxieServerLinkedRawIteratorActivity(_ctx, this, _probeManager);
  5154. }
  5155. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  5156. {
  5157. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for %s activity", getActivityText(kind));
  5158. }
  5159. };
  5160. IRoxieServerActivityFactory *createRoxieServerLinkedRawIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  5161. {
  5162. return new CRoxieServerLinkedRawIteratorActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  5163. }
  5164. //=================================================================================
  5165. class CRoxieServerDatasetResultActivity : public CRoxieServerActivity
  5166. {
  5167. public:
  5168. CRoxieServerDatasetResultActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  5169. : CRoxieServerActivity(_ctx, _factory, _probeManager)
  5170. {
  5171. }
  5172. virtual const void *nextRow()
  5173. {
  5174. throwUnexpected();
  5175. }
  5176. virtual void executeChild(size32_t & retSize, void * & ret, unsigned parentExtractSize, const byte * parentExtract)
  5177. {
  5178. try
  5179. {
  5180. start(parentExtractSize, parentExtract, false);
  5181. {
  5182. ActivityTimer t(totalCycles, timeActivities);
  5183. MemoryBuffer result;
  5184. IRecordSize * inputMeta = input->queryOutputMeta();
  5185. for (;;)
  5186. {
  5187. const void *nextrec = inputStream->ungroupedNextRow();
  5188. if (!nextrec)
  5189. break;
  5190. result.append(inputMeta->getRecordSize(nextrec), nextrec);
  5191. ReleaseRoxieRow(nextrec);
  5192. }
  5193. retSize = result.length();
  5194. ret = result.detach();
  5195. }
  5196. stop();
  5197. reset();
  5198. }
  5199. catch(IException *E)
  5200. {
  5201. ctx->notifyAbort(E);
  5202. abort();
  5203. reset();
  5204. throw;
  5205. }
  5206. catch(...)
  5207. {
  5208. Owned<IException> E = MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught at %s:%d", sanitizeSourceFile(__FILE__), __LINE__);
  5209. ctx->notifyAbort(E);
  5210. abort();
  5211. reset();
  5212. throw;
  5213. }
  5214. }
  5215. };
  5216. class CRoxieServerDatasetResultActivityFactory : public CRoxieServerActivityFactory
  5217. {
  5218. bool isRoot;
  5219. public:
  5220. CRoxieServerDatasetResultActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _isRoot)
  5221. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode), isRoot(_isRoot)
  5222. {
  5223. }
  5224. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  5225. {
  5226. return new CRoxieServerDatasetResultActivity(_ctx, this, _probeManager);
  5227. }
  5228. virtual bool isSink() const
  5229. {
  5230. return isRoot;
  5231. }
  5232. };
  5233. IRoxieServerActivityFactory *createRoxieServerDatasetResultActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _isRoot)
  5234. {
  5235. return new CRoxieServerDatasetResultActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _isRoot);
  5236. }
  5237. //=================================================================================
  5238. class CRoxieServerInlineTableActivity : public CRoxieServerActivity
  5239. {
  5240. IHThorInlineTableArg &helper;
  5241. __uint64 curRow;
  5242. __uint64 numRows;
  5243. public:
  5244. CRoxieServerInlineTableActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  5245. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorInlineTableArg &) basehelper)
  5246. {
  5247. curRow = 0;
  5248. numRows = 0;
  5249. }
  5250. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5251. {
  5252. curRow = 0;
  5253. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  5254. numRows = helper.numRows();
  5255. }
  5256. virtual bool needsAllocator() const { return true; }
  5257. virtual const void *nextRow()
  5258. {
  5259. ActivityTimer t(totalCycles, timeActivities);
  5260. // Filtering empty rows, returns the next valid row
  5261. while (curRow < numRows)
  5262. {
  5263. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  5264. unsigned outSize = helper.getRow(rowBuilder, curRow++);
  5265. if (outSize)
  5266. {
  5267. processed++;
  5268. return rowBuilder.finalizeRowClear(outSize);
  5269. }
  5270. }
  5271. return NULL;
  5272. }
  5273. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  5274. {
  5275. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  5276. }
  5277. };
  5278. class CRoxieServerStrandedInlineTableActivity : public CRoxieServerStrandedActivity
  5279. {
  5280. IHThorInlineTableArg &helper;
  5281. __uint64 numRows;
  5282. //An inline table that isn't stranded
  5283. class InlineTableSimpleProcessor : public StrandProcessor
  5284. {
  5285. protected:
  5286. IHThorInlineTableArg &helper;
  5287. __uint64 curRow;
  5288. __uint64 maxRows;
  5289. public:
  5290. InlineTableSimpleProcessor(CRoxieServerActivity &_parent, IHThorInlineTableArg &_helper)
  5291. : StrandProcessor(_parent, NULL, true), helper(_helper), curRow(0), maxRows(0)
  5292. {
  5293. }
  5294. virtual void start() override
  5295. {
  5296. StrandProcessor::start();
  5297. curRow = 0;
  5298. maxRows = queryParent().numRows;
  5299. }
  5300. virtual const void * nextRow()
  5301. {
  5302. ActivityTimer t(totalCycles, timeActivities);
  5303. //Return rows while the current section is active
  5304. while (curRow < maxRows)
  5305. {
  5306. RtlDynamicRowBuilder rowBuilder(*rowAllocator);
  5307. unsigned outSize = helper.getRow(rowBuilder, curRow++);
  5308. if (outSize)
  5309. {
  5310. processed++;
  5311. return rowBuilder.finalizeRowClear(outSize);
  5312. }
  5313. }
  5314. return NULL;
  5315. }
  5316. CRoxieServerStrandedInlineTableActivity & queryParent() { return static_cast<CRoxieServerStrandedInlineTableActivity&>(parent); }
  5317. };
  5318. class InlineTableStrandProcessor : public StrandProcessor
  5319. {
  5320. protected:
  5321. IHThorInlineTableArg &helper;
  5322. unsigned whichStrand;
  5323. unsigned numStrands = 0;
  5324. __uint64 sectionSize;
  5325. __uint64 curRow = 0;
  5326. __uint64 sectionMaxRows = 0;
  5327. __uint64 maxRows = 0;
  5328. bool isOrdered;
  5329. bool eosPending;
  5330. public:
  5331. InlineTableStrandProcessor(CRoxieServerActivity &_parent, IHThorInlineTableArg &_helper, unsigned _whichStrand, bool _isOrdered)
  5332. : StrandProcessor(_parent, NULL, true), helper(_helper), whichStrand(_whichStrand), isOrdered(_isOrdered)
  5333. {
  5334. sectionSize = queryParent().strandOptions.blockSize;
  5335. eosPending = false;
  5336. }
  5337. virtual void start() override
  5338. {
  5339. StrandProcessor::start();
  5340. numStrands = queryParent().numStrands();
  5341. maxRows = queryParent().numRows;
  5342. curRow = std::min(whichStrand * sectionSize, maxRows);
  5343. sectionMaxRows = std::min(curRow + sectionSize, maxRows);
  5344. eosPending = isOrdered && (curRow != maxRows);
  5345. }
  5346. virtual const void * nextRow()
  5347. {
  5348. ActivityTimer t(totalCycles, timeActivities);
  5349. for (;;)
  5350. {
  5351. //Return rows while the current section is active
  5352. while (curRow < sectionMaxRows)
  5353. {
  5354. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  5355. unsigned outSize = helper.getRow(rowBuilder, curRow++);
  5356. if (outSize)
  5357. {
  5358. processed++;
  5359. return rowBuilder.finalizeRowClear(outSize);
  5360. }
  5361. }
  5362. if (curRow == maxRows)
  5363. return NULL;
  5364. //Update current position to the next section
  5365. curRow += (numStrands - 1) * sectionSize;
  5366. if (curRow > maxRows)
  5367. curRow = maxRows;
  5368. sectionMaxRows = std::min(curRow + sectionSize, maxRows);
  5369. //If we have output a block of rows, then send the block as a unit - results now come from the next strand
  5370. if (eosPending)
  5371. {
  5372. //If there is another block, then second an end of section marker after it, otherwise make sure NULL is returned next.
  5373. eosPending = isOrdered && (curRow != maxRows);
  5374. return queryEndOfSectionMarker();
  5375. }
  5376. }
  5377. }
  5378. CRoxieServerStrandedInlineTableActivity & queryParent() { return static_cast<CRoxieServerStrandedInlineTableActivity&>(parent); }
  5379. };
  5380. public:
  5381. CRoxieServerStrandedInlineTableActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const StrandOptions &_strandOptions)
  5382. : CRoxieServerStrandedActivity(_ctx, _factory, _probeManager, _strandOptions), helper((IHThorInlineTableArg &) basehelper)
  5383. {
  5384. numRows = 0;
  5385. }
  5386. virtual StrandProcessor *createStrandProcessor(IEngineRowStream *instream) { throwUnexpected(); }
  5387. virtual StrandProcessor *createStrandSourceProcessor(bool inputOrdered)
  5388. {
  5389. if (strandOptions.numStrands <= 1)
  5390. return new InlineTableSimpleProcessor(*this, helper);
  5391. return new InlineTableStrandProcessor(*this, helper, strands.ordinality(), inputOrdered);
  5392. }
  5393. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5394. {
  5395. CRoxieServerStrandedActivity::start(parentExtractSize, parentExtract, paused);
  5396. numRows = helper.numRows();
  5397. onStartStrands();
  5398. startJunction(sourceJunction); // This must be started *after* all the strands have been initialised
  5399. }
  5400. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  5401. {
  5402. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  5403. }
  5404. };
  5405. class CRoxieServerInlineTableActivityFactory : public CRoxieServerActivityFactory
  5406. {
  5407. StrandOptions strandOptions;
  5408. public:
  5409. CRoxieServerInlineTableActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  5410. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode), strandOptions(_graphNode)
  5411. {
  5412. optStableInput = false; // do not force the output to be ordered
  5413. }
  5414. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  5415. {
  5416. return new CRoxieServerStrandedInlineTableActivity(_ctx, this, _probeManager, strandOptions);
  5417. }
  5418. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  5419. {
  5420. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for InlineTable activity");
  5421. }
  5422. };
  5423. IRoxieServerActivityFactory *createRoxieServerInlineTableActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  5424. {
  5425. return new CRoxieServerInlineTableActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  5426. }
  5427. //=================================================================================
  5428. class CRoxieServerWorkUnitReadActivity : public CRoxieServerActivity
  5429. {
  5430. IHThorWorkunitReadArg &helper;
  5431. CriticalSection readerCrit;
  5432. Owned<IWorkUnitRowReader> wuReader;
  5433. public:
  5434. CRoxieServerWorkUnitReadActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  5435. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorWorkunitReadArg &)basehelper)
  5436. {
  5437. }
  5438. virtual void onCreate(IHThorArg *_colocalParent)
  5439. {
  5440. CRoxieServerActivity::onCreate(_colocalParent);
  5441. if (!ctx->queryServerContext())
  5442. {
  5443. throw MakeStringException(ROXIE_INTERNAL_ERROR, "Workunit read activity cannot be executed in slave context");
  5444. }
  5445. }
  5446. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5447. {
  5448. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  5449. IXmlToRowTransformer * xmlTransformer = helper.queryXmlTransformer();
  5450. OwnedRoxieString fromWuid(helper.getWUID());
  5451. wuReader.setown(ctx->getWorkunitRowReader(fromWuid, helper.queryName(), helper.querySequence(), xmlTransformer, rowAllocator, meta.isGrouped()));
  5452. // MORE _ should that be in onCreate?
  5453. }
  5454. virtual void reset()
  5455. {
  5456. {
  5457. CriticalBlock b(readerCrit);
  5458. wuReader.clear();
  5459. }
  5460. CRoxieServerActivity::reset();
  5461. };
  5462. virtual bool needsAllocator() const { return true; }
  5463. virtual const void *nextRow()
  5464. {
  5465. ActivityTimer t(totalCycles, timeActivities);
  5466. Linked<IWorkUnitRowReader> useReader;
  5467. {
  5468. CriticalBlock b(readerCrit);
  5469. if (!wuReader)
  5470. return NULL;
  5471. useReader.set(wuReader);
  5472. }
  5473. const void *ret = useReader->nextRow();
  5474. if (ret)
  5475. processed++;
  5476. return ret;
  5477. }
  5478. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  5479. {
  5480. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  5481. }
  5482. };
  5483. class CRoxieServerWorkUnitReadActivityFactory : public CRoxieServerActivityFactory
  5484. {
  5485. public:
  5486. CRoxieServerWorkUnitReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  5487. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  5488. {
  5489. }
  5490. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  5491. {
  5492. return new CRoxieServerWorkUnitReadActivity(_ctx, this, _probeManager);
  5493. }
  5494. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  5495. {
  5496. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for WorkUnitRead activity");
  5497. }
  5498. };
  5499. IRoxieServerActivityFactory *createRoxieServerWorkUnitReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  5500. {
  5501. return new CRoxieServerWorkUnitReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  5502. }
  5503. //=================================================================================
  5504. interface ILocalGraphEx : public IEclGraphResults
  5505. {
  5506. public:
  5507. virtual void setResult(unsigned id, IGraphResult * result) = 0;
  5508. virtual IEngineRowStream * createResultIterator(unsigned id) = 0;
  5509. virtual void setGraphLoopResult(IGraphResult * result) = 0;
  5510. virtual IEngineRowStream * createGraphLoopResultIterator(unsigned id) = 0;
  5511. };
  5512. class CSafeRoxieInput : implements IEngineRowStream, implements IFinalRoxieInput, public CInterface
  5513. {
  5514. public:
  5515. CSafeRoxieInput(unsigned _sourceIdx, IFinalRoxieInput * _input) : input(_input), inputStream(NULL), sourceIdx(_sourceIdx) {}
  5516. IMPLEMENT_IINTERFACE
  5517. virtual IStrandJunction *getOutputStreams(IRoxieSlaveContext *ctx, unsigned idx, PointerArrayOf<IEngineRowStream> &streams, const StrandOptions * consumerOptions, bool consumerOrdered, IOrderedCallbackCollection * orderedCallbacks) override
  5518. {
  5519. connectInputStreams(ctx, consumerOrdered);
  5520. streams.append(this);
  5521. return NULL;
  5522. }
  5523. void connectInputStreams(IRoxieSlaveContext *ctx, bool consumerOrdered)
  5524. {
  5525. inputStream.set(connectSingleStream(ctx, input, sourceIdx, junction, consumerOrdered));
  5526. }
  5527. virtual IOutputMetaData * queryOutputMeta() const
  5528. {
  5529. return input->queryOutputMeta();
  5530. }
  5531. virtual unsigned __int64 queryTotalCycles() const
  5532. {
  5533. return input->queryTotalCycles();
  5534. }
  5535. virtual IEngineRowStream *queryConcreteOutputStream(unsigned whichInput) { assertex(whichInput==0); return this; }
  5536. virtual IStrandJunction *queryConcreteOutputJunction(unsigned idx) const { assertex(idx==0); return nullptr; }
  5537. virtual IRoxieServerActivity *queryActivity()
  5538. {
  5539. return input->queryActivity();
  5540. }
  5541. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  5542. {
  5543. return input->queryIndexReadActivity();
  5544. }
  5545. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5546. {
  5547. CriticalBlock procedure(cs);
  5548. input->start(parentExtractSize, parentExtract, paused);
  5549. startJunction(junction);
  5550. }
  5551. virtual void stop()
  5552. {
  5553. CriticalBlock procedure(cs);
  5554. inputStream->stop();
  5555. }
  5556. virtual void reset()
  5557. {
  5558. CriticalBlock procedure(cs);
  5559. input->reset();
  5560. resetJunction(junction);
  5561. }
  5562. virtual void resetEOF()
  5563. {
  5564. CriticalBlock procedure(cs);
  5565. inputStream->resetEOF();
  5566. }
  5567. virtual const void *nextRow()
  5568. {
  5569. CriticalBlock procedure(cs);
  5570. return inputStream->nextRow();
  5571. }
  5572. virtual bool nextGroup(ConstPointerArray & group)
  5573. {
  5574. CriticalBlock procedure(cs);
  5575. return inputStream->nextGroup(group);
  5576. }
  5577. private:
  5578. CriticalSection cs;
  5579. Linked<IFinalRoxieInput> input;
  5580. Linked<IEngineRowStream> inputStream;
  5581. Owned<IStrandJunction> junction;
  5582. unsigned sourceIdx;
  5583. };
  5584. //=================================================================================
  5585. class CPseudoRoxieInput : implements IEngineRowStream, implements IFinalRoxieInput, public CInterface
  5586. {
  5587. public:
  5588. IMPLEMENT_IINTERFACE;
  5589. CPseudoRoxieInput()
  5590. {
  5591. }
  5592. virtual unsigned __int64 queryTotalCycles() const
  5593. {
  5594. return 0;
  5595. }
  5596. virtual IEngineRowStream *queryConcreteOutputStream(unsigned whichInput) { assertex(whichInput==0); return this; }
  5597. virtual IStrandJunction *queryConcreteOutputJunction(unsigned idx) const { assertex(idx==0); return nullptr; }
  5598. virtual IRoxieServerActivity *queryActivity()
  5599. {
  5600. throwUnexpected();
  5601. }
  5602. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  5603. {
  5604. throwUnexpected();
  5605. }
  5606. virtual IStrandJunction *getOutputStreams(IRoxieSlaveContext *ctx, unsigned idx, PointerArrayOf<IEngineRowStream> &streams, const StrandOptions * consumerOptions, bool consumerOrdered, IOrderedCallbackCollection * orderedCallbacks) override
  5607. {
  5608. assertex(!idx);
  5609. streams.append(this);
  5610. return NULL;
  5611. }
  5612. virtual IOutputMetaData * queryOutputMeta() const { throwUnexpected(); }
  5613. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused) { }
  5614. virtual void stop() { }
  5615. virtual void reset() { }
  5616. virtual void checkAbort() { }
  5617. virtual void resetEOF() { }
  5618. };
  5619. class CIndirectRoxieInput : public CPseudoRoxieInput
  5620. {
  5621. public:
  5622. CIndirectRoxieInput() : input(NULL)
  5623. {
  5624. stream = NULL;
  5625. sourceIdx = 0;
  5626. }
  5627. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5628. {
  5629. input->start(parentExtractSize, parentExtract, paused);
  5630. startJunction(junction);
  5631. }
  5632. virtual void stop()
  5633. {
  5634. stream->stop();
  5635. }
  5636. virtual void reset()
  5637. {
  5638. input->reset();
  5639. resetJunction(junction);
  5640. }
  5641. virtual const void * nextRow()
  5642. {
  5643. return stream->nextRow();
  5644. }
  5645. virtual const void * nextRowGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  5646. {
  5647. return stream->nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);
  5648. }
  5649. virtual unsigned __int64 queryTotalCycles() const
  5650. {
  5651. return input->queryTotalCycles();
  5652. }
  5653. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  5654. {
  5655. return input->gatherConjunctions(collector);
  5656. }
  5657. virtual void resetEOF()
  5658. {
  5659. stream->resetEOF();
  5660. }
  5661. virtual unsigned numConcreteOutputs() const
  5662. {
  5663. return input->numConcreteOutputs();
  5664. }
  5665. virtual IFinalRoxieInput * queryConcreteInput(unsigned idx)
  5666. {
  5667. return input->queryConcreteInput(idx);
  5668. }
  5669. virtual IEngineRowStream *queryConcreteOutputStream(unsigned whichInput)
  5670. {
  5671. return input->queryConcreteOutputStream(whichInput);
  5672. }
  5673. virtual IStrandJunction *queryConcreteOutputJunction(unsigned idx) const
  5674. {
  5675. return input->queryConcreteOutputJunction(idx);
  5676. }
  5677. virtual IOutputMetaData * queryOutputMeta() const
  5678. {
  5679. return input->queryOutputMeta();
  5680. }
  5681. virtual IRoxieServerActivity *queryActivity()
  5682. {
  5683. return input->queryActivity();
  5684. }
  5685. inline void setInput(unsigned _sourceIdx, IFinalRoxieInput * _input)
  5686. {
  5687. input = _input;
  5688. sourceIdx = _sourceIdx;
  5689. }
  5690. inline void connectInputStreams(IRoxieSlaveContext *ctx, bool consumerOrdered)
  5691. {
  5692. stream = connectSingleStream(ctx, input, sourceIdx, junction, consumerOrdered);
  5693. }
  5694. virtual IStrandJunction *getOutputStreams(IRoxieSlaveContext *ctx, unsigned idx, PointerArrayOf<IEngineRowStream> &streams, const StrandOptions * consumerOptions, bool consumerOrdered, IOrderedCallbackCollection * orderedCallbacks) override
  5695. {
  5696. assertex(idx == 0);
  5697. connectInputStreams(ctx, consumerOrdered);
  5698. streams.append(this);
  5699. return NULL;
  5700. }
  5701. inline IFinalRoxieInput *queryInput() const
  5702. {
  5703. return input;
  5704. }
  5705. protected:
  5706. unsigned sourceIdx;
  5707. IFinalRoxieInput *input;
  5708. IEngineRowStream *stream;
  5709. Owned<IStrandJunction> junction;
  5710. };
  5711. class CExtractMapperInput : public CIndirectRoxieInput
  5712. {
  5713. unsigned savedParentExtractSize;
  5714. const byte * savedParentExtract;
  5715. public:
  5716. CExtractMapperInput()
  5717. {
  5718. savedParentExtractSize = 0;
  5719. savedParentExtract = NULL;
  5720. }
  5721. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5722. {
  5723. CIndirectRoxieInput::start(savedParentExtractSize, savedParentExtract, paused);
  5724. }
  5725. void setParentExtract(unsigned _savedParentExtractSize, const byte * _savedParentExtract)
  5726. {
  5727. savedParentExtractSize = _savedParentExtractSize;
  5728. savedParentExtract = _savedParentExtract;
  5729. }
  5730. };
  5731. class CGraphResult : implements IGraphResult, public CInterface
  5732. {
  5733. CriticalSection cs;
  5734. const byte **rowset;
  5735. size32_t count;
  5736. bool complete;
  5737. void clear()
  5738. {
  5739. CriticalBlock func(cs);
  5740. rtlReleaseRowset(count, rowset);
  5741. rowset = NULL;
  5742. count = 0;
  5743. complete = false;
  5744. }
  5745. public:
  5746. IMPLEMENT_IINTERFACE
  5747. CGraphResult()
  5748. {
  5749. complete = false; // dummy result is not supposed to be used...
  5750. rowset = NULL;
  5751. count = 0;
  5752. }
  5753. CGraphResult(size32_t _count, const byte **_rowset)
  5754. : count(_count), rowset(_rowset)
  5755. {
  5756. complete = true;
  5757. }
  5758. ~CGraphResult()
  5759. {
  5760. clear();
  5761. }
  5762. // interface IGraphResult
  5763. virtual IEngineRowStream * createIterator()
  5764. {
  5765. if (!complete)
  5766. throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Internal Error: Reading uninitialised graph result");
  5767. return new CGraphResultIterator(this);
  5768. }
  5769. virtual void getLinkedResult(unsigned & countResult, const byte * * & result) override
  5770. {
  5771. if (!complete)
  5772. throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Internal Error: Reading uninitialised graph result");
  5773. result = rtlLinkRowset(rowset);
  5774. countResult = count;
  5775. }
  5776. virtual const void * getLinkedRowResult()
  5777. {
  5778. if (!complete)
  5779. throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Internal Error: Reading uninitialised graph result");
  5780. if (count != 1)
  5781. throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Internal Error: Expected a single row result");
  5782. const void * ret = rowset[0];
  5783. LinkRoxieRow(ret);
  5784. return ret;
  5785. }
  5786. //other
  5787. const void * getRow(unsigned i)
  5788. {
  5789. CriticalBlock func(cs);
  5790. if (i >= count)
  5791. return NULL;
  5792. const void * ret = rowset[i];
  5793. if (ret) LinkRoxieRow(ret);
  5794. return ret;
  5795. }
  5796. protected:
  5797. class CGraphResultIterator : public CInterfaceOf<IEngineRowStream>
  5798. {
  5799. unsigned i;
  5800. Linked<CGraphResult> result;
  5801. public:
  5802. CGraphResultIterator(CGraphResult * _result) : result(_result) { i = 0; }
  5803. public:
  5804. virtual const void * nextRow()
  5805. {
  5806. return result->getRow(i++);
  5807. }
  5808. virtual void stop()
  5809. {
  5810. }
  5811. virtual void resetEOF()
  5812. {
  5813. throwUnexpected();
  5814. }
  5815. };
  5816. };
  5817. //=================================================================================
  5818. class CRoxieServerLocalResultReadActivity : public CRoxieServerActivity
  5819. {
  5820. IHThorLocalResultReadArg &helper;
  5821. CriticalSection iterCrit;
  5822. Owned<IEngineRowStream> iter;
  5823. ILocalGraphEx * graph;
  5824. unsigned graphId;
  5825. unsigned sequence;
  5826. public:
  5827. CRoxieServerLocalResultReadActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _graphId)
  5828. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorLocalResultReadArg &)basehelper), graphId(_graphId)
  5829. {
  5830. graph = NULL;
  5831. sequence = 0;
  5832. }
  5833. virtual void onCreate(IHThorArg *_colocalParent)
  5834. {
  5835. CRoxieServerActivity::onCreate(_colocalParent);
  5836. graph = static_cast<ILocalGraphEx *>(ctx->queryCodeContext()->resolveLocalQuery(graphId));
  5837. sequence = helper.querySequence();
  5838. }
  5839. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5840. {
  5841. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  5842. iter.setown(graph->createResultIterator(sequence));
  5843. }
  5844. virtual void reset()
  5845. {
  5846. {
  5847. CriticalBlock b(iterCrit);
  5848. iter.clear();
  5849. }
  5850. CRoxieServerActivity::reset();
  5851. };
  5852. virtual const void *nextRow()
  5853. {
  5854. ActivityTimer t(totalCycles, timeActivities);
  5855. Linked<IEngineRowStream> useIter;
  5856. {
  5857. CriticalBlock b(iterCrit);
  5858. if (!iter)
  5859. return NULL;
  5860. useIter.set(iter);
  5861. }
  5862. const void * next = useIter->nextRow();
  5863. if (next)
  5864. {
  5865. processed++;
  5866. atomic_inc(&rowsIn);
  5867. }
  5868. return next;
  5869. }
  5870. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  5871. {
  5872. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  5873. }
  5874. };
  5875. class CRoxieServerLocalResultReadActivityFactory : public CRoxieServerActivityFactory
  5876. {
  5877. unsigned graphId;
  5878. public:
  5879. CRoxieServerLocalResultReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned _graphId)
  5880. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode), graphId(_graphId)
  5881. {
  5882. }
  5883. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  5884. {
  5885. return new CRoxieServerLocalResultReadActivity(_ctx, this, _probeManager, graphId);
  5886. }
  5887. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  5888. {
  5889. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for LocalResultRead activity");
  5890. }
  5891. };
  5892. IRoxieServerActivityFactory *createRoxieServerLocalResultReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned graphId)
  5893. {
  5894. return new CRoxieServerLocalResultReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, graphId);
  5895. }
  5896. //=================================================================================
  5897. class CRoxieServerLocalResultStreamReadActivity : public CRoxieServerActivity
  5898. {
  5899. IHThorLocalResultReadArg &helper;
  5900. unsigned sequence;
  5901. public:
  5902. CRoxieServerLocalResultStreamReadActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  5903. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorLocalResultReadArg &)basehelper)
  5904. {
  5905. sequence = 0;
  5906. }
  5907. virtual void onCreate(IHThorArg *_colocalParent)
  5908. {
  5909. CRoxieServerActivity::onCreate(_colocalParent);
  5910. sequence = helper.querySequence();
  5911. }
  5912. virtual const void *nextRow()
  5913. {
  5914. ActivityTimer t(totalCycles, timeActivities);
  5915. const void * next = inputStream->nextRow();
  5916. if (next)
  5917. {
  5918. processed++;
  5919. atomic_inc(&rowsIn);
  5920. }
  5921. return next;
  5922. }
  5923. virtual bool querySetStreamInput(unsigned id, unsigned _sourceIdx, IFinalRoxieInput * _input)
  5924. {
  5925. if (id == sequence)
  5926. {
  5927. CRoxieServerActivity::setInput(0, _sourceIdx, _input);
  5928. connectInputStreams(true);
  5929. return true;
  5930. }
  5931. return false;
  5932. }
  5933. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  5934. {
  5935. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  5936. }
  5937. };
  5938. class CRoxieServerLocalResultStreamReadActivityFactory : public CRoxieServerActivityFactory
  5939. {
  5940. public:
  5941. CRoxieServerLocalResultStreamReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  5942. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  5943. {
  5944. }
  5945. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  5946. {
  5947. return new CRoxieServerLocalResultStreamReadActivity(_ctx, this, _probeManager);
  5948. }
  5949. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  5950. {
  5951. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for LocalResultRead activity");
  5952. }
  5953. };
  5954. IRoxieServerActivityFactory *createRoxieServerLocalResultStreamReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  5955. {
  5956. return new CRoxieServerLocalResultStreamReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  5957. }
  5958. //=====================================================================================================
  5959. class CRoxieServerLocalResultWriteActivity : public CRoxieServerInternalSinkActivity
  5960. {
  5961. IHThorLocalResultWriteArg &helper;
  5962. ILocalGraphEx * graph;
  5963. unsigned graphId;
  5964. public:
  5965. CRoxieServerLocalResultWriteActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _graphId, unsigned _numOutputs)
  5966. : CRoxieServerInternalSinkActivity(_ctx, _factory, _probeManager, _numOutputs), helper((IHThorLocalResultWriteArg &)basehelper), graphId(_graphId)
  5967. {
  5968. graph = NULL;
  5969. }
  5970. virtual bool needsAllocator() const { return true; }
  5971. virtual void onCreate(IHThorArg *_colocalParent)
  5972. {
  5973. CRoxieServerInternalSinkActivity::onCreate(_colocalParent);
  5974. graph = static_cast<ILocalGraphEx *>(ctx->queryCodeContext()->resolveLocalQuery(graphId));
  5975. }
  5976. virtual void onExecute()
  5977. {
  5978. RtlLinkedDatasetBuilder builder(rowAllocator);
  5979. inputStream->readAll(builder);
  5980. Owned<CGraphResult> result = new CGraphResult(builder.getcount(), builder.linkrows());
  5981. graph->setResult(helper.querySequence(), result);
  5982. }
  5983. virtual const void *nextRow()
  5984. {
  5985. return inputStream->nextRow(); // I can act as a passthrough input
  5986. }
  5987. IFinalRoxieInput * querySelectOutput(unsigned id)
  5988. {
  5989. if (id == helper.querySequence())
  5990. {
  5991. executed = true; // Ensure that we don't try to pull as a sink as well as via the passthrough
  5992. return LINK(this);
  5993. }
  5994. return NULL;
  5995. }
  5996. };
  5997. class CRoxieServerLocalResultWriteActivityFactory : public CRoxieServerInternalSinkFactory
  5998. {
  5999. unsigned graphId;
  6000. public:
  6001. CRoxieServerLocalResultWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned _usageCount, unsigned _graphId, bool _isRoot)
  6002. : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _usageCount, _isRoot), graphId(_graphId)
  6003. {
  6004. isInternal = true;
  6005. Owned<IHThorLocalResultWriteArg> helper = (IHThorLocalResultWriteArg *) helperFactory();
  6006. }
  6007. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  6008. {
  6009. return new CRoxieServerLocalResultWriteActivity(_ctx, this, _probeManager, graphId, usageCount);
  6010. }
  6011. };
  6012. IRoxieServerActivityFactory *createRoxieServerLocalResultWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned _usageCount, unsigned _graphId, bool _isRoot)
  6013. {
  6014. return new CRoxieServerLocalResultWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _usageCount, _graphId, _isRoot);
  6015. }
  6016. //=====================================================================================================
  6017. class CRoxieServerDictionaryResultWriteActivity : public CRoxieServerInternalSinkActivity
  6018. {
  6019. IHThorDictionaryResultWriteArg &helper;
  6020. ILocalGraphEx * graph;
  6021. unsigned graphId;
  6022. public:
  6023. CRoxieServerDictionaryResultWriteActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _usageCount, unsigned _graphId)
  6024. : CRoxieServerInternalSinkActivity(_ctx, _factory, _probeManager, _usageCount), helper((IHThorDictionaryResultWriteArg &)basehelper), graphId(_graphId)
  6025. {
  6026. graph = NULL;
  6027. }
  6028. virtual bool needsAllocator() const { return true; }
  6029. virtual void onCreate(IHThorArg *_colocalParent)
  6030. {
  6031. CRoxieServerInternalSinkActivity::onCreate(_colocalParent);
  6032. graph = static_cast<ILocalGraphEx *>(ctx->queryCodeContext()->resolveLocalQuery(graphId));
  6033. }
  6034. virtual void onExecute()
  6035. {
  6036. unsigned sequence = helper.querySequence();
  6037. RtlLinkedDictionaryBuilder builder(rowAllocator, helper.queryHashLookupInfo());
  6038. for (;;)
  6039. {
  6040. const void *row = inputStream->ungroupedNextRow();
  6041. if (!row)
  6042. break;
  6043. builder.appendOwn(row);
  6044. processed++;
  6045. }
  6046. Owned<CGraphResult> result = new CGraphResult(builder.getcount(), builder.linkrows());
  6047. graph->setResult(helper.querySequence(), result);
  6048. }
  6049. virtual const void *nextRow()
  6050. {
  6051. return inputStream->nextRow(); // I can act as a passthrough input
  6052. }
  6053. IFinalRoxieInput * querySelectOutput(unsigned id)
  6054. {
  6055. if (id == helper.querySequence())
  6056. {
  6057. executed = true; // Ensure that we don't try to pull as a sink as well as via the passthrough
  6058. return LINK(this);
  6059. }
  6060. return NULL;
  6061. }
  6062. };
  6063. class CRoxieServerDictionaryResultWriteActivityFactory : public CRoxieServerInternalSinkFactory
  6064. {
  6065. unsigned graphId;
  6066. public:
  6067. CRoxieServerDictionaryResultWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned _usageCount, unsigned _graphId, bool _isRoot)
  6068. : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _usageCount, _isRoot), graphId(_graphId)
  6069. {
  6070. isInternal = true;
  6071. }
  6072. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  6073. {
  6074. return new CRoxieServerDictionaryResultWriteActivity(_ctx, this, _probeManager, usageCount, graphId);
  6075. }
  6076. };
  6077. IRoxieServerActivityFactory *createRoxieServerDictionaryResultWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned _usageCount, unsigned _graphId, bool _isRoot)
  6078. {
  6079. return new CRoxieServerDictionaryResultWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _usageCount, _graphId, _isRoot);
  6080. }
  6081. //=================================================================================
  6082. class CRoxieServerGraphLoopResultReadActivity : public CRoxieServerActivity
  6083. {
  6084. protected:
  6085. IHThorGraphLoopResultReadArg &helper;
  6086. CriticalSection iterCrit;
  6087. Owned<IFinalRoxieInput> iterInput;
  6088. Owned<IEngineRowStream> iterStream;
  6089. Owned<IStrandJunction> iterJunction;
  6090. ILocalGraphEx * graph;
  6091. unsigned graphId;
  6092. unsigned sequence;
  6093. public:
  6094. CRoxieServerGraphLoopResultReadActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _graphId)
  6095. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorGraphLoopResultReadArg &)basehelper), graphId(_graphId)
  6096. {
  6097. graph = NULL;
  6098. sequence = 0;
  6099. }
  6100. virtual void onCreate(IHThorArg *_colocalParent)
  6101. {
  6102. CRoxieServerActivity::onCreate(_colocalParent);
  6103. graph = static_cast<ILocalGraphEx *>(ctx->queryCodeContext()->resolveLocalQuery(graphId));
  6104. }
  6105. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  6106. {
  6107. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  6108. if (iterInput)
  6109. iterInput->start(parentExtractSize, parentExtract, paused);
  6110. else
  6111. {
  6112. sequence = helper.querySequence();
  6113. if ((int)sequence >= 0)
  6114. {
  6115. try
  6116. {
  6117. iterStream.setown(graph->createGraphLoopResultIterator(sequence));
  6118. iterInput.clear();
  6119. }
  6120. catch (IException * E)
  6121. {
  6122. throw makeWrappedException(E);
  6123. }
  6124. }
  6125. }
  6126. startJunction(iterJunction);
  6127. }
  6128. virtual void stop()
  6129. {
  6130. if (iterStream)
  6131. iterStream->stop();
  6132. CRoxieServerActivity::stop();
  6133. }
  6134. virtual void reset()
  6135. {
  6136. {
  6137. CriticalBlock b(iterCrit);
  6138. if (iterInput)
  6139. iterInput->reset();
  6140. resetJunction(iterJunction);
  6141. iterInput.clear();
  6142. iterStream.clear();
  6143. iterJunction.clear();
  6144. }
  6145. CRoxieServerActivity::reset();
  6146. };
  6147. virtual const void *nextRow()
  6148. {
  6149. ActivityTimer t(totalCycles, timeActivities);
  6150. Linked<IEngineRowStream> useStream;
  6151. {
  6152. CriticalBlock b(iterCrit);
  6153. if (!iterStream)
  6154. return NULL;
  6155. useStream.set(iterStream);
  6156. }
  6157. const void * next = useStream->nextRow();
  6158. if (next)
  6159. {
  6160. processed++;
  6161. atomic_inc(&rowsIn);
  6162. }
  6163. return next;
  6164. }
  6165. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  6166. {
  6167. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  6168. }
  6169. virtual void gatherIterationUsage(IRoxieServerLoopResultProcessor & processor, unsigned parentExtractSize, const byte * parentExtract)
  6170. {
  6171. ensureCreated();
  6172. basehelper.onStart(parentExtract, NULL);
  6173. processor.noteUseIteration(helper.querySequence());
  6174. }
  6175. virtual void associateIterationOutputs(IRoxieServerLoopResultProcessor & processor, unsigned parentExtractSize, const byte * parentExtract, IProbeManager *probeManager, IArrayOf<IRoxieProbe> &probes)
  6176. {
  6177. //helper already initialised from the gatherIterationUsage() call.
  6178. CRoxieServerActivity::connectInputStreams(true);
  6179. iterInput.set(processor.connectIterationOutput(helper.querySequence(), probeManager, probes, this, 0));
  6180. iterStream.set(connectSingleStream(ctx, iterInput, 0, iterJunction, true));
  6181. }
  6182. virtual IInputSteppingMeta * querySteppingMeta()
  6183. {
  6184. assertex(iterInput);
  6185. return iterInput->querySteppingMeta();
  6186. }
  6187. virtual const void * nextRowGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  6188. {
  6189. assertex(iterStream);
  6190. return iterStream->nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);
  6191. }
  6192. };
  6193. //variety of CRoxieServerGraphLoopResultReadActivity created internally with a predefined sequence number
  6194. class CRoxieServerInternalGraphLoopResultReadActivity : public CRoxieServerGraphLoopResultReadActivity
  6195. {
  6196. public:
  6197. CRoxieServerInternalGraphLoopResultReadActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _graphId, unsigned _sequence)
  6198. : CRoxieServerGraphLoopResultReadActivity(_ctx, _factory, _probeManager, _graphId)
  6199. {
  6200. sequence = _sequence;
  6201. }
  6202. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  6203. {
  6204. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  6205. if ((int)sequence >= 0)
  6206. {
  6207. try
  6208. {
  6209. iterStream.setown(graph->createGraphLoopResultIterator(sequence));
  6210. iterInput.clear();
  6211. }
  6212. catch (IException * E)
  6213. {
  6214. throw makeWrappedException(E);
  6215. }
  6216. }
  6217. }
  6218. };
  6219. class CRoxieServerGraphLoopResultReadActivityFactory : public CRoxieServerActivityFactory
  6220. {
  6221. unsigned graphId;
  6222. public:
  6223. CRoxieServerGraphLoopResultReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned _graphId)
  6224. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode), graphId(_graphId)
  6225. {
  6226. }
  6227. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  6228. {
  6229. return new CRoxieServerGraphLoopResultReadActivity(_ctx, this, _probeManager, graphId);
  6230. }
  6231. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  6232. {
  6233. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for GraphLoopResultRead activity");
  6234. }
  6235. };
  6236. IRoxieServerActivityFactory *createRoxieServerGraphLoopResultReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned graphId)
  6237. {
  6238. return new CRoxieServerGraphLoopResultReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, graphId);
  6239. }
  6240. //=====================================================================================================
  6241. class CRoxieServerGraphLoopResultWriteActivity : public CRoxieServerInternalSinkActivity
  6242. {
  6243. IHThorGraphLoopResultWriteArg &helper;
  6244. ILocalGraphEx * graph;
  6245. unsigned graphId;
  6246. public:
  6247. CRoxieServerGraphLoopResultWriteActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _graphId, unsigned _numOutputs)
  6248. : CRoxieServerInternalSinkActivity(_ctx, _factory, _probeManager, _numOutputs), helper((IHThorGraphLoopResultWriteArg &)basehelper), graphId(_graphId)
  6249. {
  6250. graph = NULL;
  6251. }
  6252. virtual bool needsAllocator() const { return true; }
  6253. virtual void onCreate(IHThorArg *_colocalParent)
  6254. {
  6255. CRoxieServerInternalSinkActivity::onCreate(_colocalParent);
  6256. graph = static_cast<ILocalGraphEx *>(ctx->queryCodeContext()->resolveLocalQuery(graphId));
  6257. }
  6258. virtual void onExecute()
  6259. {
  6260. RtlLinkedDatasetBuilder builder(rowAllocator);
  6261. inputStream->readAll(builder);
  6262. Owned<CGraphResult> result = new CGraphResult(builder.getcount(), builder.linkrows());
  6263. graph->setGraphLoopResult(result);
  6264. }
  6265. virtual IFinalRoxieInput *queryOutput(unsigned idx)
  6266. {
  6267. if (idx==0)
  6268. return this;
  6269. else
  6270. return NULL;
  6271. }
  6272. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  6273. {
  6274. return input->gatherConjunctions(collector);
  6275. }
  6276. virtual void resetEOF()
  6277. {
  6278. inputStream->resetEOF();
  6279. }
  6280. virtual const void *nextRow()
  6281. {
  6282. const void * next = inputStream->nextRow();
  6283. if (next)
  6284. processed++;
  6285. return next;
  6286. }
  6287. virtual bool isPassThrough()
  6288. {
  6289. return true;
  6290. }
  6291. virtual const void * nextRowGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  6292. {
  6293. ActivityTimer t(totalCycles, timeActivities);
  6294. const void * next = inputStream->nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);
  6295. if (next)
  6296. processed++;
  6297. return next;
  6298. }
  6299. IInputSteppingMeta * querySteppingMeta()
  6300. {
  6301. return input->querySteppingMeta();
  6302. }
  6303. virtual IOutputMetaData * queryOutputMeta() const
  6304. {
  6305. return input->queryOutputMeta();
  6306. }
  6307. };
  6308. class CRoxieServerGraphLoopResultWriteActivityFactory : public CRoxieServerInternalSinkFactory
  6309. {
  6310. unsigned graphId;
  6311. public:
  6312. CRoxieServerGraphLoopResultWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned _usageCount, unsigned _graphId)
  6313. : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _usageCount, true), graphId(_graphId)
  6314. {
  6315. isInternal = true;
  6316. Owned<IHThorGraphLoopResultWriteArg> helper = (IHThorGraphLoopResultWriteArg *) helperFactory();
  6317. }
  6318. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  6319. {
  6320. return new CRoxieServerGraphLoopResultWriteActivity(_ctx, this, _probeManager, graphId, usageCount);
  6321. }
  6322. };
  6323. IRoxieServerActivityFactory *createRoxieServerGraphLoopResultWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned _usageCount, unsigned _graphId)
  6324. {
  6325. return new CRoxieServerGraphLoopResultWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _usageCount, _graphId);
  6326. }
  6327. //=================================================================================
  6328. class CRoxieServerDedupActivity : public CRoxieServerActivity
  6329. {
  6330. protected:
  6331. IHThorDedupArg &helper;
  6332. unsigned numKept;
  6333. unsigned numToKeep;
  6334. public:
  6335. CRoxieServerDedupActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  6336. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorDedupArg &)basehelper)
  6337. {
  6338. numKept = 0;
  6339. numToKeep = 0;
  6340. }
  6341. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  6342. {
  6343. numKept = 0;
  6344. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  6345. numToKeep = helper.numToKeep();
  6346. }
  6347. };
  6348. class CRoxieServerDedupKeepLeftActivity : public CRoxieServerDedupActivity
  6349. {
  6350. IRangeCompare * stepCompare;
  6351. const void *prev;
  6352. public:
  6353. CRoxieServerDedupKeepLeftActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  6354. : CRoxieServerDedupActivity(_ctx, _factory, _probeManager)
  6355. {
  6356. prev = NULL;
  6357. stepCompare = NULL;
  6358. }
  6359. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  6360. {
  6361. prev = NULL;
  6362. CRoxieServerDedupActivity::start(parentExtractSize, parentExtract, paused);
  6363. IInputSteppingMeta * stepMeta = input->querySteppingMeta();
  6364. stepCompare = NULL;
  6365. if (stepMeta)
  6366. stepCompare = stepMeta->queryCompare();
  6367. }
  6368. virtual void reset()
  6369. {
  6370. ReleaseClearRoxieRow(prev);
  6371. CRoxieServerDedupActivity::reset();
  6372. }
  6373. virtual const void * nextRow()
  6374. {
  6375. ActivityTimer t(totalCycles, timeActivities);
  6376. const void * next;
  6377. for (;;)
  6378. {
  6379. next = inputStream->nextRow();
  6380. if (!prev || !next || !helper.matches(prev,next))
  6381. {
  6382. numKept = 0;
  6383. break;
  6384. }
  6385. if (numKept < numToKeep-1)
  6386. {
  6387. numKept++;
  6388. break;
  6389. }
  6390. ReleaseRoxieRow(next);
  6391. }
  6392. ReleaseRoxieRow(prev);
  6393. prev = next;
  6394. if (next)
  6395. {
  6396. LinkRoxieRow(next);
  6397. processed++;
  6398. }
  6399. return next;
  6400. }
  6401. virtual const void * nextRowGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  6402. {
  6403. ActivityTimer t(totalCycles, timeActivities);
  6404. const void * next;
  6405. for (;;)
  6406. {
  6407. next = inputStream->nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);
  6408. //If the record was an in-exact match from the index then return it immediately
  6409. //and don't cause it to dedup following legal records.
  6410. if (!wasCompleteMatch)
  6411. {
  6412. assertex(stepExtra.returnMismatches());
  6413. return next;
  6414. }
  6415. if (!prev || !next || !helper.matches(prev,next))
  6416. {
  6417. numKept = 0;
  6418. break;
  6419. }
  6420. if (numKept < numToKeep-1)
  6421. {
  6422. numKept++;
  6423. break;
  6424. }
  6425. //Unusual - deduping by x,y stepped on x,y,z - still want any record back as soon as possible.
  6426. if (stepExtra.returnMismatches())
  6427. {
  6428. //If asked to return mismatches we are only interested in mismatches that will force the stepped
  6429. //condition to advance
  6430. if (stepCompare->docompare(next, seek, numFields) != 0)
  6431. {
  6432. wasCompleteMatch = false;
  6433. break;
  6434. }
  6435. }
  6436. ReleaseRoxieRow(next);
  6437. }
  6438. ReleaseRoxieRow(prev);
  6439. prev = next;
  6440. if (next)
  6441. {
  6442. LinkRoxieRow(next);
  6443. processed++;
  6444. }
  6445. return next;
  6446. }
  6447. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  6448. {
  6449. return input->gatherConjunctions(collector);
  6450. }
  6451. virtual void resetEOF()
  6452. {
  6453. inputStream->resetEOF();
  6454. }
  6455. IInputSteppingMeta * querySteppingMeta()
  6456. {
  6457. return input->querySteppingMeta();
  6458. }
  6459. };
  6460. //=================================================================================
  6461. class CRoxieServerDedupKeepRightActivity : public CRoxieServerDedupActivity
  6462. {
  6463. const void *kept;
  6464. bool first;
  6465. ICompare * compareBest;
  6466. public:
  6467. CRoxieServerDedupKeepRightActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  6468. : CRoxieServerDedupActivity(_ctx, _factory, _probeManager), compareBest(nullptr)
  6469. {
  6470. kept = nullptr;
  6471. first = true;
  6472. if (helper.keepBest())
  6473. compareBest = helper.queryCompareBest();
  6474. }
  6475. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  6476. {
  6477. first = true;
  6478. kept = nullptr;
  6479. CRoxieServerDedupActivity::start(parentExtractSize, parentExtract, paused);
  6480. if (numToKeep>1)
  6481. throw MakeStringException(ROXIE_UNIMPLEMENTED_ERROR, "DEDUP with RIGHT and NumToKeep>1 not supported");
  6482. }
  6483. virtual void reset()
  6484. {
  6485. ReleaseClearRoxieRow(kept);
  6486. CRoxieServerActivity::reset();
  6487. }
  6488. virtual const void * nextRow()
  6489. {
  6490. ActivityTimer t(totalCycles, timeActivities);
  6491. if (first)
  6492. {
  6493. kept = inputStream->nextRow();
  6494. first = false;
  6495. }
  6496. const void * next;
  6497. for (;;)
  6498. {
  6499. next = inputStream->nextRow();
  6500. if (!kept || !next || !helper.matches(kept,next))
  6501. break;
  6502. if (compareBest && compareBest->docompare(kept,next) <= 0)
  6503. continue;
  6504. ReleaseRoxieRow(kept);
  6505. kept = next;
  6506. }
  6507. const void * ret = kept;
  6508. kept = next;
  6509. // CTXLOG("dedup returns %p", ret);
  6510. if (ret) processed++;
  6511. return ret;
  6512. }
  6513. };
  6514. class CRoxieServerDedupAllActivity : public CRoxieServerActivity
  6515. {
  6516. IHThorDedupArg &helper;
  6517. unsigned survivorIndex;
  6518. ConstPointerArray survivors;
  6519. bool keepLeft;
  6520. bool eof;
  6521. bool first;
  6522. ICompare *primaryCompare;
  6523. public:
  6524. CRoxieServerDedupAllActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _keepLeft)
  6525. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorDedupArg &)basehelper)
  6526. {
  6527. keepLeft = _keepLeft;
  6528. primaryCompare = helper.queryComparePrimary();
  6529. eof = false;
  6530. first = true;
  6531. survivorIndex = 0;
  6532. }
  6533. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  6534. {
  6535. eof = false;
  6536. first = true;
  6537. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  6538. }
  6539. virtual void reset()
  6540. {
  6541. while (survivors.isItem(survivorIndex))
  6542. {
  6543. ReleaseRoxieRow(survivors.item(survivorIndex++));
  6544. }
  6545. survivors.kill();
  6546. eof = false;
  6547. first = true;
  6548. CRoxieServerActivity::reset();
  6549. }
  6550. void dedupRange(unsigned first, unsigned last, ConstPointerArray & group)
  6551. {
  6552. for (unsigned idxL = first; idxL < last; idxL++)
  6553. {
  6554. const void * left = group.item(idxL);
  6555. if (left)
  6556. {
  6557. for (unsigned idxR = first; idxR < last; idxR++)
  6558. {
  6559. const void * right = group.item(idxR);
  6560. if ((idxL != idxR) && right)
  6561. {
  6562. if (helper.matches(left, right))
  6563. {
  6564. if (keepLeft)
  6565. {
  6566. group.replace(NULL, idxR);
  6567. ReleaseRoxieRow(right);
  6568. }
  6569. else
  6570. {
  6571. group.replace(NULL, idxL);
  6572. ReleaseRoxieRow(left);
  6573. break;
  6574. }
  6575. }
  6576. }
  6577. }
  6578. }
  6579. }
  6580. }
  6581. void dedupRange(unsigned first, unsigned last, void ** rows)
  6582. {
  6583. for (unsigned idxL = first; idxL < last; idxL++)
  6584. {
  6585. void * left = rows[idxL];
  6586. if (left)
  6587. {
  6588. for (unsigned idxR = first; idxR < last; idxR++)
  6589. {
  6590. void * right = rows[idxR];
  6591. if ((idxL != idxR) && right)
  6592. {
  6593. if (helper.matches(left, right))
  6594. {
  6595. if (keepLeft)
  6596. {
  6597. rows[idxR] = NULL;
  6598. ReleaseRoxieRow(right);
  6599. }
  6600. else
  6601. {
  6602. rows[idxL] = NULL;
  6603. ReleaseRoxieRow(left);
  6604. break;
  6605. }
  6606. }
  6607. }
  6608. }
  6609. }
  6610. }
  6611. }
  6612. bool calcNextDedupAll()
  6613. {
  6614. survivors.kill();
  6615. survivorIndex = 0;
  6616. ConstPointerArray group;
  6617. if (eof || !inputStream->nextGroup(group))
  6618. {
  6619. eof = true;
  6620. return false;
  6621. }
  6622. unsigned max = group.ordinality();
  6623. if (primaryCompare)
  6624. {
  6625. //hard, if not impossible, to hit this code once optimisations in place
  6626. MemoryAttr indexbuff(max*sizeof(void *));
  6627. void ** temp = (void **)indexbuff.bufferBase();
  6628. void * *rows = const_cast<void * *>(group.getArray());
  6629. msortvecstableinplace(rows, max, *primaryCompare, temp);
  6630. unsigned first = 0;
  6631. for (unsigned idx = 1; idx < max; idx++)
  6632. {
  6633. if (primaryCompare->docompare(rows[first], rows[idx]) != 0)
  6634. {
  6635. dedupRange(first, idx, rows);
  6636. first = idx;
  6637. }
  6638. }
  6639. dedupRange(first, max, rows);
  6640. for(unsigned idx2=0; idx2<max; ++idx2)
  6641. {
  6642. void * cur = rows[idx2];
  6643. if(cur)
  6644. survivors.append(cur);
  6645. }
  6646. }
  6647. else
  6648. {
  6649. dedupRange(0, max, group);
  6650. for(unsigned idx=0; idx<max; ++idx)
  6651. {
  6652. const void * cur = group.item(idx);
  6653. if(cur)
  6654. survivors.append(cur);
  6655. }
  6656. }
  6657. return true;
  6658. }
  6659. virtual const void *nextRow()
  6660. {
  6661. ActivityTimer t(totalCycles, timeActivities);
  6662. if (first)
  6663. {
  6664. calcNextDedupAll();
  6665. first = false;
  6666. }
  6667. while (survivors.isItem(survivorIndex))
  6668. {
  6669. const void *ret = survivors.item(survivorIndex++);
  6670. if (ret)
  6671. {
  6672. processed++;
  6673. return ret;
  6674. }
  6675. }
  6676. calcNextDedupAll();
  6677. return NULL;
  6678. }
  6679. };
  6680. class CRoxieServerDedupActivityFactory : public CRoxieServerActivityFactory
  6681. {
  6682. bool compareAll;
  6683. bool keepLeft;
  6684. bool keepBest;
  6685. unsigned flags;
  6686. public:
  6687. CRoxieServerDedupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  6688. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  6689. {
  6690. Owned<IHThorDedupArg> helper = (IHThorDedupArg *) helperFactory();
  6691. compareAll = helper->compareAll();
  6692. keepLeft = helper->keepLeft();
  6693. keepBest = helper->keepBest();
  6694. }
  6695. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  6696. {
  6697. if (compareAll)
  6698. return new CRoxieServerDedupAllActivity(_ctx, this, _probeManager, keepLeft);
  6699. else if (keepLeft && !keepBest)
  6700. return new CRoxieServerDedupKeepLeftActivity(_ctx, this, _probeManager);
  6701. else
  6702. return new CRoxieServerDedupKeepRightActivity(_ctx, this, _probeManager);
  6703. }
  6704. };
  6705. IRoxieServerActivityFactory *createRoxieServerDedupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  6706. {
  6707. return new CRoxieServerDedupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  6708. }
  6709. //=================================================================================
  6710. class CRoxieServerHashDedupActivity : public CRoxieServerActivity
  6711. {
  6712. bool eof;
  6713. IHThorHashDedupArg &helper;
  6714. class HashDedupElement
  6715. {
  6716. public:
  6717. HashDedupElement(unsigned _hash, const void *_keyRow)
  6718. : hash(_hash), keyRow(_keyRow)
  6719. {
  6720. }
  6721. ~HashDedupElement()
  6722. {
  6723. ReleaseRoxieRow(keyRow);
  6724. }
  6725. inline unsigned queryHash() const
  6726. {
  6727. return hash;
  6728. }
  6729. inline const void *queryRow() const
  6730. {
  6731. return keyRow;
  6732. }
  6733. inline const void *getRowClear()
  6734. {
  6735. const void * row = keyRow;
  6736. keyRow = nullptr;
  6737. return row;
  6738. }
  6739. private:
  6740. unsigned hash;
  6741. const void *keyRow;
  6742. };
  6743. class HashDedupTable : public SuperHashTable
  6744. {
  6745. public:
  6746. HashDedupTable(IHThorHashDedupArg & _helper, CRoxieServerHashDedupActivity & _activity)
  6747. : helper(_helper),
  6748. activity(_activity),
  6749. keySize(helper.queryKeySize())
  6750. {
  6751. bestCompare=helper.queryCompareBest();
  6752. }
  6753. virtual ~HashDedupTable() { _releaseAll(); }
  6754. virtual unsigned getHashFromElement(const void *et) const
  6755. {
  6756. const HashDedupElement *element = reinterpret_cast<const HashDedupElement *>(et);
  6757. return element->queryHash();
  6758. }
  6759. virtual unsigned getHashFromFindParam(const void *fp) const { throwUnexpected(); }
  6760. virtual const void * getFindParam(const void *et) const { throwUnexpected(); }
  6761. virtual bool matchesElement(const void *et, const void *searchET) const { throwUnexpected(); }
  6762. virtual bool matchesFindParam(const void *et, const void *key, unsigned fphash) const
  6763. {
  6764. const HashDedupElement *element = reinterpret_cast<const HashDedupElement *>(et);
  6765. if (fphash != element->queryHash())
  6766. return false;
  6767. return (helper.queryKeyCompare()->docompare(element->queryRow(), key) == 0);
  6768. }
  6769. virtual void onAdd(void *et) {}
  6770. virtual void onRemove(void *et)
  6771. {
  6772. const HashDedupElement *element = reinterpret_cast<const HashDedupElement *>(et);
  6773. delete element;
  6774. }
  6775. void onCreate(IRoxieSlaveContext *ctx)
  6776. {
  6777. keyRowAllocator.setown(activity.createRowAllocator(keySize.queryOriginal()));
  6778. }
  6779. void reset()
  6780. {
  6781. kill();
  6782. }
  6783. bool insert(const void * row)
  6784. {
  6785. unsigned hash = helper.queryHash()->hash(row);
  6786. RtlDynamicRowBuilder keyRowBuilder(keyRowAllocator, true);
  6787. size32_t thisKeySize = helper.recordToKey(keyRowBuilder, row);
  6788. OwnedConstRoxieRow keyRow = keyRowBuilder.finalizeRowClear(thisKeySize);
  6789. if (find(hash, keyRow.get()))
  6790. return false;
  6791. addNew(new HashDedupElement(hash, keyRow.getClear()), hash);
  6792. return true;
  6793. }
  6794. bool insertBest(const void * nextrow)
  6795. {
  6796. unsigned hash = helper.queryHash()->hash(nextrow);
  6797. const void *et = find(hash, nextrow);
  6798. if (et)
  6799. {
  6800. const HashDedupElement *element = reinterpret_cast<const HashDedupElement *>(et);
  6801. const void * row = element->queryRow();
  6802. if (bestCompare->docompare(row,nextrow) <= 0)
  6803. return false;
  6804. removeExact( const_cast<void *>(et));
  6805. // drop-through to add new row
  6806. }
  6807. addNew(new HashDedupElement(hash, nextrow), hash);
  6808. return true;
  6809. }
  6810. void gatherStats(CRuntimeStatisticCollection & merged) const
  6811. {
  6812. if (keyRowAllocator)
  6813. keyRowAllocator->gatherStats(merged);
  6814. }
  6815. private:
  6816. IHThorHashDedupArg & helper;
  6817. CachedOutputMetaData keySize;
  6818. Owned<IEngineRowAllocator> keyRowAllocator;
  6819. CRoxieServerHashDedupActivity & activity;
  6820. ICompare * bestCompare;
  6821. } table;
  6822. public:
  6823. CRoxieServerHashDedupActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  6824. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorHashDedupArg &)basehelper), table(helper, *this), hashTableFilled(false), hashDedupTableIter(table)
  6825. {
  6826. eof = false;
  6827. keepBest = helper.keepBest();
  6828. }
  6829. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  6830. {
  6831. eof = false;
  6832. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  6833. }
  6834. virtual void onCreate(IHThorArg *_colocalParent)
  6835. {
  6836. CRoxieServerActivity::onCreate(colocalParent);
  6837. table.onCreate(ctx);
  6838. }
  6839. virtual void reset()
  6840. {
  6841. table.reset();
  6842. eof = false;
  6843. CRoxieServerActivity::reset();
  6844. hashTableFilled = false;
  6845. }
  6846. virtual const void *nextRow()
  6847. {
  6848. ActivityTimer t(totalCycles, timeActivities);
  6849. if (keepBest)
  6850. {
  6851. if (eof)
  6852. return NULL;
  6853. // Populate hash table with best rows
  6854. if (!hashTableFilled)
  6855. {
  6856. const void * next = inputStream->nextRow();
  6857. while(next)
  6858. {
  6859. if (!table.insertBest(next))
  6860. ReleaseRoxieRow(next);
  6861. next = inputStream->nextRow();
  6862. }
  6863. if (table.count() == 0)
  6864. eof = true;
  6865. hashTableFilled = true;
  6866. hashDedupTableIter.first();
  6867. }
  6868. // Iterate throw hash table returning rows
  6869. if (hashDedupTableIter.isValid())
  6870. {
  6871. HashDedupElement &el = hashDedupTableIter.query();
  6872. const void * row = el.getRowClear();
  6873. hashDedupTableIter.next();
  6874. return row;
  6875. }
  6876. table.reset();
  6877. hashTableFilled = false;
  6878. return NULL;
  6879. }
  6880. else
  6881. {
  6882. while(!eof)
  6883. {
  6884. const void * next = inputStream->nextRow();
  6885. if(!next)
  6886. {
  6887. if (table.count() == 0)
  6888. eof = true;
  6889. table.reset();
  6890. return NULL;
  6891. }
  6892. if(table.insert(next))
  6893. return next;
  6894. else
  6895. ReleaseRoxieRow(next);
  6896. }
  6897. return NULL;
  6898. }
  6899. }
  6900. private:
  6901. bool keepBest;
  6902. bool hashTableFilled;
  6903. SuperHashIteratorOf<HashDedupElement> hashDedupTableIter;
  6904. };
  6905. class CRoxieServerHashDedupActivityFactory : public CRoxieServerActivityFactory
  6906. {
  6907. public:
  6908. CRoxieServerHashDedupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  6909. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  6910. {
  6911. }
  6912. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  6913. {
  6914. return new CRoxieServerHashDedupActivity(_ctx, this, _probeManager);
  6915. }
  6916. };
  6917. IRoxieServerActivityFactory *createRoxieServerHashDedupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  6918. {
  6919. return new CRoxieServerHashDedupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  6920. }
  6921. //=================================================================================
  6922. class CRoxieServerRollupActivity : public CRoxieServerActivity
  6923. {
  6924. IHThorRollupArg &helper;
  6925. OwnedConstRoxieRow left;
  6926. OwnedConstRoxieRow prev;
  6927. OwnedConstRoxieRow right;
  6928. bool readFirstRow;
  6929. public:
  6930. CRoxieServerRollupActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  6931. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorRollupArg &)basehelper)
  6932. {
  6933. readFirstRow = false;
  6934. }
  6935. ~CRoxieServerRollupActivity()
  6936. {
  6937. }
  6938. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  6939. {
  6940. readFirstRow = false;
  6941. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  6942. }
  6943. virtual void reset()
  6944. {
  6945. left.clear();
  6946. prev.clear();
  6947. right.clear();
  6948. CRoxieServerActivity::reset();
  6949. }
  6950. virtual bool needsAllocator() const { return true; }
  6951. virtual const void * nextRow()
  6952. {
  6953. ActivityTimer t(totalCycles, timeActivities);
  6954. if (!readFirstRow)
  6955. {
  6956. left.setown(inputStream->nextRow());
  6957. prev.set(left);
  6958. readFirstRow = true;
  6959. }
  6960. for (;;)
  6961. {
  6962. right.setown(inputStream->nextRow());
  6963. if(!prev || !right || !helper.matches(prev,right))
  6964. {
  6965. const void * ret = left.getClear();
  6966. if(ret)
  6967. processed++;
  6968. left.setown(right.getClear());
  6969. prev.set(left);
  6970. return ret;
  6971. }
  6972. try
  6973. {
  6974. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  6975. unsigned outSize = helper.transform(rowBuilder, left, right);
  6976. if (outSize)
  6977. left.setown(rowBuilder.finalizeRowClear(outSize));
  6978. if (helper.getFlags() & RFrolledismatchleft)
  6979. prev.set(left);
  6980. else
  6981. prev.set(right);
  6982. }
  6983. catch(IException * E)
  6984. {
  6985. throw makeWrappedException(E);
  6986. }
  6987. }
  6988. }
  6989. };
  6990. class CRoxieServerRollupActivityFactory : public CRoxieServerActivityFactory
  6991. {
  6992. public:
  6993. CRoxieServerRollupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  6994. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  6995. {
  6996. }
  6997. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  6998. {
  6999. return new CRoxieServerRollupActivity(_ctx, this, _probeManager);
  7000. }
  7001. };
  7002. IRoxieServerActivityFactory *createRoxieServerRollupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  7003. {
  7004. return new CRoxieServerRollupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  7005. }
  7006. //=================================================================================
  7007. class CRoxieServerNormalizeActivity : public CRoxieServerActivity
  7008. {
  7009. IHThorNormalizeArg &helper;
  7010. unsigned numThisRow;
  7011. unsigned curRow;
  7012. const void *buffer;
  7013. unsigned numProcessedLastGroup;
  7014. public:
  7015. CRoxieServerNormalizeActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  7016. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorNormalizeArg &)basehelper)
  7017. {
  7018. buffer = NULL;
  7019. numThisRow = 0;
  7020. curRow = 0;
  7021. numProcessedLastGroup = 0;
  7022. }
  7023. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  7024. {
  7025. numThisRow = 0;
  7026. curRow = 0;
  7027. numProcessedLastGroup = 0;
  7028. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  7029. }
  7030. virtual void reset()
  7031. {
  7032. ReleaseClearRoxieRow(buffer);
  7033. CRoxieServerActivity::reset();
  7034. }
  7035. virtual bool needsAllocator() const { return true; }
  7036. virtual const void * nextRow()
  7037. {
  7038. ActivityTimer t(totalCycles, timeActivities);
  7039. for (;;)
  7040. {
  7041. while (curRow == numThisRow)
  7042. {
  7043. if (buffer)
  7044. ReleaseClearRoxieRow(buffer);
  7045. buffer = inputStream->nextRow();
  7046. if (!buffer && (processed == numProcessedLastGroup))
  7047. buffer = inputStream->nextRow();
  7048. if (!buffer)
  7049. {
  7050. numProcessedLastGroup = processed;
  7051. return NULL;
  7052. }
  7053. curRow = 0;
  7054. numThisRow = helper.numExpandedRows(buffer);
  7055. }
  7056. try
  7057. {
  7058. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  7059. unsigned actualSize = helper.transform(rowBuilder, buffer, ++curRow);
  7060. if (actualSize != 0)
  7061. {
  7062. processed++;
  7063. return rowBuilder.finalizeRowClear(actualSize);
  7064. }
  7065. }
  7066. catch (IException *E)
  7067. {
  7068. throw makeWrappedException(E);
  7069. }
  7070. }
  7071. }
  7072. };
  7073. class CRoxieServerNormalizeActivityFactory : public CRoxieServerActivityFactory
  7074. {
  7075. public:
  7076. CRoxieServerNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  7077. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  7078. {
  7079. }
  7080. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  7081. {
  7082. return new CRoxieServerNormalizeActivity(_ctx, this, _probeManager);
  7083. }
  7084. };
  7085. IRoxieServerActivityFactory *createRoxieServerNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  7086. {
  7087. return new CRoxieServerNormalizeActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  7088. }
  7089. //=================================================================================
  7090. class CRoxieServerNormalizeChildActivity : public CRoxieServerActivity
  7091. {
  7092. IHThorNormalizeChildArg &helper;
  7093. unsigned numThisRow;
  7094. unsigned curRow;
  7095. const void *buffer;
  7096. unsigned numProcessedLastGroup;
  7097. INormalizeChildIterator * cursor;
  7098. const void * curChildRow;
  7099. bool advanceInput()
  7100. {
  7101. for (;;)
  7102. {
  7103. ReleaseClearRoxieRow(buffer);
  7104. buffer = inputStream->nextRow();
  7105. if (!buffer && (processed == numProcessedLastGroup))
  7106. buffer = inputStream->nextRow();
  7107. if (!buffer)
  7108. {
  7109. numProcessedLastGroup = processed;
  7110. return false;
  7111. }
  7112. curChildRow = cursor->first(buffer);
  7113. if (curChildRow)
  7114. {
  7115. curRow = 0;
  7116. return true;
  7117. }
  7118. }
  7119. }
  7120. public:
  7121. CRoxieServerNormalizeChildActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  7122. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorNormalizeChildArg &)basehelper)
  7123. {
  7124. buffer = NULL;
  7125. cursor = NULL;
  7126. numThisRow = 0;
  7127. curRow = 0;
  7128. numProcessedLastGroup = 0;
  7129. curChildRow = NULL;
  7130. }
  7131. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  7132. {
  7133. numThisRow = 0;
  7134. curRow = 0;
  7135. numProcessedLastGroup = 0;
  7136. curChildRow = NULL;
  7137. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  7138. cursor = helper.queryIterator();
  7139. }
  7140. virtual void stop()
  7141. {
  7142. CRoxieServerActivity::stop();
  7143. }
  7144. virtual void reset()
  7145. {
  7146. cursor = NULL;
  7147. ReleaseClearRoxieRow(buffer);
  7148. CRoxieServerActivity::reset();
  7149. }
  7150. virtual bool needsAllocator() const { return true; }
  7151. const void *nextRow()
  7152. {
  7153. ActivityTimer t(totalCycles, timeActivities);
  7154. for (;;)
  7155. {
  7156. if (!buffer)
  7157. {
  7158. if (!advanceInput())
  7159. return NULL;
  7160. }
  7161. try
  7162. {
  7163. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  7164. size32_t outSize = helper.transform(rowBuilder, buffer, curChildRow, ++curRow);
  7165. curChildRow = cursor->next();
  7166. if (!curChildRow)
  7167. ReleaseClearRoxieRow(buffer);
  7168. if (outSize != 0)
  7169. {
  7170. processed++;
  7171. return rowBuilder.finalizeRowClear(outSize);
  7172. }
  7173. }
  7174. catch (IException *E)
  7175. {
  7176. throw makeWrappedException(E);
  7177. }
  7178. }
  7179. }
  7180. };
  7181. class CRoxieServerNormalizeChildActivityFactory : public CRoxieServerActivityFactory
  7182. {
  7183. public:
  7184. CRoxieServerNormalizeChildActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  7185. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  7186. {
  7187. }
  7188. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  7189. {
  7190. return new CRoxieServerNormalizeChildActivity(_ctx, this, _probeManager);
  7191. }
  7192. };
  7193. IRoxieServerActivityFactory *createRoxieServerNormalizeChildActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  7194. {
  7195. return new CRoxieServerNormalizeChildActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  7196. }
  7197. //=================================================================================
  7198. class CRoxieServerNormalizeLinkedChildActivity : public CRoxieServerActivity
  7199. {
  7200. IHThorNormalizeLinkedChildArg &helper;
  7201. OwnedConstRoxieRow curParent;
  7202. OwnedConstRoxieRow curChild;
  7203. unsigned numProcessedLastGroup;
  7204. bool advanceInput()
  7205. {
  7206. for (;;)
  7207. {
  7208. curParent.setown(inputStream->nextRow());
  7209. if (!curParent && (processed == numProcessedLastGroup))
  7210. curParent.setown(inputStream->nextRow());
  7211. if (!curParent)
  7212. {
  7213. numProcessedLastGroup = processed;
  7214. return false;
  7215. }
  7216. curChild.set(helper.first(curParent));
  7217. if (curChild)
  7218. return true;
  7219. }
  7220. }
  7221. public:
  7222. CRoxieServerNormalizeLinkedChildActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  7223. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorNormalizeLinkedChildArg &)basehelper)
  7224. {
  7225. numProcessedLastGroup = 0;
  7226. }
  7227. ~CRoxieServerNormalizeLinkedChildActivity()
  7228. {
  7229. }
  7230. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  7231. {
  7232. numProcessedLastGroup = 0;
  7233. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  7234. }
  7235. virtual void reset()
  7236. {
  7237. curParent.clear();
  7238. curChild.clear();
  7239. CRoxieServerActivity::reset();
  7240. }
  7241. const void *nextRow()
  7242. {
  7243. ActivityTimer t(totalCycles, timeActivities);
  7244. for (;;)
  7245. {
  7246. if (!curParent)
  7247. {
  7248. if (!advanceInput())
  7249. return NULL;
  7250. }
  7251. try
  7252. {
  7253. const void *ret = curChild.getClear();
  7254. curChild.set(helper.next());
  7255. if (!curChild)
  7256. curParent.clear();
  7257. if (ret)
  7258. {
  7259. processed++;
  7260. return ret;
  7261. }
  7262. }
  7263. catch (IException *E)
  7264. {
  7265. throw makeWrappedException(E);
  7266. }
  7267. }
  7268. }
  7269. };
  7270. class CRoxieServerNormalizeLinkedChildActivityFactory : public CRoxieServerActivityFactory
  7271. {
  7272. public:
  7273. CRoxieServerNormalizeLinkedChildActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  7274. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  7275. {
  7276. }
  7277. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  7278. {
  7279. return new CRoxieServerNormalizeLinkedChildActivity(_ctx, this, _probeManager);
  7280. }
  7281. };
  7282. IRoxieServerActivityFactory *createRoxieServerNormalizeLinkedChildActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  7283. {
  7284. return new CRoxieServerNormalizeLinkedChildActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  7285. }
  7286. //=================================================================================
  7287. class CRoxieServerSortActivity : public CRoxieServerActivity
  7288. {
  7289. protected:
  7290. IHThorSortArg &helper;
  7291. ICompare *compare;
  7292. Owned<ISortAlgorithm> sorter;
  7293. bool readInput;
  7294. RoxieSortAlgorithm sortAlgorithm;
  7295. unsigned sortFlags;
  7296. public:
  7297. CRoxieServerSortActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, RoxieSortAlgorithm _sortAlgorithm, unsigned _sortFlags)
  7298. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorSortArg &)basehelper), sortAlgorithm(_sortAlgorithm), sortFlags(_sortFlags)
  7299. {
  7300. compare = helper.queryCompare();
  7301. readInput = false;
  7302. }
  7303. virtual void onCreate(IHThorArg *_colocalParent)
  7304. {
  7305. CRoxieServerActivity::onCreate(_colocalParent);
  7306. if (sortAlgorithm==unknownSortAlgorithm)
  7307. sorter.clear();
  7308. else
  7309. sorter.setown(createSortAlgorithm(sortAlgorithm, compare, ctx->queryRowManager(), meta, ctx->queryCodeContext(), tempDirectory, activityId));
  7310. }
  7311. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  7312. {
  7313. assertex(!readInput);
  7314. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  7315. }
  7316. virtual void reset()
  7317. {
  7318. if (sorter)
  7319. sorter->reset();
  7320. readInput = false;
  7321. CRoxieServerActivity::reset();
  7322. }
  7323. static RoxieSortAlgorithm useAlgorithm(const char *algorithmName, unsigned sortFlags)
  7324. {
  7325. RoxieSortAlgorithm sortAlgorithm = unknownSortAlgorithm;
  7326. if (!algorithmName)
  7327. algorithmName = "";
  7328. if (stricmp(algorithmName, "quicksort")==0)
  7329. {
  7330. switch (sortFlags & (TAFstable|TAFspill))
  7331. {
  7332. case 0: sortAlgorithm = quickSortAlgorithm; break;
  7333. case TAFstable: sortAlgorithm = stableQuickSortAlgorithm; break;
  7334. case TAFspill: sortAlgorithm = spillingQuickSortAlgorithm; break;
  7335. case TAFstable|TAFspill: sortAlgorithm = stableSpillingQuickSortAlgorithm; break;
  7336. }
  7337. }
  7338. else if (stricmp(algorithmName, "parquicksort")==0)
  7339. {
  7340. switch (sortFlags & TAFstable)
  7341. {
  7342. case 0: sortAlgorithm = parallelQuickSortAlgorithm; break;
  7343. case TAFstable: sortAlgorithm = parallelStableQuickSortAlgorithm; break;
  7344. default: throwUnexpected();
  7345. }
  7346. }
  7347. else if (stricmp(algorithmName, "heapsort")==0)
  7348. sortAlgorithm = heapSortAlgorithm; // NOTE - we do allow UNSTABLE('heapsort') in order to facilitate runtime selection. Also explicit selection of heapsort overrides request to spill
  7349. else if (stricmp(algorithmName, "mergesort")==0)
  7350. sortAlgorithm = (sortFlags & TAFspill) ? spillingMergeSortAlgorithm : mergeSortAlgorithm;
  7351. else if (stricmp(algorithmName, "parmergesort")==0)
  7352. sortAlgorithm = (sortFlags & TAFspill) ? spillingParallelMergeSortAlgorithm : parallelMergeSortAlgorithm;
  7353. else if (stricmp(algorithmName, "tbbqsort")==0)
  7354. sortAlgorithm = tbbQuickSortAlgorithm;
  7355. else if (stricmp(algorithmName, "tbbstableqsort")==0)
  7356. sortAlgorithm = tbbStableQuickSortAlgorithm;
  7357. else
  7358. {
  7359. if (*algorithmName)
  7360. WARNLOG(ROXIE_UNKNOWN_ALGORITHM, "Ignoring unsupported sort order algorithm '%s', using default", algorithmName);
  7361. if (sortFlags & TAFspill)
  7362. sortAlgorithm = ((sortFlags & TAFunstable) != 0) ? spillingQuickSortAlgorithm : stableSpillingQuickSortAlgorithm;
  7363. else if (sortFlags & TAFunstable)
  7364. sortAlgorithm = quickSortAlgorithm;
  7365. else
  7366. sortAlgorithm = heapSortAlgorithm;
  7367. }
  7368. return sortAlgorithm;
  7369. }
  7370. virtual const void * nextRow()
  7371. {
  7372. ActivityTimer t(totalCycles, timeActivities);
  7373. if (!readInput)
  7374. {
  7375. if (sortAlgorithm == unknownSortAlgorithm)
  7376. {
  7377. sorter.clear();
  7378. OwnedRoxieString algorithmName(helper.getAlgorithm());
  7379. sortAlgorithm = useAlgorithm(algorithmName, sortFlags);
  7380. sorter.setown(createSortAlgorithm(sortAlgorithm, compare, ctx->queryRowManager(), meta, ctx->queryCodeContext(), tempDirectory, activityId));
  7381. }
  7382. sorter->prepare(inputStream);
  7383. noteStatistic(StTimeSortElapsed, cycle_to_nanosec(sorter->getElapsedCycles(true)));
  7384. readInput = true;
  7385. }
  7386. const void *ret = sorter->next();
  7387. if (ret)
  7388. processed++;
  7389. else
  7390. {
  7391. sorter->reset();
  7392. readInput = false; // ready for next group
  7393. }
  7394. return ret;
  7395. }
  7396. };
  7397. class CRoxieServerSortActivityFactory : public CRoxieServerActivityFactory
  7398. {
  7399. RoxieSortAlgorithm sortAlgorithm;
  7400. unsigned sortFlags;
  7401. public:
  7402. CRoxieServerSortActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  7403. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  7404. {
  7405. Owned<IHThorSortArg> sortHelper = (IHThorSortArg *) helperFactory();
  7406. const char *algorithmName = NULL;
  7407. sortFlags = sortHelper->getAlgorithmFlags();
  7408. if (sortFlags & TAFconstant)
  7409. algorithmName = sortHelper->getAlgorithm();
  7410. bool forceSpill = _queryFactory.queryOptions().allSortsMaySpill || _graphNode.getPropBool("hint[@name='spill']/@value", false);
  7411. if (forceSpill)
  7412. sortFlags |= TAFspill;
  7413. if (!(sortFlags & TAFunstable))
  7414. sortFlags |= TAFstable; // Assume stable unless specifically requested otherwise
  7415. if (sortFlags & TAFconstant)
  7416. sortAlgorithm = CRoxieServerSortActivity::useAlgorithm(algorithmName, sortFlags);
  7417. else
  7418. sortAlgorithm = unknownSortAlgorithm;
  7419. }
  7420. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  7421. {
  7422. return new CRoxieServerSortActivity(_ctx, this, _probeManager, sortAlgorithm, sortFlags);
  7423. }
  7424. virtual const StatisticsMapping &queryStatsMapping() const
  7425. {
  7426. return sortStatistics;
  7427. }
  7428. };
  7429. IRoxieServerActivityFactory *createRoxieServerSortActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  7430. {
  7431. return new CRoxieServerSortActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  7432. }
  7433. //=====================================================================================================
  7434. static int compareUint64(const void * _left, const void * _right)
  7435. {
  7436. const unsigned __int64 left = *static_cast<const unsigned __int64 *>(_left);
  7437. const unsigned __int64 right = *static_cast<const unsigned __int64 *>(_right);
  7438. if (left < right)
  7439. return -1;
  7440. if (left > right)
  7441. return -1;
  7442. return 0;
  7443. }
  7444. class CRoxieServerQuantileActivity : public CRoxieServerActivity
  7445. {
  7446. protected:
  7447. Owned<ISortAlgorithm> sorter;
  7448. IHThorQuantileArg &helper;
  7449. ConstPointerArray sorted;
  7450. ICompare *compare;
  7451. unsigned flags;
  7452. double skew;
  7453. unsigned __int64 numDivisions;
  7454. bool rangeIsAll;
  7455. size32_t rangeSize;
  7456. rtlDataAttr rangeValues;
  7457. bool calculated;
  7458. bool processedAny;
  7459. bool anyThisGroup;
  7460. bool eof;
  7461. unsigned curQuantile;
  7462. unsigned curIndex;
  7463. unsigned curIndexExtra;
  7464. unsigned skipSize;
  7465. unsigned skipExtra;
  7466. unsigned prevIndex;
  7467. public:
  7468. CRoxieServerQuantileActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _flags)
  7469. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorQuantileArg &)basehelper), flags(_flags)
  7470. {
  7471. compare = helper.queryCompare();
  7472. skew = 0.0;
  7473. numDivisions = 0;
  7474. calculated = false;
  7475. processedAny = false;
  7476. anyThisGroup = false;
  7477. eof = false;
  7478. rangeIsAll = true;
  7479. rangeSize = 0;
  7480. curQuantile = 0;
  7481. prevIndex = 0;
  7482. curIndex = 0;
  7483. curIndexExtra = 0;
  7484. skipSize = 0;
  7485. skipExtra = 0;
  7486. if (flags & TQFunstable)
  7487. sorter.setown(createQuickSortAlgorithm(compare));
  7488. else
  7489. sorter.setown(createMergeSortAlgorithm(compare));
  7490. }
  7491. virtual void reset()
  7492. {
  7493. sorter->reset();
  7494. calculated = false;
  7495. processedAny = false;
  7496. anyThisGroup = false;
  7497. ReleaseRoxieRows(sorted);
  7498. CRoxieServerActivity::reset();
  7499. }
  7500. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  7501. {
  7502. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  7503. skew = helper.getSkew();
  7504. numDivisions = helper.getNumDivisions();
  7505. //Check for -ve integer values and treat as out of range
  7506. if ((__int64)numDivisions < 1)
  7507. numDivisions = 1;
  7508. if (flags & TQFhasrange)
  7509. helper.getRange(rangeIsAll, rangeSize, rangeValues.refdata());
  7510. else
  7511. {
  7512. rangeIsAll = true;
  7513. rangeSize = 0;
  7514. }
  7515. if (rangeSize)
  7516. {
  7517. //Sort the range items into order to allow quick comparison
  7518. qsort(rangeValues.getdata(), rangeSize / sizeof(unsigned __int64), sizeof(unsigned __int64), compareUint64);
  7519. }
  7520. calculated = false;
  7521. processedAny = false;
  7522. anyThisGroup = false;
  7523. eof = false;
  7524. curQuantile = 0;
  7525. prevIndex = 0;
  7526. curIndex = 0;
  7527. curIndexExtra = 0;
  7528. }
  7529. virtual bool needsAllocator() const { return true; }
  7530. virtual const void * nextRow()
  7531. {
  7532. ActivityTimer t(totalCycles, timeActivities);
  7533. if (eof)
  7534. return NULL;
  7535. const void * ret = NULL;
  7536. for(;;)
  7537. {
  7538. if (!calculated)
  7539. {
  7540. if (flags & TQFlocalsorted)
  7541. {
  7542. for (;;)
  7543. {
  7544. const void * next = inputStream->nextRow();
  7545. if (!next)
  7546. break;
  7547. sorted.append(next);
  7548. }
  7549. }
  7550. else
  7551. {
  7552. sorter->prepare(inputStream);
  7553. sorter->getSortedGroup(sorted);
  7554. }
  7555. if (sorted.ordinality() == 0)
  7556. {
  7557. if (processedAny)
  7558. {
  7559. eof = true;
  7560. return NULL;
  7561. }
  7562. //Unusual case 0 rows - add a default row instead
  7563. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  7564. size32_t thisSize = helper.createDefault(rowBuilder);
  7565. sorted.append(rowBuilder.finalizeRowClear(thisSize));
  7566. }
  7567. calculated = true;
  7568. processedAny = true;
  7569. anyThisGroup = false;
  7570. curQuantile = 0;
  7571. curIndex = 0;
  7572. curIndexExtra = (unsigned)((numDivisions-1) / 2); // to ensure correctly rounded up
  7573. prevIndex = curIndex-1; // Ensure it doesn't match
  7574. skipSize = (unsigned)(sorted.ordinality() / numDivisions);
  7575. skipExtra = (unsigned)(sorted.ordinality() % numDivisions);
  7576. }
  7577. if (isQuantileIncluded(curQuantile))
  7578. {
  7579. if (!(flags & TQFdedup) || (prevIndex != curIndex))
  7580. {
  7581. const void * lhs = sorted.item(curIndex);
  7582. if (flags & TQFneedtransform)
  7583. {
  7584. unsigned outSize;
  7585. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  7586. try
  7587. {
  7588. outSize = helper.transform(rowBuilder, lhs, curQuantile);
  7589. }
  7590. catch (IException *E)
  7591. {
  7592. throw makeWrappedException(E);
  7593. }
  7594. if (outSize)
  7595. ret = rowBuilder.finalizeRowClear(outSize);
  7596. }
  7597. else
  7598. {
  7599. LinkRoxieRow(lhs);
  7600. ret = lhs;
  7601. }
  7602. prevIndex = curIndex; // even if output was skipped?
  7603. }
  7604. }
  7605. curIndex += skipSize;
  7606. curIndexExtra += skipExtra;
  7607. if (curIndexExtra >= numDivisions)
  7608. {
  7609. curIndex++;
  7610. curIndexExtra -= numDivisions;
  7611. }
  7612. //Ensure the current index always stays valid.
  7613. if (curIndex >= sorted.ordinality())
  7614. curIndex = sorted.ordinality()-1;
  7615. curQuantile++;
  7616. if (curQuantile > numDivisions)
  7617. {
  7618. ReleaseRoxieRows(sorted);
  7619. sorter->reset();
  7620. calculated = false; // ready for next group
  7621. }
  7622. if (ret)
  7623. {
  7624. anyThisGroup = true;
  7625. processed++;
  7626. return ret;
  7627. }
  7628. if (curQuantile > numDivisions)
  7629. {
  7630. if (anyThisGroup)
  7631. return NULL;
  7632. }
  7633. }
  7634. }
  7635. bool isQuantileIncluded(unsigned quantile) const
  7636. {
  7637. if (quantile == 0)
  7638. return (flags & TQFfirst) != 0;
  7639. if (quantile == numDivisions)
  7640. return (flags & TQFlast) != 0;
  7641. if (rangeIsAll)
  7642. return true;
  7643. //Compare against the list of ranges provided
  7644. //MORE: Since the list is sorted should only need to compare the next (and allow for dups)
  7645. unsigned rangeNum = rangeSize / sizeof(unsigned __int64);
  7646. const unsigned __int64 * ranges = static_cast<const unsigned __int64 *>(rangeValues.getdata());
  7647. for (unsigned i = 0; i < rangeNum; i++)
  7648. {
  7649. if (ranges[i] == quantile)
  7650. return true;
  7651. }
  7652. return false;
  7653. }
  7654. };
  7655. class CRoxieServerQuantileActivityFactory : public CRoxieServerActivityFactory
  7656. {
  7657. unsigned flags;
  7658. public:
  7659. CRoxieServerQuantileActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  7660. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  7661. {
  7662. Owned<IHThorQuantileArg> quantileHelper = (IHThorQuantileArg *) helperFactory();
  7663. flags = quantileHelper->getFlags();
  7664. }
  7665. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  7666. {
  7667. return new CRoxieServerQuantileActivity(_ctx, this, _probeManager, flags);
  7668. }
  7669. };
  7670. IRoxieServerActivityFactory *createRoxieServerQuantileActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  7671. {
  7672. return new CRoxieServerQuantileActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  7673. }
  7674. //=====================================================================================================
  7675. class CRoxieServerSortedActivity : public CRoxieServerActivity
  7676. {
  7677. IHThorSortedArg &helper;
  7678. ICompare * compare;
  7679. const void *prev;
  7680. IRangeCompare * stepCompare;
  7681. public:
  7682. CRoxieServerSortedActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  7683. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorSortedArg &)basehelper)
  7684. {
  7685. prev = NULL;
  7686. compare = helper.queryCompare();
  7687. stepCompare = NULL;
  7688. }
  7689. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  7690. {
  7691. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  7692. IInputSteppingMeta * stepMeta = input->querySteppingMeta();
  7693. if (stepMeta)
  7694. stepCompare = stepMeta->queryCompare();
  7695. prev = NULL;
  7696. }
  7697. virtual void reset()
  7698. {
  7699. ReleaseClearRoxieRow(prev);
  7700. CRoxieServerActivity::reset();
  7701. }
  7702. virtual const void * nextRow()
  7703. {
  7704. ActivityTimer t(totalCycles, timeActivities);
  7705. const void *ret = inputStream->nextRow();
  7706. if (ret && prev && compare->docompare(prev, ret) > 0)
  7707. {
  7708. // MORE - better to give mismatching rows that indexes?
  7709. throw MakeStringException(ROXIE_NOT_SORTED, "SORTED(%u) detected incorrectly sorted rows (row %d, %d))", activityId, processed, processed+1);
  7710. }
  7711. ReleaseRoxieRow(prev);
  7712. prev = ret;
  7713. if (ret)
  7714. {
  7715. LinkRoxieRow(prev);
  7716. processed++;
  7717. }
  7718. return ret;
  7719. }
  7720. virtual const void * nextRowGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  7721. {
  7722. ActivityTimer t(totalCycles, timeActivities);
  7723. const void *ret = inputStream->nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);
  7724. if (ret && prev && compare->docompare(prev, ret) > 0)
  7725. {
  7726. // MORE - better to give mismatching rows that indexes?
  7727. throw MakeStringException(ROXIE_NOT_SORTED, "SORTED(%u) detected incorrectly sorted rows (row %d, %d))", activityId, processed, processed+1);
  7728. }
  7729. ReleaseRoxieRow(prev);
  7730. prev = ret;
  7731. if (ret)
  7732. {
  7733. LinkRoxieRow(prev);
  7734. processed++;
  7735. }
  7736. return ret;
  7737. }
  7738. IInputSteppingMeta * querySteppingMeta()
  7739. {
  7740. return input->querySteppingMeta();
  7741. }
  7742. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  7743. {
  7744. return input->gatherConjunctions(collector);
  7745. }
  7746. virtual void resetEOF()
  7747. {
  7748. inputStream->resetEOF();
  7749. }
  7750. };
  7751. class CRoxieServerSortedActivityFactory : public CRoxieServerActivityFactory
  7752. {
  7753. public:
  7754. CRoxieServerSortedActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  7755. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  7756. {
  7757. }
  7758. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  7759. {
  7760. return new CRoxieServerSortedActivity(_ctx, this, _probeManager);
  7761. }
  7762. };
  7763. IRoxieServerActivityFactory *createRoxieServerSortedActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  7764. {
  7765. return new CRoxieServerSortedActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  7766. }
  7767. //=====================================================================================================
  7768. class CRoxieServerThroughSpillActivity : public CRoxieServerActivity
  7769. {
  7770. /*
  7771. BE VERY CAREFUL - this code is tricky.
  7772. Note that starts and stops (and resets) can occur in strange orders
  7773. The FIRST start OR stop must initialize the activity but only the first START should call the upstream start.
  7774. The last stop should call the upstream stop.
  7775. The first reset should call the upstream reset.
  7776. 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
  7777. not yet had start or stop called - for this to happen init() is called on all outputs on the first start or stop.
  7778. Some outputs may be completely pruned away when used in a GRAPH - these outputs should not receive any start/stop/reset and should be
  7779. ignored in the minIndex calculation
  7780. */
  7781. public:
  7782. IHThorArg &helper;
  7783. unsigned activeOutputs;
  7784. unsigned numOutputs;
  7785. unsigned numOriginalOutputs;
  7786. QueueOf<const void, true> buffer;
  7787. CriticalSection crit;
  7788. CriticalSection crit2;
  7789. unsigned tailIdx;
  7790. unsigned headIdx;
  7791. Owned<IException> error;
  7792. class OutputAdaptor : implements IEngineRowStream, implements IFinalRoxieInput, public CInterface
  7793. {
  7794. bool eof, eofpending, stopped;
  7795. public:
  7796. CRoxieServerThroughSpillActivity *parent;
  7797. unsigned idx;
  7798. unsigned oid;
  7799. unsigned processed;
  7800. cycle_t totalCycles; // We track this per output so that the pullers get a meaningful value to use when calculating their localtime
  7801. public:
  7802. IMPLEMENT_IINTERFACE;
  7803. OutputAdaptor()
  7804. {
  7805. parent = NULL;
  7806. oid = 0;
  7807. idx = 0;
  7808. processed = 0;
  7809. totalCycles = 0;
  7810. eofpending = false;
  7811. eof = false;
  7812. stopped = false;
  7813. }
  7814. ~OutputAdaptor()
  7815. {
  7816. if (traceStartStop)
  7817. DBGLOG("%p ~OutputAdaptor %d", this, oid);
  7818. if (processed && parent && parent->factory)
  7819. {
  7820. parent->factory->noteProcessed(oid, processed);
  7821. if (parent->ctx)
  7822. parent->ctx->noteProcessed(parent->querySubgraphId(), parent->activityId, oid, processed, 0);
  7823. }
  7824. }
  7825. void init()
  7826. {
  7827. if (traceStartStop)
  7828. DBGLOG("%p init Input adaptor %d", this, oid);
  7829. idx = 0;
  7830. processed = 0;
  7831. eofpending = false;
  7832. eof = false;
  7833. stopped = false;
  7834. }
  7835. virtual IEngineRowStream *queryConcreteOutputStream(unsigned whichInput) { assertex(idx==0); return this; }
  7836. virtual IStrandJunction *queryConcreteOutputJunction(unsigned idx) const { assertex(idx==0); return nullptr; }
  7837. virtual IRoxieServerActivity *queryActivity()
  7838. {
  7839. return parent;
  7840. }
  7841. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  7842. {
  7843. return parent->queryIndexReadActivity();
  7844. }
  7845. virtual unsigned __int64 queryTotalCycles() const
  7846. {
  7847. return totalCycles;
  7848. }
  7849. virtual const void * nextRow()
  7850. {
  7851. SimpleActivityTimer t(totalCycles, parent->timeActivities);
  7852. if (eof)
  7853. return NULL;
  7854. const void *ret = parent->readBuffered(idx, oid);
  7855. #ifdef TRACE_SPLIT
  7856. parent->CTXLOG("Adaptor %d got back %p for record %d", oid, ret, idx);
  7857. #endif
  7858. if (ret)
  7859. {
  7860. processed++;
  7861. eofpending = false;
  7862. }
  7863. else if (eofpending)
  7864. eof = true;
  7865. else
  7866. eofpending = true;
  7867. return ret;
  7868. }
  7869. virtual IOutputMetaData * queryOutputMeta() const
  7870. {
  7871. return parent->queryOutputMeta();
  7872. }
  7873. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  7874. {
  7875. // NOTE: it is tempting to move the init() of all output adaptors here. However that is not a good idea,
  7876. // since adaptors that have not yet started or stopped (but are going to) still need to have been init()'ed
  7877. // for minIndex to give the correct answers
  7878. // therefore, we call init() on all adaptors on receipt of the first start() or stop()
  7879. if (traceStartStop)
  7880. parent->CTXLOG("%p start Input adaptor %d stopped = %d", this, oid, stopped);
  7881. parent->start(oid, parentExtractSize, parentExtract, paused);
  7882. }
  7883. virtual IStrandJunction *getOutputStreams(IRoxieSlaveContext *ctx, unsigned idx, PointerArrayOf<IEngineRowStream> &streams, const StrandOptions * consumerOptions, bool consumerOrdered, IOrderedCallbackCollection * orderedCallbacks) override
  7884. {
  7885. parent->connectInputStreams(consumerOrdered);
  7886. streams.append(this);
  7887. return NULL;
  7888. }
  7889. virtual void stop()
  7890. {
  7891. if (traceStartStop)
  7892. parent->CTXLOG("%p stop Input adaptor %d stopped = %d", this, oid, stopped);
  7893. if (!stopped)
  7894. {
  7895. parent->stop(oid, idx); // NOTE - may call init()
  7896. stopped = true; // parent code relies on stop being called exactly once per adaptor, so make sure it is!
  7897. }
  7898. };
  7899. virtual void reset()
  7900. {
  7901. if (traceStartStop)
  7902. parent->CTXLOG("%p reset Input adaptor %d stopped = %d", this, oid, stopped);
  7903. parent->reset(oid);
  7904. idx = 0; // value should not be relevant really but this is the safest...
  7905. stopped = false;
  7906. };
  7907. virtual void resetEOF()
  7908. {
  7909. parent->resetEOF();
  7910. }
  7911. virtual void checkAbort()
  7912. {
  7913. parent->checkAbort();
  7914. }
  7915. } *adaptors;
  7916. bool *used;
  7917. unsigned nextFreeOutput()
  7918. {
  7919. unsigned i = numOutputs;
  7920. while (i)
  7921. {
  7922. i--;
  7923. if (!used[i])
  7924. return i;
  7925. }
  7926. throwUnexpected();
  7927. }
  7928. unsigned minIndex(unsigned exceptOid)
  7929. {
  7930. // MORE - yukky code (and slow). Could keep them heapsorted by idx or something
  7931. // this is trying to determine whether any of the adaptors will in the future read a given record
  7932. unsigned minIdx = (unsigned) -1;
  7933. for (unsigned i = 0; i < numOutputs; i++)
  7934. {
  7935. if (i != exceptOid && used[i] && adaptors[i].idx < minIdx)
  7936. minIdx = adaptors[i].idx;
  7937. }
  7938. return minIdx;
  7939. }
  7940. inline bool isLastTailReader(unsigned exceptOid)
  7941. {
  7942. for (unsigned i = 0; i < numOutputs; i++)
  7943. {
  7944. if (i != exceptOid && adaptors[i].idx == tailIdx && used[i])
  7945. return false;
  7946. }
  7947. return true;
  7948. }
  7949. void initOutputs()
  7950. {
  7951. activeOutputs = numOutputs;
  7952. for (unsigned i = 0; i < numOriginalOutputs; i++)
  7953. if (used[i])
  7954. adaptors[i].init();
  7955. state = STATEstarting;
  7956. }
  7957. public:
  7958. CRoxieServerThroughSpillActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numOutputs)
  7959. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper(basehelper), numOutputs(_numOutputs)
  7960. {
  7961. numOriginalOutputs = numOutputs;
  7962. adaptors = new OutputAdaptor[numOutputs];
  7963. used = new bool[numOutputs];
  7964. for (unsigned i = 0; i < numOutputs; i++)
  7965. {
  7966. adaptors[i].parent = this;
  7967. adaptors[i].oid = i;
  7968. used[i] = false;
  7969. }
  7970. tailIdx = 0;
  7971. headIdx = 0;
  7972. activeOutputs = numOutputs;
  7973. }
  7974. ~CRoxieServerThroughSpillActivity()
  7975. {
  7976. delete [] adaptors;
  7977. delete [] used;
  7978. }
  7979. const void *readBuffered(unsigned &idx, unsigned oid)
  7980. {
  7981. //False positives are fine, false negatives are not.. so headIdx must only be updated when a row will be available.
  7982. const unsigned curIdx = idx;
  7983. if (curIdx == headIdx) // test once without getting the crit2 sec
  7984. {
  7985. CriticalBlock b2(crit2); // but only one puller gets to read the head
  7986. if (curIdx == headIdx) // test again now that we have it
  7987. {
  7988. ActivityTimer t(totalCycles, timeActivities); // NOTE - time spent waiting for crit not included here. But it will have been included on the totalTime of the person holding the crit, so that is right
  7989. if (error)
  7990. throw error.getLink();
  7991. try
  7992. {
  7993. const void *row = inputStream->nextRow();
  7994. if (activeOutputs==1)
  7995. {
  7996. #ifdef TRACE_SPLIT
  7997. CTXLOG("spill %d optimised return of %p", activityId, row);
  7998. #endif
  7999. headIdx++;
  8000. idx++;
  8001. return row; // optimization for the case where only one output still active.
  8002. }
  8003. CriticalBlock b(crit);
  8004. headIdx++;
  8005. idx++;
  8006. if (activeOutputs==1)
  8007. return row; // optimization for the case where only one output still active.
  8008. buffer.enqueue(row);
  8009. if (row) LinkRoxieRow(row);
  8010. return row;
  8011. }
  8012. catch (IException *E)
  8013. {
  8014. #ifdef TRACE_SPLIT
  8015. CTXLOG("spill %d caught exception", activityId);
  8016. #endif
  8017. error.set(E);
  8018. throw;
  8019. }
  8020. catch (...)
  8021. {
  8022. IException *E = MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught in CRoxieServerThroughSpillActivity::readBuffered");
  8023. error.set(E);
  8024. throw E;
  8025. }
  8026. }
  8027. }
  8028. CriticalBlock b(crit);
  8029. ActivityTimer t(totalCycles, timeActivities); // NOTE - time spent waiting for crit not included here. But it will have been included on the totalTime of the person holding the crit, so that is right
  8030. unsigned lidx = curIdx - tailIdx;
  8031. idx++;
  8032. if (!lidx)
  8033. {
  8034. // The numOutputs <= 2 check optimizes slightly the common case of 2-way splitters.
  8035. // The rationale is that I MUST be the last reader if there are only 2 - the other guy must have put the record there in the first place
  8036. if (numOutputs <= 2 || isLastTailReader(oid)) // NOTE - this includes the case where minIndex returns (unsigned) -1, meaning no other active pullers
  8037. {
  8038. tailIdx++;
  8039. const void *ret = buffer.dequeue(); // no need to link - last puller
  8040. #ifdef TRACE_SPLIT
  8041. CTXLOG("last puller return of %p", ret);
  8042. #endif
  8043. return ret;
  8044. }
  8045. }
  8046. const void *ret = buffer.item(lidx);
  8047. if (ret) LinkRoxieRow(ret);
  8048. #ifdef TRACE_SPLIT
  8049. CTXLOG("standard return of %p", ret);
  8050. #endif
  8051. return ret;
  8052. }
  8053. virtual void start(unsigned oid, unsigned parentExtractSize, const byte *parentExtract, bool paused)
  8054. {
  8055. CriticalBlock b(crit);
  8056. if (error)
  8057. throw error.getLink();
  8058. if (factory)
  8059. factory->noteStarted(oid);
  8060. if (traceStartStop)
  8061. CTXLOG("SPLIT %p: start %d child %d activeOutputs %d numOutputs %d numOriginalOutputs %d state %s", this, activityId, oid, activeOutputs, numOutputs, numOriginalOutputs, queryStateText(state));
  8062. if (state != STATEstarted)
  8063. {
  8064. if (state != STATEstarting)
  8065. initOutputs();
  8066. tailIdx = 0;
  8067. headIdx = 0;
  8068. error.clear();
  8069. try
  8070. {
  8071. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  8072. }
  8073. catch (IException *E)
  8074. {
  8075. #ifdef TRACE_SPLIT
  8076. CTXLOG("spill %d caught exception in start", activityId);
  8077. #endif
  8078. error.set(E);
  8079. throw;
  8080. }
  8081. catch (...)
  8082. {
  8083. IException *E = MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught in CRoxieServerThroughSpillActivity::start");
  8084. error.set(E);
  8085. throw E;
  8086. }
  8087. }
  8088. }
  8089. void stop(unsigned oid, unsigned & idx)
  8090. {
  8091. // Note that OutputAdaptor code ensures that stop is not called more than once per adaptor
  8092. CriticalBlock b(crit);
  8093. #ifdef TRACE_STARTSTOP
  8094. if (traceStartStop)
  8095. {
  8096. CTXLOG("SPLIT %p: stop %d child %d activeOutputs %d numOutputs %d numOriginalOutputs %d state %s", this, activityId, oid, activeOutputs, numOutputs, numOriginalOutputs, queryStateText(state));
  8097. if (watchActivityId && watchActivityId==activityId)
  8098. {
  8099. CTXLOG("WATCH: stop %d", activityId);
  8100. }
  8101. }
  8102. #endif
  8103. if (state != STATEstarting && state != STATEstarted)
  8104. initOutputs();
  8105. if (activeOutputs > 1)
  8106. {
  8107. if (tailIdx==idx)
  8108. {
  8109. // Discard all buffered rows that are there purely for this adaptor to read them
  8110. unsigned min = minIndex(oid);
  8111. if (min != (unsigned) -1)
  8112. // what does -1 signify?? No-one wants anything? In which case can't we kill all rows??
  8113. // Should never happen though if there are still some active.
  8114. // there may be a small window where adaptors are blocked on the semaphore...
  8115. {
  8116. #ifdef TRACE_SPLIT
  8117. CTXLOG("%p: Discarding buffered rows from %d to %d for oid %x (%d outputs active)", this, idx, min, oid, activeOutputs);
  8118. #endif
  8119. while (tailIdx < min)
  8120. {
  8121. ReleaseRoxieRow(buffer.dequeue());
  8122. tailIdx++;
  8123. }
  8124. }
  8125. }
  8126. activeOutputs--;
  8127. idx = (unsigned) -1; // causes minIndex not to save rows for me...
  8128. return;
  8129. }
  8130. #ifdef TRACE_SPLIT
  8131. CTXLOG("%p: All outputs done", this);
  8132. #endif
  8133. activeOutputs = numOutputs;
  8134. CRoxieServerActivity::stop();
  8135. };
  8136. void reset(unsigned oid)
  8137. {
  8138. if (traceStartStop)
  8139. CTXLOG("SPLIT %p: reset %d child %d activeOutputs %d numOutputs %d numOriginalOutputs %d state %s", this, activityId, oid, activeOutputs, numOutputs, numOriginalOutputs, queryStateText(state));
  8140. activeOutputs = numOutputs;
  8141. while (buffer.ordinality())
  8142. ReleaseRoxieRow(buffer.dequeue());
  8143. error.clear();
  8144. if (state != STATEreset) // make sure input is only reset once
  8145. CRoxieServerActivity::reset();
  8146. };
  8147. void connectInputStreams(bool consumerOrdered)
  8148. {
  8149. if (!inputStream)
  8150. CRoxieServerActivity::connectInputStreams(consumerOrdered);
  8151. }
  8152. virtual const void *nextRow()
  8153. {
  8154. throwUnexpected(); // Internal logic error - we are not anybody's input
  8155. }
  8156. virtual IOutputMetaData * queryOutputMeta() const
  8157. {
  8158. // if (outputMeta)
  8159. // return outputMeta;
  8160. // else
  8161. return input->queryOutputMeta(); // not always known (e.g. disk write - though Gavin _could_ fill it in)
  8162. }
  8163. virtual IFinalRoxieInput *queryOutput(unsigned idx)
  8164. {
  8165. if (idx==(unsigned)-1)
  8166. idx = nextFreeOutput(); // MORE - what is this used for?
  8167. assertex(idx < numOriginalOutputs);
  8168. assertex(!used[idx]);
  8169. used[idx] = true;
  8170. return &adaptors[idx];
  8171. }
  8172. virtual void resetOutputsUsed()
  8173. {
  8174. numOutputs = 1;
  8175. activeOutputs = 1;
  8176. // MORE RKC->GH should we be clearing the used array here? anywhere?
  8177. }
  8178. virtual void noteOutputUsed()
  8179. {
  8180. assertex(numOutputs < numOriginalOutputs);
  8181. numOutputs++;
  8182. activeOutputs = numOutputs;
  8183. }
  8184. virtual bool isPassThrough()
  8185. {
  8186. return numOutputs==1;
  8187. }
  8188. };
  8189. class CRoxieServerThroughSpillActivityFactory : public CRoxieServerMultiOutputFactory
  8190. {
  8191. public:
  8192. CRoxieServerThroughSpillActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  8193. : CRoxieServerMultiOutputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  8194. {
  8195. Owned<IHThorSpillArg> helper = (IHThorSpillArg *) helperFactory();
  8196. setNumOutputs(helper->getTempUsageCount() + 1);
  8197. }
  8198. CRoxieServerThroughSpillActivityFactory(IQueryFactory &_queryFactory, HelperFactory *_helperFactory, unsigned _numOutputs, IPropertyTree &_graphNode)
  8199. : CRoxieServerMultiOutputFactory(0, 0, _queryFactory, _helperFactory, TAKsplit, _graphNode)
  8200. {
  8201. setNumOutputs(_numOutputs);
  8202. }
  8203. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  8204. {
  8205. return new CRoxieServerThroughSpillActivity(_ctx, this, _probeManager, numOutputs);
  8206. }
  8207. };
  8208. IRoxieServerActivityFactory *createRoxieServerThroughSpillActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  8209. {
  8210. return new CRoxieServerThroughSpillActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  8211. }
  8212. IRoxieServerActivityFactory *createRoxieServerThroughSpillActivityFactory(IQueryFactory &_queryFactory, HelperFactory *_factory, unsigned _numOutputs, IPropertyTree &_graphNode)
  8213. {
  8214. return new CRoxieServerThroughSpillActivityFactory(_queryFactory, _factory, _numOutputs, _graphNode);
  8215. }
  8216. //----------------------------------------------------------------------------------------------
  8217. class CRoxieServerSplitActivityFactory : public CRoxieServerMultiOutputFactory
  8218. {
  8219. public:
  8220. CRoxieServerSplitActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  8221. : CRoxieServerMultiOutputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  8222. {
  8223. Owned<IHThorSplitArg> helper = (IHThorSplitArg *) helperFactory();
  8224. setNumOutputs(helper->numBranches());
  8225. }
  8226. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  8227. {
  8228. return new CRoxieServerThroughSpillActivity(_ctx, this, _probeManager, numOutputs);
  8229. }
  8230. };
  8231. IRoxieServerActivityFactory *createRoxieServerSplitActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  8232. {
  8233. return new CRoxieServerSplitActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  8234. }
  8235. //=====================================================================================================
  8236. #define PIPE_BUFSIZE 0x8000
  8237. static IException *createPipeFailureException(const char *cmd, unsigned retcode, IPipeProcess *pipe)
  8238. {
  8239. StringBuffer msg;
  8240. if(pipe->hasError())
  8241. {
  8242. try
  8243. {
  8244. char error[512];
  8245. size32_t sz = pipe->readError(sizeof(error), error);
  8246. if(sz && sz!=(size32_t)-1)
  8247. msg.append(", stderr: '").append(sz, error).append("'");
  8248. }
  8249. catch (IException *e)
  8250. {
  8251. EXCLOG(e, "Error reading pipe stderr");
  8252. e->Release();
  8253. }
  8254. }
  8255. return MakeStringException(ROXIE_PIPE_ERROR, "Pipe process %s returned error %u%s", cmd, retcode, msg.str());
  8256. }
  8257. class CRoxieServerPipeReadActivity : public CRoxieServerActivity
  8258. {
  8259. IHThorPipeReadArg &helper;
  8260. Owned<IPipeProcess> pipe;
  8261. StringAttr pipeCommand;
  8262. Owned<IOutputRowDeserializer> rowDeserializer;
  8263. Owned<IReadRowStream> readTransformer;
  8264. bool groupSignalled;
  8265. public:
  8266. CRoxieServerPipeReadActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  8267. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorPipeReadArg &)basehelper)
  8268. {
  8269. groupSignalled = true;
  8270. }
  8271. virtual bool needsAllocator() const { return true; }
  8272. virtual void onCreate(IHThorArg *_colocalParent)
  8273. {
  8274. CRoxieServerActivity::onCreate(_colocalParent);
  8275. rowDeserializer.setown(rowAllocator->createDiskDeserializer(ctx->queryCodeContext()));
  8276. }
  8277. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  8278. {
  8279. groupSignalled = true; // i.e. don't start with a NULL row
  8280. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  8281. if (!readTransformer)
  8282. {
  8283. OwnedRoxieString xmlIteratorPath(helper.getXmlIteratorPath());
  8284. readTransformer.setown(createReadRowStream(rowAllocator, rowDeserializer, helper.queryXmlTransformer(), helper.queryCsvTransformer(), xmlIteratorPath, helper.getPipeFlags()));
  8285. }
  8286. OwnedRoxieString pipeProgram(helper.getPipeProgram());
  8287. openPipe(pipeProgram);
  8288. }
  8289. virtual void stop()
  8290. {
  8291. CRoxieServerActivity::stop();
  8292. pipe.clear();
  8293. readTransformer->setStream(NULL);
  8294. }
  8295. virtual const void *nextRow()
  8296. {
  8297. ActivityTimer t(totalCycles, timeActivities);
  8298. while (!waitForPipe())
  8299. {
  8300. if (!pipe)
  8301. return NULL;
  8302. if (helper.getPipeFlags() & TPFgroupeachrow)
  8303. {
  8304. if (!groupSignalled)
  8305. {
  8306. groupSignalled = true;
  8307. return NULL;
  8308. }
  8309. }
  8310. }
  8311. const void *ret = readTransformer->next();
  8312. assertex(ret != NULL); // if ret can ever be NULL then we need to recode this logic
  8313. processed++;
  8314. groupSignalled = false;
  8315. return ret;
  8316. }
  8317. protected:
  8318. bool waitForPipe()
  8319. {
  8320. if (!pipe)
  8321. return false; // done
  8322. if (!readTransformer->eos())
  8323. return true;
  8324. verifyPipe();
  8325. return false;
  8326. }
  8327. void openPipe(char const * cmd)
  8328. {
  8329. pipeCommand.setown(cmd);
  8330. pipe.setown(createPipeProcess());
  8331. if(!pipe->run(NULL, cmd, ".", false, true, true, 0x10000))
  8332. throw MakeStringException(ROXIE_PIPE_ERROR, "Could not run pipe process %s", cmd);
  8333. Owned<ISimpleReadStream> pipeReader = pipe->getOutputStream();
  8334. readTransformer->setStream(pipeReader.get());
  8335. }
  8336. void verifyPipe()
  8337. {
  8338. if (pipe)
  8339. {
  8340. unsigned err = pipe->wait();
  8341. if(err && !(helper.getPipeFlags() & TPFnofail))
  8342. {
  8343. throw createPipeFailureException(pipeCommand.get(), err, pipe);
  8344. }
  8345. pipe.clear();
  8346. }
  8347. }
  8348. };
  8349. class CRoxieServerPipeThroughActivity : public CRoxieServerActivity, implements IRecordPullerCallback
  8350. {
  8351. IHThorPipeThroughArg &helper;
  8352. RecordPullerThread puller;
  8353. Owned<IPipeProcess> pipe;
  8354. StringAttr pipeCommand;
  8355. InterruptableSemaphore pipeVerified;
  8356. InterruptableSemaphore pipeOpened;
  8357. CachedOutputMetaData inputMeta;
  8358. Owned<IOutputRowSerializer> rowSerializer;
  8359. Owned<IOutputRowDeserializer> rowDeserializer;
  8360. Owned<IPipeWriteXformHelper> writeTransformer;
  8361. Owned<IReadRowStream> readTransformer;
  8362. bool firstRead;
  8363. bool recreate;
  8364. bool inputExhausted;
  8365. bool groupSignalled;
  8366. public:
  8367. CRoxieServerPipeThroughActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  8368. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorPipeThroughArg &)basehelper), puller(false)
  8369. {
  8370. recreate = helper.recreateEachRow();
  8371. groupSignalled = true;
  8372. firstRead = false;
  8373. inputExhausted = false;
  8374. }
  8375. virtual bool needsAllocator() const { return true; }
  8376. virtual void onCreate(IHThorArg *_colocalParent)
  8377. {
  8378. CRoxieServerActivity::onCreate(_colocalParent);
  8379. rowSerializer.setown(inputMeta.createDiskSerializer(ctx->queryCodeContext(), activityId));
  8380. rowDeserializer.setown(rowAllocator->createDiskDeserializer(ctx->queryCodeContext()));
  8381. writeTransformer.setown(createPipeWriteXformHelper(helper.getPipeFlags(), helper.queryXmlOutput(), helper.queryCsvOutput(), rowSerializer));
  8382. }
  8383. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  8384. {
  8385. firstRead = true;
  8386. inputExhausted = false;
  8387. groupSignalled = true; // i.e. don't start with a NULL row
  8388. pipeVerified.reinit();
  8389. pipeOpened.reinit();
  8390. writeTransformer->ready();
  8391. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  8392. if (!readTransformer)
  8393. {
  8394. OwnedRoxieString xmlIterator(helper.getXmlIteratorPath());
  8395. readTransformer.setown(createReadRowStream(rowAllocator, rowDeserializer, helper.queryXmlTransformer(), helper.queryCsvTransformer(), xmlIterator, helper.getPipeFlags()));
  8396. }
  8397. if(!recreate)
  8398. {
  8399. OwnedRoxieString pipeProgram(helper.getPipeProgram());
  8400. openPipe(pipeProgram);
  8401. }
  8402. puller.start(parentExtractSize, parentExtract, paused, 0, false, ctx); // Pipe does not support preload presently - locks up
  8403. }
  8404. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  8405. {
  8406. if (idx)
  8407. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", sanitizeSourceFile(__FILE__), __LINE__);
  8408. puller.setInput(this, _sourceIdx, _in);
  8409. inputMeta.set(_in->queryOutputMeta());
  8410. }
  8411. virtual IStrandJunction *getOutputStreams(IRoxieSlaveContext *ctx, unsigned idx, PointerArrayOf<IEngineRowStream> &streams, const StrandOptions * consumerOptions, bool consumerOrdered, IOrderedCallbackCollection * orderedCallbacks)
  8412. {
  8413. puller.connectInputStreams(ctx, consumerOrdered);
  8414. return CRoxieServerActivity::getOutputStreams(ctx, idx, streams, consumerOptions, consumerOrdered, orderedCallbacks);
  8415. }
  8416. virtual IFinalRoxieInput *queryInput(unsigned idx) const
  8417. {
  8418. if (idx==0)
  8419. return puller.queryInput();
  8420. else
  8421. return NULL;
  8422. }
  8423. virtual void stop()
  8424. {
  8425. pipeVerified.interrupt(NULL);
  8426. pipeOpened.interrupt(NULL);
  8427. puller.stop();
  8428. CRoxieServerActivity::stop();
  8429. pipe.clear();
  8430. if (readTransformer)
  8431. readTransformer->setStream(NULL);
  8432. }
  8433. virtual void reset()
  8434. {
  8435. puller.reset();
  8436. CRoxieServerActivity::reset();
  8437. }
  8438. virtual const void *nextRow()
  8439. {
  8440. ActivityTimer t(totalCycles, timeActivities);
  8441. while (!waitForPipe())
  8442. {
  8443. if (!pipe)
  8444. return NULL;
  8445. if (helper.getPipeFlags() & TPFgroupeachrow)
  8446. {
  8447. if (!groupSignalled)
  8448. {
  8449. groupSignalled = true;
  8450. return NULL;
  8451. }
  8452. }
  8453. }
  8454. const void *ret = readTransformer->next();
  8455. assertex(ret != NULL); // if ret can ever be NULL then we need to recode this logic
  8456. processed++;
  8457. groupSignalled = false;
  8458. return ret;
  8459. }
  8460. virtual void processRow(const void *row)
  8461. {
  8462. // called from puller thread
  8463. if(recreate)
  8464. openPipe(helper.getNameFromRow(row));
  8465. writeTransformer->writeTranslatedText(row, pipe);
  8466. ReleaseRoxieRow(row);
  8467. if(recreate)
  8468. {
  8469. closePipe();
  8470. pipeVerified.wait();
  8471. }
  8472. }
  8473. virtual void processDone()
  8474. {
  8475. // called from puller thread
  8476. if(recreate)
  8477. {
  8478. inputExhausted = true;
  8479. pipeOpened.signal();
  8480. }
  8481. else
  8482. {
  8483. closePipe();
  8484. pipeVerified.wait();
  8485. }
  8486. }
  8487. virtual void processEOG()
  8488. {
  8489. }
  8490. void processGroup(const ConstPointerArray &)
  8491. {
  8492. throwUnexpected();
  8493. }
  8494. virtual bool fireException(IException *e)
  8495. {
  8496. pipeOpened.interrupt(LINK(e));
  8497. pipeVerified.interrupt(e);
  8498. return true;
  8499. }
  8500. private:
  8501. bool waitForPipe()
  8502. {
  8503. if (firstRead)
  8504. {
  8505. pipeOpened.wait();
  8506. firstRead = false;
  8507. }
  8508. if (!pipe)
  8509. return false; // done
  8510. if (!readTransformer->eos())
  8511. return true;
  8512. verifyPipe();
  8513. if (recreate && !inputExhausted)
  8514. pipeOpened.wait();
  8515. return false;
  8516. }
  8517. void openPipe(char const * cmd)
  8518. {
  8519. pipeCommand.setown(cmd);
  8520. pipe.setown(createPipeProcess());
  8521. if(!pipe->run(NULL, cmd, ".", true, true, true, 0x10000))
  8522. throw MakeStringException(ROXIE_PIPE_ERROR, "Could not run pipe process %s", cmd);
  8523. writeTransformer->writeHeader(pipe);
  8524. Owned<ISimpleReadStream> pipeReader = pipe->getOutputStream();
  8525. readTransformer->setStream(pipeReader.get());
  8526. pipeOpened.signal();
  8527. }
  8528. void closePipe()
  8529. {
  8530. writeTransformer->writeFooter(pipe);
  8531. pipe->closeInput();
  8532. }
  8533. void verifyPipe()
  8534. {
  8535. if (pipe)
  8536. {
  8537. unsigned err = pipe->wait();
  8538. if(err && !(helper.getPipeFlags() & TPFnofail))
  8539. {
  8540. throw createPipeFailureException(pipeCommand.get(), err, pipe);
  8541. }
  8542. pipe.clear();
  8543. pipeVerified.signal();
  8544. }
  8545. }
  8546. };
  8547. class CRoxieServerPipeWriteActivity : public CRoxieServerInternalSinkActivity
  8548. {
  8549. IHThorPipeWriteArg &helper;
  8550. Owned<IPipeProcess> pipe;
  8551. StringAttr pipeCommand;
  8552. CachedOutputMetaData inputMeta;
  8553. Owned<IOutputRowSerializer> rowSerializer;
  8554. Owned<IPipeWriteXformHelper> writeTransformer;
  8555. bool firstRead;
  8556. bool recreate;
  8557. bool inputExhausted;
  8558. public:
  8559. CRoxieServerPipeWriteActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numOutputs)
  8560. : CRoxieServerInternalSinkActivity(_ctx, _factory, _probeManager, _numOutputs), helper((IHThorPipeWriteArg &)basehelper)
  8561. {
  8562. recreate = helper.recreateEachRow();
  8563. firstRead = false;
  8564. inputExhausted = false;
  8565. }
  8566. virtual bool needsAllocator() const { return true; }
  8567. virtual void onCreate(IHThorArg *_colocalParent)
  8568. {
  8569. CRoxieServerActivity::onCreate(_colocalParent);
  8570. inputMeta.set(input->queryOutputMeta());
  8571. rowSerializer.setown(inputMeta.createDiskSerializer(ctx->queryCodeContext(), activityId));
  8572. writeTransformer.setown(createPipeWriteXformHelper(helper.getPipeFlags(), helper.queryXmlOutput(), helper.queryCsvOutput(), rowSerializer));
  8573. }
  8574. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  8575. {
  8576. firstRead = true;
  8577. inputExhausted = false;
  8578. writeTransformer->ready();
  8579. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  8580. if(!recreate)
  8581. {
  8582. OwnedRoxieString pipeProgram(helper.getPipeProgram());
  8583. openPipe(pipeProgram);
  8584. }
  8585. }
  8586. virtual void stop()
  8587. {
  8588. if (!aborted && helper.getSequence() >= 0)
  8589. {
  8590. WorkunitUpdate wu = ctx->updateWorkUnit();
  8591. if (wu)
  8592. {
  8593. Owned<IWUResult> result = wu->updateResultBySequence(helper.getSequence());
  8594. if (result)
  8595. {
  8596. result->setResultTotalRowCount(processed);
  8597. result->setResultStatus(ResultStatusCalculated);
  8598. }
  8599. }
  8600. }
  8601. CRoxieServerActivity::stop();
  8602. pipe.clear();
  8603. }
  8604. virtual void onExecute()
  8605. {
  8606. for (;;)
  8607. {
  8608. const void *row = inputStream->ungroupedNextRow();
  8609. if (!row)
  8610. break;
  8611. processed++;
  8612. if(recreate)
  8613. openPipe(helper.getNameFromRow(row));
  8614. writeTransformer->writeTranslatedText(row, pipe);
  8615. ReleaseRoxieRow(row);
  8616. if(recreate)
  8617. closePipe();
  8618. }
  8619. closePipe();
  8620. }
  8621. private:
  8622. void openPipe(char const * cmd)
  8623. {
  8624. pipeCommand.setown(cmd);
  8625. pipe.setown(createPipeProcess());
  8626. if(!pipe->run(NULL, cmd, ".", true, false, true, 0x10000))
  8627. throw MakeStringException(ROXIE_PIPE_ERROR, "Could not run pipe process %s", cmd);
  8628. writeTransformer->writeHeader(pipe);
  8629. }
  8630. void closePipe()
  8631. {
  8632. writeTransformer->writeFooter(pipe);
  8633. pipe->closeInput();
  8634. unsigned err = pipe->wait();
  8635. if(err && !(helper.getPipeFlags() & TPFnofail))
  8636. {
  8637. throw createPipeFailureException(pipeCommand.get(), err, pipe);
  8638. }
  8639. pipe.clear();
  8640. }
  8641. };
  8642. class CRoxieServerPipeReadActivityFactory : public CRoxieServerActivityFactory
  8643. {
  8644. public:
  8645. CRoxieServerPipeReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  8646. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  8647. {
  8648. }
  8649. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  8650. {
  8651. return new CRoxieServerPipeReadActivity(_ctx, this, _probeManager);
  8652. }
  8653. };
  8654. class CRoxieServerPipeThroughActivityFactory : public CRoxieServerActivityFactory
  8655. {
  8656. public:
  8657. CRoxieServerPipeThroughActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  8658. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  8659. {
  8660. }
  8661. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  8662. {
  8663. return new CRoxieServerPipeThroughActivity(_ctx, this, _probeManager);
  8664. }
  8665. };
  8666. class CRoxieServerPipeWriteActivityFactory : public CRoxieServerInternalSinkFactory
  8667. {
  8668. public:
  8669. CRoxieServerPipeWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned _usageCount, bool _isRoot)
  8670. : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _usageCount, _isRoot)
  8671. {
  8672. }
  8673. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  8674. {
  8675. return new CRoxieServerPipeWriteActivity(_ctx, this, _probeManager, usageCount);
  8676. }
  8677. };
  8678. IRoxieServerActivityFactory *createRoxieServerPipeReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  8679. {
  8680. return new CRoxieServerPipeReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  8681. }
  8682. IRoxieServerActivityFactory *createRoxieServerPipeThroughActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  8683. {
  8684. return new CRoxieServerPipeThroughActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  8685. }
  8686. IRoxieServerActivityFactory *createRoxieServerPipeWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned _usageCount, bool _isRoot)
  8687. {
  8688. return new CRoxieServerPipeWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _usageCount, _isRoot);
  8689. }
  8690. //=====================================================================================================
  8691. class CRoxieServerStreamedIteratorActivity : public CRoxieServerActivity
  8692. {
  8693. IHThorStreamedIteratorArg &helper;
  8694. Owned<IRowStream> rows;
  8695. public:
  8696. CRoxieServerStreamedIteratorActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  8697. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorStreamedIteratorArg &)basehelper)
  8698. {
  8699. }
  8700. ~CRoxieServerStreamedIteratorActivity()
  8701. {
  8702. }
  8703. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  8704. {
  8705. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  8706. rows.setown(helper.createInput());
  8707. }
  8708. virtual void stop()
  8709. {
  8710. if (rows)
  8711. {
  8712. rows->stop();
  8713. rows.clear();
  8714. }
  8715. CRoxieServerActivity::stop();
  8716. }
  8717. virtual const void *nextRow()
  8718. {
  8719. ActivityTimer t(totalCycles, timeActivities);
  8720. assertex(rows != NULL);
  8721. const void * next = rows->nextRow();
  8722. if (next)
  8723. processed++;
  8724. return next;
  8725. }
  8726. };
  8727. class CRoxieServerStreamedIteratorActivityFactory : public CRoxieServerActivityFactory
  8728. {
  8729. public:
  8730. CRoxieServerStreamedIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  8731. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  8732. {
  8733. }
  8734. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  8735. {
  8736. return new CRoxieServerStreamedIteratorActivity(_ctx, this, _probeManager);
  8737. }
  8738. };
  8739. IRoxieServerActivityFactory *createRoxieServerStreamedIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  8740. {
  8741. return new CRoxieServerStreamedIteratorActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  8742. }
  8743. //=====================================================================================================
  8744. class CRoxieServerFilterActivity : public CRoxieServerLateStartActivity
  8745. {
  8746. IHThorFilterArg &helper;
  8747. bool anyThisGroup;
  8748. IRangeCompare * stepCompare;
  8749. public:
  8750. CRoxieServerFilterActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  8751. : CRoxieServerLateStartActivity(_ctx, _factory, _probeManager), helper((IHThorFilterArg &)basehelper)
  8752. {
  8753. anyThisGroup = false;
  8754. stepCompare = NULL;
  8755. }
  8756. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  8757. {
  8758. anyThisGroup = false;
  8759. CRoxieServerLateStartActivity::start(parentExtractSize, parentExtract, paused);
  8760. lateStart(parentExtractSize, parentExtract, helper.canMatchAny());
  8761. stepCompare = NULL;
  8762. if (!eof)
  8763. {
  8764. IInputSteppingMeta * stepMeta = input->querySteppingMeta();
  8765. if (stepMeta)
  8766. stepCompare = stepMeta->queryCompare();
  8767. }
  8768. }
  8769. virtual const void * nextRow()
  8770. {
  8771. ActivityTimer t(totalCycles, timeActivities);
  8772. if (eof)
  8773. return NULL;
  8774. for (;;)
  8775. {
  8776. OwnedConstRoxieRow ret(inputStream->nextRow());
  8777. if (!ret)
  8778. {
  8779. //stop returning two NULLs in a row.
  8780. if (anyThisGroup)
  8781. {
  8782. anyThisGroup = false;
  8783. return NULL;
  8784. }
  8785. ret.setown(inputStream->nextRow());
  8786. if (!ret)
  8787. {
  8788. eof = true;
  8789. return NULL; // eof...
  8790. }
  8791. }
  8792. if (helper.isValid(ret))
  8793. {
  8794. anyThisGroup = true;
  8795. processed++;
  8796. return ret.getClear();
  8797. }
  8798. }
  8799. }
  8800. virtual const void * nextRowGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  8801. {
  8802. //Could assert that this isn't grouped
  8803. // MORE - will need rethinking once we rethink the nextRowGE interface for global smart-stepping.
  8804. ActivityTimer t(totalCycles, timeActivities);
  8805. if (eof)
  8806. return NULL;
  8807. for (;;)
  8808. {
  8809. OwnedConstRoxieRow ret(inputStream->nextRowGE(seek, numFields, wasCompleteMatch, stepExtra));
  8810. if (!ret)
  8811. {
  8812. eof = true;
  8813. return NULL;
  8814. }
  8815. if (!wasCompleteMatch)
  8816. {
  8817. anyThisGroup = false; // RKC->GH - is this right??
  8818. return ret.getClear();
  8819. }
  8820. if (helper.isValid(ret))
  8821. {
  8822. anyThisGroup = true;
  8823. processed++;
  8824. return ret.getClear();
  8825. }
  8826. if (!stepExtra.returnMismatches())
  8827. {
  8828. ret.clear();
  8829. return nextRow();
  8830. }
  8831. //If asked to return mismatches we are only interested in mismatches that will force the stepped
  8832. //condition to advance
  8833. if (stepCompare->docompare(ret, seek, numFields) != 0)
  8834. {
  8835. wasCompleteMatch = false;
  8836. anyThisGroup = false; // WHY?
  8837. return ret.getClear();
  8838. }
  8839. }
  8840. }
  8841. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  8842. {
  8843. return input->gatherConjunctions(collector);
  8844. }
  8845. virtual void resetEOF()
  8846. {
  8847. eof = prefiltered;
  8848. anyThisGroup = false;
  8849. inputStream->resetEOF();
  8850. }
  8851. IInputSteppingMeta * querySteppingMeta()
  8852. {
  8853. return input->querySteppingMeta();
  8854. }
  8855. };
  8856. class CRoxieServerFilterActivityFactory : public CRoxieServerActivityFactory
  8857. {
  8858. public:
  8859. CRoxieServerFilterActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  8860. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  8861. {
  8862. optStableInput = false;
  8863. }
  8864. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  8865. {
  8866. return new CRoxieServerFilterActivity(_ctx, this, _probeManager);
  8867. }
  8868. };
  8869. IRoxieServerActivityFactory *createRoxieServerFilterActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  8870. {
  8871. return new CRoxieServerFilterActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  8872. }
  8873. //=====================================================================================================
  8874. class CRoxieServerFilterGroupActivity : public CRoxieServerLateStartActivity
  8875. {
  8876. IHThorFilterGroupArg &helper;
  8877. unsigned curIndex;
  8878. ConstPointerArray gathered;
  8879. IRangeCompare * stepCompare;
  8880. public:
  8881. CRoxieServerFilterGroupActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  8882. : CRoxieServerLateStartActivity(_ctx, _factory, _probeManager), helper((IHThorFilterGroupArg &)basehelper)
  8883. {
  8884. curIndex = 0;
  8885. stepCompare = NULL;
  8886. }
  8887. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  8888. {
  8889. CRoxieServerLateStartActivity::start(parentExtractSize, parentExtract, paused);
  8890. lateStart(parentExtractSize, parentExtract, helper.canMatchAny());//sets eof
  8891. assertex(eof == !helper.canMatchAny());
  8892. curIndex = 0;
  8893. stepCompare = NULL;
  8894. if (!eof)
  8895. {
  8896. IInputSteppingMeta * inputStepping = input->querySteppingMeta();
  8897. if (inputStepping)
  8898. stepCompare = inputStepping->queryCompare();
  8899. }
  8900. }
  8901. virtual void reset()
  8902. {
  8903. releaseGathered();
  8904. CRoxieServerLateStartActivity::reset();
  8905. }
  8906. inline void releaseGathered()
  8907. {
  8908. roxiemem::ReleaseRoxieRowRange(gathered.getArray(), curIndex, gathered.ordinality());
  8909. gathered.kill();
  8910. curIndex = 0;
  8911. }
  8912. virtual const void * nextRow()
  8913. {
  8914. ActivityTimer t(totalCycles, timeActivities);
  8915. for (;;)
  8916. {
  8917. if (eof)
  8918. return NULL;
  8919. if (gathered.ordinality())
  8920. {
  8921. if (gathered.isItem(curIndex))
  8922. {
  8923. const void * ret = gathered.item(curIndex++);
  8924. processed++;
  8925. return ret;
  8926. }
  8927. curIndex = 0;
  8928. gathered.kill();
  8929. return NULL;
  8930. }
  8931. const void * ret = inputStream->nextRow();
  8932. while (ret)
  8933. {
  8934. gathered.append(ret);
  8935. ret = inputStream->nextRow();
  8936. }
  8937. unsigned num = gathered.ordinality();
  8938. if (num != 0)
  8939. {
  8940. if (!helper.isValid(num, (const void * *)gathered.getArray()))
  8941. ReleaseRoxieRows(gathered); // read next group
  8942. }
  8943. else
  8944. eof = true;
  8945. }
  8946. }
  8947. virtual const void * nextRowGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  8948. {
  8949. ActivityTimer t(totalCycles, timeActivities);
  8950. if (eof)
  8951. return NULL;
  8952. if (gathered.ordinality())
  8953. {
  8954. while (gathered.isItem(curIndex))
  8955. {
  8956. const void * ret = gathered.item(curIndex++);
  8957. if (stepCompare->docompare(ret, seek, numFields) >= 0)
  8958. {
  8959. processed++;
  8960. return ret;
  8961. }
  8962. ReleaseRoxieRow(ret);
  8963. }
  8964. curIndex = 0;
  8965. gathered.kill();
  8966. //nextRowGE never returns an end of group marker.
  8967. }
  8968. //Not completely sure about this - it could lead the the start of a group being skipped,
  8969. //so the group filter could potentially work on a different group. If so, we'd need to check the
  8970. //next fields were a subset of the grouping fields - more an issue for the group activity.
  8971. //MORE: What do we do with wasCompleteMatch? something like the following????
  8972. #if 0
  8973. for (;;)
  8974. {
  8975. const void * ret;
  8976. if (stepExtra.returnMismatches())
  8977. {
  8978. bool matchedCompletely = true;
  8979. ret = input->nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);
  8980. if (!wasCompleteMatch)
  8981. return ret;
  8982. }
  8983. else
  8984. ret = input->nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);
  8985. #endif
  8986. const void * ret = inputStream->nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);
  8987. while (ret)
  8988. {
  8989. gathered.append(ret);
  8990. ret = inputStream->nextRow();
  8991. }
  8992. unsigned num = gathered.ordinality();
  8993. if (num != 0)
  8994. {
  8995. if (!helper.isValid(num, (const void * *)gathered.getArray()))
  8996. ReleaseRoxieRows(gathered); // read next group
  8997. }
  8998. else
  8999. eof = true;
  9000. return IEngineRowStream::ungroupedNextRow();
  9001. }
  9002. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  9003. {
  9004. return input->gatherConjunctions(collector);
  9005. }
  9006. virtual void resetEOF()
  9007. {
  9008. eof = false;
  9009. releaseGathered();
  9010. inputStream->resetEOF();
  9011. }
  9012. IInputSteppingMeta * querySteppingMeta()
  9013. {
  9014. return input->querySteppingMeta();
  9015. }
  9016. };
  9017. class CRoxieServerFilterGroupActivityFactory : public CRoxieServerActivityFactory
  9018. {
  9019. public:
  9020. CRoxieServerFilterGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  9021. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  9022. {
  9023. }
  9024. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  9025. {
  9026. return new CRoxieServerFilterGroupActivity(_ctx, this, _probeManager);
  9027. }
  9028. };
  9029. IRoxieServerActivityFactory *createRoxieServerFilterGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  9030. {
  9031. return new CRoxieServerFilterGroupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  9032. }
  9033. //=================================================================================
  9034. class CRoxieServerSideEffectActivity : public CRoxieServerActivity
  9035. {
  9036. IHThorSideEffectArg &helper;
  9037. CriticalSection ecrit;
  9038. Owned<IException> exception;
  9039. bool executed;
  9040. public:
  9041. CRoxieServerSideEffectActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  9042. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorSideEffectArg &)basehelper)
  9043. {
  9044. executed = false;
  9045. }
  9046. virtual const void * nextRow()
  9047. {
  9048. ActivityTimer t(totalCycles, timeActivities);
  9049. CriticalBlock b(ecrit);
  9050. if (exception)
  9051. throw(exception.getLink());
  9052. if (!executed)
  9053. {
  9054. try
  9055. {
  9056. executed = true;
  9057. helper.action();
  9058. }
  9059. catch(IException *E)
  9060. {
  9061. exception.set(E);
  9062. throw;
  9063. }
  9064. }
  9065. return NULL;
  9066. }
  9067. virtual void execute(unsigned parentExtractSize, const byte * parentExtract)
  9068. {
  9069. CriticalBlock b(ecrit);
  9070. if (exception)
  9071. throw(exception.getLink());
  9072. if (!executed)
  9073. {
  9074. try
  9075. {
  9076. ActivityTimer t(totalCycles, timeActivities);
  9077. executed = true;
  9078. start(parentExtractSize, parentExtract, false);
  9079. helper.action();
  9080. stop();
  9081. }
  9082. catch(IException *E)
  9083. {
  9084. ctx->notifyAbort(E);
  9085. abort();
  9086. exception.set(E);
  9087. throw;
  9088. }
  9089. }
  9090. }
  9091. virtual void reset()
  9092. {
  9093. executed = false;
  9094. exception.clear();
  9095. CRoxieServerActivity::reset();
  9096. }
  9097. };
  9098. class CRoxieServerSideEffectActivityFactory : public CRoxieServerActivityFactory
  9099. {
  9100. bool isRoot;
  9101. public:
  9102. CRoxieServerSideEffectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _isRoot)
  9103. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode), isRoot(_isRoot)
  9104. {
  9105. }
  9106. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  9107. {
  9108. return new CRoxieServerSideEffectActivity(_ctx, this, _probeManager);
  9109. }
  9110. virtual bool isSink() const
  9111. {
  9112. return isRoot && !meta.queryOriginal();
  9113. }
  9114. };
  9115. IRoxieServerActivityFactory *createRoxieServerSideEffectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _isRoot)
  9116. {
  9117. return new CRoxieServerSideEffectActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _isRoot);
  9118. }
  9119. //=================================================================================
  9120. class CRoxieServerActionActivity : public CRoxieServerInternalSinkActivity
  9121. {
  9122. IHThorActionArg &helper;
  9123. public:
  9124. CRoxieServerActionActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numOutputs)
  9125. : CRoxieServerInternalSinkActivity(_ctx, _factory, _probeManager, _numOutputs), helper((IHThorActionArg &)basehelper)
  9126. {
  9127. }
  9128. virtual void onExecute()
  9129. {
  9130. helper.action();
  9131. }
  9132. };
  9133. class CRoxieServerActionActivityFactory : public CRoxieServerInternalSinkFactory
  9134. {
  9135. public:
  9136. CRoxieServerActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned _usageCount, bool _isRoot)
  9137. : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _usageCount, _isRoot)
  9138. {
  9139. }
  9140. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  9141. {
  9142. return new CRoxieServerActionActivity(_ctx, this, _probeManager, usageCount);
  9143. }
  9144. };
  9145. IRoxieServerActivityFactory *createRoxieServerActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned _usageCount, bool _isRoot)
  9146. {
  9147. return new CRoxieServerActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _usageCount, _isRoot);
  9148. }
  9149. //=================================================================================
  9150. class CRoxieServerSampleActivity : public CRoxieServerActivity
  9151. {
  9152. IHThorSampleArg &helper;
  9153. unsigned numSamples;
  9154. unsigned numToSkip;
  9155. unsigned whichSample;
  9156. bool anyThisGroup;
  9157. bool eof;
  9158. public:
  9159. CRoxieServerSampleActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  9160. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorSampleArg &)basehelper)
  9161. {
  9162. numSamples = 0;
  9163. numToSkip = 0;
  9164. whichSample = 0;
  9165. anyThisGroup = false;
  9166. eof = false;
  9167. }
  9168. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9169. {
  9170. anyThisGroup = false;
  9171. eof = false;
  9172. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  9173. numSamples = helper.getProportion();
  9174. whichSample = helper.getSampleNumber();
  9175. numToSkip = (whichSample ? whichSample-1 : 0);
  9176. }
  9177. virtual const void * nextRow()
  9178. {
  9179. ActivityTimer t(totalCycles, timeActivities);
  9180. if (eof)
  9181. return NULL;
  9182. for (;;)
  9183. {
  9184. const void * ret = inputStream->nextRow();
  9185. if (!ret)
  9186. {
  9187. //this does work with groups - may or may not be useful...
  9188. //reset the sample for each group.... probably best.
  9189. numToSkip = (whichSample ? whichSample-1 : 0);
  9190. if (anyThisGroup)
  9191. {
  9192. anyThisGroup = false;
  9193. return NULL;
  9194. }
  9195. ret = inputStream->nextRow();
  9196. if (!ret)
  9197. {
  9198. eof = true;
  9199. return NULL; // eof...
  9200. }
  9201. }
  9202. if (numToSkip == 0)
  9203. {
  9204. anyThisGroup = true;
  9205. numToSkip = numSamples-1;
  9206. processed++;
  9207. return ret;
  9208. }
  9209. numToSkip--;
  9210. ReleaseRoxieRow(ret);
  9211. }
  9212. }
  9213. };
  9214. class CRoxieServerSampleActivityFactory : public CRoxieServerActivityFactory
  9215. {
  9216. public:
  9217. CRoxieServerSampleActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  9218. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  9219. {
  9220. }
  9221. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  9222. {
  9223. return new CRoxieServerSampleActivity(_ctx, this, _probeManager);
  9224. }
  9225. };
  9226. IRoxieServerActivityFactory *createRoxieServerSampleActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  9227. {
  9228. return new CRoxieServerSampleActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  9229. }
  9230. //=================================================================================
  9231. class CRoxieServerChooseSetsActivity : public CRoxieServerActivity
  9232. {
  9233. IHThorChooseSetsArg &helper;
  9234. unsigned numSets;
  9235. unsigned * setCounts;
  9236. bool done;
  9237. public:
  9238. CRoxieServerChooseSetsActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  9239. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorChooseSetsArg &)basehelper)
  9240. {
  9241. setCounts = NULL;
  9242. numSets = 0;
  9243. done = false;
  9244. }
  9245. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9246. {
  9247. done = false;
  9248. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  9249. numSets = helper.getNumSets();
  9250. setCounts = new unsigned[numSets];
  9251. memset(setCounts, 0, sizeof(unsigned)*numSets);
  9252. helper.setCounts(setCounts);
  9253. }
  9254. virtual void reset()
  9255. {
  9256. delete [] setCounts;
  9257. setCounts = NULL;
  9258. CRoxieServerActivity::reset();
  9259. }
  9260. virtual const void * nextRow()
  9261. {
  9262. ActivityTimer t(totalCycles, timeActivities);
  9263. if (done)
  9264. return NULL;
  9265. for (;;)
  9266. {
  9267. const void * ret = inputStream->ungroupedNextRow();
  9268. if (!ret)
  9269. {
  9270. done = true;
  9271. return NULL;
  9272. }
  9273. processed++;
  9274. switch (helper.getRecordAction(ret))
  9275. {
  9276. case 2:
  9277. done = true;
  9278. return ret;
  9279. case 1:
  9280. return ret;
  9281. }
  9282. ReleaseRoxieRow(ret);
  9283. }
  9284. }
  9285. };
  9286. class CRoxieServerChooseSetsActivityFactory : public CRoxieServerActivityFactory
  9287. {
  9288. public:
  9289. CRoxieServerChooseSetsActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  9290. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  9291. {
  9292. }
  9293. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  9294. {
  9295. return new CRoxieServerChooseSetsActivity(_ctx, this, _probeManager);
  9296. }
  9297. };
  9298. IRoxieServerActivityFactory *createRoxieServerChooseSetsActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  9299. {
  9300. return new CRoxieServerChooseSetsActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  9301. }
  9302. //=================================================================================
  9303. class CRoxieServerChooseSetsExActivity : public CRoxieServerActivity
  9304. {
  9305. protected:
  9306. IHThorChooseSetsExArg &helper;
  9307. unsigned numSets;
  9308. unsigned curIndex;
  9309. unsigned * setCounts;
  9310. count_t * limits;
  9311. bool done;
  9312. ConstPointerArray gathered;
  9313. virtual bool includeRow(const void * row) = 0;
  9314. virtual void calculateSelection() = 0;
  9315. public:
  9316. CRoxieServerChooseSetsExActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  9317. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorChooseSetsExArg &)basehelper)
  9318. {
  9319. setCounts = NULL;
  9320. limits = NULL;
  9321. done = false;
  9322. curIndex = 0;
  9323. numSets = 0;
  9324. }
  9325. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9326. {
  9327. done = false;
  9328. curIndex = 0;
  9329. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  9330. numSets = helper.getNumSets();
  9331. setCounts = new unsigned[numSets];
  9332. memset(setCounts, 0, sizeof(unsigned)*numSets);
  9333. limits = (count_t *)calloc(sizeof(count_t), numSets);
  9334. helper.getLimits(limits);
  9335. }
  9336. virtual void reset()
  9337. {
  9338. delete [] setCounts;
  9339. setCounts = NULL;
  9340. free(limits);
  9341. limits = NULL;
  9342. roxiemem::ReleaseRoxieRowRange(gathered.getArray(), curIndex, gathered.ordinality());
  9343. gathered.kill();
  9344. curIndex = 0;
  9345. CRoxieServerActivity::reset();
  9346. }
  9347. virtual const void * nextRow()
  9348. {
  9349. ActivityTimer t(totalCycles, timeActivities);
  9350. if (gathered.ordinality() == 0)
  9351. {
  9352. curIndex = 0;
  9353. if (!inputStream->nextGroup(gathered))
  9354. {
  9355. done = true;
  9356. return NULL;
  9357. }
  9358. ForEachItemIn(idx1, gathered)
  9359. {
  9360. unsigned category = helper.getCategory(gathered.item(idx1));
  9361. if (category)
  9362. setCounts[category-1]++;
  9363. }
  9364. calculateSelection();
  9365. }
  9366. while (gathered.isItem(curIndex))
  9367. {
  9368. const void * row = gathered.item(curIndex);
  9369. gathered.replace(NULL, curIndex);
  9370. curIndex++;
  9371. if (includeRow(row))
  9372. {
  9373. processed++;
  9374. return row;
  9375. }
  9376. ReleaseRoxieRow(row);
  9377. }
  9378. gathered.kill();
  9379. return NULL;
  9380. }
  9381. };
  9382. class CRoxieServerChooseSetsLastActivity : public CRoxieServerChooseSetsExActivity
  9383. {
  9384. unsigned * numToSkip;
  9385. public:
  9386. CRoxieServerChooseSetsLastActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager) : CRoxieServerChooseSetsExActivity(_ctx, _factory, _probeManager)
  9387. {
  9388. numToSkip = NULL;
  9389. }
  9390. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9391. {
  9392. CRoxieServerChooseSetsExActivity::start(parentExtractSize, parentExtract, paused);
  9393. numToSkip = (unsigned *)calloc(sizeof(unsigned), numSets);
  9394. }
  9395. virtual void reset()
  9396. {
  9397. free(numToSkip);
  9398. numToSkip = NULL;
  9399. CRoxieServerChooseSetsExActivity::reset();
  9400. }
  9401. protected:
  9402. virtual void calculateSelection()
  9403. {
  9404. for (unsigned idx=0; idx < numSets; idx++)
  9405. {
  9406. if (setCounts[idx] < limits[idx])
  9407. numToSkip[idx] = 0;
  9408. else
  9409. numToSkip[idx] = (unsigned)(setCounts[idx] - limits[idx]);
  9410. }
  9411. }
  9412. virtual bool includeRow(const void * row)
  9413. {
  9414. unsigned category = helper.getCategory(row);
  9415. if (category)
  9416. {
  9417. if (numToSkip[category-1] == 0)
  9418. return true;
  9419. numToSkip[category-1]--;
  9420. }
  9421. return false;
  9422. }
  9423. };
  9424. class CRoxieServerChooseSetsEnthActivity : public CRoxieServerChooseSetsExActivity
  9425. {
  9426. count_t * counter;
  9427. public:
  9428. CRoxieServerChooseSetsEnthActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager) : CRoxieServerChooseSetsExActivity(_ctx, _factory, _probeManager)
  9429. {
  9430. counter = NULL;
  9431. }
  9432. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9433. {
  9434. CRoxieServerChooseSetsExActivity::start(parentExtractSize, parentExtract, paused);
  9435. counter = (count_t *)calloc(sizeof(count_t), numSets);
  9436. }
  9437. virtual void reset()
  9438. {
  9439. free(counter);
  9440. counter = NULL;
  9441. CRoxieServerChooseSetsExActivity::reset();
  9442. }
  9443. protected:
  9444. virtual void calculateSelection()
  9445. {
  9446. }
  9447. virtual bool includeRow(const void * row)
  9448. {
  9449. unsigned category = helper.getCategory(row);
  9450. if (category)
  9451. {
  9452. assertex(category <= numSets);
  9453. counter[category-1] += limits[category-1];
  9454. if(counter[category-1] >= setCounts[category-1])
  9455. {
  9456. counter[category-1] -= setCounts[category-1];
  9457. return true;
  9458. }
  9459. }
  9460. return false;
  9461. }
  9462. };
  9463. class CRoxieServerChooseSetsEnthActivityFactory : public CRoxieServerActivityFactory
  9464. {
  9465. public:
  9466. CRoxieServerChooseSetsEnthActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  9467. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  9468. {
  9469. }
  9470. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  9471. {
  9472. return new CRoxieServerChooseSetsEnthActivity(_ctx, this, _probeManager);
  9473. }
  9474. };
  9475. IRoxieServerActivityFactory *createRoxieServerChooseSetsEnthActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  9476. {
  9477. return new CRoxieServerChooseSetsEnthActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  9478. }
  9479. class CRoxieServerChooseSetsLastActivityFactory : public CRoxieServerActivityFactory
  9480. {
  9481. public:
  9482. CRoxieServerChooseSetsLastActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  9483. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  9484. {
  9485. }
  9486. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  9487. {
  9488. return new CRoxieServerChooseSetsLastActivity(_ctx, this, _probeManager);
  9489. }
  9490. };
  9491. IRoxieServerActivityFactory *createRoxieServerChooseSetsLastActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  9492. {
  9493. return new CRoxieServerChooseSetsLastActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  9494. }
  9495. //=================================================================================
  9496. class CRoxieServerEnthActivity : public CRoxieServerActivity
  9497. {
  9498. IHThorEnthArg &helper;
  9499. unsigned __int64 numerator;
  9500. unsigned __int64 denominator;
  9501. unsigned __int64 counter;
  9502. bool eof;
  9503. public:
  9504. CRoxieServerEnthActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  9505. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorEnthArg &)basehelper)
  9506. {
  9507. eof = false;
  9508. numerator = denominator = counter = 0;
  9509. }
  9510. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9511. {
  9512. eof = false;
  9513. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  9514. numerator = helper.getProportionNumerator();
  9515. denominator = helper.getProportionDenominator();
  9516. if(denominator == 0) denominator = 1; //MORE: simplest way to avoid disaster in this case
  9517. counter = (helper.getSampleNumber()-1) * greatestCommonDivisor(numerator, denominator);
  9518. if (counter >= denominator)
  9519. counter %= denominator;
  9520. }
  9521. inline bool wanted()
  9522. {
  9523. counter += numerator;
  9524. if(counter >= denominator)
  9525. {
  9526. counter -= denominator;
  9527. return true;
  9528. }
  9529. return false;
  9530. }
  9531. virtual const void * nextRow()
  9532. {
  9533. ActivityTimer t(totalCycles, timeActivities);
  9534. if (eof)
  9535. return NULL;
  9536. const void * ret;
  9537. for (;;)
  9538. {
  9539. ret = inputStream->ungroupedNextRow();
  9540. if (!ret) //eof
  9541. {
  9542. eof = true;
  9543. return ret;
  9544. }
  9545. if (wanted())
  9546. return ret;
  9547. ReleaseRoxieRow(ret);
  9548. }
  9549. }
  9550. };
  9551. class CRoxieServerEnthActivityFactory : public CRoxieServerActivityFactory
  9552. {
  9553. public:
  9554. CRoxieServerEnthActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  9555. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  9556. {
  9557. }
  9558. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  9559. {
  9560. return new CRoxieServerEnthActivity(_ctx, this, _probeManager);
  9561. }
  9562. };
  9563. IRoxieServerActivityFactory *createRoxieServerEnthActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  9564. {
  9565. return new CRoxieServerEnthActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  9566. }
  9567. //=================================================================================
  9568. class CRoxieServerAggregateActivity : public CRoxieServerActivity
  9569. {
  9570. IHThorAggregateArg &helper;
  9571. bool eof;
  9572. bool isInputGrouped;
  9573. bool abortEarly;
  9574. public:
  9575. CRoxieServerAggregateActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  9576. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorAggregateArg &)basehelper)
  9577. {
  9578. eof = false;
  9579. isInputGrouped = false;
  9580. abortEarly = false;
  9581. }
  9582. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9583. {
  9584. eof = false;
  9585. isInputGrouped = input->queryOutputMeta()->isGrouped(); // could be done earlier, in setInput?
  9586. abortEarly = !isInputGrouped && (factory->getKind() == TAKexistsaggregate); // ditto
  9587. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  9588. }
  9589. virtual bool needsAllocator() const { return true; }
  9590. virtual const void * nextRow()
  9591. {
  9592. ActivityTimer t(totalCycles, timeActivities);
  9593. if (eof)
  9594. return NULL;
  9595. const void * next = inputStream->nextRow();
  9596. if (!next && isInputGrouped)
  9597. {
  9598. eof = true;
  9599. return NULL;
  9600. }
  9601. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  9602. size32_t finalSize = helper.clearAggregate(rowBuilder);
  9603. if (next)
  9604. {
  9605. finalSize = helper.processFirst(rowBuilder, next);
  9606. ReleaseRoxieRow(next);
  9607. if (!abortEarly)
  9608. {
  9609. for (;;)
  9610. {
  9611. next = inputStream->nextRow();
  9612. if (!next)
  9613. break;
  9614. finalSize = helper.processNext(rowBuilder, next);
  9615. ReleaseRoxieRow(next);
  9616. }
  9617. }
  9618. }
  9619. if (!isInputGrouped) // either read all, or aborted early
  9620. eof = true;
  9621. processed++;
  9622. return rowBuilder.finalizeRowClear(finalSize);
  9623. }
  9624. };
  9625. class CRoxieServerStrandedAggregateActivity : public CRoxieServerStrandedActivity, implements IOrderedCallbackCollection
  9626. {
  9627. class AggregateProcessor : public StrandProcessor, implements IStrandThreaded, implements IOrderedOutputCallback
  9628. {
  9629. protected:
  9630. IHThorAggregateArg &helper;
  9631. OwnedConstRoxieRow result;
  9632. bool eof = false;
  9633. bool isInputGrouped = false;
  9634. bool abortEarly = false;
  9635. public:
  9636. AggregateProcessor(CRoxieServerActivity &_parent, IEngineRowStream *_inputStream, IHThorAggregateArg &_helper, bool _isInputGrouped, bool _abortEarly)
  9637. : StrandProcessor(_parent, _inputStream, true), helper(_helper), isInputGrouped(_isInputGrouped), abortEarly(_abortEarly)
  9638. {
  9639. }
  9640. virtual const void * nextRow() override
  9641. {
  9642. ActivityTimer t(totalCycles, timeActivities);
  9643. if (eof || isAborting())
  9644. return NULL;
  9645. const void * next = inputStream->nextRow();
  9646. if (!next && isInputGrouped)
  9647. {
  9648. eof = true;
  9649. return NULL;
  9650. }
  9651. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  9652. size32_t finalSize = helper.clearAggregate(rowBuilder);
  9653. if (next)
  9654. {
  9655. finalSize = helper.processFirst(rowBuilder, next);
  9656. ReleaseRoxieRow(next);
  9657. if (!abortEarly)
  9658. {
  9659. for (;;)
  9660. {
  9661. next = inputStream->nextRow();
  9662. if (!next)
  9663. break;
  9664. finalSize = helper.processNext(rowBuilder, next);
  9665. ReleaseRoxieRow(next);
  9666. if (isAborting())
  9667. break;
  9668. }
  9669. }
  9670. }
  9671. if (!isInputGrouped) // either read all, or aborted early
  9672. eof = true;
  9673. processed++;
  9674. return rowBuilder.finalizeRowClear(finalSize);
  9675. }
  9676. virtual void threadmain() override
  9677. {
  9678. isInputGrouped = true; // gather no row if there are no input rows.
  9679. result.setown(nextRow());
  9680. queryActivity().noteStrandFinished(inputStream);
  9681. }
  9682. virtual void reset() override
  9683. {
  9684. StrandProcessor::reset();
  9685. result.clear();
  9686. eof = false;
  9687. }
  9688. //interface IOutputOutputCallback
  9689. virtual bool noteEndOfInputChunk() { return true; }
  9690. virtual void noteEndOfInput() {}
  9691. virtual void stopStream()
  9692. {
  9693. inputStream->stop();
  9694. }
  9695. const void * queryResult() const { return result; }
  9696. CRoxieServerStrandedAggregateActivity & queryActivity() { return static_cast<CRoxieServerStrandedAggregateActivity &>(parent); }
  9697. };
  9698. //This class is only used when a single aggregate is being calculated.
  9699. class AggregateCombiner : public CInterfaceOf<IEngineRowStream>
  9700. {
  9701. public:
  9702. explicit AggregateCombiner(CRoxieServerStrandedAggregateActivity & _parent) : parent(_parent)
  9703. {
  9704. }
  9705. virtual const void *nextRow()
  9706. {
  9707. return parent.getCombinedAggregate();
  9708. }
  9709. virtual void stop()
  9710. {
  9711. parent.outputStopped();
  9712. }
  9713. virtual void resetEOF()
  9714. {
  9715. throwUnexpected();
  9716. }
  9717. protected:
  9718. CRoxieServerStrandedAggregateActivity & parent;
  9719. } combiner;
  9720. class NullCallback : implements IOrderedOutputCallback
  9721. {
  9722. public:
  9723. virtual bool noteEndOfInputChunk() { return true; }
  9724. virtual void noteEndOfInput() {}
  9725. } nullCallback;
  9726. public:
  9727. CRoxieServerStrandedAggregateActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const StrandOptions &_strandOptions)
  9728. : CRoxieServerStrandedActivity(_ctx, _factory, _probeManager, _strandOptions), helper((IHThorAggregateArg &)basehelper), combiner(*this)
  9729. {
  9730. isInputGrouped = false;
  9731. abortEarly = false;
  9732. }
  9733. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  9734. {
  9735. CRoxieServerStrandedActivity::setInput(idx, _sourceIdx, _in);
  9736. isInputGrouped = input->queryOutputMeta()->isGrouped(); // could be done earlier, in setInput?
  9737. abortEarly = !isInputGrouped && (factory->getKind() == TAKexistsaggregate); // ditto
  9738. //For EXISTS(), and aggregates that rely on the input order, force to execute single threaded
  9739. //MORE: Ordered should be able to process a block at a time and then merge them, similar to disk write processing.
  9740. if (abortEarly || (!isInputGrouped && queryFactory()->isInputOrdered(false, 0)))
  9741. strandOptions.numStrands = 1;
  9742. else if (!isInputGrouped)
  9743. combineStreams = true;
  9744. }
  9745. virtual IStrandJunction *getOutputStreams(IRoxieSlaveContext *ctx, unsigned idx, PointerArrayOf<IEngineRowStream> &streams, const StrandOptions * consumerOptions, bool consumerOrdered, IOrderedCallbackCollection * orderedCallbacks) override
  9746. {
  9747. PointerArrayOf<IEngineRowStream> localStreams;
  9748. //If streams are being combined, this class should be notified of end of sections, otherwise grouped aggregates can inform a downstream activity.
  9749. IOrderedCallbackCollection * callbacks = combineStreams ? static_cast<IOrderedCallbackCollection *>(this) : orderedCallbacks;
  9750. Owned<IStrandJunction> outJunction = CRoxieServerStrandedActivity::getOutputStreams(ctx, idx, localStreams, consumerOptions, consumerOrdered, callbacks);
  9751. if (localStreams.ordinality() == 1)
  9752. combineStreams = false; // Select a more efficient/simpler code path
  9753. if (combineStreams)
  9754. {
  9755. assertex(!outJunction); // this needs more thought!
  9756. streams.append(&combiner);
  9757. }
  9758. else
  9759. {
  9760. streams.swapWith(localStreams);
  9761. }
  9762. return outJunction.getClear();
  9763. }
  9764. virtual StrandProcessor *createStrandProcessor(IEngineRowStream *instream)
  9765. {
  9766. if (traceLevel > 4)
  9767. DBGLOG("Create aggregate strand processor %u", strandOptions.numStrands);
  9768. return new AggregateProcessor(*this, instream, (IHThorAggregateArg &) basehelper, isInputGrouped && !combineStreams, abortEarly);
  9769. }
  9770. virtual StrandProcessor *createStrandSourceProcessor(bool inputOrdered) { throwUnexpected(); }
  9771. virtual bool needsAllocator() const { return true; }
  9772. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused) override
  9773. {
  9774. CRoxieServerStrandedActivity::start(parentExtractSize, parentExtract, paused);
  9775. if (combineStreams)
  9776. {
  9777. barrier.setown(createStrandBarrier());
  9778. ForEachItemIn(i, strands)
  9779. barrier->startStrand(queryAggregate(i));
  9780. active.store(1);
  9781. }
  9782. else
  9783. active.store(0);
  9784. }
  9785. virtual void reset() override
  9786. {
  9787. CRoxieServerStrandedActivity::reset();
  9788. barrier.clear();
  9789. calculated = false;
  9790. }
  9791. //Helper functions for the single aggregate case
  9792. const void * getCombinedAggregate()
  9793. {
  9794. if (calculated)
  9795. return NULL;
  9796. calculated= true;
  9797. barrier->waitForStrands();
  9798. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  9799. size32_t finalSize = helper.clearAggregate(rowBuilder);
  9800. bool isFirst = true;
  9801. for (unsigned i=0; i < numStrands(); i++)
  9802. {
  9803. const void * next = queryAggregate(i).queryResult();
  9804. if (next)
  9805. {
  9806. if (isFirst)
  9807. {
  9808. finalSize = cloneRow(rowBuilder, next, helper.queryOutputMeta());
  9809. isFirst = false;
  9810. }
  9811. else
  9812. finalSize = helper.mergeAggregate(rowBuilder, next);
  9813. }
  9814. }
  9815. return rowBuilder.finalizeRowClear(finalSize);
  9816. }
  9817. void outputStopped()
  9818. {
  9819. //only called if generating a single result.
  9820. assertex(combineStreams);
  9821. if (barrier)
  9822. {
  9823. requestAbort(); // if strands are still running, abort them
  9824. barrier->waitForStrands();
  9825. }
  9826. else
  9827. {
  9828. ForEachItemIn(i, strands)
  9829. queryAggregate(i).stopStream();
  9830. }
  9831. CRoxieServerStrandedActivity::stop();
  9832. }
  9833. void noteStrandFinished(IRowStream * stream)
  9834. {
  9835. barrier->noteStrandFinished(stream);
  9836. }
  9837. virtual IOrderedOutputCallback * queryCallback(unsigned i)
  9838. {
  9839. //The non-ordered aggregate does not need to process the ordered call back information.
  9840. //If the ordered single aggregate was implemented then it would need to be processed instead of ignored,
  9841. //however it needs some care since the strands are not yet created. So cannot return strand(i).
  9842. return &nullCallback;
  9843. }
  9844. inline AggregateProcessor & queryAggregate(unsigned i)
  9845. {
  9846. return static_cast<AggregateProcessor &>(strands.item(i));
  9847. }
  9848. protected:
  9849. IHThorAggregateArg &helper;
  9850. Owned<IStrandBarrier> barrier;
  9851. IEngineRowStream * combinedStream = nullptr;
  9852. bool isInputGrouped;
  9853. bool abortEarly;
  9854. bool combineStreams = false;
  9855. bool calculated = false;
  9856. };
  9857. class CRoxieServerAggregateActivityFactory : public CRoxieServerActivityFactory
  9858. {
  9859. StrandOptions strandOptions;
  9860. public:
  9861. CRoxieServerAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  9862. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode), strandOptions(_graphNode)
  9863. {
  9864. Owned<IHThorAggregateArg> helper = (IHThorAggregateArg *) helperFactory();
  9865. if (!(helper->getAggregateFlags() & TAForderedmerge))
  9866. optStableInput = false;
  9867. }
  9868. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  9869. {
  9870. return new CRoxieServerStrandedAggregateActivity(_ctx, this, _probeManager, strandOptions);
  9871. }
  9872. };
  9873. IRoxieServerActivityFactory *createRoxieServerAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  9874. {
  9875. return new CRoxieServerAggregateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  9876. }
  9877. //=================================================================================
  9878. typedef unsigned t_hashPrefix;
  9879. class CRoxieServerHashAggregateActivity : public CRoxieServerActivity
  9880. {
  9881. IHThorHashAggregateArg &helper;
  9882. RowAggregator aggregated;
  9883. bool eof;
  9884. bool gathered;
  9885. bool isGroupedAggregate;
  9886. public:
  9887. CRoxieServerHashAggregateActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, bool _isGroupedAggregate, IProbeManager *_probeManager)
  9888. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorHashAggregateArg &)basehelper),
  9889. isGroupedAggregate(_isGroupedAggregate),
  9890. aggregated(helper, helper)
  9891. {
  9892. eof = false;
  9893. gathered = false;
  9894. }
  9895. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9896. {
  9897. eof = false;
  9898. gathered = false;
  9899. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  9900. }
  9901. virtual void reset()
  9902. {
  9903. aggregated.reset();
  9904. CRoxieServerActivity::reset();
  9905. }
  9906. virtual bool needsAllocator() const { return true; }
  9907. virtual const void * nextRow()
  9908. {
  9909. ActivityTimer t(totalCycles, timeActivities);
  9910. if (eof)
  9911. return NULL;
  9912. if (!gathered)
  9913. {
  9914. aggregated.start(rowAllocator);
  9915. bool eog = true;
  9916. for (;;)
  9917. {
  9918. const void * next = inputStream->nextRow();
  9919. if (!next)
  9920. {
  9921. if (isGroupedAggregate)
  9922. {
  9923. if (eog)
  9924. eof = true;
  9925. break;
  9926. }
  9927. next = inputStream->nextRow();
  9928. if (!next)
  9929. break;
  9930. }
  9931. eog = false;
  9932. aggregated.addRow(next);
  9933. ReleaseRoxieRow(next);
  9934. }
  9935. gathered = true;
  9936. }
  9937. Owned<AggregateRowBuilder> next = aggregated.nextResult();
  9938. if (next)
  9939. {
  9940. processed++;
  9941. return next->finalizeRowClear();
  9942. }
  9943. if (!isGroupedAggregate)
  9944. eof = true;
  9945. aggregated.reset();
  9946. gathered = false;
  9947. return NULL;
  9948. }
  9949. };
  9950. class CRoxieServerHashAggregateActivityFactory : public CRoxieServerActivityFactory
  9951. {
  9952. public:
  9953. CRoxieServerHashAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  9954. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  9955. {
  9956. isGroupedAggregate = _graphNode.getPropBool("att[@name='grouped']/@value");
  9957. }
  9958. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  9959. {
  9960. return new CRoxieServerHashAggregateActivity(_ctx, this, isGroupedAggregate, _probeManager);
  9961. }
  9962. protected:
  9963. bool isGroupedAggregate;
  9964. };
  9965. IRoxieServerActivityFactory *createRoxieServerHashAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  9966. {
  9967. return new CRoxieServerHashAggregateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  9968. }
  9969. //=================================================================================
  9970. class CRoxieServerDegroupActivity : public CRoxieServerActivity
  9971. {
  9972. IHThorDegroupArg &helper;
  9973. bool eof;
  9974. public:
  9975. CRoxieServerDegroupActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  9976. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorDegroupArg &)basehelper)
  9977. {
  9978. eof = false;
  9979. }
  9980. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9981. {
  9982. eof = false;
  9983. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  9984. }
  9985. virtual const void * nextRow()
  9986. {
  9987. ActivityTimer t(totalCycles, timeActivities);
  9988. if (eof)
  9989. return NULL;
  9990. const void * ret = inputStream->ungroupedNextRow();
  9991. if (ret)
  9992. processed++;
  9993. else
  9994. eof = true;
  9995. return ret;
  9996. }
  9997. virtual const void * nextRowGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  9998. {
  9999. ActivityTimer t(totalCycles, timeActivities);
  10000. if (eof)
  10001. return NULL;
  10002. const void * ret = inputStream->nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);
  10003. if (ret)
  10004. processed++;
  10005. else
  10006. eof = true;
  10007. return ret;
  10008. }
  10009. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  10010. {
  10011. return input->gatherConjunctions(collector);
  10012. }
  10013. virtual void resetEOF()
  10014. {
  10015. eof = false;
  10016. inputStream->resetEOF();
  10017. }
  10018. IInputSteppingMeta * querySteppingMeta()
  10019. {
  10020. return input->querySteppingMeta();
  10021. }
  10022. };
  10023. class CRoxieServerDegroupActivityFactory : public CRoxieServerActivityFactory
  10024. {
  10025. public:
  10026. CRoxieServerDegroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  10027. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  10028. {
  10029. }
  10030. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  10031. {
  10032. return new CRoxieServerDegroupActivity(_ctx, this, _probeManager);
  10033. }
  10034. };
  10035. IRoxieServerActivityFactory *createRoxieServerDegroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  10036. {
  10037. return new CRoxieServerDegroupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  10038. }
  10039. //=================================================================================
  10040. class CRoxieServerSpillReadActivity : public CRoxieServerActivity
  10041. {
  10042. IHThorDiskReadArg &helper;
  10043. bool needTransform;
  10044. bool eof;
  10045. bool anyThisGroup;
  10046. unsigned __int64 rowLimit;
  10047. unsigned __int64 choosenLimit;
  10048. public:
  10049. CRoxieServerSpillReadActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  10050. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorDiskReadArg &)basehelper)
  10051. {
  10052. needTransform = helper.needTransform();
  10053. rowLimit = (unsigned __int64) -1;
  10054. choosenLimit = 0;
  10055. eof = false;
  10056. anyThisGroup = false;
  10057. }
  10058. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  10059. {
  10060. anyThisGroup = false;
  10061. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  10062. if (helper.canMatchAny())
  10063. eof = false;
  10064. else
  10065. eof = true;
  10066. choosenLimit = helper.getChooseNLimit();
  10067. rowLimit = helper.getRowLimit();
  10068. helper.setCallback(NULL); // members should not be called - change if they are
  10069. }
  10070. virtual bool needsAllocator() const { return true; }
  10071. virtual const void * nextRow()
  10072. {
  10073. ActivityTimer t(totalCycles, timeActivities);
  10074. if (eof)
  10075. return NULL;
  10076. if (processed==choosenLimit)
  10077. {
  10078. eof = true;
  10079. return NULL;
  10080. }
  10081. if (needTransform)
  10082. {
  10083. for (;;)
  10084. {
  10085. const void *in = inputStream->nextRow();
  10086. if (!in)
  10087. {
  10088. if (anyThisGroup)
  10089. {
  10090. anyThisGroup = false;
  10091. return NULL;
  10092. }
  10093. in = inputStream->nextRow();
  10094. if (!in)
  10095. {
  10096. eof = true;
  10097. return NULL; // eof...
  10098. }
  10099. }
  10100. unsigned outSize;
  10101. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  10102. try
  10103. {
  10104. outSize = helper.transform(rowBuilder, in);
  10105. ReleaseRoxieRow(in);
  10106. }
  10107. catch (IException *E)
  10108. {
  10109. throw makeWrappedException(E);
  10110. }
  10111. if (outSize)
  10112. {
  10113. anyThisGroup = true;
  10114. processed++;
  10115. if (processed==rowLimit)
  10116. {
  10117. if (traceLevel > 4)
  10118. DBGLOG("activityid = %d line = %d", activityId, __LINE__);
  10119. helper.onLimitExceeded();
  10120. }
  10121. return rowBuilder.finalizeRowClear(outSize);
  10122. }
  10123. }
  10124. }
  10125. else
  10126. {
  10127. const void *ret = inputStream->nextRow();
  10128. if (ret)
  10129. {
  10130. processed++;
  10131. if (processed==rowLimit)
  10132. {
  10133. if (traceLevel > 4)
  10134. DBGLOG("activityid = %d line = %d", activityId, __LINE__);
  10135. ReleaseClearRoxieRow(ret);
  10136. helper.onLimitExceeded(); // should not return
  10137. throwUnexpected();
  10138. }
  10139. }
  10140. return ret;
  10141. }
  10142. }
  10143. };
  10144. class CRoxieServerSpillReadActivityFactory : public CRoxieServerActivityFactory
  10145. {
  10146. public:
  10147. CRoxieServerSpillReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  10148. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  10149. {
  10150. }
  10151. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  10152. {
  10153. return new CRoxieServerSpillReadActivity(_ctx, this, _probeManager);
  10154. }
  10155. virtual void addDependency(unsigned source, ThorActivityKind sourceKind, unsigned sourceIdx, int controlId, const char *edgeId)
  10156. {
  10157. if (sourceKind==TAKspill || sourceKind==TAKdiskwrite) // Bit of a hack - codegen probably should differentiate
  10158. setInput(0, source, sourceIdx);
  10159. else
  10160. CRoxieServerActivityFactory::addDependency(source, kind, sourceIdx, controlId, edgeId);
  10161. }
  10162. };
  10163. IRoxieServerActivityFactory *createRoxieServerSpillReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  10164. {
  10165. return new CRoxieServerSpillReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  10166. }
  10167. //=================================================================================
  10168. class CRoxieServerSpillWriteActivity : public CRoxieServerActivity
  10169. {
  10170. public:
  10171. CRoxieServerSpillWriteActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  10172. : CRoxieServerActivity(_ctx, _factory, _probeManager)
  10173. {
  10174. }
  10175. ~CRoxieServerSpillWriteActivity()
  10176. {
  10177. }
  10178. virtual const void *nextRow()
  10179. {
  10180. ActivityTimer t(totalCycles, timeActivities);
  10181. return inputStream->nextRow();
  10182. }
  10183. };
  10184. //==================================================================================
  10185. class CRoxieServerDiskWriteActivity : public CRoxieServerInternalSinkActivity, implements IRoxiePublishCallback
  10186. {
  10187. protected:
  10188. Owned<IExtRowWriter> outSeq;
  10189. Owned<IOutputRowSerializer> rowSerializer;
  10190. Linked<IFileIOStream> diskout;
  10191. bool blockcompressed;
  10192. bool extend;
  10193. bool overwrite;
  10194. bool encrypted;
  10195. bool grouped;
  10196. IHThorDiskWriteArg &helper;
  10197. Owned<IRecordSize> diskmeta;
  10198. Owned<IRoxieWriteHandler> writer;
  10199. bool tallycrc;
  10200. unsigned __int64 uncompressedBytesWritten;
  10201. CRC32 crc;
  10202. void updateWorkUnitResult(unsigned __int64 reccount)
  10203. {
  10204. assertex(writer);
  10205. // MORE - a lot of this is common with hthor
  10206. WorkunitUpdate wu = ctx->updateWorkUnit();
  10207. if (wu)
  10208. {
  10209. OwnedRoxieString rawLogicalName = helper.getFileName();
  10210. StringBuffer lfn; // logical filename
  10211. expandLogicalFilename(lfn, rawLogicalName, wu, false, false);
  10212. if (lfn.length())
  10213. {
  10214. unsigned flags = helper.getFlags();
  10215. WUFileKind fileKind;
  10216. if (TDXtemporary & flags)
  10217. fileKind = WUFileTemporary;
  10218. else if(TDXjobtemp & flags)
  10219. fileKind = WUFileJobOwned;
  10220. else if(TDWowned & flags)
  10221. fileKind = WUFileOwned;
  10222. else
  10223. fileKind = WUFileStandard;
  10224. StringArray clusters;
  10225. writer->getClusters(clusters);
  10226. wu->addFile(lfn.str(), &clusters, helper.getTempUsageCount(), fileKind, NULL);
  10227. if (!(flags & TDXtemporary) && helper.getSequence() >= 0)
  10228. {
  10229. Owned<IWUResult> result = wu->updateResultBySequence(helper.getSequence());
  10230. if (result)
  10231. {
  10232. result->setResultTotalRowCount(reccount);
  10233. result->setResultStatus(ResultStatusCalculated);
  10234. if (helper.getFlags() & TDWresult)
  10235. result->setResultFilename(lfn.str());
  10236. else
  10237. result->setResultLogicalName(lfn.str());
  10238. }
  10239. }
  10240. }
  10241. }
  10242. }
  10243. void resolve()
  10244. {
  10245. OwnedRoxieString rawLogicalName = helper.getFileName();
  10246. assertex(rawLogicalName);
  10247. assertex((helper.getFlags() & TDXtemporary) == 0);
  10248. StringArray clusters;
  10249. unsigned clusterIdx = 0;
  10250. while(true)
  10251. {
  10252. OwnedRoxieString cluster(helper.getCluster(clusterIdx));
  10253. if(!cluster)
  10254. break;
  10255. clusters.append(cluster);
  10256. clusterIdx++;
  10257. }
  10258. if (clusters.length())
  10259. {
  10260. if (extend)
  10261. throw MakeStringException(0, "Cannot combine EXTEND and CLUSTER flags on disk write of file %s", rawLogicalName.get());
  10262. }
  10263. else
  10264. {
  10265. if (roxieName.length())
  10266. clusters.append(roxieName.str());
  10267. else
  10268. clusters.append(".");
  10269. }
  10270. writer.setown(ctx->createLFN(rawLogicalName, overwrite, extend, clusters));
  10271. // MORE - need to check somewhere that single part if it's an existing file or an external one...
  10272. }
  10273. public:
  10274. CRoxieServerDiskWriteActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  10275. : CRoxieServerInternalSinkActivity(_ctx, _factory, _probeManager, 0), helper((IHThorDiskWriteArg &) basehelper)
  10276. {
  10277. extend = ((helper.getFlags() & TDWextend) != 0);
  10278. overwrite = ((helper.getFlags() & TDWoverwrite) != 0);
  10279. grouped = (helper.getFlags() & TDXgrouped) != 0;
  10280. diskmeta.set(helper.queryDiskRecordSize()->querySerializedDiskMeta());
  10281. if (grouped)
  10282. diskmeta.setown(createDeltaRecordSize(diskmeta, +1));
  10283. blockcompressed = (((helper.getFlags() & TDWnewcompress) != 0) || (((helper.getFlags() & TDXcompress) != 0) && (diskmeta->getFixedSize() >= MIN_ROWCOMPRESS_RECSIZE))); //always use new compression
  10284. encrypted = false; // set later
  10285. tallycrc = true;
  10286. uncompressedBytesWritten = 0;
  10287. }
  10288. ~CRoxieServerDiskWriteActivity()
  10289. {
  10290. }
  10291. virtual bool needsAllocator() const
  10292. {
  10293. return true;
  10294. }
  10295. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  10296. {
  10297. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  10298. resolve();
  10299. Owned<IFileIO> io;
  10300. void *ekey;
  10301. size32_t ekeylen;
  10302. helper.getEncryptKey(ekeylen, ekey);
  10303. Owned<ICompressor> ecomp;
  10304. if (ekeylen!=0)
  10305. {
  10306. ecomp.setown(createAESCompressor256(ekeylen,ekey));
  10307. memset(ekey,0,ekeylen);
  10308. rtlFree(ekey);
  10309. encrypted = true;
  10310. blockcompressed = true;
  10311. }
  10312. if (blockcompressed)
  10313. io.setown(createCompressedFileWriter(writer->queryFile(), (diskmeta->isFixedSize() ? diskmeta->getFixedSize() : 0), extend, true, ecomp));
  10314. else
  10315. io.setown(writer->queryFile()->open(extend ? IFOwrite : IFOcreate));
  10316. if (!io)
  10317. throw MakeStringException(errno, "Failed to create%s file %s for writing", (encrypted ? " encrypted" : (blockcompressed ? " compressed" : "")), writer->queryFile()->queryFilename());
  10318. diskout.setown(createBufferedIOStream(io));
  10319. if (extend)
  10320. diskout->seek(0, IFSend);
  10321. tallycrc = !factory->queryQueryFactory().queryOptions().skipFileFormatCrcCheck && !(helper.getFlags() & TDRnocrccheck) && !blockcompressed;
  10322. Owned<IRowInterfaces> rowIf = createRowInterfaces(input->queryOutputMeta(), activityId, factory->getHeapFlags(), ctx->queryCodeContext());
  10323. rowSerializer.set(rowIf->queryRowSerializer());
  10324. unsigned rwFlags = rw_autoflush;
  10325. if(grouped)
  10326. rwFlags |= rw_grouped;
  10327. if(tallycrc)
  10328. rwFlags |= rw_crc;
  10329. outSeq.setown(createRowWriter(diskout, rowIf, rwFlags));
  10330. }
  10331. virtual void stop()
  10332. {
  10333. if (aborted)
  10334. {
  10335. if (writer)
  10336. writer->finish(false, this);
  10337. }
  10338. else
  10339. {
  10340. if (outSeq)
  10341. outSeq->flush(&crc);
  10342. if (outSeq)
  10343. uncompressedBytesWritten = outSeq->getPosition();
  10344. outSeq.clear();
  10345. diskout.clear(); // Make sure file is properly closed or date may not match published info
  10346. if (writer)
  10347. {
  10348. updateWorkUnitResult(processed);
  10349. writer->finish(true, this);
  10350. }
  10351. }
  10352. writer.clear();
  10353. CRoxieServerActivity::stop();
  10354. }
  10355. virtual void reset()
  10356. {
  10357. CRoxieServerActivity::reset();
  10358. diskout.clear();
  10359. outSeq.clear();
  10360. writer.clear();
  10361. uncompressedBytesWritten = 0;
  10362. crc.reset();
  10363. }
  10364. virtual void onExecute()
  10365. {
  10366. for (;;)
  10367. {
  10368. const void *row = inputStream->nextRow();
  10369. if (!row)
  10370. {
  10371. row = inputStream->nextRow();
  10372. if (!row)
  10373. break;
  10374. if (grouped)
  10375. outSeq->putRow(NULL);
  10376. }
  10377. processed++;
  10378. outSeq->putRow(row);
  10379. }
  10380. }
  10381. virtual void setFileProperties(IFileDescriptor *desc) const
  10382. {
  10383. IPropertyTree &partProps = desc->queryPart(0)->queryProperties(); //properties of the first file part.
  10384. IPropertyTree &fileProps = desc->queryProperties(); // properties of the logical file
  10385. if (blockcompressed)
  10386. {
  10387. // caller has already set @size from file size...
  10388. fileProps.setPropBool("@blockCompressed", true);
  10389. fileProps.setPropInt64("@compressedSize", partProps.getPropInt64("@size", 0));
  10390. partProps.setPropInt64("@compressedSize", partProps.getPropInt64("@size", 0));
  10391. fileProps.setPropInt64("@size", uncompressedBytesWritten);
  10392. partProps.setPropInt64("@size", uncompressedBytesWritten);
  10393. }
  10394. else if (tallycrc && crc.get())
  10395. partProps.setPropInt64("@fileCrc", crc.get());
  10396. if (encrypted)
  10397. fileProps.setPropBool("@encrypted", true);
  10398. fileProps.setPropInt64("@recordCount", processed);
  10399. unsigned flags = helper.getFlags();
  10400. if (flags & TDWpersist)
  10401. fileProps.setPropBool("@persistent", true);
  10402. if (grouped)
  10403. fileProps.setPropBool("@grouped", true);
  10404. if (flags & (TDWowned|TDXjobtemp|TDXtemporary))
  10405. fileProps.setPropBool("@owned", true);
  10406. if (flags & TDWresult)
  10407. fileProps.setPropBool("@result", true);
  10408. IConstWorkUnit *workUnit = ctx->queryWorkUnit();
  10409. if (workUnit)
  10410. {
  10411. fileProps.setProp("@owner", workUnit->queryUser());
  10412. fileProps.setProp("@workunit", workUnit->queryWuid());
  10413. fileProps.setProp("@job", workUnit->queryJobName());
  10414. }
  10415. if (flags & TDWexpires)
  10416. setExpiryTime(fileProps, helper.getExpiryDays());
  10417. if (flags & TDWupdate)
  10418. {
  10419. unsigned eclCRC;
  10420. unsigned __int64 totalCRC;
  10421. helper.getUpdateCRCs(eclCRC, totalCRC);
  10422. fileProps.setPropInt("@eclCRC", eclCRC);
  10423. fileProps.setPropInt64("@totalCRC", totalCRC);
  10424. }
  10425. fileProps.setPropInt("@formatCrc", helper.getFormatCrc());
  10426. IRecordSize * inputMeta = input->queryOutputMeta();
  10427. if ((inputMeta->isFixedSize()) && !isOutputTransformed())
  10428. fileProps.setPropInt("@recordSize", inputMeta->getFixedSize() + (grouped ? 1 : 0));
  10429. const char *recordECL = helper.queryRecordECL();
  10430. if (recordECL && *recordECL)
  10431. fileProps.setProp("ECL", recordECL);
  10432. fileProps.setProp("@kind", "flat"); // default, derivitives may override
  10433. }
  10434. virtual IUserDescriptor *queryUserDescriptor() const
  10435. {
  10436. IConstWorkUnit *workUnit = ctx->queryWorkUnit();
  10437. if (workUnit)
  10438. return workUnit->queryUserDescriptor();
  10439. else
  10440. return NULL;
  10441. }
  10442. virtual bool isOutputTransformed() const { return false; }
  10443. };
  10444. //=================================================================================
  10445. class CRoxieServerCsvWriteActivity : public CRoxieServerDiskWriteActivity
  10446. {
  10447. IHThorCsvWriteArg &csvHelper;
  10448. CSVOutputStream csvOutput;
  10449. public:
  10450. CRoxieServerCsvWriteActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  10451. : CRoxieServerDiskWriteActivity(_ctx, _factory, _probeManager), csvHelper(static_cast<IHThorCsvWriteArg &>(helper))
  10452. {
  10453. csvOutput.init(csvHelper.queryCsvParameters(), false);
  10454. }
  10455. virtual void onExecute()
  10456. {
  10457. OwnedRoxieString header(csvHelper.queryCsvParameters()->getHeader());
  10458. if (header)
  10459. {
  10460. csvOutput.beginLine();
  10461. csvOutput.writeHeaderLn(strlen(header), header);
  10462. diskout->write(csvOutput.length(), csvOutput.str());
  10463. }
  10464. for (;;)
  10465. {
  10466. const void *nextrec = inputStream->ungroupedNextRow();
  10467. if (!nextrec)
  10468. break;
  10469. processed++;
  10470. csvOutput.beginLine();
  10471. csvHelper.writeRow((const byte *)nextrec, &csvOutput);
  10472. csvOutput.endLine();
  10473. diskout->write(csvOutput.length(), csvOutput.str());
  10474. ReleaseRoxieRow(nextrec);
  10475. }
  10476. OwnedRoxieString footer(csvHelper.queryCsvParameters()->getFooter());
  10477. if (footer)
  10478. {
  10479. csvOutput.beginLine();
  10480. csvOutput.writeHeaderLn(strlen(footer), footer);
  10481. diskout->write(csvOutput.length(), csvOutput.str());
  10482. }
  10483. }
  10484. virtual void setFileProperties(IFileDescriptor *desc) const
  10485. {
  10486. CRoxieServerDiskWriteActivity::setFileProperties(desc);
  10487. IPropertyTree &props = desc->queryProperties();
  10488. props.setProp("@format","utf8n");
  10489. ICsvParameters *csvParameters = csvHelper.queryCsvParameters();
  10490. StringBuffer separator;
  10491. OwnedRoxieString rs(csvParameters->getSeparator(0));
  10492. const char *s = rs;
  10493. while (s && *s)
  10494. {
  10495. if (',' == *s)
  10496. separator.append("\\,");
  10497. else
  10498. separator.append(*s);
  10499. ++s;
  10500. }
  10501. props.setProp("@csvSeparate", separator.str());
  10502. props.setProp("@csvQuote", rs.setown(csvParameters->getQuote(0)));
  10503. props.setProp("@csvTerminate", rs.setown(csvParameters->getTerminator(0)));
  10504. props.setProp("@csvEscape", rs.setown(csvParameters->getEscape(0)));
  10505. props.setProp("@kind", "csv");
  10506. }
  10507. virtual bool isOutputTransformed() const { return true; }
  10508. };
  10509. class CRoxieServerXmlWriteActivity : public CRoxieServerDiskWriteActivity
  10510. {
  10511. IHThorXmlWriteArg &xmlHelper;
  10512. StringAttr rowTag;
  10513. ThorActivityKind kind;
  10514. unsigned headerLength;
  10515. unsigned footerLength;
  10516. public:
  10517. CRoxieServerXmlWriteActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, ThorActivityKind _kind)
  10518. : CRoxieServerDiskWriteActivity(_ctx, _factory, _probeManager), xmlHelper(static_cast<IHThorXmlWriteArg &>(helper)), kind(_kind), headerLength(0), footerLength(0)
  10519. {
  10520. }
  10521. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  10522. {
  10523. CRoxieServerDiskWriteActivity::start(parentExtractSize, parentExtract, paused);
  10524. OwnedRoxieString xmlpath(xmlHelper.getXmlIteratorPath());
  10525. if (!xmlpath)
  10526. rowTag.set(DEFAULTXMLROWTAG);
  10527. else
  10528. {
  10529. const char *path = xmlpath;
  10530. if (*path == '/') path++;
  10531. if (strchr(path, '/')) UNIMPLEMENTED; // more what do we do with /mydata/row
  10532. rowTag.set(path);
  10533. }
  10534. }
  10535. virtual void onExecute()
  10536. {
  10537. StringBuffer header;
  10538. OwnedRoxieString suppliedHeader(xmlHelper.getHeader());
  10539. if (kind==TAKjsonwrite)
  10540. buildJsonHeader(header, suppliedHeader, rowTag);
  10541. else if (suppliedHeader)
  10542. header.set(suppliedHeader);
  10543. else
  10544. header.append(DEFAULTXMLHEADER).newline();
  10545. headerLength = header.length();
  10546. diskout->write(header.length(), header.str());
  10547. Owned<IXmlWriterExt> writer = createIXmlWriterExt(xmlHelper.getXmlFlags(), 0, NULL, (kind==TAKjsonwrite) ? WTJSON : WTStandard);
  10548. writer->outputBeginArray(rowTag); //need to set this
  10549. writer->clear(); //but not output it
  10550. for (;;)
  10551. {
  10552. OwnedConstRoxieRow nextrec = inputStream->ungroupedNextRow();
  10553. if (!nextrec)
  10554. break;
  10555. processed++;
  10556. writer->clear().outputBeginNested(rowTag, false);
  10557. xmlHelper.toXML((const byte *)nextrec.get(), *writer);
  10558. writer->outputEndNested(rowTag);
  10559. diskout->write(writer->length(), writer->str());
  10560. }
  10561. OwnedRoxieString suppliedFooter(xmlHelper.getFooter());
  10562. StringBuffer footer;
  10563. if (kind==TAKjsonwrite)
  10564. buildJsonFooter(footer.newline(), suppliedFooter, rowTag);
  10565. else if (suppliedFooter)
  10566. footer.append(suppliedFooter);
  10567. else
  10568. footer.append(DEFAULTXMLFOOTER);
  10569. footerLength=footer.length();
  10570. diskout->write(footer.length(), footer);
  10571. }
  10572. virtual void reset()
  10573. {
  10574. CRoxieServerDiskWriteActivity::reset();
  10575. rowTag.clear();
  10576. }
  10577. virtual void setFileProperties(IFileDescriptor *desc) const
  10578. {
  10579. CRoxieServerDiskWriteActivity::setFileProperties(desc);
  10580. desc->queryProperties().setProp("@format","utf8n");
  10581. desc->queryProperties().setProp("@rowTag",rowTag.get());
  10582. desc->queryProperties().setProp("@kind", (kind==TAKjsonwrite) ? "json" : "xml");
  10583. desc->queryProperties().setPropInt(FPheaderLength, headerLength);
  10584. desc->queryProperties().setPropInt(FPfooterLength, footerLength);
  10585. }
  10586. virtual bool isOutputTransformed() const { return true; }
  10587. };
  10588. class CRoxieServerDiskWriteActivityFactory : public CRoxieServerMultiOutputFactory
  10589. {
  10590. bool isRoot;
  10591. bool isTemp;
  10592. public:
  10593. CRoxieServerDiskWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _isRoot)
  10594. : CRoxieServerMultiOutputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode), isRoot(_isRoot)
  10595. {
  10596. Owned<IHThorDiskWriteArg> helper = (IHThorDiskWriteArg *) helperFactory();
  10597. isTemp = (helper->getFlags() & TDXtemporary) != 0;
  10598. setNumOutputs(helper->getTempUsageCount());
  10599. if (_kind!=TAKdiskwrite)
  10600. assertex(numOutputs == 0);
  10601. }
  10602. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  10603. {
  10604. switch (numOutputs)
  10605. {
  10606. case 0:
  10607. switch (kind)
  10608. {
  10609. case TAKdiskwrite: return new CRoxieServerDiskWriteActivity(_ctx, this, _probeManager);
  10610. case TAKcsvwrite: return new CRoxieServerCsvWriteActivity(_ctx, this, _probeManager);
  10611. case TAKxmlwrite:
  10612. case TAKjsonwrite:
  10613. return new CRoxieServerXmlWriteActivity(_ctx, this, _probeManager, kind);
  10614. };
  10615. throwUnexpected();
  10616. case 1:
  10617. return new CRoxieServerSpillWriteActivity(_ctx, this, _probeManager);
  10618. default:
  10619. return new CRoxieServerThroughSpillActivity(_ctx, this, _probeManager, numOutputs);
  10620. }
  10621. }
  10622. virtual bool isSink() const
  10623. {
  10624. return numOutputs == 0 && !isTemp; // MORE - check with Gavin if this is right if not a temp but reread in same job...
  10625. }
  10626. };
  10627. IRoxieServerActivityFactory *createRoxieServerDiskWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _isRoot)
  10628. {
  10629. return new CRoxieServerDiskWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _isRoot);
  10630. }
  10631. //=================================================================================
  10632. class CRoxieServerIndexWriteActivity : public CRoxieServerInternalSinkActivity, implements IRoxiePublishCallback
  10633. {
  10634. IHThorIndexWriteArg &helper;
  10635. bool overwrite;
  10636. Owned<ClusterWriteHandler> clusterHandler;
  10637. Owned<IRoxieWriteHandler> writer;
  10638. unsigned __int64 reccount;
  10639. unsigned int fileCrc;
  10640. StringBuffer filename;
  10641. void updateWorkUnitResult()
  10642. {
  10643. // MORE - a lot of this is common with hthor
  10644. WorkunitUpdate wu = ctx->updateWorkUnit();
  10645. if (wu)
  10646. {
  10647. OwnedRoxieString rawLogicalName = helper.getFileName();
  10648. StringBuffer lfn; // logical filename
  10649. expandLogicalFilename(lfn, rawLogicalName, wu, false, false);
  10650. if (lfn.length())
  10651. {
  10652. if (helper.getSequence() >= 0)
  10653. {
  10654. Owned<IWUResult> result = wu->updateResultBySequence(helper.getSequence());
  10655. if (result)
  10656. {
  10657. result->setResultTotalRowCount(reccount);
  10658. result->setResultStatus(ResultStatusCalculated);
  10659. result->setResultLogicalName(lfn.str());
  10660. }
  10661. }
  10662. if(clusterHandler)
  10663. clusterHandler->finish(writer->queryFile());
  10664. CTXLOG("Created roxie index file %s", lfn.str());
  10665. }
  10666. }
  10667. }
  10668. virtual void resolve()
  10669. {
  10670. StringArray clusters;
  10671. unsigned clusterIdx = 0;
  10672. while(true)
  10673. {
  10674. OwnedRoxieString cluster(helper.getCluster(clusterIdx));
  10675. if(!cluster)
  10676. break;
  10677. clusters.append(cluster);
  10678. clusterIdx++;
  10679. }
  10680. if (roxieName.length())
  10681. clusters.append(roxieName.str());
  10682. else
  10683. clusters.append(".");
  10684. OwnedRoxieString fname(helper.getFileName());
  10685. writer.setown(ctx->createLFN(fname, overwrite, false, clusters)); // MORE - if there's a workunit, use if for scope.
  10686. filename.set(writer->queryFile()->queryFilename());
  10687. if (writer->queryFile()->exists())
  10688. {
  10689. if (overwrite)
  10690. {
  10691. CTXLOG("Removing existing %s from DFS",filename.str());
  10692. writer->queryFile()->remove();
  10693. }
  10694. else
  10695. throw MakeStringException(99, "Cannot write index file %s, file already exists (missing OVERWRITE attribute?)", filename.str());
  10696. }
  10697. }
  10698. void buildUserMetadata(Owned<IPropertyTree> & metadata)
  10699. {
  10700. size32_t nameLen;
  10701. char * nameBuff;
  10702. size32_t valueLen;
  10703. char * valueBuff;
  10704. unsigned idx = 0;
  10705. while(helper.getIndexMeta(nameLen, nameBuff, valueLen, valueBuff, idx++))
  10706. {
  10707. StringBuffer name(nameLen, nameBuff);
  10708. StringBuffer value(valueLen, valueBuff);
  10709. if(*nameBuff == '_' && strcmp(name, "_nodeSize") != 0)
  10710. {
  10711. OwnedRoxieString fname(helper.getFileName());
  10712. throw MakeStringException(0, "Invalid name %s in user metadata for index %s (names beginning with underscore are reserved)", name.str(), fname.get());
  10713. }
  10714. if(!validateXMLTag(name.str()))
  10715. {
  10716. OwnedRoxieString fname(helper.getFileName());
  10717. throw MakeStringException(0, "Invalid name %s in user metadata for index %s (not legal XML element name)", name.str(), fname.get());
  10718. }
  10719. if(!metadata)
  10720. metadata.setown(createPTree("metadata", ipt_fast));
  10721. metadata->setProp(name.str(), value.str());
  10722. }
  10723. }
  10724. void buildLayoutMetadata(Owned<IPropertyTree> & metadata)
  10725. {
  10726. if(!metadata)
  10727. metadata.setown(createPTree("metadata", ipt_fast));
  10728. metadata->setProp("_record_ECL", helper.queryRecordECL());
  10729. if (helper.queryDiskRecordSize()->queryTypeInfo())
  10730. {
  10731. MemoryBuffer out;
  10732. dumpTypeInfo(out, helper.queryDiskRecordSize()->queryTypeInfo());
  10733. metadata->setPropBin("_rtlType", out.length(), out.toByteArray());
  10734. }
  10735. }
  10736. public:
  10737. CRoxieServerIndexWriteActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  10738. : CRoxieServerInternalSinkActivity(_ctx, _factory, _probeManager, 0), helper(static_cast<IHThorIndexWriteArg &>(basehelper))
  10739. {
  10740. overwrite = ((helper.getFlags() & TIWoverwrite) != 0);
  10741. reccount = 0;
  10742. fileCrc = 0;
  10743. }
  10744. ~CRoxieServerIndexWriteActivity()
  10745. {
  10746. }
  10747. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  10748. {
  10749. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  10750. resolve();
  10751. }
  10752. virtual void onExecute()
  10753. {
  10754. bool isVariable = helper.queryDiskRecordSize()->isVariableSize();
  10755. size32_t fileposSize = hasTrailingFileposition(helper.queryDiskRecordSize()->queryTypeInfo()) ? sizeof(offset_t) : 0;
  10756. size32_t maxDiskRecordSize;
  10757. if (isVariable)
  10758. {
  10759. if (helper.getFlags() & TIWmaxlength)
  10760. maxDiskRecordSize = helper.getMaxKeySize();
  10761. else
  10762. maxDiskRecordSize = KEYBUILD_MAXLENGTH; // Current default behaviour, could be improved in the future
  10763. }
  10764. else
  10765. maxDiskRecordSize = helper.queryDiskRecordSize()->getFixedSize()-fileposSize;
  10766. if (maxDiskRecordSize > KEYBUILD_MAXLENGTH)
  10767. throw MakeStringException(99, "Index maximum record length (%d) exceeds 32k internal limit", maxDiskRecordSize);
  10768. OwnedMalloc<char> rowBuffer(maxDiskRecordSize, true);
  10769. fileCrc = -1;
  10770. {
  10771. Owned<IFileIO> io;
  10772. try
  10773. {
  10774. io.setown(writer->queryFile()->open(IFOcreate));
  10775. }
  10776. catch(IException * e)
  10777. {
  10778. e->Release();
  10779. clearKeyStoreCache(false);
  10780. io.setown(writer->queryFile()->open(IFOcreate));
  10781. }
  10782. if(!io)
  10783. throw MakeStringException(errno, "Failed to create file %s for writing", filename.str());
  10784. Owned<IFileIOStream> out = createIOStream(io);
  10785. unsigned flags = COL_PREFIX | HTREE_FULLSORT_KEY;
  10786. if (helper.getFlags() & TIWrowcompress)
  10787. flags |= HTREE_COMPRESSED_KEY|HTREE_QUICK_COMPRESSED_KEY;
  10788. else if (!(helper.getFlags() & TIWnolzwcompress))
  10789. flags |= HTREE_COMPRESSED_KEY;
  10790. if (isVariable)
  10791. flags |= HTREE_VARSIZE;
  10792. Owned<IPropertyTree> metadata;
  10793. buildUserMetadata(metadata);
  10794. buildLayoutMetadata(metadata);
  10795. unsigned nodeSize = metadata ? metadata->getPropInt("_nodeSize", NODESIZE) : NODESIZE;
  10796. Owned<IKeyBuilder> builder = createKeyBuilder(out, flags, maxDiskRecordSize, nodeSize, helper.getKeyedSize(), 0);
  10797. class BcWrapper : implements IBlobCreator
  10798. {
  10799. IKeyBuilder *builder;
  10800. public:
  10801. BcWrapper(IKeyBuilder *_builder) : builder(_builder) {}
  10802. virtual unsigned __int64 createBlob(size32_t size, const void * ptr)
  10803. {
  10804. return builder->createBlob(size, (const char *) ptr);
  10805. }
  10806. } bc(builder);
  10807. // Loop thru the results
  10808. for (;;)
  10809. {
  10810. OwnedConstRoxieRow nextrec(inputStream->ungroupedNextRow());
  10811. if (!nextrec)
  10812. break;
  10813. try
  10814. {
  10815. unsigned __int64 fpos=0;
  10816. RtlStaticRowBuilder rowBuilder(rowBuffer, maxDiskRecordSize);
  10817. size32_t thisSize = helper.transform(rowBuilder, nextrec, &bc, fpos);
  10818. builder->processKeyData(rowBuffer, fpos, thisSize);
  10819. }
  10820. catch(IException * e)
  10821. {
  10822. throw makeWrappedException(e);
  10823. }
  10824. reccount++;
  10825. }
  10826. builder->finish(metadata, &fileCrc);
  10827. }
  10828. }
  10829. virtual void stop()
  10830. {
  10831. if (writer)
  10832. {
  10833. if (!aborted)
  10834. updateWorkUnitResult();
  10835. writer->finish(!aborted, this);
  10836. writer.clear();
  10837. }
  10838. CRoxieServerActivity::stop();
  10839. }
  10840. virtual void reset()
  10841. {
  10842. CRoxieServerActivity::reset();
  10843. writer.clear();
  10844. }
  10845. //interface IRoxiePublishCallback
  10846. virtual void setFileProperties(IFileDescriptor *desc) const
  10847. {
  10848. IPropertyTree &partProps = desc->queryPart(0)->queryProperties(); //properties of the first file part.
  10849. IPropertyTree &fileProps = desc->queryProperties(); // properties of the logical file
  10850. // Now publish to name services
  10851. StringBuffer dir,base;
  10852. offset_t indexFileSize = writer->queryFile()->size();
  10853. if(clusterHandler)
  10854. clusterHandler->splitPhysicalFilename(dir, base);
  10855. else
  10856. splitFilename(filename.str(), &dir, &dir, &base, &base);
  10857. desc->setDefaultDir(dir.str());
  10858. //properties of the first file part.
  10859. Owned<IPropertyTree> attrs;
  10860. if(clusterHandler)
  10861. attrs.setown(createPTree("Part", ipt_fast)); // clusterHandler is going to set attributes
  10862. else
  10863. {
  10864. // add cluster
  10865. StringBuffer mygroupname;
  10866. desc->setNumParts(1);
  10867. desc->setPartMask(base.str());
  10868. attrs.set(&desc->queryPart(0)->queryProperties());
  10869. }
  10870. attrs->setPropInt64("@size", indexFileSize);
  10871. CDateTime createTime, modifiedTime, accessedTime;
  10872. writer->queryFile()->getTime(&createTime, &modifiedTime, &accessedTime);
  10873. // round file time down to nearest sec. Nanosec accurancy is not preserved elsewhere and can lead to mismatch later.
  10874. unsigned hour, min, sec, nanosec;
  10875. modifiedTime.getTime(hour, min, sec, nanosec);
  10876. modifiedTime.setTime(hour, min, sec, 0);
  10877. StringBuffer timestr;
  10878. modifiedTime.getString(timestr);
  10879. if(timestr.length())
  10880. attrs->setProp("@modified", timestr.str());
  10881. if(clusterHandler)
  10882. clusterHandler->setDescriptorParts(desc, base.str(), attrs);
  10883. // properties of the logical file
  10884. IPropertyTree & properties = desc->queryProperties();
  10885. properties.setProp("@kind", "key");
  10886. properties.setPropInt64("@size", indexFileSize);
  10887. properties.setPropInt64("@recordCount", reccount);
  10888. WorkunitUpdate workUnit = ctx->updateWorkUnit();
  10889. if (workUnit)
  10890. {
  10891. properties.setProp("@owner", workUnit->queryUser());
  10892. properties.setProp("@workunit", workUnit->queryWuid());
  10893. properties.setProp("@job", workUnit->queryJobName());
  10894. }
  10895. char const * rececl = helper.queryRecordECL();
  10896. if(rececl && *rececl)
  10897. properties.setProp("ECL", rececl);
  10898. if (helper.getFlags() & TIWexpires)
  10899. setExpiryTime(properties, helper.getExpiryDays());
  10900. if (helper.getFlags() & TIWupdate)
  10901. {
  10902. unsigned eclCRC;
  10903. unsigned __int64 totalCRC;
  10904. helper.getUpdateCRCs(eclCRC, totalCRC);
  10905. properties.setPropInt("@eclCRC", eclCRC);
  10906. properties.setPropInt64("@totalCRC", totalCRC);
  10907. }
  10908. properties.setPropInt("@fileCrc", fileCrc);
  10909. properties.setPropInt("@formatCrc", helper.getFormatCrc());
  10910. // Legacy record layout info
  10911. void * layoutMetaBuff;
  10912. size32_t layoutMetaSize;
  10913. if(helper.getIndexLayout(layoutMetaSize, layoutMetaBuff))
  10914. {
  10915. properties.setPropBin("_record_layout", layoutMetaSize, layoutMetaBuff);
  10916. rtlFree(layoutMetaBuff);
  10917. }
  10918. // New record layout info
  10919. if (helper.queryDiskRecordSize()->queryTypeInfo())
  10920. {
  10921. MemoryBuffer out;
  10922. dumpTypeInfo(out, helper.queryDiskRecordSize()->queryTypeInfo());
  10923. properties.setPropBin("_rtlType", out.length(), out.toByteArray());
  10924. }
  10925. }
  10926. IUserDescriptor *queryUserDescriptor() const
  10927. {
  10928. IConstWorkUnit *workUnit = ctx->queryWorkUnit();
  10929. if (workUnit)
  10930. return workUnit->queryUserDescriptor();
  10931. else
  10932. return NULL;
  10933. }
  10934. };
  10935. //=================================================================================
  10936. class CRoxieServerIndexWriteActivityFactory : public CRoxieServerMultiOutputFactory
  10937. {
  10938. public:
  10939. CRoxieServerIndexWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _isRoot)
  10940. : CRoxieServerMultiOutputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  10941. {
  10942. setNumOutputs(0);
  10943. }
  10944. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  10945. {
  10946. return new CRoxieServerIndexWriteActivity(_ctx, this, _probeManager);
  10947. }
  10948. virtual bool isSink() const
  10949. {
  10950. return true;
  10951. }
  10952. };
  10953. IRoxieServerActivityFactory *createRoxieServerIndexWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _isRoot)
  10954. {
  10955. return new CRoxieServerIndexWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _isRoot);
  10956. }
  10957. //=================================================================================
  10958. static inline void getLimitType(unsigned flags, bool & limitFail, bool & limitOnFail)
  10959. {
  10960. if((flags & JFmatchAbortLimitSkips) != 0)
  10961. {
  10962. limitFail = false;
  10963. limitOnFail = false;
  10964. }
  10965. else
  10966. {
  10967. limitOnFail = ((flags & JFonfail) != 0);
  10968. limitFail = !limitOnFail;
  10969. }
  10970. }
  10971. class CRoxieServerJoinActivity : public CRoxieServerTwoInputActivity
  10972. {
  10973. enum { JSfill, JSfillleft, JSfillright, JScollate, JScompare, JSleftonly, JSrightonly } state;
  10974. IHThorJoinArg &helper;
  10975. ICompare * collate;
  10976. ICompare * collateupper;
  10977. ThorActivityKind activityKind;
  10978. bool leftOuterJoin;
  10979. bool rightOuterJoin;
  10980. bool exclude;
  10981. bool limitFail;
  10982. bool limitOnFail;
  10983. bool forceSpill;
  10984. unsigned keepLimit;
  10985. unsigned joinLimit;
  10986. unsigned atmostLimit;
  10987. unsigned abortLimit;
  10988. unsigned atmostsTriggered;
  10989. bool betweenjoin;
  10990. OwnedRowArray right;
  10991. const void * left;
  10992. const void * pendingRight;
  10993. unsigned rightIndex;
  10994. unsigned joinCounter;
  10995. BoolArray matchedRight;
  10996. bool matchedLeft;
  10997. Owned<IException> failingLimit;
  10998. ConstPointerArray filteredRight;
  10999. Owned<IRHLimitedCompareHelper> limitedhelper;
  11000. OwnedConstRoxieRow defaultLeft;
  11001. OwnedConstRoxieRow defaultRight;
  11002. Owned<IEngineRowAllocator> defaultLeftAllocator;
  11003. Owned<IEngineRowAllocator> defaultRightAllocator;
  11004. Owned<IGroupedInput> sortedLeft;
  11005. Owned<IGroupedInput> groupedSortedRight;
  11006. bool cloneLeft;
  11007. void createDefaultLeft()
  11008. {
  11009. if (!defaultLeft)
  11010. {
  11011. if (!defaultLeftAllocator)
  11012. defaultLeftAllocator.setown(createRowAllocator(input->queryOutputMeta()));
  11013. RtlDynamicRowBuilder rowBuilder(defaultLeftAllocator);
  11014. size32_t thisSize = helper.createDefaultLeft(rowBuilder);
  11015. defaultLeft.setown(rowBuilder.finalizeRowClear(thisSize));
  11016. }
  11017. }
  11018. void createDefaultRight()
  11019. {
  11020. if (!defaultRight)
  11021. {
  11022. if (!defaultRightAllocator)
  11023. defaultRightAllocator.setown(createRowAllocator(input1->queryOutputMeta()));
  11024. RtlDynamicRowBuilder rowBuilder(defaultRightAllocator);
  11025. size32_t thisSize = helper.createDefaultRight(rowBuilder);
  11026. defaultRight.setown(rowBuilder.finalizeRowClear(thisSize));
  11027. }
  11028. }
  11029. public:
  11030. CRoxieServerJoinActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _forceSpill)
  11031. : CRoxieServerTwoInputActivity(_ctx, _factory, _probeManager), helper((IHThorJoinArg &)basehelper), forceSpill(_forceSpill)
  11032. {
  11033. // MORE - some of this should be done in factory
  11034. unsigned joinFlags = helper.getJoinFlags();
  11035. leftOuterJoin = (joinFlags & JFleftouter) != 0;
  11036. rightOuterJoin = (joinFlags & JFrightouter) != 0;
  11037. exclude = (joinFlags & JFexclude) != 0;
  11038. cloneLeft = (joinFlags & JFtransformmatchesleft) != 0;
  11039. getLimitType(joinFlags, limitFail, limitOnFail);
  11040. if (joinFlags & JFslidingmatch)
  11041. {
  11042. betweenjoin = true;
  11043. collate = helper.queryCompareLeftRightLower();
  11044. collateupper = helper.queryCompareLeftRightUpper();
  11045. }
  11046. else
  11047. {
  11048. betweenjoin = false;
  11049. collate = collateupper = helper.queryCompareLeftRight();
  11050. }
  11051. rightIndex = 0;
  11052. joinCounter = 0;
  11053. state = JSfill;
  11054. matchedLeft = false;
  11055. joinLimit = 0;
  11056. keepLimit = 0; // wait until ctx available
  11057. atmostLimit = 0; // wait until ctx available
  11058. abortLimit = 0; // wait until ctx available
  11059. atmostsTriggered = 0;
  11060. assertex((joinFlags & (JFfirst | JFfirstleft | JFfirstright)) == 0);
  11061. left = NULL;
  11062. pendingRight = NULL;
  11063. activityKind = _factory->getKind();
  11064. }
  11065. virtual bool needsAllocator() const { return true; }
  11066. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  11067. {
  11068. left = NULL;
  11069. rightIndex = 0;
  11070. joinCounter = 0;
  11071. state = JSfill;
  11072. matchedLeft = false;
  11073. CRoxieServerTwoInputActivity::start(parentExtractSize, parentExtract, paused);
  11074. keepLimit = helper.getKeepLimit();
  11075. if (keepLimit == 0)
  11076. keepLimit = (unsigned)-1;
  11077. atmostsTriggered = 0;
  11078. atmostLimit = helper.getJoinLimit();
  11079. if(atmostLimit == 0)
  11080. atmostLimit = (unsigned)-1;
  11081. else
  11082. assertex(!rightOuterJoin && !betweenjoin);
  11083. abortLimit = helper.getMatchAbortLimit();
  11084. if (abortLimit == 0)
  11085. abortLimit = (unsigned)-1;
  11086. if (rightOuterJoin)
  11087. createDefaultLeft();
  11088. if ((leftOuterJoin && (activityKind==TAKjoin || activityKind==TAKjoinlight || activityKind==TAKdenormalizegroup)) || limitOnFail)
  11089. createDefaultRight();
  11090. bool isStable = (helper.getJoinFlags() & JFunstable) == 0;
  11091. RoxieSortAlgorithm sortAlgorithm;
  11092. if (forceSpill)
  11093. sortAlgorithm = isStable ? stableSpillingQuickSortAlgorithm : spillingQuickSortAlgorithm;
  11094. else
  11095. sortAlgorithm = isStable ? stableQuickSortAlgorithm : quickSortAlgorithm;
  11096. if (helper.isLeftAlreadySorted())
  11097. sortedLeft.setown(createDegroupedInputReader(inputStream));
  11098. else
  11099. sortedLeft.setown(createSortedInputReader(inputStream, createSortAlgorithm(sortAlgorithm, helper.queryCompareLeft(), ctx->queryRowManager(), input->queryOutputMeta(), ctx->queryCodeContext(), tempDirectory, activityId)));
  11100. ICompare *compareRight = helper.queryCompareRight();
  11101. if (helper.isRightAlreadySorted())
  11102. groupedSortedRight.setown(createGroupedInputReader(inputStream1, compareRight));
  11103. else
  11104. groupedSortedRight.setown(createSortedGroupedInputReader(inputStream1, compareRight, createSortAlgorithm(sortAlgorithm, compareRight, ctx->queryRowManager(), input1->queryOutputMeta(), ctx->queryCodeContext(), tempDirectory, activityId)));
  11105. if ((helper.getJoinFlags() & JFlimitedprefixjoin) && helper.getJoinLimit())
  11106. { //limited match join (s[1..n])
  11107. limitedhelper.setown(createRHLimitedCompareHelper());
  11108. limitedhelper->init( helper.getJoinLimit(), groupedSortedRight, collate, helper.queryPrefixCompare() );
  11109. }
  11110. }
  11111. virtual void reset()
  11112. {
  11113. if (atmostsTriggered)
  11114. noteStatistic(StNumAtmostTriggered, atmostsTriggered);
  11115. right.clear();
  11116. ReleaseClearRoxieRow(left);
  11117. ReleaseClearRoxieRow(pendingRight);
  11118. defaultRight.clear();
  11119. defaultLeft.clear();
  11120. sortedLeft.clear();
  11121. groupedSortedRight.clear();
  11122. CRoxieServerTwoInputActivity::reset();
  11123. }
  11124. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  11125. {
  11126. if (!idx && (helper.getJoinFlags() & JFparallel) != 0)
  11127. {
  11128. puller.setown(new CRoxieServerReadAheadInput(ctx, ctx->queryOptions().parallelJoinPreload));
  11129. puller->setInput(0, _sourceIdx, _in);
  11130. _in = puller;
  11131. _sourceIdx = 0;
  11132. }
  11133. CRoxieServerTwoInputActivity::setInput(idx, _sourceIdx, _in);
  11134. }
  11135. virtual IFinalRoxieInput *queryOutput(unsigned idx)
  11136. {
  11137. if (idx==(unsigned)-1)
  11138. idx = 0;
  11139. return idx ? NULL : this;
  11140. }
  11141. void fillLeft()
  11142. {
  11143. matchedLeft = false;
  11144. left = sortedLeft->nextRow(); // NOTE: already degrouped by the IGroupedInput we attached
  11145. if (betweenjoin && left && pendingRight && (collate->docompare(left, pendingRight) >= 0))
  11146. fillRight();
  11147. if (limitedhelper && 0==rightIndex)
  11148. {
  11149. rightIndex = 0;
  11150. joinCounter = 0;
  11151. right.clear();
  11152. matchedRight.kill();
  11153. if (left)
  11154. {
  11155. limitedhelper->getGroup(right,left);
  11156. ForEachItemIn(idx, right)
  11157. matchedRight.append(false);
  11158. }
  11159. }
  11160. }
  11161. void fillRight()
  11162. {
  11163. if (limitedhelper)
  11164. return;
  11165. failingLimit.clear();
  11166. if(betweenjoin && left)
  11167. {
  11168. aindex_t start = 0;
  11169. while(right.isItem(start) && (collateupper->docompare(left, right.item(start)) > 0))
  11170. start++;
  11171. if(start>0)
  11172. right.clearPart(0, start);
  11173. }
  11174. else
  11175. right.clear();
  11176. rightIndex = 0;
  11177. joinCounter = 0;
  11178. unsigned groupCount = 0;
  11179. const void * next;
  11180. while(true)
  11181. {
  11182. if(pendingRight)
  11183. {
  11184. next = pendingRight;
  11185. pendingRight = NULL;
  11186. }
  11187. else
  11188. {
  11189. next = groupedSortedRight->nextRow();
  11190. }
  11191. if(!rightOuterJoin && next && (!left || (collateupper->docompare(left, next) > 0))) // if right is less than left, and not right outer, can skip group
  11192. {
  11193. while(next)
  11194. {
  11195. ReleaseClearRoxieRow(next);
  11196. next = groupedSortedRight->nextRow();
  11197. }
  11198. continue;
  11199. }
  11200. while(next)
  11201. {
  11202. if(groupCount==abortLimit)
  11203. {
  11204. if(limitFail)
  11205. failLimit();
  11206. if (ctx->queryDebugContext())
  11207. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  11208. if(limitOnFail)
  11209. {
  11210. assertex(!failingLimit);
  11211. try
  11212. {
  11213. failLimit();
  11214. }
  11215. catch(IException * except)
  11216. {
  11217. failingLimit.setown(except);
  11218. }
  11219. assertex(failingLimit != NULL);
  11220. }
  11221. right.append(next);
  11222. do
  11223. {
  11224. next = groupedSortedRight->nextRow();
  11225. ReleaseRoxieRow(next);
  11226. } while(next);
  11227. break;
  11228. }
  11229. else if(groupCount==atmostLimit)
  11230. {
  11231. atmostsTriggered++;
  11232. right.clear();
  11233. groupCount = 0;
  11234. while(next)
  11235. {
  11236. ReleaseRoxieRow(next);
  11237. next = groupedSortedRight->nextRow();
  11238. }
  11239. }
  11240. else
  11241. {
  11242. right.append(next);
  11243. groupCount++;
  11244. }
  11245. next = groupedSortedRight->nextRow();
  11246. }
  11247. // 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
  11248. if(betweenjoin && left)
  11249. {
  11250. pendingRight = groupedSortedRight->nextRow();
  11251. if(!pendingRight || (collate->docompare(left, pendingRight) < 0))
  11252. break;
  11253. }
  11254. else
  11255. break;
  11256. }
  11257. matchedRight.kill();
  11258. ForEachItemIn(idx, right)
  11259. matchedRight.append(false);
  11260. }
  11261. const void * joinRecords(const void * curLeft, const void * curRight, unsigned counter, unsigned flags)
  11262. {
  11263. if (cloneLeft)
  11264. {
  11265. LinkRoxieRow(curLeft);
  11266. return curLeft;
  11267. }
  11268. try
  11269. {
  11270. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  11271. size32_t thisSize = helper.transform(rowBuilder, curLeft, curRight, counter, flags);
  11272. if (thisSize)
  11273. return rowBuilder.finalizeRowClear(thisSize);
  11274. else
  11275. return NULL;
  11276. }
  11277. catch (IException *E)
  11278. {
  11279. throw makeWrappedException(E);
  11280. }
  11281. }
  11282. const void * denormalizeRecords(const void * curLeft, ConstPointerArray & rows, unsigned flags)
  11283. {
  11284. try
  11285. {
  11286. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  11287. unsigned numRows = rows.ordinality();
  11288. const void * right = numRows ? rows.item(0) : defaultRight.get();
  11289. if (numRows>0)
  11290. flags |= JTFmatchedright;
  11291. size32_t thisSize = helper.transform(rowBuilder, curLeft, right, numRows, (const void * *)rows.getArray(), flags);
  11292. if (thisSize)
  11293. return rowBuilder.finalizeRowClear(thisSize);
  11294. else
  11295. return NULL;
  11296. }
  11297. catch (IException *E)
  11298. {
  11299. throw makeWrappedException(E);
  11300. }
  11301. }
  11302. const void * joinException(const void * curLeft, IException * except)
  11303. {
  11304. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  11305. size32_t thisSize = helper.onFailTransform(rowBuilder, curLeft, defaultRight, except, JTFmatchedleft);
  11306. return rowBuilder.finalizeRowClear(thisSize);
  11307. }
  11308. void failLimit()
  11309. {
  11310. helper.onMatchAbortLimitExceeded();
  11311. CommonXmlWriter xmlwrite(0);
  11312. if (input->queryOutputMeta() && input->queryOutputMeta()->hasXML())
  11313. {
  11314. input->queryOutputMeta()->toXML((byte *) left, xmlwrite);
  11315. }
  11316. throw MakeStringException(ROXIE_TOO_MANY_RESULTS, "More than %d match candidates in join %d for row %s", abortLimit, queryId(), xmlwrite.str());
  11317. }
  11318. virtual const void * nextRow()
  11319. {
  11320. ActivityTimer t(totalCycles, timeActivities);
  11321. for (;;)
  11322. {
  11323. switch (state)
  11324. {
  11325. case JSfill:
  11326. fillLeft();
  11327. state = JSfillright;
  11328. break;
  11329. case JSfillright:
  11330. fillRight();
  11331. state = JScollate;
  11332. break;
  11333. case JSfillleft:
  11334. fillLeft();
  11335. state = JScollate;
  11336. break;
  11337. case JScollate:
  11338. if (right.ordinality() == 0)
  11339. {
  11340. if (left == NULL)
  11341. return NULL;
  11342. state = JSleftonly;
  11343. }
  11344. else
  11345. {
  11346. if (!left)
  11347. state = JSrightonly;
  11348. else
  11349. {
  11350. int diff;
  11351. if(betweenjoin)
  11352. diff = ((collate->docompare(left, right.item(0)) < 0) ? -1 : ((collateupper->docompare(left, right.item(right.ordinality()-1)) > 0) ? +1 : 0));
  11353. else
  11354. diff = collate->docompare(left, right.item(0));
  11355. bool limitExceeded = right.ordinality()>abortLimit;
  11356. if (diff == 0)
  11357. {
  11358. if (limitExceeded)
  11359. {
  11360. const void * ret = NULL;
  11361. if(failingLimit)
  11362. ret = joinException(left, failingLimit);
  11363. ReleaseRoxieRow(left);
  11364. left = NULL;
  11365. state = JSfillleft;
  11366. ForEachItemIn(idx, right)
  11367. matchedRight.replace(true, idx);
  11368. if(ret)
  11369. {
  11370. processed++;
  11371. return ret;
  11372. }
  11373. }
  11374. else
  11375. {
  11376. state = JScompare;
  11377. joinLimit = keepLimit;
  11378. }
  11379. }
  11380. else if (diff < 0)
  11381. state = JSleftonly;
  11382. else if (limitExceeded)
  11383. {
  11384. // MORE - Roxie code seems to think there should be a destroyRowset(right) here....
  11385. state = JSfillright;
  11386. }
  11387. else
  11388. state = JSrightonly;
  11389. }
  11390. }
  11391. break;
  11392. case JSrightonly:
  11393. if (rightOuterJoin)
  11394. {
  11395. switch (activityKind)
  11396. {
  11397. case TAKjoin:
  11398. {
  11399. while (right.isItem(rightIndex))
  11400. {
  11401. if (!matchedRight.item(rightIndex))
  11402. {
  11403. const void * rhs = right.item(rightIndex++);
  11404. const void *ret = joinRecords(defaultLeft, rhs, 0, JTFmatchedright);
  11405. if (ret)
  11406. {
  11407. processed++;
  11408. return ret;
  11409. }
  11410. }
  11411. else
  11412. rightIndex++;
  11413. }
  11414. break;
  11415. }
  11416. //Probably excessive to implement the following, but possibly useful
  11417. case TAKdenormalize:
  11418. {
  11419. OwnedConstRoxieRow newLeft;
  11420. newLeft.set(defaultLeft);
  11421. unsigned rowSize = 0;
  11422. unsigned leftCount = 0;
  11423. while (right.isItem(rightIndex))
  11424. {
  11425. if (!matchedRight.item(rightIndex))
  11426. {
  11427. const void * rhs = right.item(rightIndex);
  11428. try
  11429. {
  11430. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  11431. unsigned thisSize = helper.transform(rowBuilder, newLeft, rhs, ++leftCount, JTFmatchedright);
  11432. if (thisSize)
  11433. {
  11434. rowSize = thisSize;
  11435. newLeft.setown(rowBuilder.finalizeRowClear(rowSize));
  11436. }
  11437. }
  11438. catch (IException *E)
  11439. {
  11440. throw makeWrappedException(E);
  11441. }
  11442. }
  11443. rightIndex++;
  11444. }
  11445. state = JSfillright;
  11446. if (rowSize)
  11447. {
  11448. processed++;
  11449. return newLeft.getClear();
  11450. }
  11451. break;
  11452. }
  11453. case TAKdenormalizegroup:
  11454. {
  11455. filteredRight.kill();
  11456. while (right.isItem(rightIndex))
  11457. {
  11458. if (!matchedRight.item(rightIndex))
  11459. filteredRight.append(right.item(rightIndex));
  11460. rightIndex++;
  11461. }
  11462. state = JSfillright;
  11463. if (filteredRight.ordinality())
  11464. {
  11465. const void * ret = denormalizeRecords(defaultLeft, filteredRight, 0);
  11466. filteredRight.kill();
  11467. if (ret)
  11468. {
  11469. processed++;
  11470. return ret;
  11471. }
  11472. }
  11473. break;
  11474. }
  11475. }
  11476. }
  11477. state = JSfillright;
  11478. break;
  11479. case JSleftonly:
  11480. {
  11481. const void * ret = NULL;
  11482. if (!matchedLeft && leftOuterJoin)
  11483. {
  11484. switch (activityKind)
  11485. {
  11486. case TAKjoin:
  11487. ret = joinRecords(left, defaultRight, 0, JTFmatchedleft);
  11488. break;
  11489. case TAKdenormalize:
  11490. ret = left;
  11491. left = NULL;
  11492. break;
  11493. case TAKdenormalizegroup:
  11494. filteredRight.kill();
  11495. ret = denormalizeRecords(left, filteredRight, JTFmatchedleft);
  11496. break;
  11497. }
  11498. }
  11499. ReleaseRoxieRow(left);
  11500. left = NULL;
  11501. state = JSfillleft;
  11502. if (ret)
  11503. {
  11504. processed++;
  11505. return ret;
  11506. }
  11507. break;
  11508. }
  11509. case JScompare:
  11510. if (joinLimit != 0)
  11511. {
  11512. switch (activityKind)
  11513. {
  11514. case TAKjoin:
  11515. {
  11516. while (right.isItem(rightIndex))
  11517. {
  11518. const void * rhs = right.item(rightIndex++);
  11519. if (helper.match(left, rhs))
  11520. {
  11521. matchedRight.replace(true, rightIndex-1);
  11522. matchedLeft = true;
  11523. if (!exclude)
  11524. {
  11525. const void *ret = joinRecords(left, rhs, ++joinCounter, JTFmatchedleft|JTFmatchedright);
  11526. if (ret)
  11527. {
  11528. processed++;
  11529. joinLimit--;
  11530. return ret;
  11531. }
  11532. }
  11533. }
  11534. }
  11535. break;
  11536. }
  11537. case TAKdenormalize:
  11538. {
  11539. OwnedConstRoxieRow newLeft;
  11540. newLeft.set(left);
  11541. unsigned rowSize = 0;
  11542. unsigned leftCount = 0;
  11543. while (right.isItem(rightIndex) && joinLimit)
  11544. {
  11545. try
  11546. {
  11547. const void * rhs = right.item(rightIndex++);
  11548. if (helper.match(left, rhs))
  11549. {
  11550. matchedRight.replace(true, rightIndex-1);
  11551. matchedLeft = true;
  11552. if (!exclude)
  11553. {
  11554. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  11555. unsigned thisSize = helper.transform(rowBuilder, newLeft, rhs, ++leftCount, JTFmatchedleft|JTFmatchedright);
  11556. if (thisSize)
  11557. {
  11558. rowSize = thisSize;
  11559. newLeft.setown(rowBuilder.finalizeRowClear(rowSize));
  11560. joinLimit--;
  11561. }
  11562. }
  11563. }
  11564. }
  11565. catch (IException *E)
  11566. {
  11567. throw makeWrappedException(E);
  11568. }
  11569. }
  11570. state = JSleftonly;
  11571. rightIndex = 0;
  11572. if (rowSize)
  11573. {
  11574. processed++;
  11575. return newLeft.getClear();
  11576. }
  11577. break;
  11578. }
  11579. case TAKdenormalizegroup:
  11580. {
  11581. filteredRight.kill();
  11582. while (right.isItem(rightIndex))
  11583. {
  11584. const void * rhs = right.item(rightIndex++);
  11585. if (helper.match(left, rhs))
  11586. {
  11587. matchedRight.replace(true, rightIndex-1);
  11588. filteredRight.append(rhs);
  11589. matchedLeft = true;
  11590. if (filteredRight.ordinality()==joinLimit)
  11591. break;
  11592. }
  11593. }
  11594. state = JSleftonly;
  11595. rightIndex = 0;
  11596. if (!exclude && filteredRight.ordinality())
  11597. {
  11598. const void * ret = denormalizeRecords(left, filteredRight, JTFmatchedleft);
  11599. filteredRight.kill();
  11600. if (ret)
  11601. {
  11602. processed++;
  11603. return ret;
  11604. }
  11605. }
  11606. break;
  11607. }
  11608. }
  11609. }
  11610. state = JSleftonly;
  11611. rightIndex = 0;
  11612. joinCounter = 0;
  11613. break;
  11614. }
  11615. }
  11616. }
  11617. };
  11618. class CRoxieServerJoinActivityFactory : public CRoxieServerActivityFactory
  11619. {
  11620. unsigned input2;
  11621. unsigned input2idx;
  11622. bool forceSpill;
  11623. public:
  11624. CRoxieServerJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  11625. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  11626. {
  11627. forceSpill = _graphNode.getPropBool("hint[@name='spill']/@value", _queryFactory.queryOptions().allSortsMaySpill);
  11628. input2 = 0;
  11629. input2idx = 0;
  11630. }
  11631. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  11632. {
  11633. return new CRoxieServerJoinActivity(_ctx, this, _probeManager, forceSpill);
  11634. }
  11635. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  11636. {
  11637. if (idx==1)
  11638. {
  11639. input2 = source;
  11640. input2idx = sourceidx;
  11641. }
  11642. else
  11643. CRoxieServerActivityFactory::setInput(idx, source, sourceidx);
  11644. }
  11645. virtual unsigned getInput(unsigned idx, unsigned &sourceidx) const
  11646. {
  11647. switch (idx)
  11648. {
  11649. case 1:
  11650. sourceidx = input2idx;
  11651. return input2;
  11652. case 0:
  11653. return CRoxieServerActivityFactory::getInput(idx, sourceidx);
  11654. default:
  11655. return (unsigned) -1;
  11656. }
  11657. }
  11658. virtual unsigned numInputs() const { return 2; }
  11659. virtual const StatisticsMapping &queryStatsMapping() const
  11660. {
  11661. return joinStatistics;
  11662. }
  11663. };
  11664. IRoxieServerActivityFactory *createRoxieServerJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  11665. {
  11666. return new CRoxieServerJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  11667. }
  11668. //=================================================================================
  11669. #define CONCAT_READAHEAD 1000
  11670. class CRoxieThreadedConcatReader : implements IRecordPullerCallback, public CInterface
  11671. {
  11672. public:
  11673. IMPLEMENT_IINTERFACE;
  11674. CRoxieThreadedConcatReader(InterruptableSemaphore &_ready, bool _grouped)
  11675. : puller(false), grouped(_grouped), atEog(true), ready(_ready), eof(false)
  11676. {
  11677. }
  11678. void start(unsigned parentExtractSize, const byte *parentExtract, bool paused, IRoxieSlaveContext *ctx)
  11679. {
  11680. space.reinit(CONCAT_READAHEAD);
  11681. puller.start(parentExtractSize, parentExtract, paused, ctx->queryOptions().concatPreload, false, ctx);
  11682. }
  11683. void stop()
  11684. {
  11685. space.interrupt();
  11686. puller.stop();
  11687. }
  11688. IFinalRoxieInput *queryInput() const
  11689. {
  11690. return puller.queryInput();
  11691. }
  11692. void reset()
  11693. {
  11694. puller.reset();
  11695. ForEachItemIn(idx, buffer)
  11696. ReleaseRoxieRow(buffer.item(idx));
  11697. buffer.clear();
  11698. eof = false;
  11699. atEog = true;
  11700. }
  11701. void setInput(unsigned _sourceIdx, IFinalRoxieInput *_in)
  11702. {
  11703. puller.setInput(this, _sourceIdx, _in);
  11704. }
  11705. void connectInputStreams(IRoxieSlaveContext *ctx, bool consumerOrdered)
  11706. {
  11707. puller.connectInputStreams(ctx, consumerOrdered);
  11708. }
  11709. virtual void processRow(const void *row)
  11710. {
  11711. buffer.enqueue(row);
  11712. ready.signal();
  11713. space.wait();
  11714. }
  11715. virtual void processGroup(const ConstPointerArray &rows)
  11716. {
  11717. // We use record-by-record input mode of the puller thread even in grouped mode.
  11718. throwUnexpected();
  11719. }
  11720. virtual void processEOG()
  11721. {
  11722. if (grouped)
  11723. processRow(NULL);
  11724. }
  11725. virtual void processDone()
  11726. {
  11727. processRow(NULL);
  11728. }
  11729. virtual bool fireException(IException *e)
  11730. {
  11731. // called from puller thread on failure
  11732. ready.interrupt(LINK(e));
  11733. space.interrupt(e);
  11734. return true;
  11735. }
  11736. bool peek(const void * &row, bool &anyActive)
  11737. {
  11738. if (!eof)
  11739. {
  11740. if (buffer.ordinality())
  11741. {
  11742. space.signal();
  11743. row = buffer.dequeue();
  11744. if (row==NULL)
  11745. {
  11746. if (atEog)
  11747. {
  11748. eof = true;
  11749. return false;
  11750. }
  11751. else
  11752. atEog = true;
  11753. }
  11754. else if (grouped)
  11755. atEog = false;
  11756. return true;
  11757. }
  11758. anyActive = true;
  11759. }
  11760. return false;
  11761. }
  11762. protected:
  11763. RecordPullerThread puller;
  11764. InterruptableSemaphore space;
  11765. InterruptableSemaphore &ready;
  11766. SafeQueueOf<const void, true> buffer;
  11767. bool atEog;
  11768. bool eof;
  11769. bool grouped;
  11770. };
  11771. typedef CopyReferenceArrayOf<CRoxieThreadedConcatReader> ReaderArray;
  11772. class CRoxieServerThreadedConcatActivity : public CRoxieServerActivity
  11773. {
  11774. InterruptableSemaphore ready;
  11775. ReaderArray pullers;
  11776. unsigned numInputs;
  11777. unsigned nextPuller; // for round robin
  11778. unsigned readyPending;
  11779. bool eof;
  11780. bool inGroup;
  11781. bool grouped;
  11782. public:
  11783. CRoxieServerThreadedConcatActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _grouped, unsigned _numInputs)
  11784. : CRoxieServerActivity(_ctx, _factory, _probeManager), grouped(_grouped)
  11785. {
  11786. numInputs = _numInputs;
  11787. eof = (numInputs==0);
  11788. inGroup = false;
  11789. nextPuller = 0;
  11790. readyPending = 0;
  11791. for (unsigned i = 0; i < numInputs; i++)
  11792. pullers.append(*new CRoxieThreadedConcatReader(ready, _grouped));
  11793. }
  11794. ~CRoxieServerThreadedConcatActivity()
  11795. {
  11796. ForEachItemIn(idx, pullers)
  11797. delete &pullers.item(idx);
  11798. }
  11799. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  11800. {
  11801. eof = (numInputs==0);
  11802. inGroup = false;
  11803. nextPuller = 0;
  11804. readyPending = 0;
  11805. ready.reinit();
  11806. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  11807. ForEachItemIn(idx, pullers)
  11808. {
  11809. pullers.item(idx).start(parentExtractSize, parentExtract, paused, ctx);
  11810. // NOTE - it is ok to start the thread running while parts of the subgraph are still being started, since everything
  11811. // in the part of the subgraph that the thread uses has been started.
  11812. // Note that splitters are supposed to cope with being used when only some outputs have been started.
  11813. }
  11814. }
  11815. virtual void stop()
  11816. {
  11817. ready.interrupt();
  11818. ForEachItemIn(idx, pullers)
  11819. pullers.item(idx).stop();
  11820. CRoxieServerActivity::stop();
  11821. }
  11822. virtual unsigned __int64 queryLocalCycles() const
  11823. {
  11824. return 0;
  11825. }
  11826. virtual IFinalRoxieInput *queryInput(unsigned idx) const
  11827. {
  11828. if (pullers.isItem(idx))
  11829. return pullers.item(idx).queryInput();
  11830. else
  11831. return NULL;
  11832. }
  11833. virtual void reset()
  11834. {
  11835. CRoxieServerActivity::reset();
  11836. ForEachItemIn(idx, pullers)
  11837. pullers.item(idx).reset();
  11838. eof = false;
  11839. inGroup = false;
  11840. nextPuller = 0;
  11841. readyPending = 0;
  11842. }
  11843. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  11844. {
  11845. if (pullers.isItem(idx))
  11846. pullers.item(idx).setInput(_sourceIdx, _in);
  11847. else
  11848. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", sanitizeSourceFile(__FILE__), __LINE__);
  11849. }
  11850. virtual IStrandJunction *getOutputStreams(IRoxieSlaveContext *ctx, unsigned idx, PointerArrayOf<IEngineRowStream> &streams, const StrandOptions * consumerOptions, bool consumerOrdered, IOrderedCallbackCollection * orderedCallbacks)
  11851. {
  11852. ForEachItemIn(i, pullers)
  11853. pullers.item(i).connectInputStreams(ctx, consumerOrdered);
  11854. return CRoxieServerActivity::getOutputStreams(ctx, idx, streams, nullptr, consumerOrdered, nullptr); // No input actually connected
  11855. }
  11856. virtual const void * nextRow()
  11857. {
  11858. ActivityTimer t(totalCycles, timeActivities);
  11859. if (eof)
  11860. return NULL;
  11861. for (;;)
  11862. {
  11863. if (readyPending && !inGroup)
  11864. {
  11865. if (readyPending > 1)
  11866. ready.signal(readyPending-1);
  11867. readyPending = 0;
  11868. }
  11869. else
  11870. ready.wait();
  11871. bool anyActive = false;
  11872. ForEachItemIn(unused_index, pullers)
  11873. {
  11874. // NOTE - we round robin not just because it's more efficient, but because it ensures the preservation of grouping information
  11875. const void *ret;
  11876. bool fetched = pullers.item(nextPuller).peek(ret, anyActive);
  11877. if (fetched)
  11878. {
  11879. inGroup = (ret != NULL);
  11880. return ret;
  11881. }
  11882. if (inGroup && grouped)
  11883. {
  11884. // Some other puller has data, but we can't consume it until the group we are reading is complete.
  11885. readyPending++;
  11886. anyActive = true;
  11887. break;
  11888. }
  11889. nextPuller++;
  11890. if (nextPuller==pullers.ordinality())
  11891. nextPuller = 0;
  11892. }
  11893. if (!anyActive)
  11894. break;
  11895. // A ready signal without anything being ready means someone reached end-of-file.
  11896. }
  11897. eof = true;
  11898. return NULL;
  11899. }
  11900. };
  11901. class CRoxieServerOrderedConcatActivity : public CRoxieServerMultiInputActivity
  11902. {
  11903. IEngineRowStream *curStream;
  11904. bool eogSeen;
  11905. bool anyThisGroup;
  11906. bool grouped;
  11907. unsigned streamIdx;
  11908. public:
  11909. CRoxieServerOrderedConcatActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _grouped, unsigned _numInputs)
  11910. : CRoxieServerMultiInputActivity(_ctx, _factory, _probeManager, _numInputs)
  11911. {
  11912. eogSeen = false;
  11913. anyThisGroup = false;
  11914. grouped = _grouped;
  11915. streamIdx = 0;
  11916. curStream = NULL;
  11917. }
  11918. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  11919. {
  11920. CRoxieServerMultiInputActivity::start(parentExtractSize, parentExtract, paused);
  11921. streamIdx = 0;
  11922. curStream = streamArray[streamIdx];
  11923. eogSeen = false;
  11924. anyThisGroup = false;
  11925. }
  11926. virtual const void * nextRow()
  11927. {
  11928. ActivityTimer t(totalCycles, timeActivities);
  11929. if (!curStream)
  11930. return NULL; // eof
  11931. const void * next = curStream->nextRow();
  11932. if (next)
  11933. {
  11934. anyThisGroup = true;
  11935. eogSeen = false;
  11936. processed++;
  11937. return next;
  11938. }
  11939. else if (!eogSeen)
  11940. {
  11941. eogSeen = true;
  11942. if (grouped)
  11943. {
  11944. if (anyThisGroup)
  11945. {
  11946. anyThisGroup = false;
  11947. return NULL;
  11948. }
  11949. else
  11950. return nextRow();
  11951. }
  11952. else
  11953. return nextRow();
  11954. }
  11955. else if (streamIdx < numStreams-1)
  11956. {
  11957. streamIdx++;
  11958. curStream = streamArray[streamIdx];
  11959. eogSeen = false;
  11960. return nextRow();
  11961. }
  11962. else
  11963. {
  11964. curStream = NULL;
  11965. return NULL;
  11966. }
  11967. }
  11968. };
  11969. class CRoxieServerConcatActivityFactory : public CRoxieServerMultiInputFactory
  11970. {
  11971. bool ordered;
  11972. bool grouped;
  11973. public:
  11974. CRoxieServerConcatActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  11975. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  11976. {
  11977. Owned <IHThorFunnelArg> helper = (IHThorFunnelArg *) helperFactory();
  11978. ordered = helper->isOrdered();
  11979. grouped = helper->queryOutputMeta()->isGrouped();
  11980. }
  11981. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  11982. {
  11983. if (ordered || (_probeManager && _probeManager->queryDebugManager()))
  11984. return new CRoxieServerOrderedConcatActivity(_ctx, this, _probeManager, grouped, numInputs());
  11985. else
  11986. return new CRoxieServerThreadedConcatActivity(_ctx, this, _probeManager, grouped, numInputs());
  11987. }
  11988. };
  11989. IRoxieServerActivityFactory *createRoxieServerConcatActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  11990. {
  11991. return new CRoxieServerConcatActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  11992. }
  11993. //=================================================================================
  11994. class CRoxieServerNonEmptyActivity : public CRoxieServerMultiInputBaseActivity
  11995. {
  11996. IEngineRowStream* selectedStream;
  11997. unsigned savedParentExtractSize;
  11998. const byte * savedParentExtract;
  11999. bool foundInput;
  12000. bool unusedStopped;
  12001. public:
  12002. CRoxieServerNonEmptyActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  12003. : CRoxieServerMultiInputBaseActivity(_ctx, _factory, _probeManager, _numInputs)
  12004. {
  12005. foundInput = false;
  12006. unusedStopped = false;
  12007. selectedStream = NULL;
  12008. savedParentExtractSize = 0;;
  12009. savedParentExtract = NULL;
  12010. }
  12011. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  12012. {
  12013. //Don't start the inputs yet so we can short-circuit...
  12014. CRoxieServerMultiInputBaseActivity::start(parentExtractSize, parentExtract, paused);
  12015. savedParentExtractSize = parentExtractSize;
  12016. savedParentExtract = parentExtract;
  12017. }
  12018. virtual void stop()
  12019. {
  12020. if (unusedStopped)
  12021. {
  12022. if (selectedStream)
  12023. selectedStream->stop();
  12024. }
  12025. else
  12026. {
  12027. //May possibly call stop too many times if input->start() throws an exception (e.g. due to a dependency)
  12028. for (unsigned i = 0; i < numStreams; i++)
  12029. streamArray[i]->stop();
  12030. }
  12031. CRoxieServerMultiInputBaseActivity::stop();
  12032. }
  12033. virtual void reset()
  12034. {
  12035. CRoxieServerMultiInputBaseActivity::reset();
  12036. foundInput = false;
  12037. unusedStopped = false;
  12038. selectedStream = NULL;
  12039. }
  12040. virtual unsigned __int64 queryLocalCycles() const
  12041. {
  12042. return 0; // Can't easily calculate anything reliable but local processing is negligible
  12043. }
  12044. virtual const void * nextRow()
  12045. {
  12046. ActivityTimer t(totalCycles, timeActivities);
  12047. if (!foundInput)
  12048. {
  12049. foundInput = true;
  12050. assertex(numInputs == numStreams); // If this ceases to be true we will need to rethink some of this
  12051. //If we get an exception in this loop then stop() will stop any started inputs
  12052. for (unsigned i=0; i < numStreams; i++)
  12053. {
  12054. selectedStream = streamArray[i];
  12055. inputArray[i]->start(savedParentExtractSize, savedParentExtract, false); // Assumes 1:1 mapping streams to inputs
  12056. startJunction(junctionArray[i]);
  12057. const void * next = selectedStream->nextRow();
  12058. if (next)
  12059. {
  12060. //Found a row so stop remaining
  12061. for (unsigned j=i+1; j < numInputs; j++)
  12062. streamArray[j]->stop();
  12063. unusedStopped = true;
  12064. processed++;
  12065. return next;
  12066. }
  12067. selectedStream->stop();
  12068. }
  12069. unusedStopped = true;
  12070. selectedStream = NULL;
  12071. return NULL;
  12072. }
  12073. if (!selectedStream)
  12074. return NULL;
  12075. const void * next = selectedStream->nextRow();
  12076. if (next)
  12077. processed++;
  12078. return next;
  12079. }
  12080. };
  12081. class CRoxieServerNonEmptyActivityFactory : public CRoxieServerMultiInputFactory
  12082. {
  12083. public:
  12084. CRoxieServerNonEmptyActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  12085. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  12086. {
  12087. }
  12088. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  12089. {
  12090. return new CRoxieServerNonEmptyActivity(_ctx, this, _probeManager, numInputs());
  12091. }
  12092. };
  12093. IRoxieServerActivityFactory *createRoxieServerNonEmptyActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  12094. {
  12095. return new CRoxieServerNonEmptyActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  12096. }
  12097. //=================================================================================
  12098. class CRoxieServerMergeActivity : public CRoxieServerMultiInputActivity
  12099. {
  12100. IHThorMergeArg &helper;
  12101. unsigned *mergeheap;
  12102. unsigned activeInputs;
  12103. const void **pending;
  12104. bool first;
  12105. ICompare *compare;
  12106. bool dedup;
  12107. void permute()
  12108. {
  12109. assertex(activeInputs == 0);
  12110. for(unsigned i = 0; i < numStreams; i++)
  12111. if(pullInput(i))
  12112. mergeheap[activeInputs++] = i;
  12113. // the tree structure: element p has children p*2+1 and p*2+2, or element c has parent (unsigned)(c-1)/2
  12114. // the heap property: no element should be smaller than its parent
  12115. // the dedup variant: if(dedup), the top of the heap should also not be equal to either child
  12116. // 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
  12117. if (activeInputs >= 2)
  12118. for(unsigned p = (activeInputs-2)/2; p > 0; --p)
  12119. siftDown(p);
  12120. if(dedup)
  12121. siftDownDedupTop();
  12122. else
  12123. siftDown(0);
  12124. }
  12125. void readNext()
  12126. {
  12127. if(!pullInput(mergeheap[0]))
  12128. if(!promote(0))
  12129. return;
  12130. // we have changed the element at the top of the heap, so need to sift it down to maintain the heap property
  12131. if(dedup)
  12132. siftDownDedupTop();
  12133. else
  12134. siftDown(0);
  12135. }
  12136. bool pullInput(unsigned i)
  12137. {
  12138. const void *next = streamArray[i]->ungroupedNextRow();
  12139. pending[i] = next;
  12140. return (next != NULL);
  12141. }
  12142. bool promote(unsigned p)
  12143. {
  12144. activeInputs--;
  12145. if(activeInputs == p)
  12146. return false;
  12147. mergeheap[p] = mergeheap[activeInputs];
  12148. return true;
  12149. }
  12150. bool siftDown(unsigned p)
  12151. {
  12152. // assuming that all descendants of p form a heap, sift p down to its correct position, and so include it in the heap
  12153. bool nochange = true;
  12154. while(1)
  12155. {
  12156. unsigned c = p*2 + 1;
  12157. if(c >= activeInputs)
  12158. return nochange;
  12159. if(c+1 < activeInputs)
  12160. {
  12161. int childcmp = BuffCompare(c+1, c);
  12162. if((childcmp < 0) || ((childcmp == 0) && (mergeheap[c+1] < mergeheap[c])))
  12163. ++c;
  12164. }
  12165. int cmp = BuffCompare(c, p);
  12166. if((cmp > 0) || ((cmp == 0) && (mergeheap[c] > mergeheap[p])))
  12167. return nochange;
  12168. nochange = false;
  12169. unsigned r = mergeheap[c];
  12170. mergeheap[c] = mergeheap[p];
  12171. mergeheap[p] = r;
  12172. p = c;
  12173. }
  12174. }
  12175. void siftDownDedupTop()
  12176. {
  12177. // same as siftDown(0), except that it also ensures that the top of the heap is not equal to either of its children
  12178. if(activeInputs < 2)
  12179. return;
  12180. unsigned c = 1;
  12181. int childcmp = 1;
  12182. if(activeInputs >= 3)
  12183. {
  12184. childcmp = BuffCompare(2, 1);
  12185. if(childcmp < 0)
  12186. c = 2;
  12187. }
  12188. int cmp = BuffCompare(c, 0);
  12189. if(cmp > 0)
  12190. return;
  12191. // the following loop ensures the correct property holds on the smaller branch, and that childcmp==0 iff the top matches the other branch
  12192. while(cmp <= 0)
  12193. {
  12194. if(cmp == 0)
  12195. {
  12196. if(mergeheap[c] < mergeheap[0])
  12197. {
  12198. unsigned r = mergeheap[c];
  12199. mergeheap[c] = mergeheap[0];
  12200. mergeheap[0] = r;
  12201. }
  12202. ReleaseClearRoxieRow(pending[mergeheap[c]]);
  12203. if(!pullInput(mergeheap[c]))
  12204. if(!promote(c))
  12205. break;
  12206. siftDown(c);
  12207. }
  12208. else
  12209. {
  12210. unsigned r = mergeheap[c];
  12211. mergeheap[c] = mergeheap[0];
  12212. mergeheap[0] = r;
  12213. if(siftDown(c))
  12214. break;
  12215. }
  12216. cmp = BuffCompare(c, 0);
  12217. }
  12218. // the following loop ensures the uniqueness property holds on the other branch too
  12219. c = 3-c;
  12220. if(activeInputs <= c)
  12221. return;
  12222. while(childcmp == 0)
  12223. {
  12224. if(mergeheap[c] < mergeheap[0])
  12225. {
  12226. unsigned r = mergeheap[c];
  12227. mergeheap[c] = mergeheap[0];
  12228. mergeheap[0] = r;
  12229. }
  12230. ReleaseClearRoxieRow(pending[mergeheap[c]]);
  12231. if(!pullInput(mergeheap[c]))
  12232. if(!promote(c))
  12233. break;
  12234. siftDown(c);
  12235. childcmp = BuffCompare(c, 0);
  12236. }
  12237. }
  12238. inline int BuffCompare(unsigned a, unsigned b)
  12239. {
  12240. return compare->docompare(pending[mergeheap[a]], pending[mergeheap[b]]);
  12241. }
  12242. public:
  12243. CRoxieServerMergeActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  12244. : CRoxieServerMultiInputActivity(_ctx, _factory, _probeManager, _numInputs), helper((IHThorMergeArg &)basehelper)
  12245. {
  12246. activeInputs = 0;
  12247. first = true;
  12248. mergeheap = new unsigned[numInputs];
  12249. pending = new const void *[numStreams];
  12250. compare = helper.queryCompare();
  12251. dedup = helper.dedup();
  12252. for (unsigned i = 0; i < numStreams; i++)
  12253. pending[i] = NULL;
  12254. }
  12255. ~CRoxieServerMergeActivity()
  12256. {
  12257. delete [] mergeheap;
  12258. delete [] pending;
  12259. }
  12260. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  12261. {
  12262. activeInputs = 0;
  12263. first = true;
  12264. CRoxieServerMultiInputActivity::start(parentExtractSize, parentExtract, paused);
  12265. }
  12266. virtual void reset()
  12267. {
  12268. for (unsigned i = 0; i < numStreams; i++)
  12269. ReleaseClearRoxieRow(pending[i]);
  12270. CRoxieServerMultiInputActivity::reset();
  12271. }
  12272. virtual const void * nextRow()
  12273. {
  12274. ActivityTimer t(totalCycles, timeActivities);
  12275. if (first)
  12276. {
  12277. permute();
  12278. first = false;
  12279. }
  12280. if (activeInputs)
  12281. {
  12282. const void *next = pending[mergeheap[0]];
  12283. readNext();
  12284. if (next)
  12285. processed++;
  12286. return next;
  12287. }
  12288. else
  12289. return NULL;
  12290. }
  12291. };
  12292. class CRoxieServerMergeActivityFactory : public CRoxieServerMultiInputFactory
  12293. {
  12294. public:
  12295. CRoxieServerMergeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  12296. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  12297. {
  12298. }
  12299. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  12300. {
  12301. return new CRoxieServerMergeActivity(_ctx, this, _probeManager, numInputs());
  12302. }
  12303. };
  12304. IRoxieServerActivityFactory *createRoxieServerMergeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  12305. {
  12306. return new CRoxieServerMergeActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  12307. }
  12308. //=================================================================================
  12309. class CRoxieServerRegroupActivity : public CRoxieServerMultiInputActivity
  12310. {
  12311. IHThorRegroupArg &helper;
  12312. unsigned streamIndex;
  12313. bool eof;
  12314. unsigned __int64 numProcessedLastGroup;
  12315. public:
  12316. CRoxieServerRegroupActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  12317. : CRoxieServerMultiInputActivity(_ctx, _factory, _probeManager, _numInputs), helper((IHThorRegroupArg &)basehelper)
  12318. {
  12319. streamIndex = 0;
  12320. eof = false;
  12321. numProcessedLastGroup = 0;
  12322. }
  12323. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  12324. {
  12325. streamIndex = 0;
  12326. eof = false;
  12327. numProcessedLastGroup = processed;
  12328. CRoxieServerMultiInputActivity::start(parentExtractSize, parentExtract, paused);
  12329. }
  12330. const void * nextFromInputs()
  12331. {
  12332. unsigned initialStream = streamIndex;
  12333. while (streamIndex < numStreams)
  12334. {
  12335. const void * next = streamArray[streamIndex]->nextRow();
  12336. if (next)
  12337. {
  12338. if ((streamIndex != initialStream) && (streamIndex != initialStream+1))
  12339. {
  12340. ReleaseRoxieRow(next);
  12341. throw MakeStringException(ROXIE_MISMATCH_GROUP_ERROR, "Mismatched groups supplied to Regroup (%d)", factory->queryId());
  12342. }
  12343. return next;
  12344. }
  12345. streamIndex++;
  12346. }
  12347. if ((initialStream != 0) && (initialStream+1 != numStreams))
  12348. throw MakeStringException(ROXIE_MISMATCH_GROUP_ERROR, "Mismatched groups supplied to Regroup (%d)", factory->queryId());
  12349. streamIndex = 0;
  12350. return NULL;
  12351. }
  12352. virtual const void * nextRow()
  12353. {
  12354. ActivityTimer t(totalCycles, timeActivities);
  12355. if (eof)
  12356. return NULL;
  12357. const void * ret = nextFromInputs();
  12358. if (ret)
  12359. {
  12360. processed++;
  12361. return ret;
  12362. }
  12363. if (numProcessedLastGroup != processed)
  12364. {
  12365. numProcessedLastGroup = processed;
  12366. return NULL;
  12367. }
  12368. eof = true;
  12369. return NULL;
  12370. }
  12371. };
  12372. class CRoxieServerRegroupActivityFactory : public CRoxieServerMultiInputFactory
  12373. {
  12374. public:
  12375. CRoxieServerRegroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  12376. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  12377. {
  12378. }
  12379. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  12380. {
  12381. return new CRoxieServerRegroupActivity(_ctx, this, _probeManager, numInputs());
  12382. }
  12383. };
  12384. IRoxieServerActivityFactory *createRoxieServerRegroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  12385. {
  12386. return new CRoxieServerRegroupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  12387. }
  12388. //=================================================================================
  12389. class CRoxieServerCombineActivity : public CRoxieServerMultiInputActivity
  12390. {
  12391. IHThorCombineArg &helper;
  12392. unsigned __int64 numProcessedLastGroup;
  12393. public:
  12394. CRoxieServerCombineActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  12395. : CRoxieServerMultiInputActivity(_ctx, _factory, _probeManager, _numInputs), helper((IHThorCombineArg &)basehelper)
  12396. {
  12397. numProcessedLastGroup = 0;
  12398. }
  12399. ~CRoxieServerCombineActivity()
  12400. {
  12401. }
  12402. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  12403. {
  12404. numProcessedLastGroup = processed;
  12405. CRoxieServerMultiInputActivity::start(parentExtractSize, parentExtract, paused);
  12406. }
  12407. void nextInputs(ConstPointerArray & out)
  12408. {
  12409. for (unsigned i=0; i < numStreams; i++)
  12410. {
  12411. const void * next = streamArray[i]->nextRow();
  12412. if (next)
  12413. out.append(next);
  12414. }
  12415. }
  12416. virtual bool needsAllocator() const { return true; }
  12417. virtual const void * nextRow()
  12418. {
  12419. ActivityTimer t(totalCycles, timeActivities);
  12420. for (;;)
  12421. {
  12422. ConstPointerArray group;
  12423. nextInputs(group);
  12424. if ((group.ordinality() == 0) && (numProcessedLastGroup == processed))
  12425. nextInputs(group);
  12426. if (group.ordinality() == 0)
  12427. {
  12428. numProcessedLastGroup = processed;
  12429. return NULL;
  12430. }
  12431. else if (group.ordinality() != numInputs)
  12432. {
  12433. ReleaseRoxieRows(group);
  12434. throw MakeStringException(ROXIE_MISMATCH_GROUP_ERROR, "Mismatched group input for Combine Activity(%d)", factory->queryId());
  12435. }
  12436. try
  12437. {
  12438. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  12439. size32_t outSize = helper.transform(rowBuilder, group.ordinality(), group.getArray());
  12440. ReleaseRoxieRows(group);
  12441. if (outSize)
  12442. {
  12443. processed++;
  12444. return rowBuilder.finalizeRowClear(outSize);
  12445. }
  12446. }
  12447. catch (IException *E)
  12448. {
  12449. ReleaseRoxieRows(group);
  12450. throw makeWrappedException(E);
  12451. }
  12452. }
  12453. }
  12454. };
  12455. class CRoxieServerCombineActivityFactory : public CRoxieServerMultiInputFactory
  12456. {
  12457. public:
  12458. CRoxieServerCombineActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  12459. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  12460. {
  12461. }
  12462. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  12463. {
  12464. return new CRoxieServerCombineActivity(_ctx, this, _probeManager, numInputs());
  12465. }
  12466. };
  12467. IRoxieServerActivityFactory *createRoxieServerCombineActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  12468. {
  12469. return new CRoxieServerCombineActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  12470. }
  12471. //=================================================================================
  12472. class CRoxieServerCombineGroupActivity : public CRoxieServerTwoInputActivity
  12473. {
  12474. IHThorCombineGroupArg &helper;
  12475. unsigned __int64 numProcessedLastGroup;
  12476. public:
  12477. CRoxieServerCombineGroupActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  12478. : CRoxieServerTwoInputActivity(_ctx, _factory, _probeManager), helper((IHThorCombineGroupArg &)basehelper)
  12479. {
  12480. numProcessedLastGroup = 0;
  12481. }
  12482. ~CRoxieServerCombineGroupActivity()
  12483. {
  12484. }
  12485. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  12486. {
  12487. numProcessedLastGroup = processed;
  12488. CRoxieServerTwoInputActivity::start(parentExtractSize, parentExtract, paused);
  12489. }
  12490. virtual IFinalRoxieInput *queryOutput(unsigned idx)
  12491. {
  12492. if (idx==(unsigned)-1)
  12493. idx = 0;
  12494. return idx ? NULL : this;
  12495. }
  12496. virtual bool needsAllocator() const { return true; }
  12497. virtual const void * nextRow()
  12498. {
  12499. ActivityTimer t(totalCycles, timeActivities);
  12500. for (;;)
  12501. {
  12502. const void * left = inputStream->nextRow();
  12503. if (!left && (numProcessedLastGroup == processed))
  12504. left = inputStream->nextRow();
  12505. if (!left)
  12506. {
  12507. if (numProcessedLastGroup == processed)
  12508. {
  12509. const void * nextRight = inputStream1->nextRow();
  12510. if (nextRight)
  12511. {
  12512. ReleaseRoxieRow(nextRight);
  12513. throw MakeStringException(ROXIE_MISSING_GROUP_ERROR, "Missing LEFT record for Combine Group (%d)", factory->queryId());
  12514. }
  12515. }
  12516. else
  12517. numProcessedLastGroup = processed;
  12518. return NULL;
  12519. }
  12520. ConstPointerArray group;
  12521. for (;;)
  12522. {
  12523. const void * in = inputStream1->nextRow();
  12524. if (!in)
  12525. break;
  12526. group.append(in);
  12527. }
  12528. if (group.ordinality() == 0)
  12529. {
  12530. ReleaseRoxieRow(left);
  12531. ReleaseRoxieRows(group);
  12532. throw MakeStringException(ROXIE_MISSING_GROUP_ERROR, "Missing RIGHT group for Combine Group (%d)", factory->queryId());
  12533. }
  12534. try
  12535. {
  12536. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  12537. size32_t outSize = helper.transform(rowBuilder, left, group.ordinality(), (const void * *)group.getArray());
  12538. ReleaseRoxieRow(left);
  12539. ReleaseRoxieRows(group);
  12540. if (outSize)
  12541. {
  12542. processed++;
  12543. return rowBuilder.finalizeRowClear(outSize);
  12544. }
  12545. }
  12546. catch (IException *E)
  12547. {
  12548. ReleaseRoxieRow(left);
  12549. ReleaseRoxieRows(group);
  12550. throw makeWrappedException(E);
  12551. }
  12552. }
  12553. }
  12554. };
  12555. class CRoxieServerCombineGroupActivityFactory : public CRoxieServerActivityFactory
  12556. {
  12557. unsigned input2;
  12558. unsigned input2idx;
  12559. public:
  12560. CRoxieServerCombineGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  12561. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  12562. {
  12563. input2 = 0;
  12564. input2idx = 0;
  12565. }
  12566. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  12567. {
  12568. return new CRoxieServerCombineGroupActivity(_ctx, this, _probeManager);
  12569. }
  12570. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  12571. {
  12572. if (idx==1)
  12573. {
  12574. input2 = source;
  12575. input2idx = sourceidx;
  12576. }
  12577. else
  12578. CRoxieServerActivityFactory::setInput(idx, source, sourceidx);
  12579. }
  12580. virtual unsigned getInput(unsigned idx, unsigned &sourceidx) const
  12581. {
  12582. switch (idx)
  12583. {
  12584. case 1:
  12585. sourceidx = input2idx;
  12586. return input2;
  12587. case 0:
  12588. return CRoxieServerActivityFactory::getInput(idx, sourceidx);
  12589. default:
  12590. return (unsigned) -1;
  12591. }
  12592. }
  12593. virtual unsigned numInputs() const { return 2; }
  12594. };
  12595. IRoxieServerActivityFactory *createRoxieServerCombineGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  12596. {
  12597. return new CRoxieServerCombineGroupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  12598. }
  12599. //=================================================================================
  12600. class CRoxieServerRollupGroupActivity : public CRoxieServerActivity
  12601. {
  12602. IHThorRollupGroupArg &helper;
  12603. bool eof;
  12604. public:
  12605. CRoxieServerRollupGroupActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  12606. : CRoxieServerActivity(_ctx, _factory, _probeManager),
  12607. helper((IHThorRollupGroupArg &)basehelper)
  12608. {
  12609. eof = false;
  12610. }
  12611. ~CRoxieServerRollupGroupActivity()
  12612. {
  12613. }
  12614. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  12615. {
  12616. eof = false;
  12617. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  12618. }
  12619. virtual bool needsAllocator() const { return true; }
  12620. virtual const void * nextRow()
  12621. {
  12622. ActivityTimer t(totalCycles, timeActivities);
  12623. if (eof)
  12624. return NULL;
  12625. for (;;)
  12626. {
  12627. ConstPointerArray group;
  12628. for (;;)
  12629. {
  12630. const void * in = inputStream->nextRow();
  12631. if (!in)
  12632. break;
  12633. group.append(in);
  12634. }
  12635. if (group.ordinality() == 0)
  12636. {
  12637. eof = true;
  12638. return NULL;
  12639. }
  12640. try
  12641. {
  12642. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  12643. size32_t outSize = helper.transform(rowBuilder, group.ordinality(), (const void * *)group.getArray());
  12644. ReleaseRoxieRows(group);
  12645. if (outSize)
  12646. {
  12647. processed++;
  12648. return rowBuilder.finalizeRowClear(outSize);
  12649. }
  12650. }
  12651. catch (IException * E)
  12652. {
  12653. ReleaseRoxieRows(group);
  12654. throw makeWrappedException(E);
  12655. }
  12656. }
  12657. }
  12658. };
  12659. class CRoxieServerRollupGroupActivityFactory : public CRoxieServerActivityFactory
  12660. {
  12661. public:
  12662. CRoxieServerRollupGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  12663. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  12664. {
  12665. }
  12666. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  12667. {
  12668. return new CRoxieServerRollupGroupActivity(_ctx, this, _probeManager);
  12669. }
  12670. };
  12671. IRoxieServerActivityFactory *createRoxieServerRollupGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  12672. {
  12673. return new CRoxieServerRollupGroupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  12674. }
  12675. //=================================================================================
  12676. class CRoxieServerFilterProjectActivity : public CRoxieServerLateStartActivity
  12677. {
  12678. IHThorFilterProjectArg &helper;
  12679. unsigned numProcessedLastGroup;
  12680. unsigned __int64 recordCount;
  12681. public:
  12682. CRoxieServerFilterProjectActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  12683. : CRoxieServerLateStartActivity(_ctx, _factory, _probeManager), helper((IHThorFilterProjectArg &)basehelper)
  12684. {
  12685. numProcessedLastGroup = 0;
  12686. recordCount = 0;
  12687. }
  12688. ~CRoxieServerFilterProjectActivity()
  12689. {
  12690. }
  12691. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  12692. {
  12693. numProcessedLastGroup = 0;
  12694. recordCount = 0;
  12695. CRoxieServerLateStartActivity::start(parentExtractSize, parentExtract, paused);
  12696. lateStart(parentExtractSize, parentExtract, helper.canMatchAny()); //sets eof
  12697. }
  12698. virtual bool needsAllocator() const { return true; }
  12699. virtual const void * nextRow()
  12700. {
  12701. ActivityTimer t(totalCycles, timeActivities);
  12702. if (eof)
  12703. return NULL;
  12704. for (;;)
  12705. {
  12706. const void * in = inputStream->nextRow();
  12707. if (!in)
  12708. {
  12709. recordCount = 0;
  12710. if (numProcessedLastGroup == processed)
  12711. in = inputStream->nextRow();
  12712. if (!in)
  12713. {
  12714. numProcessedLastGroup = processed;
  12715. return NULL;
  12716. }
  12717. }
  12718. try
  12719. {
  12720. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  12721. size32_t outSize = helper.transform(rowBuilder, in, ++recordCount);
  12722. ReleaseRoxieRow(in);
  12723. if (outSize)
  12724. {
  12725. processed++;
  12726. return rowBuilder.finalizeRowClear(outSize);
  12727. }
  12728. }
  12729. catch (IException *E)
  12730. {
  12731. throw makeWrappedException(E);
  12732. }
  12733. }
  12734. }
  12735. };
  12736. class CRoxieServerFilterProjectActivityFactory : public CRoxieServerActivityFactory
  12737. {
  12738. public:
  12739. CRoxieServerFilterProjectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  12740. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  12741. {
  12742. //MORE: Code generator needs to indicate if the count is used.
  12743. //optStableInput = false;
  12744. }
  12745. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  12746. {
  12747. return new CRoxieServerFilterProjectActivity(_ctx, this, _probeManager);
  12748. }
  12749. };
  12750. IRoxieServerActivityFactory *createRoxieServerFilterProjectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  12751. {
  12752. return new CRoxieServerFilterProjectActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  12753. }
  12754. //=====================================================
  12755. class CRoxieServerStrandedProjectActivity : public CRoxieServerStrandedActivity
  12756. {
  12757. class ProjectProcessor : public StrandProcessor
  12758. {
  12759. protected:
  12760. IHThorProjectArg &helper;
  12761. public:
  12762. ProjectProcessor(CRoxieServerActivity &_parent, IEngineRowStream *_inputStream, IHThorProjectArg &_helper)
  12763. : StrandProcessor(_parent, _inputStream, true), helper(_helper)
  12764. {
  12765. }
  12766. virtual const void * nextRow()
  12767. {
  12768. ActivityTimer t(totalCycles, timeActivities);
  12769. for (;;)
  12770. {
  12771. OwnedConstRoxieRow in = inputStream->nextRow();
  12772. if (!in)
  12773. {
  12774. if (numProcessedLastGroup == processed)
  12775. in.setown(inputStream->nextRow());
  12776. if (!in)
  12777. {
  12778. numProcessedLastGroup = processed;
  12779. return NULL;
  12780. }
  12781. }
  12782. try
  12783. {
  12784. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  12785. size32_t outSize;
  12786. outSize = helper.transform(rowBuilder, in);
  12787. if (outSize)
  12788. {
  12789. processed++;
  12790. return rowBuilder.finalizeRowClear(outSize);
  12791. }
  12792. }
  12793. catch (IException *E)
  12794. {
  12795. throw parent.makeWrappedException(E);
  12796. }
  12797. }
  12798. }
  12799. };
  12800. public:
  12801. CRoxieServerStrandedProjectActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const StrandOptions &_strandOptions)
  12802. : CRoxieServerStrandedActivity(_ctx, _factory, _probeManager, _strandOptions)
  12803. {
  12804. }
  12805. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  12806. {
  12807. CRoxieServerStrandedActivity::start(parentExtractSize, parentExtract, paused);
  12808. onStartStrands();
  12809. }
  12810. virtual StrandProcessor *createStrandProcessor(IEngineRowStream *instream)
  12811. {
  12812. return new ProjectProcessor(*this, instream, (IHThorProjectArg &) basehelper);
  12813. }
  12814. virtual StrandProcessor *createStrandSourceProcessor(bool inputOrdered) { throwUnexpected(); }
  12815. };
  12816. class CRoxieServerProjectActivity : public CRoxieServerActivity
  12817. {
  12818. unsigned numProcessedLastGroup;
  12819. unsigned __int64 recordCount;
  12820. bool count;
  12821. public:
  12822. CRoxieServerProjectActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _count)
  12823. : CRoxieServerActivity(_ctx, _factory, _probeManager),
  12824. count(_count)
  12825. {
  12826. numProcessedLastGroup = 0;
  12827. recordCount = 0;
  12828. }
  12829. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  12830. {
  12831. numProcessedLastGroup = 0;
  12832. recordCount = 0;
  12833. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  12834. }
  12835. virtual bool needsAllocator() const { return true; }
  12836. virtual const void * nextRow()
  12837. {
  12838. ActivityTimer t(totalCycles, timeActivities);
  12839. for (;;)
  12840. {
  12841. OwnedConstRoxieRow in = inputStream->nextRow();
  12842. if (!in)
  12843. {
  12844. recordCount = 0;
  12845. if (numProcessedLastGroup == processed)
  12846. in.setown(inputStream->nextRow());
  12847. if (!in)
  12848. {
  12849. numProcessedLastGroup = processed;
  12850. return NULL;
  12851. }
  12852. }
  12853. try
  12854. {
  12855. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  12856. size32_t outSize;
  12857. if (count)
  12858. outSize = ((IHThorCountProjectArg &) basehelper).transform(rowBuilder, in, ++recordCount);
  12859. else
  12860. outSize = ((IHThorProjectArg &) basehelper).transform(rowBuilder, in);
  12861. if (outSize)
  12862. {
  12863. processed++;
  12864. return rowBuilder.finalizeRowClear(outSize);
  12865. }
  12866. }
  12867. catch (IException *E)
  12868. {
  12869. throw makeWrappedException(E);
  12870. }
  12871. }
  12872. }
  12873. };
  12874. class CRoxieServerProjectActivityFactory : public CRoxieServerActivityFactory
  12875. {
  12876. protected:
  12877. StrandOptions strandOptions;
  12878. bool count;
  12879. public:
  12880. CRoxieServerProjectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  12881. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode), strandOptions(_graphNode)
  12882. {
  12883. count = (kind==TAKcountproject || kind==TAKprefetchcountproject);
  12884. optStableInput = count;
  12885. }
  12886. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  12887. {
  12888. // NOTE - if they explicitly requested numStrands = 1 via hint, we could use either of the below. For now use the stranded version to ensure it is tested.
  12889. if (kind == TAKproject) // Not supported on prefetch or count projects
  12890. return new CRoxieServerStrandedProjectActivity(_ctx, this, _probeManager, strandOptions);
  12891. else
  12892. return new CRoxieServerProjectActivity(_ctx, this, _probeManager, count);
  12893. }
  12894. };
  12895. IRoxieServerActivityFactory *createRoxieServerProjectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  12896. {
  12897. return new CRoxieServerProjectActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  12898. }
  12899. //=================================================================================
  12900. class CRoxieServerPrefetchProjectActivity : public CRoxieServerActivity, implements IRecordPullerCallback
  12901. {
  12902. unsigned numProcessedLastGroup;
  12903. bool count;
  12904. bool eof;
  12905. bool allPulled;
  12906. bool isThreaded;
  12907. unsigned preload;
  12908. unsigned __int64 recordCount;
  12909. IHThorPrefetchProjectArg &helper;
  12910. RecordPullerThread puller;
  12911. InterruptableSemaphore ready;
  12912. InterruptableSemaphore space;
  12913. class PrefetchInfo : public CInterface
  12914. {
  12915. public:
  12916. inline PrefetchInfo(IHThorPrefetchProjectArg &helper, const void *_in, unsigned __int64 _recordCount)
  12917. {
  12918. if (helper.preTransform(extract, _in, _recordCount))
  12919. {
  12920. in.setown(_in);
  12921. recordCount = _recordCount;
  12922. }
  12923. else
  12924. {
  12925. ReleaseRoxieRow(_in);
  12926. recordCount = 0;
  12927. }
  12928. }
  12929. OwnedConstRoxieRow in;
  12930. unsigned __int64 recordCount;
  12931. rtlRowBuilder extract;
  12932. };
  12933. QueueOf<PrefetchInfo, true> pulled;
  12934. CriticalSection pulledCrit;
  12935. public:
  12936. CRoxieServerPrefetchProjectActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _count)
  12937. : CRoxieServerActivity(_ctx, _factory, _probeManager),
  12938. helper((IHThorPrefetchProjectArg &) basehelper),
  12939. puller(false),
  12940. count(_count)
  12941. {
  12942. numProcessedLastGroup = 0;
  12943. recordCount = 0;
  12944. eof = false;
  12945. allPulled = false;
  12946. isThreaded = (helper.getFlags() & PPFparallel) != 0;
  12947. preload = 0;
  12948. }
  12949. ~CRoxieServerPrefetchProjectActivity()
  12950. {
  12951. while (pulled.ordinality())
  12952. ::Release(pulled.dequeue());
  12953. }
  12954. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  12955. {
  12956. if (idx)
  12957. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", sanitizeSourceFile(__FILE__), __LINE__);
  12958. puller.setInput(this, _sourceIdx, _in);
  12959. }
  12960. virtual IStrandJunction *getOutputStreams(IRoxieSlaveContext *ctx, unsigned idx, PointerArrayOf<IEngineRowStream> &streams, const StrandOptions * consumerOptions, bool consumerOrdered, IOrderedCallbackCollection * orderedCallbacks)
  12961. {
  12962. puller.connectInputStreams(ctx, consumerOrdered);
  12963. return CRoxieServerActivity::getOutputStreams(ctx, idx, streams, consumerOptions, consumerOrdered, orderedCallbacks);
  12964. }
  12965. virtual IFinalRoxieInput *queryInput(unsigned idx) const
  12966. {
  12967. if (idx==0)
  12968. return puller.queryInput();
  12969. else
  12970. return NULL;
  12971. }
  12972. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  12973. {
  12974. numProcessedLastGroup = 0;
  12975. recordCount = 0;
  12976. eof = false;
  12977. allPulled = false;
  12978. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  12979. preload = helper.getLookahead();
  12980. if (!preload)
  12981. preload = ctx->queryOptions().prefetchProjectPreload;
  12982. space.reinit(preload);
  12983. ready.reinit();
  12984. puller.start(parentExtractSize, parentExtract, paused, preload, !isThreaded, ctx);
  12985. }
  12986. virtual void stop()
  12987. {
  12988. space.interrupt();
  12989. ready.interrupt();
  12990. CRoxieServerActivity::stop();
  12991. puller.stop();
  12992. }
  12993. virtual void reset()
  12994. {
  12995. CRoxieServerActivity::reset();
  12996. puller.reset();
  12997. allPulled = false;
  12998. while (pulled.ordinality())
  12999. ::Release(pulled.dequeue());
  13000. }
  13001. virtual PrefetchInfo *readNextRecord()
  13002. {
  13003. if (!isThreaded)
  13004. {
  13005. if (!allPulled) // This looks like it's thread unsafe but we are inside the if(!isThreaded) so should be ok
  13006. puller.pullRecords(1);
  13007. }
  13008. else
  13009. ready.wait();
  13010. CriticalBlock b(pulledCrit);
  13011. PrefetchInfo *ret = pulled.ordinality() ? pulled.dequeue() : NULL;
  13012. space.signal();
  13013. return ret;
  13014. }
  13015. virtual bool needsAllocator() const { return true; }
  13016. virtual const void * nextRow()
  13017. {
  13018. ActivityTimer t(totalCycles, timeActivities);
  13019. if (eof)
  13020. return NULL;
  13021. for (;;)
  13022. {
  13023. Owned<PrefetchInfo> in = readNextRecord();
  13024. if (!in)
  13025. {
  13026. recordCount = 0;
  13027. if (numProcessedLastGroup == processed)
  13028. in.setown(readNextRecord());
  13029. if (!in)
  13030. {
  13031. numProcessedLastGroup = processed;
  13032. eof = true;
  13033. return NULL;
  13034. }
  13035. }
  13036. try
  13037. {
  13038. if (in->in)
  13039. {
  13040. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  13041. size32_t outSize;
  13042. IThorChildGraph *child = helper.queryChild();
  13043. Owned<IEclGraphResults> results;
  13044. if (child)
  13045. results.setown(child->evaluate(in->extract.size(), in->extract.getbytes()));
  13046. outSize = helper.transform(rowBuilder, in->in, results, in->recordCount);
  13047. if (outSize)
  13048. {
  13049. processed++;
  13050. return rowBuilder.finalizeRowClear(outSize);
  13051. }
  13052. }
  13053. }
  13054. catch (IException *E)
  13055. {
  13056. throw makeWrappedException(E);
  13057. }
  13058. }
  13059. }
  13060. // interface IExceptionHandler
  13061. virtual bool fireException(IException *e)
  13062. {
  13063. // called from puller thread on failure
  13064. ready.interrupt(LINK(e));
  13065. space.interrupt(e);
  13066. return true;
  13067. }
  13068. // interface IRecordPullerCallback
  13069. virtual void processRow(const void *row)
  13070. {
  13071. {
  13072. CriticalBlock b(pulledCrit);
  13073. pulled.enqueue(new PrefetchInfo(helper, row, ++recordCount));
  13074. }
  13075. if (isThreaded)
  13076. {
  13077. ready.signal();
  13078. space.wait();
  13079. }
  13080. }
  13081. virtual void processEOG()
  13082. {
  13083. {
  13084. CriticalBlock b(pulledCrit);
  13085. pulled.enqueue(NULL);
  13086. }
  13087. if (isThreaded)
  13088. {
  13089. ready.signal();
  13090. space.wait();
  13091. }
  13092. }
  13093. virtual void processGroup(const ConstPointerArray &rows)
  13094. {
  13095. throwUnexpected();
  13096. }
  13097. virtual void processDone()
  13098. {
  13099. CriticalBlock b(pulledCrit);
  13100. allPulled = true;
  13101. if (isThreaded)
  13102. ready.signal();
  13103. }
  13104. };
  13105. class CRoxieServerPrefetchProjectActivityFactory : public CRoxieServerProjectActivityFactory
  13106. {
  13107. public:
  13108. CRoxieServerPrefetchProjectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  13109. : CRoxieServerProjectActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  13110. {
  13111. }
  13112. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  13113. {
  13114. return new CRoxieServerPrefetchProjectActivity(_ctx, this, _probeManager, count);
  13115. }
  13116. };
  13117. extern IRoxieServerActivityFactory *createRoxieServerPrefetchProjectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  13118. {
  13119. return new CRoxieServerPrefetchProjectActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  13120. }
  13121. //=================================================================================
  13122. class CPointerArrayRoxieInput : public CPseudoRoxieInput
  13123. {
  13124. public:
  13125. CPointerArrayRoxieInput()
  13126. {
  13127. rowset = NULL;
  13128. rowcount = 0;
  13129. curRow = 0;
  13130. }
  13131. void init(size32_t _rowcount, const byte **_rowset)
  13132. {
  13133. rowset = _rowset;
  13134. rowcount = _rowcount;
  13135. curRow = 0;
  13136. }
  13137. virtual const void * nextRow()
  13138. {
  13139. if (curRow < rowcount)
  13140. {
  13141. const void * ret = rowset[curRow];
  13142. if (ret)
  13143. LinkRoxieRow(ret);
  13144. curRow++;
  13145. return ret;
  13146. }
  13147. return NULL;
  13148. }
  13149. protected:
  13150. const byte **rowset;
  13151. size32_t rowcount;
  13152. size32_t curRow;
  13153. };
  13154. class CRoxieServerLoopActivity : public CRoxieServerActivity
  13155. {
  13156. protected:
  13157. IHThorLoopArg &helper;
  13158. ThorActivityKind activityKind;
  13159. unsigned maxIterations;
  13160. bool finishedLooping;
  13161. unsigned flags;
  13162. bool eof;
  13163. rtlRowBuilder loopExtractBuilder;
  13164. unsigned loopGraphId;
  13165. Linked<IOutputMetaData> counterMeta;
  13166. public:
  13167. CRoxieServerLoopActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _loopGraphId, IOutputMetaData * _counterMeta)
  13168. : CRoxieServerActivity(_ctx, _factory, _probeManager),
  13169. helper((IHThorLoopArg &)basehelper), loopGraphId(_loopGraphId), counterMeta(_counterMeta)
  13170. {
  13171. eof = false;
  13172. finishedLooping = false;
  13173. activityKind = factory->getKind();
  13174. flags = helper.getFlags();
  13175. maxIterations = 0;
  13176. }
  13177. virtual bool needsAllocator() const { return true; }
  13178. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  13179. {
  13180. eof = false;
  13181. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  13182. int iterations = (int) helper.numIterations();
  13183. maxIterations = (iterations >= 0) ? iterations : 0;
  13184. finishedLooping = ((activityKind == TAKloopcount) && (maxIterations == 0));
  13185. if ((flags & IHThorLoopArg::LFnewloopagain) && !helper.loopFirstTime())
  13186. finishedLooping = true;
  13187. loopExtractBuilder.clear();
  13188. helper.createParentExtract(loopExtractBuilder); // could possibly delay this until execution actually happens
  13189. }
  13190. virtual void stop()
  13191. {
  13192. CRoxieServerActivity::stop();
  13193. loopExtractBuilder.clear();
  13194. }
  13195. void createCounterResult(IRoxieServerChildGraph * graph, unsigned counter)
  13196. {
  13197. if (flags & IHThorLoopArg::LFcounter)
  13198. {
  13199. void * counterRow = ctx->queryRowManager().allocate(sizeof(thor_loop_counter_t), activityId);
  13200. *((thor_loop_counter_t *)counterRow) = counter;
  13201. RtlLinkedDatasetBuilder builder(rowAllocator);
  13202. builder.appendOwn(counterRow);
  13203. Owned<CGraphResult> counterResult = new CGraphResult(builder.getcount(), builder.linkrows());
  13204. graph->setInputResult(2, counterResult);
  13205. }
  13206. }
  13207. };
  13208. //=================================================================================
  13209. class CRoxieServerSequentialLoopActivity : public CRoxieServerLoopActivity
  13210. {
  13211. Owned<IActivityGraph> loopQuery;
  13212. Owned<IRoxieServerChildGraph> loopGraph;
  13213. IEngineRowStream * curStream;
  13214. RtlLinkedDatasetBuilder *loopInputBuilder;
  13215. CPointerArrayRoxieInput arrayInput;
  13216. Linked<IEngineRowStream> resultStream;
  13217. unsigned loopCounter;
  13218. public:
  13219. CRoxieServerSequentialLoopActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _loopGraphId, IOutputMetaData * _counterMeta)
  13220. : CRoxieServerLoopActivity(_ctx, _factory, _probeManager, _loopGraphId, _counterMeta)
  13221. {
  13222. curStream = NULL;
  13223. loopCounter = 0;
  13224. loopInputBuilder = NULL;
  13225. }
  13226. virtual bool needsAllocator() const { return true; }
  13227. virtual void onCreate(IHThorArg *_colocalParent)
  13228. {
  13229. CRoxieServerLoopActivity::onCreate(_colocalParent);
  13230. loopQuery.set(ctx->queryChildGraph(loopGraphId));
  13231. }
  13232. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  13233. {
  13234. curStream = inputStream;
  13235. loopCounter = 1;
  13236. CRoxieServerLoopActivity::start(parentExtractSize, parentExtract, paused);
  13237. //MORE: Not sure about this, should IRoxieServerChildGraph be combined with IActivityGraph?
  13238. loopGraph.set(loopQuery->queryLoopGraph());
  13239. loopInputBuilder = new RtlLinkedDatasetBuilder(rowAllocator);
  13240. }
  13241. virtual void stop()
  13242. {
  13243. delete loopInputBuilder;
  13244. loopInputBuilder = NULL;
  13245. CRoxieServerLoopActivity::stop();
  13246. }
  13247. virtual const void * nextRow()
  13248. {
  13249. ActivityTimer t(totalCycles, timeActivities);
  13250. if (eof)
  13251. return NULL;
  13252. unsigned emptyIterations = 0;
  13253. for (;;)
  13254. {
  13255. for (;;)
  13256. {
  13257. const void * ret = curStream->nextRow();
  13258. if (!ret)
  13259. {
  13260. ret = curStream->nextRow(); // more cope with groups somehow....
  13261. if (!ret)
  13262. {
  13263. if (finishedLooping)
  13264. {
  13265. eof = true;
  13266. return NULL;
  13267. }
  13268. break;
  13269. }
  13270. }
  13271. if (finishedLooping ||
  13272. ((flags & IHThorLoopArg::LFfiltered) && !helper.sendToLoop(loopCounter, ret)))
  13273. {
  13274. processed++;
  13275. return ret;
  13276. }
  13277. loopInputBuilder->appendOwn(ret);
  13278. }
  13279. switch (activityKind)
  13280. {
  13281. case TAKloopdataset:
  13282. {
  13283. if (!(flags & IHThorLoopArg::LFnewloopagain))
  13284. {
  13285. if (!helper.loopAgain(loopCounter, loopInputBuilder->getcount(), (const void**) loopInputBuilder->queryrows()))
  13286. {
  13287. if (loopInputBuilder->getcount() == 0)
  13288. {
  13289. eof = true;
  13290. return NULL;
  13291. }
  13292. arrayInput.init(loopInputBuilder->getcount(), loopInputBuilder->linkrows());
  13293. // MORE - should builder be cleared here?
  13294. curStream = &arrayInput;
  13295. finishedLooping = true;
  13296. continue; // back to the input loop again
  13297. }
  13298. }
  13299. break;
  13300. }
  13301. case TAKlooprow:
  13302. if (!loopInputBuilder->getcount())
  13303. {
  13304. finishedLooping = true;
  13305. eof = true;
  13306. return NULL;
  13307. }
  13308. break;
  13309. }
  13310. if (loopInputBuilder->getcount())
  13311. emptyIterations = 0;
  13312. else
  13313. {
  13314. //note: any outputs which didn't go around the loop again, would return the record, reinitializing emptyIterations
  13315. emptyIterations++;
  13316. if (emptyIterations > maxEmptyLoopIterations)
  13317. throw MakeStringException(ROXIE_TOO_MANY_EMPTY_LOOP, "Executed LOOP with empty input and output %u times", emptyIterations);
  13318. if (emptyIterations % 32 == 0)
  13319. CTXLOG("Executing LOOP with empty input and output %u times", emptyIterations);
  13320. }
  13321. checkAbort();
  13322. try
  13323. {
  13324. Owned<IRoxieGraphResults> results = executeIteration(loopExtractBuilder.size(), loopExtractBuilder.getbytes(), loopCounter);
  13325. resultStream.setown(results->createIterator(0));
  13326. if (flags & IHThorLoopArg::LFnewloopagain)
  13327. {
  13328. Owned<IEngineRowStream> againResult = results->createIterator(helper.loopAgainResult());
  13329. OwnedConstRoxieRow row = againResult->nextRow();
  13330. assertex(row);
  13331. //Result is a row which contains a single boolean field.
  13332. if (!((const bool *)row.get())[0])
  13333. finishedLooping = true;
  13334. }
  13335. }
  13336. catch (IException *E)
  13337. {
  13338. throw makeWrappedException(E);
  13339. }
  13340. curStream = resultStream.get();
  13341. loopCounter++;
  13342. if ((activityKind == TAKloopcount) && (loopCounter > maxIterations))
  13343. finishedLooping = true;
  13344. }
  13345. }
  13346. IRoxieGraphResults * executeIteration(unsigned parentExtractSize, const byte *parentExtract, unsigned counter)
  13347. {
  13348. try
  13349. {
  13350. loopGraph->beforeExecute();
  13351. Owned<IGraphResult> inputRowsResult = new CGraphResult(loopInputBuilder->getcount(), loopInputBuilder->linkrows());
  13352. loopInputBuilder->clear();
  13353. loopGraph->setInputResult(1, inputRowsResult);
  13354. createCounterResult(loopGraph, counter);
  13355. Owned<IRoxieGraphResults> ret = loopGraph->execute(parentExtractSize, parentExtract);
  13356. loopGraph->afterExecute();
  13357. return ret.getClear();
  13358. }
  13359. catch (...)
  13360. {
  13361. CTXLOG("Exception thrown in loop body - cleaning up");
  13362. loopGraph->afterExecute();
  13363. throw;
  13364. }
  13365. }
  13366. };
  13367. //=================================================================================
  13368. typedef SafeQueueOf<const void, true> SafeRowQueue;
  13369. class CRowQueuePseudoInput : public CPseudoRoxieInput
  13370. {
  13371. public:
  13372. CRowQueuePseudoInput(SafeRowQueue & _input, IOutputMetaData * _meta)
  13373. : meta(_meta), input(_input)
  13374. {
  13375. eof = false;
  13376. }
  13377. virtual const void * nextRow()
  13378. {
  13379. if (eof)
  13380. return NULL;
  13381. const void * ret = input.dequeue();
  13382. if (!ret)
  13383. eof = true;
  13384. return ret;
  13385. }
  13386. virtual IOutputMetaData * queryOutputMeta() const { return meta; }
  13387. protected:
  13388. SafeRowQueue & input;
  13389. IOutputMetaData * meta;
  13390. bool eof;
  13391. };
  13392. class CRoxieServerParallelLoopActivity;
  13393. class LoopFilterPseudoInput : public CIndirectRoxieInput
  13394. {
  13395. public:
  13396. LoopFilterPseudoInput(CRoxieServerParallelLoopActivity * _activity, unsigned _counter) :
  13397. activity(_activity), counter(_counter)
  13398. {
  13399. }
  13400. virtual const void * nextRow();
  13401. protected:
  13402. CRoxieServerParallelLoopActivity * activity;
  13403. unsigned counter;
  13404. };
  13405. class LoopExecutorThread : public RestartableThread
  13406. {
  13407. protected:
  13408. Owned<CSafeRoxieInput> safeInput;
  13409. CRoxieServerParallelLoopActivity * activity;
  13410. bool eof;
  13411. CriticalSection crit;
  13412. unsigned flags;
  13413. SafeRowQueue tempResults[2];
  13414. unsigned savedParentExtractSize;
  13415. const byte * savedParentExtract;
  13416. IArrayOf<IActivityGraph> cachedGraphs;
  13417. IRoxieSlaveContext *ctx;
  13418. public:
  13419. LoopExecutorThread()
  13420. : RestartableThread("LoopExecutorThread")
  13421. {
  13422. activity = NULL;
  13423. eof = false;
  13424. flags = 0;
  13425. ctx = NULL;
  13426. savedParentExtract = NULL;
  13427. savedParentExtractSize = 0;
  13428. }
  13429. void setInput(CRoxieServerParallelLoopActivity * _activity, unsigned _sourceIdx, IFinalRoxieInput *_input, unsigned _flags)
  13430. {
  13431. activity = _activity;
  13432. flags = _flags;
  13433. // 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-nextRow etc etc.
  13434. safeInput.setown(new CSafeRoxieInput(_sourceIdx, _input));
  13435. }
  13436. void connectInputStreams(bool consumerOrdered)
  13437. {
  13438. safeInput->connectInputStreams(ctx, consumerOrdered);
  13439. }
  13440. IFinalRoxieInput *queryInput() const
  13441. {
  13442. return safeInput;
  13443. }
  13444. void onCreate(IRoxieSlaveContext * _ctx);
  13445. void start(unsigned parentExtractSize, const byte *parentExtract, bool paused);
  13446. void stop();
  13447. void reset();
  13448. virtual int run();
  13449. protected:
  13450. void executeLoop();
  13451. void executeLoopInstance(unsigned counter, unsigned numIterations, unsigned inputIdx, IFinalRoxieInput * input, SafeRowQueue * spillOutput);
  13452. IFinalRoxieInput * createLoopIterationGraph(unsigned i, unsigned inputIdx, IFinalRoxieInput * input, unsigned counter);
  13453. };
  13454. class CRoxieServerParallelLoopActivity : public CRoxieServerLoopActivity
  13455. {
  13456. friend class LoopFilterPseudoInput;
  13457. friend class LoopExecutorThread;
  13458. QueueOf<const void, true> ready;
  13459. CriticalSection helperCS;
  13460. CriticalSection cs;
  13461. unsigned defaultNumParallel;
  13462. LoopExecutorThread executor;
  13463. IProbeManager* probeManager;
  13464. CriticalSection canAccess;
  13465. CriticalSection scrit;
  13466. InterruptableSemaphore readySpace;
  13467. InterruptableSemaphore recordsReady;
  13468. protected:
  13469. bool includeInLoop(unsigned counter, const void * row)
  13470. {
  13471. CriticalBlock b(helperCS);
  13472. return helper.sendToLoop(counter, row);
  13473. }
  13474. public:
  13475. CRoxieServerParallelLoopActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _loopGraphId, IOutputMetaData * _counterMeta)
  13476. : CRoxieServerLoopActivity(_ctx, _factory, _probeManager, _loopGraphId, _counterMeta),
  13477. readySpace(parallelLoopFlowLimit)
  13478. {
  13479. probeManager = _probeManager;
  13480. defaultNumParallel = 0;
  13481. }
  13482. virtual void onCreate(IHThorArg *_colocalParent)
  13483. {
  13484. CRoxieServerActivity::onCreate(_colocalParent);
  13485. executor.onCreate(ctx);
  13486. }
  13487. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  13488. {
  13489. CriticalBlock b(scrit); // can stop while still starting, if unlucky...
  13490. readySpace.reinit(parallelLoopFlowLimit);
  13491. recordsReady.reinit();
  13492. CRoxieServerLoopActivity::start(parentExtractSize, parentExtract, paused);
  13493. defaultNumParallel = helper.defaultParallelIterations();
  13494. if (!defaultNumParallel)
  13495. defaultNumParallel = DEFAULT_PARALLEL_LOOP_THREADS;
  13496. //MORE: If numIterations <= number of parallel iterations[1],
  13497. //then we don't need to create a separate thread to do the processing, and the results will also avoid
  13498. //being transferred via a queue
  13499. executor.start(parentExtractSize, parentExtract, paused);
  13500. }
  13501. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  13502. {
  13503. if (idx)
  13504. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", sanitizeSourceFile(__FILE__), __LINE__);
  13505. executor.setInput(this, _sourceIdx, _in, flags);
  13506. }
  13507. virtual IStrandJunction *getOutputStreams(IRoxieSlaveContext *ctx, unsigned idx, PointerArrayOf<IEngineRowStream> &streams, const StrandOptions * consumerOptions, bool consumerOrdered, IOrderedCallbackCollection * orderedCallbacks)
  13508. {
  13509. executor.connectInputStreams(consumerOrdered);
  13510. return CRoxieServerActivity::getOutputStreams(ctx, idx, streams, nullptr, consumerOrdered, nullptr);
  13511. }
  13512. virtual IFinalRoxieInput *queryInput(unsigned idx) const
  13513. {
  13514. if (idx==0)
  13515. return executor.queryInput();
  13516. else
  13517. return NULL;
  13518. }
  13519. virtual void stop()
  13520. {
  13521. CriticalBlock b(scrit); // can stop while still starting, if unlucky...
  13522. readySpace.interrupt();
  13523. recordsReady.interrupt();
  13524. executor.join(); // MORE - may not be needed given stop/reset split
  13525. CRoxieServerLoopActivity::stop();
  13526. }
  13527. virtual void reset()
  13528. {
  13529. while (ready.ordinality())
  13530. ReleaseRoxieRow(ready.dequeue());
  13531. executor.reset();
  13532. CRoxieServerActivity::reset();
  13533. }
  13534. virtual const void * nextRow()
  13535. {
  13536. ActivityTimer t(totalCycles, timeActivities);
  13537. for (;;)
  13538. {
  13539. if (eof)
  13540. return NULL;
  13541. recordsReady.wait();
  13542. CriticalBlock procedure(canAccess);
  13543. if (ready.ordinality())
  13544. {
  13545. const void *result = ready.dequeue();
  13546. readySpace.signal();
  13547. if (result)
  13548. processed++;
  13549. return result;
  13550. }
  13551. else
  13552. eof = true;
  13553. }
  13554. }
  13555. unsigned getNumParallel(unsigned iter)
  13556. {
  13557. return defaultNumParallel;
  13558. }
  13559. inline void enqueueResult(const void * row)
  13560. {
  13561. try
  13562. {
  13563. while(!readySpace.wait(1000))
  13564. {
  13565. CTXLOG("Blocked waiting for space in loop %p activity id: %d output queue: %d records in queue", this, queryId(), ready.ordinality());
  13566. }
  13567. }
  13568. catch (...)
  13569. {
  13570. ReleaseRoxieRow(row);
  13571. throw;
  13572. }
  13573. CriticalBlock b2(canAccess);
  13574. ready.enqueue(row);
  13575. recordsReady.signal();
  13576. }
  13577. inline void finishResults()
  13578. {
  13579. recordsReady.signal();
  13580. }
  13581. virtual bool fireException(IException *e)
  13582. {
  13583. readySpace.interrupt(LINK(e));
  13584. recordsReady.interrupt(e);
  13585. return true;
  13586. }
  13587. IActivityGraph * createChildGraphInstance()
  13588. {
  13589. return factory->createChildGraph(ctx, &helper, loopGraphId, this, probeManager, *this);
  13590. }
  13591. IActivityGraph * queryChildGraph()
  13592. {
  13593. return ctx->queryChildGraph(loopGraphId);
  13594. }
  13595. };
  13596. //=================================================================================
  13597. const void * LoopFilterPseudoInput::nextRow()
  13598. {
  13599. for (;;)
  13600. {
  13601. const void * next = stream->nextRow();
  13602. if (!next || activity->includeInLoop(counter, next))
  13603. return next;
  13604. activity->enqueueResult(next);
  13605. }
  13606. }
  13607. void LoopExecutorThread::onCreate(IRoxieSlaveContext * _ctx)
  13608. {
  13609. //Initialise the cached graph list with the child instance that will always be created. Other iterations will be created on demand.
  13610. ctx = _ctx;
  13611. cachedGraphs.append(*LINK(activity->queryChildGraph()));
  13612. }
  13613. void LoopExecutorThread::start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  13614. {
  13615. savedParentExtractSize = parentExtractSize;
  13616. savedParentExtract = parentExtract;
  13617. eof = false;
  13618. StringBuffer logPrefix("[");
  13619. ctx->getLogPrefix(logPrefix).append("] ");
  13620. RestartableThread::start(logPrefix);
  13621. }
  13622. int LoopExecutorThread::run()
  13623. {
  13624. try
  13625. {
  13626. executeLoop();
  13627. }
  13628. catch (IException *e)
  13629. {
  13630. activity->fireException(e);
  13631. }
  13632. catch (...)
  13633. {
  13634. activity->fireException(MakeStringException(ROXIE_INTERNAL_ERROR, "Unexpected exception caught in LoopExecutorThread::run"));
  13635. }
  13636. return 0;
  13637. }
  13638. void LoopExecutorThread::stop()
  13639. {
  13640. safeInput->stop();
  13641. RestartableThread::join();
  13642. }
  13643. void LoopExecutorThread::reset()
  13644. {
  13645. safeInput->reset();
  13646. }
  13647. void LoopExecutorThread::executeLoop()
  13648. {
  13649. unsigned iterations = 0;
  13650. unsigned counter = 0;
  13651. unsigned outputIndex = 0;
  13652. //Note, activities don't link inputs, so need to be careful that special inputs remain linked while the activity is executing.
  13653. for (;;)
  13654. {
  13655. if (activity->activityKind == TAKloopcount)
  13656. {
  13657. if (counter == activity->maxIterations)
  13658. break;
  13659. }
  13660. else
  13661. {
  13662. //This condition isn't quite right because it needs to be whether the filtered
  13663. //input is empty. May be ok if we include that in the semantics,
  13664. if (tempResults[1-outputIndex].ordinality() == 0)
  13665. break;
  13666. }
  13667. unsigned numParallel = activity->getNumParallel(iterations);
  13668. Linked<IFinalRoxieInput> curInput;
  13669. if (iterations == 0)
  13670. curInput.set(safeInput);
  13671. else
  13672. {
  13673. SafeRowQueue & inputQueue = tempResults[1-outputIndex];
  13674. inputQueue.enqueue(NULL);
  13675. curInput.setown(new CRowQueuePseudoInput(inputQueue, activity->queryOutputMeta()));
  13676. }
  13677. SafeRowQueue * curOutput = NULL;
  13678. if (counter+numParallel > activity->maxIterations)
  13679. numParallel = activity->maxIterations - counter;
  13680. else if (counter+numParallel < activity->maxIterations)
  13681. curOutput = &tempResults[outputIndex];
  13682. executeLoopInstance(counter, numParallel, 0, curInput, curOutput); // CurInput is always SOME sort of proxy so idx always 0
  13683. outputIndex = 1-outputIndex;
  13684. counter += numParallel;
  13685. iterations++;
  13686. }
  13687. //Check for TAKlooprow, where end of loop couldn't be determined ahead of time
  13688. SafeRowQueue & inputQueue = tempResults[1-outputIndex];
  13689. while (inputQueue.ordinality())
  13690. {
  13691. const void * next = inputQueue.dequeue();
  13692. activity->enqueueResult(next);
  13693. }
  13694. activity->finishResults();
  13695. }
  13696. void LoopExecutorThread::executeLoopInstance(unsigned counter, unsigned numIterations, unsigned inputIdx, IFinalRoxieInput * input, SafeRowQueue * spillOutput)
  13697. {
  13698. IArrayOf<IFinalRoxieInput> savedInputs; // activities don't link their inputs, so this list keeps filters alive.
  13699. Linked<IFinalRoxieInput> curInput = input;
  13700. unsigned i;
  13701. for (i= 0; i != numIterations; i++)
  13702. {
  13703. unsigned thisCounter = counter+i+1;
  13704. IFinalRoxieInput * filtered = curInput;
  13705. if (flags & IHThorLoopArg::LFfiltered)
  13706. {
  13707. LoopFilterPseudoInput *newFiltered = new LoopFilterPseudoInput(activity, thisCounter);
  13708. newFiltered->setInput(inputIdx, curInput);
  13709. filtered = newFiltered;
  13710. savedInputs.append(*filtered);
  13711. inputIdx = 0;
  13712. }
  13713. //graph is kept, so new curInput will be guaranteed to exist
  13714. curInput.setown(createLoopIterationGraph(i, inputIdx, filtered, thisCounter));
  13715. inputIdx = 0;
  13716. }
  13717. Owned<IStrandJunction> curJunction;
  13718. IEngineRowStream *curStream = connectSingleStream(ctx, curInput, inputIdx, curJunction, true);
  13719. Owned<IException> failure;
  13720. try
  13721. {
  13722. curInput->start(savedParentExtractSize, savedParentExtract, false);
  13723. if (spillOutput)
  13724. {
  13725. for (;;)
  13726. {
  13727. const void * next = curStream->nextRow();
  13728. if (!next)
  13729. break;
  13730. spillOutput->enqueue(next);
  13731. }
  13732. }
  13733. else
  13734. {
  13735. for (;;)
  13736. {
  13737. const void * next = curStream->nextRow();
  13738. if (!next)
  13739. break;
  13740. activity->enqueueResult(next);
  13741. }
  13742. }
  13743. }
  13744. catch (IException *E)
  13745. {
  13746. ctx->notifyAbort(E);
  13747. failure.setown(E);
  13748. }
  13749. for (i= 0; i != numIterations; i++)
  13750. {
  13751. IRoxieServerChildGraph * loopGraph = cachedGraphs.item(i).queryLoopGraph();
  13752. loopGraph->afterExecute();
  13753. //NOTE: inputIdx is always 0 - the code above could be cleaned up.
  13754. loopGraph->querySetInputResult(1, 0, nullptr);
  13755. }
  13756. curStream->stop();
  13757. curInput->reset();
  13758. if (failure)
  13759. throw failure.getClear();
  13760. }
  13761. IFinalRoxieInput * LoopExecutorThread::createLoopIterationGraph(unsigned i, unsigned inputIdx, IFinalRoxieInput * input, unsigned counter)
  13762. {
  13763. if (!cachedGraphs.isItem(i))
  13764. cachedGraphs.append(*activity->createChildGraphInstance());
  13765. Linked<IRoxieServerChildGraph> loopGraph = cachedGraphs.item(i).queryLoopGraph();
  13766. loopGraph->beforeExecute();
  13767. if (!loopGraph->querySetInputResult(1, inputIdx, input))
  13768. throwUnexpected(); // a loop which doesn't use the value from the previous iteration. Should probably handle even if daft.
  13769. activity->createCounterResult(loopGraph, counter);
  13770. return loopGraph->selectOutput(0);
  13771. }
  13772. //=================================================================================
  13773. class CCounterRowMetaData : implements IOutputMetaData, public CInterface
  13774. {
  13775. public:
  13776. IMPLEMENT_IINTERFACE
  13777. virtual size32_t getRecordSize(const void *) { return sizeof(thor_loop_counter_t); }
  13778. virtual size32_t getMinRecordSize() const { return sizeof(thor_loop_counter_t); }
  13779. virtual size32_t getFixedSize() const { return sizeof(thor_loop_counter_t); }
  13780. virtual void toXML(const byte * self, IXmlWriter & out) { }
  13781. virtual unsigned getVersion() const { return OUTPUTMETADATA_VERSION; }
  13782. virtual unsigned getMetaFlags() { return 0; }
  13783. virtual void destruct(byte * self) {}
  13784. virtual IOutputRowSerializer * createDiskSerializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
  13785. virtual IOutputRowDeserializer * createDiskDeserializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
  13786. virtual ISourceRowPrefetcher * createDiskPrefetcher(ICodeContext * ctx, unsigned activityId) { return NULL; }
  13787. virtual IOutputMetaData * querySerializedDiskMeta() { return this; }
  13788. virtual IOutputRowSerializer * createInternalSerializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
  13789. virtual IOutputRowDeserializer * createInternalDeserializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
  13790. virtual void walkIndirectMembers(const byte * self, IIndirectMemberVisitor & visitor) {}
  13791. virtual IOutputMetaData * queryChildMeta(unsigned i) { return NULL; }
  13792. virtual const RtlRecord &queryRecordAccessor(bool expand) const { throwUnexpected(); } // could provide a static implementation if needed
  13793. };
  13794. class CRoxieServerLoopActivityFactory : public CRoxieServerActivityFactory
  13795. {
  13796. unsigned loopGraphId;
  13797. unsigned flags;
  13798. Linked<IOutputMetaData> counterMeta;
  13799. public:
  13800. CRoxieServerLoopActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned _loopGraphId)
  13801. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode), loopGraphId(_loopGraphId)
  13802. {
  13803. Owned<IHThorLoopArg> helper = (IHThorLoopArg *) helperFactory();
  13804. flags = helper->getFlags();
  13805. counterMeta.setown(new CCounterRowMetaData);
  13806. }
  13807. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  13808. {
  13809. if (flags & IHThorLoopArg::LFparallel)
  13810. return new CRoxieServerParallelLoopActivity(_ctx, this, _probeManager, loopGraphId, counterMeta);
  13811. else
  13812. return new CRoxieServerSequentialLoopActivity(_ctx, this, _probeManager, loopGraphId, counterMeta);
  13813. }
  13814. };
  13815. IRoxieServerActivityFactory *createRoxieServerLoopActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned _loopGraphId)
  13816. {
  13817. return new CRoxieServerLoopActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _loopGraphId);
  13818. }
  13819. //=================================================================================
  13820. class CRoxieServerGraphLoopActivity : public CRoxieServerActivity
  13821. {
  13822. protected:
  13823. IHThorGraphLoopArg &helper;
  13824. unsigned maxIterations;
  13825. unsigned flags;
  13826. rtlRowBuilder GraphExtractBuilder;
  13827. unsigned loopGraphId;
  13828. Linked<IOutputMetaData> counterMeta;
  13829. public:
  13830. CRoxieServerGraphLoopActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _GraphGraphId, IOutputMetaData * _counterMeta)
  13831. : CRoxieServerActivity(_ctx, _factory, _probeManager),
  13832. helper((IHThorGraphLoopArg &)basehelper), loopGraphId(_GraphGraphId), counterMeta(_counterMeta)
  13833. {
  13834. flags = helper.getFlags();
  13835. maxIterations = 0;
  13836. }
  13837. virtual bool needsAllocator() const { return true; }
  13838. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  13839. {
  13840. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  13841. int iterations = (int) helper.numIterations();
  13842. maxIterations = (iterations >= 0) ? iterations : 0;
  13843. if (maxIterations > maxGraphLoopIterations)
  13844. throw MakeStringException(ROXIE_TOO_MANY_GRAPH_LOOP, "Attempt to execute graph %u times", maxIterations);
  13845. if (maxIterations != 0)
  13846. {
  13847. GraphExtractBuilder.clear();
  13848. helper.createParentExtract(GraphExtractBuilder);
  13849. }
  13850. }
  13851. virtual void stop()
  13852. {
  13853. CRoxieServerActivity::stop();
  13854. GraphExtractBuilder.clear();
  13855. }
  13856. void createCounterResult(IRoxieServerChildGraph * graph, unsigned counter)
  13857. {
  13858. if (flags & IHThorGraphLoopArg::GLFcounter)
  13859. {
  13860. void * counterRow = ctx->queryRowManager().allocate(sizeof(thor_loop_counter_t), activityId);
  13861. *((thor_loop_counter_t *)counterRow) = counter;
  13862. RtlLinkedDatasetBuilder builder(rowAllocator);
  13863. builder.appendOwn(counterRow);
  13864. Owned<CGraphResult> counterResult = new CGraphResult(builder.getcount(), builder.linkrows());
  13865. graph->setInputResult(0, counterResult);
  13866. }
  13867. }
  13868. };
  13869. //=================================================================================
  13870. class CRoxieServerSequentialGraphLoopActivity : public CRoxieServerGraphLoopActivity
  13871. {
  13872. Owned<IActivityGraph> GraphQuery;
  13873. Owned<IRoxieServerChildGraph> loopGraph;
  13874. Linked<IEngineRowStream> resultStream;
  13875. bool evaluated;
  13876. public:
  13877. CRoxieServerSequentialGraphLoopActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _GraphGraphId, IOutputMetaData * _counterMeta)
  13878. : CRoxieServerGraphLoopActivity(_ctx, _factory, _probeManager, _GraphGraphId, _counterMeta)
  13879. {
  13880. evaluated = false;
  13881. }
  13882. virtual void onCreate(IHThorArg *_colocalParent)
  13883. {
  13884. CRoxieServerGraphLoopActivity::onCreate(_colocalParent);
  13885. GraphQuery.set(ctx->queryChildGraph(loopGraphId));
  13886. }
  13887. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  13888. {
  13889. CRoxieServerGraphLoopActivity::start(parentExtractSize, parentExtract, paused);
  13890. //MORE: Not sure about this, should IRoxieServerChildGraph be combined with IActivityGraph?
  13891. loopGraph.set(GraphQuery->queryLoopGraph());
  13892. evaluated = false;
  13893. }
  13894. virtual void stop()
  13895. {
  13896. if (loopGraph)
  13897. loopGraph->clearGraphLoopResults();
  13898. CRoxieServerGraphLoopActivity::stop();
  13899. }
  13900. virtual const void * nextRow()
  13901. {
  13902. ActivityTimer t(totalCycles, timeActivities);
  13903. if (!evaluated)
  13904. {
  13905. executeEntireGraph();
  13906. evaluated = true;
  13907. }
  13908. const void * ret = resultStream->nextRow();
  13909. if (ret)
  13910. processed++;
  13911. return ret;
  13912. }
  13913. void executeIteration(unsigned parentExtractSize, const byte *parentExtract, unsigned counter)
  13914. {
  13915. try
  13916. {
  13917. loopGraph->beforeExecute();
  13918. createCounterResult(loopGraph, counter);
  13919. loopGraph->executeGraphLoop(parentExtractSize, parentExtract);
  13920. loopGraph->afterExecute();
  13921. }
  13922. catch (...)
  13923. {
  13924. CTXLOG("Exception thrown in graph body - cleaning up");
  13925. loopGraph->afterExecute();
  13926. throw;
  13927. }
  13928. }
  13929. void createInitialGraphInput()
  13930. {
  13931. loopGraph->clearGraphLoopResults();
  13932. RtlLinkedDatasetBuilder builder(rowAllocator);
  13933. inputStream->readAll(builder);
  13934. Owned<CGraphResult> result = new CGraphResult(builder.getcount(), builder.linkrows());
  13935. loopGraph->setGraphLoopResult(0, result);
  13936. }
  13937. void executeEntireGraph()
  13938. {
  13939. createInitialGraphInput();
  13940. for (unsigned loopCounter=1; loopCounter <= maxIterations; loopCounter++)
  13941. {
  13942. executeIteration(GraphExtractBuilder.size(), GraphExtractBuilder.getbytes(), loopCounter);
  13943. }
  13944. resultStream.setown(loopGraph->getGraphLoopResult(maxIterations));
  13945. }
  13946. };
  13947. //=================================================================================
  13948. struct GraphOutputSplitterArg : public CThorSplitArg
  13949. {
  13950. public:
  13951. virtual unsigned numBranches()
  13952. {
  13953. return 0;
  13954. }
  13955. virtual IOutputMetaData * queryOutputMeta()
  13956. {
  13957. return NULL;// get it from the parent..
  13958. }
  13959. };
  13960. extern "C" IHThorArg * createGraphOutputSplitter() { return new GraphOutputSplitterArg; }
  13961. class CGraphIterationInfo : public CInterface
  13962. {
  13963. private:
  13964. Owned<IRoxieServerActivityFactory> factory; // Note - before sourceAct, so destroyed last
  13965. unsigned sourceIdx;
  13966. Linked<IRoxieServerActivity> sourceAct;
  13967. Linked<IFinalRoxieInput> sourceInput;
  13968. unsigned numUses;
  13969. unsigned iteration;
  13970. public:
  13971. CGraphIterationInfo(IRoxieServerActivity * _sourceAct, IFinalRoxieInput *_input, unsigned _sourceIdx, unsigned _iteration)
  13972. : sourceAct(_sourceAct), sourceInput(_input), sourceIdx(_sourceIdx), iteration(_iteration)
  13973. {
  13974. numUses = 0;
  13975. }
  13976. inline void noteUsed()
  13977. {
  13978. numUses++;
  13979. }
  13980. void createSplitter(IRoxieSlaveContext *ctx, IProbeManager *probeManager, IArrayOf<IRoxieProbe> &probes)
  13981. {
  13982. if (numUses > 1)
  13983. {
  13984. Owned<IPropertyTree> splitterNode = createPTree(ipt_fast);
  13985. factory.setown(createRoxieServerThroughSpillActivityFactory(sourceAct->queryFactory()->queryQueryFactory(), createGraphOutputSplitter, numUses, *splitterNode));
  13986. IRoxieServerActivity *splitter = factory->createActivity(ctx, NULL);
  13987. splitter->onCreate(NULL);
  13988. IFinalRoxieInput *input = sourceAct->queryOutput(sourceIdx);
  13989. if (probeManager)
  13990. {
  13991. IRoxieProbe * inputProbe = probeManager->createProbe(static_cast<IInputBase*>(input), sourceAct, splitter, sourceIdx, 0, iteration);
  13992. probes.append(*LINK(inputProbe));
  13993. input = &dynamic_cast<IFinalRoxieInput &>(inputProbe->queryInput());
  13994. sourceIdx = 0;
  13995. }
  13996. sourceAct.setown(splitter);
  13997. sourceAct->setInput(0, sourceIdx, input);
  13998. sourceIdx = 0;
  13999. sourceInput.clear();
  14000. }
  14001. }
  14002. IFinalRoxieInput *connectOutput(IProbeManager *probeManager, IArrayOf<IRoxieProbe> &probes, IRoxieServerActivity *targetAct, unsigned targetIdx)
  14003. {
  14004. // MORE - not really necessary to create splitters in separate pass, is it?
  14005. if (factory) // we created a splitter....
  14006. sourceInput.set(sourceAct->queryOutput(sourceIdx));
  14007. IFinalRoxieInput *ret = sourceInput;
  14008. if (probeManager)
  14009. {
  14010. IRoxieProbe * inputProbe = probeManager->createProbe(sourceInput, sourceAct, targetAct, sourceIdx, targetIdx, iteration);
  14011. probes.append(*LINK(inputProbe));
  14012. ret = &dynamic_cast<IFinalRoxieInput &>(inputProbe->queryInput());
  14013. // MORE - do we need to connect the stream in the probe?
  14014. }
  14015. if (factory) // we created a splitter....
  14016. sourceIdx++;
  14017. return ret;
  14018. }
  14019. };
  14020. class CRoxieServerParallelGraphLoopActivity : public CRoxieServerGraphLoopActivity, implements IRoxieServerLoopResultProcessor
  14021. {
  14022. Owned<IActivityGraph> childGraph;
  14023. IFinalRoxieInput * resultInput;
  14024. IEngineRowStream * resultStream;
  14025. Owned<IStrandJunction> resultJunction;
  14026. CIArrayOf<CGraphIterationInfo> outputs;
  14027. IArrayOf<IRoxieServerChildGraph> iterationGraphs;
  14028. Owned<CExtractMapperInput> inputExtractMapper;
  14029. IProbeManager *probeManager;
  14030. unsigned createLoopCounter;
  14031. IArrayOf<IRoxieProbe> probes;
  14032. public:
  14033. CRoxieServerParallelGraphLoopActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _GraphGraphId, IOutputMetaData * _counterMeta)
  14034. : CRoxieServerGraphLoopActivity(_ctx, _factory, _probeManager, _GraphGraphId, _counterMeta), probeManager(_probeManager)
  14035. {
  14036. inputExtractMapper.setown(new CExtractMapperInput);
  14037. resultInput = NULL;
  14038. resultStream = NULL;
  14039. createLoopCounter = 0;
  14040. }
  14041. virtual void onCreate(IHThorArg *_colocalParent)
  14042. {
  14043. CRoxieServerGraphLoopActivity::onCreate(_colocalParent);
  14044. childGraph.set(ctx->queryChildGraph(loopGraphId));
  14045. }
  14046. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  14047. {
  14048. //Input needs to be handled very carefully.....
  14049. //We don't want to call onStart on the input unless it is actually used, so don't use the base CRoxieServerActivity implementation.
  14050. //This activity's input needs to be started with (parentExtractSize, parentExtract), but the elements in the graph need to be started with the
  14051. //GraphExtractBuilder parent extract. So we need to wrap the input in a pseudo-input (inputExtractMapper) that passes through a different
  14052. //parentExtract. Something very similar will be needed for query library calls with streaming inputs when they are implemented.
  14053. assertex(idx == 0);
  14054. inputExtractMapper->setInput(_sourceIdx, _in);
  14055. }
  14056. virtual void connectInputStreams(bool consumerOrdered)
  14057. {
  14058. //NB: inputExtractMapper is not connected at this point - only if/when it is used from within the graph
  14059. CRoxieServerActivity::connectInputStreams(consumerOrdered);
  14060. }
  14061. virtual IFinalRoxieInput *queryInput(unsigned idx) const
  14062. {
  14063. if (idx==0)
  14064. return inputExtractMapper->queryInput();
  14065. else
  14066. return NULL;
  14067. }
  14068. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14069. {
  14070. CRoxieServerGraphLoopActivity::start(parentExtractSize, parentExtract, paused); // initialises GraphExtractBuilder
  14071. inputExtractMapper->setParentExtract(parentExtractSize, parentExtract);
  14072. createExpandedGraph(GraphExtractBuilder.size(), GraphExtractBuilder.getbytes(), probeManager);
  14073. resultInput->start(GraphExtractBuilder.size(), GraphExtractBuilder.getbytes(), paused);
  14074. startJunction(resultJunction);
  14075. }
  14076. virtual void stop()
  14077. {
  14078. if (resultStream)
  14079. resultStream->stop();
  14080. CRoxieServerGraphLoopActivity::stop();
  14081. }
  14082. virtual void reset()
  14083. {
  14084. if (resultInput)
  14085. resultInput->reset();
  14086. resetJunction(resultJunction);
  14087. resultInput = NULL;
  14088. resultStream = NULL;
  14089. resultJunction.clear();
  14090. ForEachItemIn(i, iterationGraphs)
  14091. iterationGraphs.item(i).updateFactoryStatistics();
  14092. outputs.kill();
  14093. iterationGraphs.kill(); // must be done after all activities killed
  14094. if (probeManager)
  14095. {
  14096. probeManager->deleteGraph(NULL, (IArrayOf<IInputBase>*)&probes);
  14097. probes.kill();
  14098. }
  14099. CRoxieServerGraphLoopActivity::reset();
  14100. }
  14101. virtual const void * nextRow()
  14102. {
  14103. ActivityTimer t(totalCycles, timeActivities);
  14104. const void * ret = resultStream->nextRow();
  14105. if (ret)
  14106. processed++;
  14107. return ret;
  14108. }
  14109. void createExpandedGraph(unsigned parentExtractSize, const byte *parentExtract, IProbeManager *probeManager)
  14110. {
  14111. //result(0) is the input to the graph.
  14112. resultInput = inputExtractMapper;
  14113. outputs.append(* new CGraphIterationInfo(resultInput->queryActivity(), resultInput, 0, 1));
  14114. for (createLoopCounter=1; createLoopCounter <= maxIterations; createLoopCounter++)
  14115. {
  14116. IRoxieServerChildGraph * graph = childGraph->createGraphLoopInstance(ctx, createLoopCounter, parentExtractSize, parentExtract, *this);
  14117. graph->beforeExecute();
  14118. iterationGraphs.append(*graph);
  14119. graph->gatherIterationUsage(*this);
  14120. CGraphIterationInfo *iteration = graph->selectGraphLoopOutput();
  14121. outputs.append(*iteration);
  14122. }
  14123. createLoopCounter = 0;
  14124. createSplitters(probeManager, probes);
  14125. ForEachItemIn(i2, iterationGraphs)
  14126. iterationGraphs.item(i2).associateIterationOutputs(*this);
  14127. resultInput = outputs.tos().connectOutput(probeManager, probes, this, 0);
  14128. resultStream = connectSingleStream(ctx, resultInput, 0, resultJunction, true);
  14129. }
  14130. void createSplitters(IProbeManager *probeManager, IArrayOf<IRoxieProbe> &probes)
  14131. {
  14132. ForEachItemIn(i, outputs)
  14133. {
  14134. CGraphIterationInfo & next = outputs.item(i);
  14135. next.createSplitter(ctx, probeManager, probes);
  14136. }
  14137. }
  14138. //IRoxieServerLoopResultProcessor
  14139. virtual void noteUseIteration(unsigned _whichIteration)
  14140. {
  14141. int whichIteration = (int) _whichIteration; // May go negative - API is unsigned for historical reasons
  14142. if (whichIteration >= 0)
  14143. {
  14144. if (!outputs.isItem(whichIteration))
  14145. throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Error reading graph result %d from iteration %d", whichIteration, createLoopCounter);
  14146. outputs.item(whichIteration).noteUsed();
  14147. }
  14148. }
  14149. virtual IFinalRoxieInput* connectIterationOutput(unsigned whichIteration, IProbeManager *probeManager, IArrayOf<IRoxieProbe> &probes, IRoxieServerActivity *targetAct, unsigned targetIdx)
  14150. {
  14151. if (outputs.isItem(whichIteration))
  14152. {
  14153. CGraphIterationInfo & next = outputs.item(whichIteration);
  14154. return next.connectOutput(probeManager, probes, targetAct, targetIdx);
  14155. }
  14156. return NULL;
  14157. }
  14158. };
  14159. //=================================================================================
  14160. class CRoxieServerGraphLoopActivityFactory : public CRoxieServerActivityFactory
  14161. {
  14162. unsigned loopGraphId;
  14163. unsigned flags;
  14164. Linked<IOutputMetaData> counterMeta;
  14165. public:
  14166. CRoxieServerGraphLoopActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned _loopGraphId)
  14167. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode), loopGraphId(_loopGraphId)
  14168. {
  14169. Owned<IHThorGraphLoopArg> helper = (IHThorGraphLoopArg *) helperFactory();
  14170. flags = helper->getFlags();
  14171. counterMeta.setown(new CCounterRowMetaData);
  14172. }
  14173. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  14174. {
  14175. if (kind == TAKparallelgraphloop)
  14176. return new CRoxieServerParallelGraphLoopActivity(_ctx, this, _probeManager, loopGraphId, counterMeta);
  14177. else
  14178. return new CRoxieServerSequentialGraphLoopActivity(_ctx, this, _probeManager, loopGraphId, counterMeta);
  14179. }
  14180. };
  14181. IRoxieServerActivityFactory *createRoxieServerGraphLoopActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned _loopGraphId)
  14182. {
  14183. return new CRoxieServerGraphLoopActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _loopGraphId);
  14184. }
  14185. //=====================================================================================================
  14186. class CRoxieServerLibraryCallActivity : public CRoxieServerActivity
  14187. {
  14188. class OutputAdaptor : public CExtractMapperInput
  14189. {
  14190. bool stopped;
  14191. public:
  14192. CRoxieServerLibraryCallActivity *parent;
  14193. IOutputMetaData * meta = nullptr;
  14194. unsigned oid;
  14195. unsigned processed;
  14196. public:
  14197. OutputAdaptor()
  14198. {
  14199. parent = NULL;
  14200. oid = 0;
  14201. init();
  14202. }
  14203. ~OutputAdaptor()
  14204. {
  14205. if (traceStartStop)
  14206. DBGLOG("%p ~OutputAdaptor %d", this, oid);
  14207. if (processed && parent && parent->factory)
  14208. {
  14209. parent->factory->noteProcessed(oid, processed);
  14210. if (parent->ctx)
  14211. parent->ctx->noteProcessed(parent->querySubgraphId(), parent->activityId, oid, processed, 0);
  14212. }
  14213. }
  14214. void setParent(CRoxieServerLibraryCallActivity * _parent, IOutputMetaData * _meta, unsigned _oid)
  14215. {
  14216. parent = _parent;
  14217. meta = _meta;
  14218. oid = _oid;
  14219. }
  14220. void init()
  14221. {
  14222. processed = 0;
  14223. stopped = false;
  14224. }
  14225. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14226. {
  14227. parent->start(oid, parentExtractSize, parentExtract, paused);
  14228. CExtractMapperInput::start(parentExtractSize, parentExtract, paused);
  14229. }
  14230. virtual IStrandJunction *getOutputStreams(IRoxieSlaveContext *ctx, unsigned idx, PointerArrayOf<IEngineRowStream> &streams, const StrandOptions * consumerOptions, bool consumerOrdered, IOrderedCallbackCollection * orderedCallbacks)
  14231. {
  14232. //MORE value of consumerOrdered depends on whether this activity is marked as ordered.
  14233. if (!oid) // Only need to set up once
  14234. {
  14235. parent->connectInputStreams(true); // To handle dependencies etc
  14236. }
  14237. return CExtractMapperInput::getOutputStreams(ctx, 0, streams, nullptr, true, nullptr);
  14238. }
  14239. //This override should not really be needed, but input is set up too late for the call to connect strands
  14240. virtual IOutputMetaData * queryOutputMeta() const
  14241. {
  14242. return meta;
  14243. }
  14244. virtual void stop()
  14245. {
  14246. if (!stopped)
  14247. {
  14248. stopped = true;
  14249. parent->stop(oid); // parent code relies on stop being called exactly once per adaptor, so make sure it is!
  14250. CExtractMapperInput::stop();
  14251. }
  14252. };
  14253. virtual void reset()
  14254. {
  14255. parent->reset(oid);
  14256. CExtractMapperInput::reset();
  14257. init();
  14258. };
  14259. virtual void checkAbort()
  14260. {
  14261. parent->checkAbort();
  14262. }
  14263. };
  14264. IHThorLibraryCallArg &helper;
  14265. unsigned numInputs;
  14266. unsigned numOutputs;
  14267. unsigned numActiveOutputs;
  14268. bool started;
  14269. OutputAdaptor* outputAdaptors;
  14270. CExtractMapperInput * * inputAdaptors;
  14271. bool * inputUsed;
  14272. bool * outputUsed;
  14273. Owned<IException> error;
  14274. CriticalSection crit;
  14275. rtlRowBuilder libraryExtractBuilder;
  14276. Owned<IActivityGraph> libraryGraph;
  14277. const LibraryCallFactoryExtra & extra;
  14278. public:
  14279. CRoxieServerLibraryCallActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs, unsigned _numOutputs, const LibraryCallFactoryExtra & _extra)
  14280. : CRoxieServerActivity(_ctx, _factory, _probeManager),
  14281. helper((IHThorLibraryCallArg &)basehelper), extra(_extra)
  14282. {
  14283. numInputs = _numInputs;
  14284. numOutputs = _numOutputs;
  14285. numActiveOutputs = numOutputs;
  14286. inputAdaptors = new CExtractMapperInput*[numInputs];
  14287. inputUsed = new bool[numInputs];
  14288. for (unsigned i1 = 0; i1 < numInputs; i1++)
  14289. {
  14290. inputAdaptors[i1] = new CExtractMapperInput;
  14291. inputUsed[i1] = false;
  14292. }
  14293. outputAdaptors = new OutputAdaptor[numOutputs];
  14294. outputUsed = new bool[numOutputs];
  14295. for (unsigned i2 = 0; i2 < numOutputs; i2++)
  14296. {
  14297. outputAdaptors[i2].setParent(this, helper.queryOutputMeta(i2), i2);
  14298. outputUsed[i2] = false;
  14299. }
  14300. started = false;
  14301. }
  14302. ~CRoxieServerLibraryCallActivity()
  14303. {
  14304. for (unsigned i1 = 0; i1 < numInputs; i1++)
  14305. ::Release(inputAdaptors[i1]);
  14306. delete [] inputAdaptors;
  14307. delete [] inputUsed;
  14308. delete [] outputAdaptors;
  14309. delete [] outputUsed;
  14310. }
  14311. virtual void onCreate(IHThorArg *_colocalParent)
  14312. {
  14313. CRoxieServerActivity::onCreate(_colocalParent);
  14314. libraryGraph.setown(ctx->getLibraryGraph(extra, this));
  14315. libraryGraph->onCreate(_colocalParent);
  14316. //Now map the inputs and outputs to the adapters
  14317. IRoxieServerChildGraph * graph = libraryGraph->queryLoopGraph();
  14318. for (unsigned i1=0; i1<numInputs; i1++)
  14319. inputUsed[i1] = graph->querySetInputResult(i1, 0, inputAdaptors[i1]);
  14320. for (unsigned i2=0; i2<numOutputs; i2++)
  14321. {
  14322. unsigned outputIndex = extra.outputs.item(i2);
  14323. Owned<IFinalRoxieInput> output = graph->selectOutput(numInputs+outputIndex);
  14324. outputAdaptors[i2].setInput(0, output); // MORE - no idea if this 0 is right??
  14325. outputAdaptors[i2].connectInputStreams(ctx, true);
  14326. }
  14327. }
  14328. virtual void start(unsigned oid, unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14329. {
  14330. CriticalBlock b(crit);
  14331. if (error)
  14332. throw error.getLink();
  14333. if (factory)
  14334. factory->noteStarted(oid);
  14335. if (!started)
  14336. {
  14337. // even though it is not complete, we don't want to run this again if it fails.
  14338. started = true;
  14339. //see notes on splitter above
  14340. try
  14341. {
  14342. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  14343. }
  14344. catch (IException *E)
  14345. {
  14346. #ifdef TRACE_SPLIT
  14347. CTXLOG("spill %d caught exception in start", activityId);
  14348. #endif
  14349. error.set(E);
  14350. throw;
  14351. }
  14352. catch (...)
  14353. {
  14354. IException *E = MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught in CRoxieServerLibraryCallActivity::start");
  14355. error.set(E);
  14356. throw E;
  14357. }
  14358. //recreate the parent extract, and use it to reinitialize the graphs...
  14359. libraryExtractBuilder.clear();
  14360. helper.createParentExtract(libraryExtractBuilder);
  14361. // 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
  14362. // some inputs before we see start on others.
  14363. for (unsigned i1 = 0; i1 < numInputs; i1++)
  14364. {
  14365. if (inputUsed[i1])
  14366. inputAdaptors[i1]->setParentExtract(parentExtractSize, parentExtract);
  14367. else
  14368. inputAdaptors[i1]->queryInput()->stopall();
  14369. }
  14370. for (unsigned i2 = 0; i2 < numOutputs; i2++)
  14371. outputAdaptors[i2].setParentExtract(libraryExtractBuilder.size(), libraryExtractBuilder.getbytes());
  14372. //call stop on all the unused inputs.
  14373. IRoxieServerChildGraph * graph = libraryGraph->queryLoopGraph();
  14374. graph->beforeExecute();
  14375. ForEachItemIn(i3, extra.unusedOutputs)
  14376. {
  14377. Owned<IFinalRoxieInput> output = graph->selectOutput(numInputs+extra.unusedOutputs.item(i3));
  14378. output->stopall();
  14379. }
  14380. }
  14381. }
  14382. virtual void stop(unsigned oid)
  14383. {
  14384. CriticalBlock b(crit);
  14385. if (--numActiveOutputs == 0)
  14386. {
  14387. //call stop on all the unused inputs.
  14388. IRoxieServerChildGraph * graph = libraryGraph->queryLoopGraph();
  14389. graph->beforeExecute();
  14390. ForEachItemIn(i3, extra.unusedOutputs)
  14391. {
  14392. Owned<IFinalRoxieInput> output = graph->selectOutput(numInputs+extra.unusedOutputs.item(i3));
  14393. output->stopall();
  14394. }
  14395. CRoxieServerActivity::stop();
  14396. }
  14397. }
  14398. void reset(unsigned oid)
  14399. {
  14400. started = false;
  14401. error.clear();
  14402. numActiveOutputs = numOutputs;
  14403. if (state != STATEreset) // make sure input is only reset once
  14404. {
  14405. CRoxieServerActivity::reset();
  14406. libraryGraph->reset();
  14407. //Call reset on all unused inputs/outputs from the graph - no one else will.
  14408. for (unsigned i1 = 0; i1 < numInputs; i1++)
  14409. {
  14410. if (!inputUsed[i1])
  14411. inputAdaptors[i1]->reset();
  14412. }
  14413. IRoxieServerChildGraph * graph = libraryGraph->queryLoopGraph();
  14414. ForEachItemIn(i3, extra.unusedOutputs)
  14415. {
  14416. Owned<IFinalRoxieInput> output = graph->selectOutput(numInputs+extra.unusedOutputs.item(i3));
  14417. output->reset();
  14418. }
  14419. }
  14420. };
  14421. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  14422. {
  14423. inputAdaptors[idx]->setInput(_sourceIdx, _in);
  14424. }
  14425. virtual IFinalRoxieInput *queryInput(unsigned idx) const
  14426. {
  14427. if (idx < numInputs && inputAdaptors[idx])
  14428. return inputAdaptors[idx]->queryInput();
  14429. else
  14430. return NULL;
  14431. }
  14432. public:
  14433. virtual const void *nextRow()
  14434. {
  14435. throwUnexpected(); // Internal logic error - we are not anybody's input
  14436. }
  14437. virtual IOutputMetaData * queryOutputMeta() const
  14438. {
  14439. throwUnexpected(); // should be called on outputs instead
  14440. }
  14441. virtual IFinalRoxieInput *queryOutput(unsigned idx)
  14442. {
  14443. assertex(idx!=(unsigned)-1);
  14444. assertex(!outputUsed[idx]);
  14445. outputUsed[idx] = true;
  14446. return &outputAdaptors[idx];
  14447. }
  14448. virtual void updateFactoryStatistics() const override
  14449. {
  14450. if (libraryGraph)
  14451. libraryGraph->updateFactoryStatistics();
  14452. CRoxieServerActivity::updateFactoryStatistics();
  14453. }
  14454. };
  14455. void LibraryCallFactoryExtra::set(const LibraryCallFactoryExtra & _other)
  14456. {
  14457. ForEachItemIn(i1, _other.outputs)
  14458. outputs.append(_other.outputs.item(i1));
  14459. ForEachItemIn(i2, _other.unusedOutputs)
  14460. unusedOutputs.append(_other.unusedOutputs.item(i2));
  14461. maxOutputs = _other.maxOutputs;
  14462. graphid = _other.graphid;
  14463. libraryName.set(_other.libraryName);
  14464. embeddedGraphName.set(_other.embeddedGraphName);
  14465. interfaceHash = _other.interfaceHash;
  14466. embedded = _other.embedded;
  14467. }
  14468. void LibraryCallFactoryExtra::calcUnused()
  14469. {
  14470. for (unsigned i=0; i < maxOutputs; i++)
  14471. if (!outputs.contains(i))
  14472. unusedOutputs.append(i);
  14473. }
  14474. class CRoxieServerLibraryCallActivityFactory : public CRoxieServerMultiOutputFactory
  14475. {
  14476. private:
  14477. CRoxieServerMultiInputInfo inputs;
  14478. LibraryCallFactoryExtra extra;
  14479. public:
  14480. CRoxieServerLibraryCallActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, LibraryCallFactoryExtra & _extra)
  14481. : CRoxieServerMultiOutputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  14482. {
  14483. extra.set(_extra);
  14484. extra.calcUnused();
  14485. setNumOutputs(extra.outputs.ordinality());
  14486. }
  14487. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  14488. {
  14489. return new CRoxieServerLibraryCallActivity(_ctx, this, _probeManager, numInputs(), numOutputs, extra);
  14490. }
  14491. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  14492. {
  14493. inputs.set(idx, source, sourceidx);
  14494. }
  14495. virtual unsigned getInput(unsigned idx, unsigned &sourceidx) const
  14496. {
  14497. return inputs.get(idx, sourceidx);
  14498. }
  14499. virtual unsigned numInputs() const { return inputs.ordinality(); }
  14500. virtual void getXrefInfo(IPropertyTree &reply, const IRoxieContextLogger &logctx) const
  14501. {
  14502. addXrefLibraryInfo(reply, extra.libraryName);
  14503. }
  14504. };
  14505. IRoxieServerActivityFactory *createRoxieServerLibraryCallActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, LibraryCallFactoryExtra & _extra)
  14506. {
  14507. return new CRoxieServerLibraryCallActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _extra);
  14508. }
  14509. //=====================================================================================================
  14510. // CRoxieServerNWayInputActivity is a multi-input, multi-output activity, where the outputs are a subset of the inputs
  14511. // Used to implement RANGE(<rowset-expression>, [set-of-indices])
  14512. class CRoxieServerNWayInputBaseActivity : public CRoxieServerMultiInputBaseActivity
  14513. {
  14514. protected:
  14515. PointerArrayOf<IFinalRoxieInput> selectedInputs;
  14516. PointerArrayOf<IEngineRowStream> selectedStreams;
  14517. PointerArrayOf<IStrandJunction> selectedJunctions;
  14518. public:
  14519. CRoxieServerNWayInputBaseActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  14520. : CRoxieServerMultiInputBaseActivity(_ctx, _factory, _probeManager, _numInputs)
  14521. {
  14522. }
  14523. virtual unsigned __int64 queryLocalCycles() const
  14524. {
  14525. __int64 localCycles = totalCycles.totalCycles;
  14526. ForEachItemIn(i, selectedInputs)
  14527. {
  14528. localCycles -= selectedInputs.item(i)->queryTotalCycles();
  14529. }
  14530. if (localCycles < 0)
  14531. localCycles = 0;
  14532. return localCycles;
  14533. }
  14534. virtual IFinalRoxieInput *queryInput(unsigned idx) const
  14535. {
  14536. if (selectedInputs.isItem(idx))
  14537. return selectedInputs.item(idx);
  14538. else
  14539. return NULL;
  14540. }
  14541. virtual void reset()
  14542. {
  14543. ForEachItemIn(i, selectedInputs)
  14544. selectedInputs.item(i)->reset();
  14545. selectedInputs.kill();
  14546. selectedStreams.kill();
  14547. selectedJunctions.kill();
  14548. CRoxieServerMultiInputBaseActivity::reset();
  14549. }
  14550. virtual const void * nextRow()
  14551. {
  14552. throwUnexpected();
  14553. }
  14554. virtual unsigned numConcreteOutputs() const
  14555. {
  14556. return selectedInputs.ordinality();
  14557. }
  14558. virtual IFinalRoxieInput * queryConcreteInput(unsigned idx)
  14559. {
  14560. return queryInput(idx);
  14561. }
  14562. virtual IEngineRowStream *queryConcreteOutputStream(unsigned whichInput)
  14563. {
  14564. if (selectedStreams.isItem(whichInput))
  14565. return selectedStreams.item(whichInput);
  14566. return NULL;
  14567. }
  14568. virtual IStrandJunction *queryConcreteOutputJunction(unsigned idx) const
  14569. {
  14570. if (selectedJunctions.isItem(idx))
  14571. return selectedJunctions.item(idx);
  14572. return NULL;
  14573. }
  14574. };
  14575. class CRoxieServerNWayInputActivity : public CRoxieServerNWayInputBaseActivity
  14576. {
  14577. IHThorNWayInputArg & helper;
  14578. public:
  14579. CRoxieServerNWayInputActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  14580. : CRoxieServerNWayInputBaseActivity(_ctx, _factory, _probeManager, _numInputs), helper((IHThorNWayInputArg &)basehelper)
  14581. {
  14582. }
  14583. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14584. {
  14585. CRoxieServerNWayInputBaseActivity::start(parentExtractSize, parentExtract, paused);
  14586. bool selectionIsAll;
  14587. size32_t selectionLen;
  14588. rtlDataAttr selection;
  14589. helper.getInputSelection(selectionIsAll, selectionLen, selection.refdata());
  14590. selectedInputs.kill();
  14591. selectedStreams.kill();
  14592. selectedJunctions.kill();
  14593. assertex(numInputs==numStreams); // Will need refactoring when that ceases to be true
  14594. if (selectionIsAll)
  14595. {
  14596. for (unsigned i=0; i < numInputs; i++)
  14597. {
  14598. selectedInputs.append(inputArray[i]);
  14599. selectedStreams.append(streamArray[i]); // Assumes 1:1 relationship - is that good?
  14600. selectedJunctions.append(junctionArray[i]);
  14601. }
  14602. }
  14603. else
  14604. {
  14605. const size32_t * selections = (const size32_t *)selection.getdata();
  14606. unsigned max = selectionLen/sizeof(size32_t);
  14607. for (unsigned i = 0; i < max; i++)
  14608. {
  14609. unsigned nextIndex = selections[i];
  14610. //Check there are no duplicates..... Assumes there are a fairly small number of inputs, so n^2 search is ok.
  14611. for (unsigned j=i+1; j < max; j++)
  14612. {
  14613. if (nextIndex == selections[j])
  14614. throw MakeStringException(ROXIE_NWAY_INPUT_ERROR, "Selection list for nway input can not contain duplicates");
  14615. }
  14616. if (nextIndex > numInputs || nextIndex > numStreams)
  14617. throw MakeStringException(ROXIE_NWAY_INPUT_ERROR, "Index %d in RANGE selection list is out of range", nextIndex);
  14618. selectedInputs.append(inputArray[nextIndex-1]);
  14619. selectedStreams.append(streamArray[nextIndex-1]); // Assumes 1:1 relationship - is that good?
  14620. selectedJunctions.append(junctionArray[nextIndex-1]);
  14621. }
  14622. }
  14623. // NB: Whatever pulls this nwayinput activity, starts and stops the selectedInputs and selectedJunctions
  14624. // But the N-Way input itself is now done with processing, and can stop itself/dependencies.
  14625. stop();
  14626. }
  14627. };
  14628. class CRoxieServerNWayInputActivityFactory : public CRoxieServerMultiInputFactory
  14629. {
  14630. public:
  14631. CRoxieServerNWayInputActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  14632. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  14633. {
  14634. }
  14635. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  14636. {
  14637. return new CRoxieServerNWayInputActivity(_ctx, this, _probeManager, numInputs());
  14638. }
  14639. };
  14640. IRoxieServerActivityFactory *createRoxieServerNWayInputActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  14641. {
  14642. return new CRoxieServerNWayInputActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  14643. }
  14644. //=====================================================================================================
  14645. class CRoxieServerNWayGraphLoopResultReadActivity : public CRoxieServerNWayInputBaseActivity
  14646. {
  14647. IHThorNWayGraphLoopResultReadArg & helper;
  14648. IArrayOf<IRoxieServerActivity> resultReaders;
  14649. Owned<IStrandJunction> *resultJunctions;
  14650. unsigned graphId;
  14651. bool grouped;
  14652. bool selectionIsAll;
  14653. size32_t selectionLen;
  14654. rtlDataAttr selection;
  14655. public:
  14656. CRoxieServerNWayGraphLoopResultReadActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _graphId)
  14657. : CRoxieServerNWayInputBaseActivity(_ctx, _factory, _probeManager, 0), helper((IHThorNWayGraphLoopResultReadArg &)basehelper)
  14658. {
  14659. grouped = helper.isGrouped();
  14660. graphId = _graphId;
  14661. selectionIsAll = false;
  14662. selectionLen = 0;
  14663. resultJunctions = NULL;
  14664. }
  14665. ~CRoxieServerNWayGraphLoopResultReadActivity()
  14666. {
  14667. delete [] resultJunctions;
  14668. }
  14669. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14670. {
  14671. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  14672. if (selectedInputs.ordinality() == 0)
  14673. {
  14674. initInputSelection();
  14675. unsigned max = selectionLen / sizeof(size32_t);
  14676. const size32_t * selections = (const size32_t *)selection.getdata();
  14677. IProbeManager * probeManager = NULL; // MORE!!
  14678. for (unsigned i = 0; i < max; i++)
  14679. {
  14680. CRoxieServerActivity * resultInput = new CRoxieServerInternalGraphLoopResultReadActivity(ctx, factory, probeManager, graphId, selections[i]);
  14681. resultReaders.append(*resultInput);
  14682. selectedInputs.append(resultInput);
  14683. resultInput->onCreate(colocalParent);
  14684. resultInput->start(parentExtractSize, parentExtract, paused);
  14685. selectedStreams.append(connectSingleStream(ctx, resultInput, 0, resultJunctions[i], true));
  14686. selectedJunctions.append(resultJunctions[i]);
  14687. }
  14688. }
  14689. // I have done with my processing - note that this won't stop my inputs
  14690. stop();
  14691. }
  14692. virtual void reset()
  14693. {
  14694. resultReaders.kill();
  14695. CRoxieServerNWayInputBaseActivity::reset();
  14696. ForEachItemIn(i, selectedStreams)
  14697. resetJunction(resultJunctions[i]);
  14698. }
  14699. virtual void gatherIterationUsage(IRoxieServerLoopResultProcessor & processor, unsigned parentExtractSize, const byte * parentExtract)
  14700. {
  14701. ensureCreated();
  14702. basehelper.onStart(parentExtract, NULL);
  14703. initInputSelection();
  14704. unsigned max = selectionLen / sizeof(size32_t);
  14705. const size32_t * selections = (const size32_t *)selection.getdata();
  14706. for (unsigned i = 0; i < max; i++)
  14707. processor.noteUseIteration(selections[i]);
  14708. }
  14709. virtual void associateIterationOutputs(IRoxieServerLoopResultProcessor & processor, unsigned parentExtractSize, const byte * parentExtract, IProbeManager *probeManager, IArrayOf<IRoxieProbe> &probes)
  14710. {
  14711. //selection etc. already initialised from the gatherIterationUsage() call.
  14712. unsigned max = selectionLen / sizeof(size32_t);
  14713. const size32_t * selections = (const size32_t *)selection.getdata();
  14714. resultJunctions = new Owned<IStrandJunction> [max];
  14715. for (unsigned i = 0; i < max; i++)
  14716. {
  14717. IFinalRoxieInput *in = processor.connectIterationOutput(selections[i], probeManager, probes, this, i);
  14718. selectedInputs.append(in);
  14719. selectedStreams.append(connectSingleStream(ctx, in, 0, resultJunctions[i], true));
  14720. selectedJunctions.append(resultJunctions[i]);
  14721. }
  14722. }
  14723. protected:
  14724. void initInputSelection()
  14725. {
  14726. helper.getInputSelection(selectionIsAll, selectionLen, selection.refdata());
  14727. if (selectionIsAll)
  14728. throw MakeStringException(ROXIE_NWAY_INPUT_ERROR, "ALL not yet supported for NWay graph inputs");
  14729. }
  14730. };
  14731. class CRoxieServerNWayGraphLoopResultReadActivityFactory : public CRoxieServerActivityFactory
  14732. {
  14733. unsigned graphId;
  14734. public:
  14735. CRoxieServerNWayGraphLoopResultReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned _graphId)
  14736. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode), graphId(_graphId)
  14737. {
  14738. }
  14739. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  14740. {
  14741. return new CRoxieServerNWayGraphLoopResultReadActivity(_ctx, this, _probeManager, graphId);
  14742. }
  14743. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  14744. {
  14745. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for NWay GraphLoopResultRead activity");
  14746. }
  14747. };
  14748. IRoxieServerActivityFactory *createRoxieServerNWayGraphLoopResultReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned graphId)
  14749. {
  14750. return new CRoxieServerNWayGraphLoopResultReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, graphId);
  14751. }
  14752. //=================================================================================
  14753. class RoxieSteppedInput : implements ISteppedInput, public CInterface
  14754. {
  14755. public:
  14756. RoxieSteppedInput(IFinalRoxieInput * _input, IEngineRowStream *_stream) { input = _input; inputStream = _stream; }
  14757. IMPLEMENT_IINTERFACE
  14758. protected:
  14759. virtual const void * nextInputRow()
  14760. {
  14761. #ifdef TRACE_SEEK_REQUESTS
  14762. IRoxieContextLogger * logger = input->queryActivity();
  14763. const void * ret = doNextInputRow();
  14764. {
  14765. CommonXmlWriter xmlwrite(XWFtrim|XWFopt|XWFnoindent);
  14766. if (!ret)
  14767. xmlwrite.outputBool(true,"eof");
  14768. else if (input->queryOutputMeta()->hasXML())
  14769. input->queryOutputMeta()->toXML((byte *) ret, xmlwrite);
  14770. logger->CTXLOG("next() returns (%s)", xmlwrite.str());
  14771. }
  14772. return ret;
  14773. #else
  14774. return inputStream->ungroupedNextRow();
  14775. #endif
  14776. }
  14777. virtual const void * nextInputRowGE(const void * seek, unsigned numFields, bool & wasCompleteMatch, const SmartStepExtra & stepExtra)
  14778. {
  14779. #ifdef TRACE_SEEK_REQUESTS
  14780. IRoxieContextLogger * logger = input->queryActivity();
  14781. {
  14782. CommonXmlWriter xmlwrite(XWFtrim|XWFopt|XWFnoindent);
  14783. if (input->queryOutputMeta()->hasXML())
  14784. input->queryOutputMeta()->toXML((byte *) seek, xmlwrite);
  14785. logger->CTXLOG("nextInputRowGE(%d, %s%s%s, %s) seek(%s)",
  14786. numFields,
  14787. stepExtra.readAheadManyResults() ? "readahead " : "",
  14788. stepExtra.returnMismatches() ? "mismatch" : "exact",
  14789. stepExtra.onlyReturnFirstSeekMatch() ? " single-match" : "",
  14790. stepExtra.queryExtraSeeks() ? "multi-seek":"",
  14791. xmlwrite.str());
  14792. }
  14793. const void * ret = doNextInputRowGE(seek, numFields, wasCompleteMatch, stepExtra);
  14794. {
  14795. CommonXmlWriter xmlwrite(XWFtrim|XWFopt|XWFnoindent);
  14796. if (!ret)
  14797. xmlwrite.outputBool(true,"eof");
  14798. else if (input->queryOutputMeta()->hasXML())
  14799. input->queryOutputMeta()->toXML((byte *) ret, xmlwrite);
  14800. logger->CTXLOG("nextInputRowGE(%d, %s%s%s, %s) result(%s)",
  14801. numFields,
  14802. stepExtra.readAheadManyResults() ? "readahead " : "",
  14803. stepExtra.returnMismatches() ? "mismatch" : "exact",
  14804. stepExtra.onlyReturnFirstSeekMatch() ? " single-match" : "",
  14805. stepExtra.queryExtraSeeks() ? "multi-seek":"",
  14806. xmlwrite.str());
  14807. }
  14808. return ret;
  14809. #else
  14810. return doNextInputRowGE(seek, numFields, wasCompleteMatch, stepExtra);
  14811. #endif
  14812. }
  14813. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  14814. {
  14815. return input->gatherConjunctions(collector);
  14816. }
  14817. virtual void resetEOF()
  14818. {
  14819. inputStream->resetEOF();
  14820. }
  14821. virtual IInputSteppingMeta * queryInputSteppingMeta()
  14822. {
  14823. return input->querySteppingMeta();
  14824. }
  14825. inline const void * doNextInputRowGE(const void * seek, unsigned numFields, bool & wasCompleteMatch, const SmartStepExtra & stepExtra)
  14826. {
  14827. assertex(wasCompleteMatch);
  14828. return inputStream->nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);
  14829. }
  14830. protected:
  14831. IFinalRoxieInput * input;
  14832. IEngineRowStream * inputStream;
  14833. };
  14834. //=================================================================================
  14835. class CRoxieServerNWayBaseActivity : public CRoxieServerMultiInputBaseActivity
  14836. {
  14837. public:
  14838. CRoxieServerNWayBaseActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  14839. : CRoxieServerMultiInputBaseActivity(_ctx, _factory, _probeManager, _numInputs)
  14840. {
  14841. }
  14842. void startExpandedInputs(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14843. {
  14844. ForEachItemIn(ei, expandedInputs)
  14845. expandedInputs.item(ei)->start(parentExtractSize, parentExtract, paused);
  14846. ForEachItemIn(idx, expandedInputs)
  14847. startJunction(expandedJunctions.item(idx));
  14848. }
  14849. virtual void stop()
  14850. {
  14851. ForEachItemIn(i, expandedStreams)
  14852. expandedStreams.item(i)->stop();
  14853. CRoxieServerMultiInputBaseActivity::stop();
  14854. }
  14855. virtual void reset()
  14856. {
  14857. ForEachItemIn(idx, expandedInputs)
  14858. resetJunction(expandedJunctions.item(idx));
  14859. expandedInputs.kill();
  14860. expandedStreams.kill();
  14861. expandedJunctions.kill();
  14862. CRoxieServerMultiInputBaseActivity::reset();
  14863. }
  14864. protected:
  14865. PointerArrayOf<IFinalRoxieInput> expandedInputs;
  14866. PointerArrayOf<IEngineRowStream> expandedStreams;
  14867. PointerArrayOf<IStrandJunction> expandedJunctions;
  14868. };
  14869. //=================================================================================
  14870. class CRoxieServerNaryActivity : public CRoxieServerNWayBaseActivity
  14871. {
  14872. public:
  14873. CRoxieServerNaryActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  14874. : CRoxieServerNWayBaseActivity(_ctx, _factory, _probeManager, _numInputs)
  14875. {
  14876. }
  14877. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14878. {
  14879. CRoxieServerNWayBaseActivity::start(parentExtractSize, parentExtract, paused);
  14880. for (unsigned i=0; i < numInputs; i++)
  14881. {
  14882. IFinalRoxieInput * cur = inputArray[i];
  14883. CRoxieServerNWayInputBaseActivity *nWayInput = dynamic_cast<CRoxieServerNWayInputBaseActivity *>(cur);
  14884. if (nWayInput)
  14885. {
  14886. nWayInput->start(parentExtractSize, parentExtract, paused);
  14887. unsigned numRealInputs = cur->numConcreteOutputs();
  14888. for (unsigned j = 0; j < numRealInputs; j++)
  14889. {
  14890. expandedInputs.append(cur->queryConcreteInput(j));
  14891. expandedStreams.append(cur->queryConcreteOutputStream(j));
  14892. expandedJunctions.append(cur->queryConcreteOutputJunction(j));
  14893. }
  14894. }
  14895. else
  14896. {
  14897. expandedInputs.append(cur);
  14898. // NB: this activities input streams + junction have been setup and held in CRoxieServerMultiInputActivity base
  14899. expandedStreams.append(queryConcreteOutputStream(i));
  14900. expandedJunctions.append(queryConcreteOutputJunction(i));
  14901. }
  14902. }
  14903. startExpandedInputs(parentExtractSize, parentExtract, paused);
  14904. }
  14905. };
  14906. //=================================================================================
  14907. class CRoxieStreamMerger : public CStreamMerger
  14908. {
  14909. public:
  14910. CRoxieStreamMerger() : CStreamMerger(true)
  14911. {
  14912. streamArray = NULL;
  14913. }
  14914. void initInputs(unsigned _numInputs, IEngineRowStream ** _streamArray)
  14915. {
  14916. CStreamMerger::initInputs(_numInputs);
  14917. streamArray = _streamArray;
  14918. }
  14919. virtual bool pullInput(unsigned i, const void * seek, unsigned numFields, const SmartStepExtra * stepExtra)
  14920. {
  14921. const void * next;
  14922. bool matches = true;
  14923. if (seek)
  14924. next = streamArray[i]->nextRowGE(seek, numFields, matches, *stepExtra);
  14925. else
  14926. next = streamArray[i]->ungroupedNextRow();
  14927. pending[i] = next;
  14928. pendingMatches[i] = matches;
  14929. return (next != NULL);
  14930. }
  14931. virtual void releaseRow(const void * row)
  14932. {
  14933. ReleaseRoxieRow(row);
  14934. }
  14935. protected:
  14936. IEngineRowStream **streamArray;
  14937. };
  14938. class CRoxieServerNWayMergeActivity : public CRoxieServerNaryActivity
  14939. {
  14940. public:
  14941. CRoxieServerNWayMergeActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  14942. : CRoxieServerNaryActivity(_ctx, _factory, _probeManager, _numInputs),
  14943. helper((IHThorNWayMergeArg &)basehelper)
  14944. {
  14945. initializedMeta = false;
  14946. }
  14947. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14948. {
  14949. CRoxieServerNaryActivity::start(parentExtractSize, parentExtract, paused);
  14950. merger.init(helper.queryCompare(), helper.dedup(), helper.querySteppingMeta()->queryCompare());
  14951. merger.initInputs(expandedStreams.length(), expandedStreams.getArray());
  14952. }
  14953. virtual void stop()
  14954. {
  14955. merger.done();
  14956. CRoxieServerNaryActivity::stop();
  14957. }
  14958. virtual void reset()
  14959. {
  14960. merger.cleanup();
  14961. CRoxieServerNaryActivity::reset();
  14962. initializedMeta = false;
  14963. }
  14964. virtual const void * nextRow()
  14965. {
  14966. ActivityTimer t(totalCycles, timeActivities);
  14967. const void * next = merger.nextRow();
  14968. if (next)
  14969. processed++;
  14970. return next;
  14971. }
  14972. virtual const void * nextRowGE(const void * seek, unsigned numFields, bool & wasCompleteMatch, const SmartStepExtra & stepExtra)
  14973. {
  14974. ActivityTimer t(totalCycles, timeActivities);
  14975. const void * next = merger.nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);
  14976. if (next)
  14977. processed++;
  14978. return next;
  14979. }
  14980. virtual IInputSteppingMeta * querySteppingMeta()
  14981. {
  14982. if (expandedStreams.ordinality() == 0)
  14983. return NULL;
  14984. if (!initializedMeta)
  14985. {
  14986. meta.init(helper.querySteppingMeta(), false);
  14987. ForEachItemIn(i, expandedStreams)
  14988. {
  14989. if (meta.getNumFields() == 0)
  14990. break;
  14991. IInputSteppingMeta * inputMeta = expandedInputs.item(i)->querySteppingMeta();
  14992. meta.intersect(inputMeta);
  14993. }
  14994. initializedMeta = true;
  14995. }
  14996. if (meta.getNumFields() == 0)
  14997. return NULL;
  14998. return &meta;
  14999. }
  15000. protected:
  15001. IHThorNWayMergeArg &helper;
  15002. CRoxieStreamMerger merger;
  15003. CSteppingMeta meta;
  15004. bool initializedMeta;
  15005. };
  15006. class CRoxieServerNWayMergeActivityFactory : public CRoxieServerMultiInputFactory
  15007. {
  15008. public:
  15009. CRoxieServerNWayMergeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  15010. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  15011. {
  15012. }
  15013. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  15014. {
  15015. return new CRoxieServerNWayMergeActivity(_ctx, this, _probeManager, numInputs());
  15016. }
  15017. };
  15018. IRoxieServerActivityFactory *createRoxieServerNWayMergeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  15019. {
  15020. return new CRoxieServerNWayMergeActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  15021. }
  15022. //=================================================================================
  15023. class CRoxieServerNWayMergeJoinActivity : public CRoxieServerNaryActivity
  15024. {
  15025. public:
  15026. CRoxieServerNWayMergeJoinActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs, CMergeJoinProcessor & _processor)
  15027. : CRoxieServerNaryActivity(_ctx, _factory, _probeManager, _numInputs),processor(_processor),
  15028. helper((IHThorNWayMergeJoinArg &)basehelper)
  15029. {
  15030. }
  15031. virtual void onCreate(IHThorArg *_colocalParent)
  15032. {
  15033. CRoxieServerNaryActivity::onCreate(_colocalParent);
  15034. ICodeContext * codectx = ctx->queryCodeContext();
  15035. inputAllocator.setown(createRowAllocator(helper.queryInputMeta()));
  15036. outputAllocator.setown(createRowAllocator(helper.queryOutputMeta()));
  15037. }
  15038. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  15039. {
  15040. CRoxieServerNaryActivity::start(parentExtractSize, parentExtract, paused);
  15041. ForEachItemIn(i1, expandedInputs)
  15042. {
  15043. Owned<RoxieSteppedInput> stepInput = new RoxieSteppedInput(expandedInputs.item(i1), expandedStreams.item(i1));
  15044. processor.addInput(stepInput);
  15045. }
  15046. processor.beforeProcessing(inputAllocator, outputAllocator);
  15047. }
  15048. virtual void stop()
  15049. {
  15050. processor.afterProcessing();
  15051. CRoxieServerNaryActivity::stop();
  15052. }
  15053. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  15054. {
  15055. return processor.gatherConjunctions(collector);
  15056. }
  15057. virtual void resetEOF()
  15058. {
  15059. processor.queryResetEOF();
  15060. }
  15061. virtual const void * nextRow()
  15062. {
  15063. ActivityTimer t(totalCycles, timeActivities);
  15064. const void * next = processor.nextRow();
  15065. if (next)
  15066. processed++;
  15067. return next;
  15068. }
  15069. virtual const void * nextRowGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  15070. {
  15071. ActivityTimer t(totalCycles, timeActivities);
  15072. const void * next = processor.nextGE(seek, numFields, wasCompleteMatch, stepExtra);
  15073. if (next)
  15074. processed++;
  15075. return next;
  15076. }
  15077. virtual IInputSteppingMeta * querySteppingMeta()
  15078. {
  15079. return processor.queryInputSteppingMeta();
  15080. }
  15081. virtual void gatherStats(CRuntimeStatisticCollection & merged) const override
  15082. {
  15083. CRoxieServerNaryActivity::gatherStats(merged);
  15084. if (inputAllocator)
  15085. inputAllocator->gatherStats(merged);
  15086. if (outputAllocator)
  15087. outputAllocator->gatherStats(merged);
  15088. }
  15089. protected:
  15090. IHThorNWayMergeJoinArg & helper;
  15091. CMergeJoinProcessor & processor;
  15092. Owned<IEngineRowAllocator> inputAllocator;
  15093. Owned<IEngineRowAllocator> outputAllocator;
  15094. };
  15095. class CRoxieServerAndMergeJoinActivity : public CRoxieServerNWayMergeJoinActivity
  15096. {
  15097. public:
  15098. CRoxieServerAndMergeJoinActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  15099. : CRoxieServerNWayMergeJoinActivity(_ctx, _factory, _probeManager, _numInputs, andProcessor), andProcessor(helper)
  15100. {
  15101. }
  15102. protected:
  15103. CAndMergeJoinProcessor andProcessor;
  15104. };
  15105. class CRoxieServerAndLeftMergeJoinActivity : public CRoxieServerNWayMergeJoinActivity
  15106. {
  15107. public:
  15108. CRoxieServerAndLeftMergeJoinActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  15109. : CRoxieServerNWayMergeJoinActivity(_ctx, _factory, _probeManager, _numInputs, andLeftProcessor), andLeftProcessor(helper)
  15110. {
  15111. }
  15112. protected:
  15113. CAndLeftMergeJoinProcessor andLeftProcessor;
  15114. };
  15115. class CRoxieServerMofNMergeJoinActivity : public CRoxieServerNWayMergeJoinActivity
  15116. {
  15117. public:
  15118. CRoxieServerMofNMergeJoinActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  15119. : CRoxieServerNWayMergeJoinActivity(_ctx, _factory, _probeManager, _numInputs, mofnProcessor), mofnProcessor(helper)
  15120. {
  15121. }
  15122. protected:
  15123. CMofNMergeJoinProcessor mofnProcessor;
  15124. };
  15125. class CRoxieServerProximityJoinActivity : public CRoxieServerNWayMergeJoinActivity
  15126. {
  15127. public:
  15128. CRoxieServerProximityJoinActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  15129. : CRoxieServerNWayMergeJoinActivity(_ctx, _factory, _probeManager, _numInputs, proximityProcessor), proximityProcessor(helper)
  15130. {
  15131. }
  15132. protected:
  15133. CProximityJoinProcessor proximityProcessor;
  15134. };
  15135. class CRoxieServerNWayMergeJoinActivityFactory : public CRoxieServerMultiInputFactory
  15136. {
  15137. unsigned flags;
  15138. public:
  15139. CRoxieServerNWayMergeJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  15140. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  15141. {
  15142. Owned<IHThorNWayMergeJoinArg> helper = (IHThorNWayMergeJoinArg *) helperFactory();
  15143. flags = helper->getJoinFlags();
  15144. }
  15145. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  15146. {
  15147. if (flags & IHThorNWayMergeJoinArg::MJFhasrange)
  15148. return new CRoxieServerProximityJoinActivity(_ctx, this, _probeManager, numInputs());
  15149. switch (flags & IHThorNWayMergeJoinArg::MJFkindmask)
  15150. {
  15151. case IHThorNWayMergeJoinArg::MJFinner:
  15152. return new CRoxieServerAndMergeJoinActivity(_ctx, this, _probeManager, numInputs());
  15153. case IHThorNWayMergeJoinArg::MJFleftonly:
  15154. case IHThorNWayMergeJoinArg::MJFleftouter:
  15155. return new CRoxieServerAndLeftMergeJoinActivity(_ctx, this, _probeManager, numInputs());
  15156. case IHThorNWayMergeJoinArg::MJFmofn:
  15157. return new CRoxieServerMofNMergeJoinActivity(_ctx, this, _probeManager, numInputs());
  15158. default:
  15159. throwUnexpected();
  15160. }
  15161. }
  15162. };
  15163. IRoxieServerActivityFactory *createRoxieServerNWayMergeJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  15164. {
  15165. return new CRoxieServerNWayMergeJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  15166. }
  15167. //=================================================================================
  15168. class CRoxieServerNWaySelectActivity : public CRoxieServerNWayBaseActivity
  15169. {
  15170. IHThorNWaySelectArg &helper;
  15171. public:
  15172. CRoxieServerNWaySelectActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  15173. : CRoxieServerNWayBaseActivity(_ctx, _factory, _probeManager, _numInputs),
  15174. helper((IHThorNWaySelectArg &)basehelper)
  15175. {
  15176. }
  15177. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  15178. {
  15179. CRoxieServerNWayBaseActivity::start(parentExtractSize, parentExtract, paused);
  15180. unsigned whichInput = helper.getInputIndex();
  15181. selectedInput = nullptr;
  15182. selectedStream = nullptr;
  15183. if (whichInput--)
  15184. {
  15185. for (unsigned i=0; i < numInputs; i++)
  15186. {
  15187. IFinalRoxieInput * cur = inputArray[i];
  15188. CRoxieServerNWayInputBaseActivity *nWayInput = dynamic_cast<CRoxieServerNWayInputBaseActivity *>(cur);
  15189. if (nWayInput)
  15190. {
  15191. nWayInput->start(parentExtractSize, parentExtract, paused);
  15192. unsigned numRealInputs = cur->numConcreteOutputs();
  15193. if (whichInput < numRealInputs)
  15194. {
  15195. expandedInputs.append(cur->queryConcreteInput(whichInput));
  15196. expandedStreams.append(cur->queryConcreteOutputStream(whichInput));
  15197. expandedJunctions.append(cur->queryConcreteOutputJunction(whichInput));
  15198. break;
  15199. }
  15200. whichInput -= numRealInputs;
  15201. }
  15202. else
  15203. {
  15204. if (whichInput == 0)
  15205. {
  15206. expandedInputs.append(cur);
  15207. // NB: this activities input streams + junction have been setup and held in CRoxieServerMultiInputActivity base
  15208. expandedStreams.append(queryConcreteOutputStream(i));
  15209. expandedJunctions.append(queryConcreteOutputJunction(i));
  15210. break;
  15211. }
  15212. whichInput -= 1;
  15213. }
  15214. }
  15215. }
  15216. if (expandedInputs.ordinality())
  15217. {
  15218. startExpandedInputs(parentExtractSize, parentExtract, paused);
  15219. selectedInput = expandedInputs.item(0);
  15220. selectedStream = expandedStreams.item(0);
  15221. }
  15222. }
  15223. const void * nextRow()
  15224. {
  15225. ActivityTimer t(totalCycles, timeActivities);
  15226. if (!selectedStream)
  15227. return NULL;
  15228. return selectedStream->nextRow();
  15229. }
  15230. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  15231. {
  15232. if (!selectedInput)
  15233. return false;
  15234. return selectedInput->gatherConjunctions(collector);
  15235. }
  15236. virtual void resetEOF()
  15237. {
  15238. if (selectedStream)
  15239. selectedStream->resetEOF();
  15240. }
  15241. virtual const void * nextRowGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  15242. {
  15243. ActivityTimer t(totalCycles, timeActivities);
  15244. if (!selectedStream)
  15245. return NULL;
  15246. return selectedStream->nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);
  15247. }
  15248. IInputSteppingMeta * querySteppingMeta()
  15249. {
  15250. if (selectedInput)
  15251. return selectedInput->querySteppingMeta();
  15252. return NULL;
  15253. }
  15254. protected:
  15255. IFinalRoxieInput * selectedInput = nullptr;
  15256. IEngineRowStream * selectedStream = nullptr;
  15257. Owned<IStrandJunction> selectedJunction;
  15258. };
  15259. class CRoxieServerNWaySelectActivityFactory : public CRoxieServerMultiInputFactory
  15260. {
  15261. public:
  15262. CRoxieServerNWaySelectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  15263. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  15264. {
  15265. }
  15266. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  15267. {
  15268. return new CRoxieServerNWaySelectActivity(_ctx, this, _probeManager, numInputs());
  15269. }
  15270. };
  15271. IRoxieServerActivityFactory *createRoxieServerNWaySelectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  15272. {
  15273. return new CRoxieServerNWaySelectActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  15274. }
  15275. //=================================================================================
  15276. class CRoxieServerRemoteActivity : public CRoxieServerActivity, implements IRoxieServerErrorHandler
  15277. {
  15278. protected:
  15279. IHThorRemoteArg &helper;
  15280. CRemoteResultAdaptor remote;
  15281. public:
  15282. CRoxieServerRemoteActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteID)
  15283. : CRoxieServerActivity(_ctx, _factory, _probeManager),
  15284. helper((IHThorRemoteArg &)basehelper),
  15285. remote(_ctx, this, _remoteID, meta.queryOriginal(), helper, *this, false, false) // MORE - if they need it stable we'll have to think!
  15286. {
  15287. }
  15288. virtual const IResolvedFile *queryVarFileInfo() const
  15289. {
  15290. return NULL;
  15291. }
  15292. virtual void onCreate(IHThorArg *_colocalParent)
  15293. {
  15294. CRoxieServerActivity::onCreate(_colocalParent);
  15295. remote.onCreate(_colocalParent);
  15296. }
  15297. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  15298. {
  15299. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  15300. remote.onStart(parentExtractSize, parentExtract);
  15301. remote.setLimits(helper.getRowLimit(), (unsigned __int64) -1, I64C(0x7FFFFFFFFFFFFFFF));
  15302. unsigned fileNo = 0; // MORE - superfiles require us to do this per file part... maybe (needs thought)
  15303. remote.getMem(0, fileNo, 0); // the cached context is all we need to send
  15304. remote.flush();
  15305. remote.senddone();
  15306. }
  15307. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  15308. {
  15309. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  15310. }
  15311. virtual IFinalRoxieInput *queryOutput(unsigned idx)
  15312. {
  15313. if (idx==(unsigned)-1)
  15314. idx = 0;
  15315. return idx ? NULL: &remote;
  15316. }
  15317. virtual void reset()
  15318. {
  15319. processed = remote.processed;
  15320. remote.processed = 0;
  15321. CRoxieServerActivity::reset();
  15322. }
  15323. virtual void onLimitExceeded(bool isKeyed)
  15324. {
  15325. if (traceLevel > 4)
  15326. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  15327. helper.onLimitExceeded();
  15328. }
  15329. virtual const void *createLimitFailRow(bool isKeyed)
  15330. {
  15331. UNIMPLEMENTED; // MORE - is there an ONFAIL for a limit folded into a remote?
  15332. }
  15333. virtual const void *nextRow()
  15334. {
  15335. throwUnexpected(); // I am nobody's input
  15336. }
  15337. virtual void gatherStats(CRuntimeStatisticCollection & merged) const override
  15338. {
  15339. CRoxieServerActivity::gatherStats(merged);
  15340. remote.gatherStats(merged);
  15341. }
  15342. };
  15343. class CRoxieServerRemoteActivityFactory : public CRoxieServerActivityFactory
  15344. {
  15345. public:
  15346. RemoteActivityId remoteId;
  15347. bool isRoot;
  15348. CRoxieServerRemoteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, const RemoteActivityId &_remoteId, bool _isRoot)
  15349. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode), remoteId(_remoteId), isRoot(_isRoot)
  15350. {
  15351. }
  15352. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  15353. {
  15354. return new CRoxieServerRemoteActivity(_ctx, this, _probeManager, remoteId);
  15355. }
  15356. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  15357. {
  15358. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for %s activity", getActivityText(kind));
  15359. }
  15360. virtual bool isSink() const
  15361. {
  15362. //I don't think the action version of this is implemented - but this would be the code
  15363. return isRoot && !meta.queryOriginal();
  15364. }
  15365. virtual const StatisticsMapping &queryStatsMapping() const
  15366. {
  15367. return allStatistics; // Child queries...
  15368. }
  15369. };
  15370. IRoxieServerActivityFactory *createRoxieServerRemoteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, const RemoteActivityId &_remoteId, bool _isRoot)
  15371. {
  15372. return new CRoxieServerRemoteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _remoteId, _isRoot);
  15373. }
  15374. //=================================================================================
  15375. class CRoxieServerIterateActivity : public CRoxieServerActivity
  15376. {
  15377. IHThorIterateArg &helper;
  15378. OwnedConstRoxieRow defaultRecord;
  15379. OwnedConstRoxieRow left;
  15380. OwnedConstRoxieRow right;
  15381. unsigned counter;
  15382. public:
  15383. CRoxieServerIterateActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  15384. : CRoxieServerActivity(_ctx, _factory, _probeManager),
  15385. helper((IHThorIterateArg &)basehelper)
  15386. {
  15387. counter = 0;
  15388. }
  15389. virtual bool needsAllocator() const { return true; }
  15390. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  15391. {
  15392. counter = 0;
  15393. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  15394. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  15395. size32_t thisSize = helper.createDefault(rowBuilder);
  15396. defaultRecord.setown(rowBuilder.finalizeRowClear(thisSize));
  15397. }
  15398. virtual void reset()
  15399. {
  15400. defaultRecord.clear();
  15401. right.clear();
  15402. left.clear();
  15403. CRoxieServerActivity::reset();
  15404. }
  15405. virtual const void * nextRow()
  15406. {
  15407. ActivityTimer t(totalCycles, timeActivities);
  15408. for (;;)
  15409. {
  15410. right.setown(inputStream->nextRow());
  15411. if (!right)
  15412. {
  15413. bool skippedGroup = (left == NULL) && (counter > 0); //we have just skipped entire group, but shouldn't output a double null
  15414. left.clear();
  15415. counter = 0;
  15416. if (skippedGroup) continue;
  15417. return NULL;
  15418. }
  15419. try
  15420. {
  15421. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  15422. unsigned outSize = helper.transform(rowBuilder, left ? left : defaultRecord, right, ++counter);
  15423. if (outSize)
  15424. {
  15425. left.setown(rowBuilder.finalizeRowClear(outSize));
  15426. processed++;
  15427. return left.getLink();
  15428. }
  15429. }
  15430. catch (IException *E)
  15431. {
  15432. throw makeWrappedException(E);
  15433. }
  15434. }
  15435. }
  15436. };
  15437. class CRoxieServerIterateActivityFactory : public CRoxieServerActivityFactory
  15438. {
  15439. public:
  15440. CRoxieServerIterateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  15441. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  15442. {
  15443. }
  15444. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  15445. {
  15446. return new CRoxieServerIterateActivity(_ctx, this, _probeManager);
  15447. }
  15448. };
  15449. IRoxieServerActivityFactory *createRoxieServerIterateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  15450. {
  15451. return new CRoxieServerIterateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  15452. }
  15453. //=================================================================================
  15454. class CRoxieServerProcessActivity : public CRoxieServerActivity
  15455. {
  15456. IHThorProcessArg &helper;
  15457. OwnedConstRoxieRow curRight;
  15458. OwnedConstRoxieRow initialRight;
  15459. unsigned counter;
  15460. Owned<IEngineRowAllocator> rightRowAllocator;
  15461. public:
  15462. CRoxieServerProcessActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  15463. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorProcessArg &)basehelper)
  15464. {
  15465. counter = 0;
  15466. }
  15467. virtual bool needsAllocator() const { return true; }
  15468. virtual void onCreate(IHThorArg *_colocalParent)
  15469. {
  15470. CRoxieServerActivity::onCreate(_colocalParent);
  15471. rightRowAllocator.setown(createRowAllocator(helper.queryRightRecordSize()));
  15472. }
  15473. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  15474. {
  15475. counter = 0;
  15476. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  15477. RtlDynamicRowBuilder rowBuilder(rightRowAllocator);
  15478. size32_t thisSize = helper.createInitialRight(rowBuilder);
  15479. initialRight.setown(rowBuilder.finalizeRowClear(thisSize));
  15480. curRight.set(initialRight);
  15481. }
  15482. virtual const void * nextRow()
  15483. {
  15484. ActivityTimer t(totalCycles, timeActivities);
  15485. try
  15486. {
  15487. for (;;)
  15488. {
  15489. const void * in = inputStream->nextRow();
  15490. if (!in)
  15491. {
  15492. bool eog = (curRight != initialRight); // processed any records?
  15493. counter = 0;
  15494. curRight.set(initialRight);
  15495. if (eog)
  15496. return NULL;
  15497. in = inputStream->nextRow();
  15498. if (!in)
  15499. return NULL;
  15500. }
  15501. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  15502. RtlDynamicRowBuilder rightRowBuilder(rightRowAllocator);
  15503. size32_t outSize = helper.transform(rowBuilder, rightRowBuilder, in, curRight, ++counter);
  15504. ReleaseRoxieRow(in);
  15505. if (outSize)
  15506. {
  15507. //MORE: This should be returned...
  15508. size32_t rightSize = rightRowAllocator->queryOutputMeta()->getRecordSize(rightRowBuilder.getSelf());
  15509. curRight.setown(rightRowBuilder.finalizeRowClear(rightSize));
  15510. processed++;
  15511. return rowBuilder.finalizeRowClear(outSize);
  15512. }
  15513. }
  15514. }
  15515. catch (IException *E)
  15516. {
  15517. throw makeWrappedException(E);
  15518. }
  15519. }
  15520. virtual void gatherStats(CRuntimeStatisticCollection & merged) const override
  15521. {
  15522. CRoxieServerActivity::gatherStats(merged);
  15523. if (rightRowAllocator)
  15524. rightRowAllocator->gatherStats(merged);
  15525. }
  15526. };
  15527. class CRoxieServerProcessActivityFactory : public CRoxieServerActivityFactory
  15528. {
  15529. public:
  15530. CRoxieServerProcessActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  15531. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  15532. {
  15533. }
  15534. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  15535. {
  15536. return new CRoxieServerProcessActivity(_ctx, this, _probeManager);
  15537. }
  15538. };
  15539. IRoxieServerActivityFactory *createRoxieServerProcessActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  15540. {
  15541. return new CRoxieServerProcessActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  15542. }
  15543. //=================================================================================
  15544. class CRoxieServerGroupActivity : public CRoxieServerActivity
  15545. {
  15546. IHThorGroupArg &helper;
  15547. bool endPending;
  15548. bool eof;
  15549. bool first;
  15550. unsigned numGroups;
  15551. unsigned numGroupMax;
  15552. unsigned numProcessedLastGroup;
  15553. const void *next;
  15554. public:
  15555. CRoxieServerGroupActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  15556. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorGroupArg &)basehelper)
  15557. {
  15558. next = NULL;
  15559. endPending = false;
  15560. eof = false;
  15561. first = true;
  15562. numGroups = 0;
  15563. numGroupMax = 0;
  15564. numProcessedLastGroup = 0;
  15565. }
  15566. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  15567. {
  15568. endPending = false;
  15569. eof = false;
  15570. first = true;
  15571. numGroups = 0;
  15572. numGroupMax = 0;
  15573. numProcessedLastGroup = processed;
  15574. assertex(next == NULL);
  15575. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  15576. }
  15577. virtual void reset()
  15578. {
  15579. noteStatistic(StNumGroups, numGroups);
  15580. noteStatistic(StNumGroupMax, numGroupMax);
  15581. ReleaseClearRoxieRow(next);
  15582. CRoxieServerActivity::reset();
  15583. }
  15584. virtual const void * nextRow()
  15585. {
  15586. ActivityTimer t(totalCycles, timeActivities);
  15587. if (first)
  15588. {
  15589. next = inputStream->nextRow();
  15590. first = false;
  15591. }
  15592. if (eof || endPending)
  15593. {
  15594. endPending = false;
  15595. return NULL;
  15596. }
  15597. const void * prev = next;
  15598. next = inputStream->ungroupedNextRow();
  15599. if (next)
  15600. {
  15601. assertex(prev);
  15602. if (!helper.isSameGroup(prev, next))
  15603. {
  15604. noteEndOfGroup();
  15605. endPending = true;
  15606. }
  15607. }
  15608. else
  15609. {
  15610. noteEndOfGroup();
  15611. eof = true;
  15612. }
  15613. if (prev)
  15614. processed++;
  15615. return prev;
  15616. }
  15617. inline void noteEndOfGroup()
  15618. {
  15619. unsigned numThisGroup = processed - numProcessedLastGroup;
  15620. if (numThisGroup == 0)
  15621. return;
  15622. numProcessedLastGroup = processed;
  15623. if (numThisGroup > numGroupMax)
  15624. numGroupMax = numThisGroup;
  15625. numGroups++;
  15626. }
  15627. };
  15628. class CRoxieServerGroupActivityFactory : public CRoxieServerActivityFactory
  15629. {
  15630. public:
  15631. CRoxieServerGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  15632. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  15633. {
  15634. }
  15635. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  15636. {
  15637. return new CRoxieServerGroupActivity(_ctx, this, _probeManager);
  15638. }
  15639. virtual const StatisticsMapping &queryStatsMapping() const
  15640. {
  15641. return groupStatistics;
  15642. }
  15643. };
  15644. IRoxieServerActivityFactory *createRoxieServerGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  15645. {
  15646. return new CRoxieServerGroupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  15647. }
  15648. //=================================================================================
  15649. class CRoxieServerFirstNActivity : public CRoxieServerLateStartActivity
  15650. {
  15651. unsigned __int64 limit;
  15652. unsigned __int64 skip;
  15653. unsigned doneThisGroup;
  15654. IHThorFirstNArg &helper;
  15655. public:
  15656. CRoxieServerFirstNActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  15657. : CRoxieServerLateStartActivity(_ctx, _factory, _probeManager), helper((IHThorFirstNArg &)basehelper)
  15658. {
  15659. doneThisGroup = 0;
  15660. limit = 0;
  15661. skip = 0;
  15662. }
  15663. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  15664. {
  15665. doneThisGroup = 0;
  15666. CRoxieServerLateStartActivity::start(parentExtractSize, parentExtract, paused);
  15667. limit = helper.getLimit();
  15668. skip = helper.numToSkip();
  15669. lateStart(parentExtractSize, parentExtract, limit > 0);
  15670. if (limit + skip >= limit)
  15671. limit += skip;
  15672. }
  15673. const void * nextRow()
  15674. {
  15675. ActivityTimer t(totalCycles, timeActivities);
  15676. if (eof)
  15677. return NULL;
  15678. const void *ret;
  15679. for (;;)
  15680. {
  15681. ret = inputStream->nextRow();
  15682. if (!ret)
  15683. {
  15684. if (meta.isGrouped())
  15685. {
  15686. if (doneThisGroup > skip)
  15687. {
  15688. doneThisGroup = 0;
  15689. return NULL;
  15690. }
  15691. doneThisGroup = 0;
  15692. }
  15693. ret = inputStream->nextRow();
  15694. if (!ret)
  15695. {
  15696. eof = true;
  15697. return NULL;
  15698. }
  15699. }
  15700. doneThisGroup++;
  15701. if (doneThisGroup > skip)
  15702. break;
  15703. ReleaseRoxieRow(ret);
  15704. }
  15705. if (doneThisGroup <= limit)
  15706. {
  15707. processed++;
  15708. return ret;
  15709. }
  15710. ReleaseRoxieRow(ret);
  15711. if (meta.isGrouped())
  15712. {
  15713. while ((ret = inputStream->nextRow()) != NULL)
  15714. ReleaseRoxieRow(ret);
  15715. doneThisGroup = 0;
  15716. }
  15717. else
  15718. eof = true;
  15719. return NULL;
  15720. }
  15721. };
  15722. class CRoxieServerFirstNActivityFactory : public CRoxieServerActivityFactory
  15723. {
  15724. public:
  15725. CRoxieServerFirstNActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  15726. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  15727. {
  15728. }
  15729. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  15730. {
  15731. return new CRoxieServerFirstNActivity(_ctx, this, _probeManager);
  15732. }
  15733. };
  15734. IRoxieServerActivityFactory *createRoxieServerFirstNActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  15735. {
  15736. return new CRoxieServerFirstNActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  15737. }
  15738. //=================================================================================
  15739. class CRoxieServerSelectNActivity : public CRoxieServerActivity
  15740. {
  15741. bool done;
  15742. IHThorSelectNArg &helper;
  15743. public:
  15744. CRoxieServerSelectNActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  15745. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorSelectNArg &)basehelper)
  15746. {
  15747. done = false;
  15748. }
  15749. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  15750. {
  15751. done = false;
  15752. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  15753. }
  15754. const void *defaultRow()
  15755. {
  15756. if (!rowAllocator)
  15757. ensureRowAllocator(); // We delay as often not needed...
  15758. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  15759. size32_t thisSize = helper.createDefault(rowBuilder);
  15760. return rowBuilder.finalizeRowClear(thisSize);
  15761. }
  15762. virtual const void * nextRow()
  15763. {
  15764. ActivityTimer t(totalCycles, timeActivities);
  15765. if (done)
  15766. return NULL;
  15767. done = true;
  15768. processed++; // always going to return a row!
  15769. unsigned __int64 index = helper.getRowToSelect();
  15770. while (--index)
  15771. {
  15772. const void * next = inputStream->ungroupedNextRow();
  15773. if (!next)
  15774. return defaultRow();
  15775. ReleaseRoxieRow(next);
  15776. }
  15777. const void * next = inputStream->ungroupedNextRow();
  15778. if (!next)
  15779. next = defaultRow();
  15780. return next;
  15781. }
  15782. };
  15783. class CRoxieServerSelectNActivityFactory : public CRoxieServerActivityFactory
  15784. {
  15785. public:
  15786. CRoxieServerSelectNActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  15787. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  15788. {
  15789. }
  15790. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  15791. {
  15792. return new CRoxieServerSelectNActivity(_ctx, this, _probeManager);
  15793. }
  15794. };
  15795. IRoxieServerActivityFactory *createRoxieServerSelectNActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  15796. {
  15797. return new CRoxieServerSelectNActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  15798. }
  15799. //=================================================================================
  15800. class CRoxieServerSelfJoinActivity : public CRoxieServerActivity
  15801. {
  15802. IHThorJoinArg &helper;
  15803. ICompare *collate;
  15804. OwnedRowArray group;
  15805. bool matchedLeft;
  15806. BoolArray matchedRight;
  15807. bool eof;
  15808. bool first;
  15809. unsigned leftIndex;
  15810. unsigned rightIndex;
  15811. unsigned rightOuterIndex;
  15812. unsigned joinLimit;
  15813. unsigned atmostLimit;
  15814. unsigned atmostsTriggered;
  15815. unsigned abortLimit;
  15816. unsigned keepLimit;
  15817. unsigned joinCounter;
  15818. bool leftOuterJoin;
  15819. bool rightOuterJoin;
  15820. bool exclude;
  15821. bool limitFail;
  15822. bool limitOnFail;
  15823. bool cloneLeft;
  15824. bool forceSpill;
  15825. OwnedConstRoxieRow defaultLeft;
  15826. OwnedConstRoxieRow defaultRight;
  15827. OwnedConstRoxieRow lhs;
  15828. Owned<IException> failingLimit;
  15829. bool failingOuterAtmost;
  15830. Owned<IEngineRowAllocator> defaultAllocator;
  15831. Owned<IRHLimitedCompareHelper> limitedhelper;
  15832. Owned<CRHDualCache> dualcache;
  15833. Owned<IGroupedInput> groupedInput;
  15834. IRowStream *dualCacheInput;
  15835. bool fillGroup()
  15836. {
  15837. group.clear();
  15838. matchedLeft = false;
  15839. matchedRight.kill();
  15840. failingOuterAtmost = false;
  15841. const void * next;
  15842. unsigned groupCount = 0;
  15843. while((next = groupedInput->nextRow()) != NULL)
  15844. {
  15845. if(groupCount==abortLimit)
  15846. {
  15847. if(limitFail)
  15848. failLimit(next);
  15849. if (ctx->queryDebugContext())
  15850. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  15851. if(limitOnFail)
  15852. {
  15853. assertex(!failingLimit);
  15854. try
  15855. {
  15856. failLimit(next);
  15857. }
  15858. catch(IException * except)
  15859. {
  15860. failingLimit.setown(except);
  15861. }
  15862. assertex(failingLimit != NULL);
  15863. group.append(next);
  15864. groupCount++;
  15865. break;
  15866. }
  15867. group.clear();
  15868. groupCount = 0;
  15869. while(next)
  15870. {
  15871. ReleaseRoxieRow(next);
  15872. next = groupedInput->nextRow();
  15873. }
  15874. }
  15875. else if(groupCount==atmostLimit)
  15876. {
  15877. atmostsTriggered++;
  15878. if(leftOuterJoin)
  15879. {
  15880. group.append(next);
  15881. groupCount++;
  15882. failingOuterAtmost = true;
  15883. break;
  15884. }
  15885. else
  15886. {
  15887. group.clear();
  15888. groupCount = 0;
  15889. while (next)
  15890. {
  15891. ReleaseRoxieRow(next);
  15892. next = groupedInput->nextRow();
  15893. }
  15894. }
  15895. }
  15896. else
  15897. {
  15898. group.append(next);
  15899. groupCount++;
  15900. }
  15901. }
  15902. if(group.ordinality()==0)
  15903. {
  15904. eof = true;
  15905. return false;
  15906. }
  15907. leftIndex = 0;
  15908. rightIndex = 0;
  15909. rightOuterIndex = 0;
  15910. joinCounter = 0;
  15911. joinLimit = keepLimit;
  15912. ForEachItemIn(idx, group)
  15913. matchedRight.append(false);
  15914. return true;
  15915. }
  15916. void failLimit(const void * next)
  15917. {
  15918. helper.onMatchAbortLimitExceeded();
  15919. CommonXmlWriter xmlwrite(XWFtrim|XWFopt );
  15920. if (!ctx->isBlind() && input->queryOutputMeta() && input->queryOutputMeta()->hasXML())
  15921. {
  15922. input->queryOutputMeta()->toXML((byte *) next, xmlwrite);
  15923. }
  15924. throw MakeStringException(ROXIE_TOO_MANY_RESULTS, "More than %d match candidates in self-join %d for row %s", abortLimit, queryId(), xmlwrite.str());
  15925. }
  15926. virtual bool needsAllocator() const { return true; }
  15927. const void *joinRecords(const void * curLeft, const void * curRight, unsigned counter, IException * except, unsigned flags)
  15928. {
  15929. try
  15930. {
  15931. if (cloneLeft && !except)
  15932. {
  15933. LinkRoxieRow(curLeft);
  15934. return curLeft;
  15935. }
  15936. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  15937. size32_t outsize = except ? helper.onFailTransform(rowBuilder, curLeft, curRight, except, flags) : helper.transform(rowBuilder, curLeft, curRight, counter, flags);
  15938. if (outsize)
  15939. return rowBuilder.finalizeRowClear(outsize);
  15940. else
  15941. return NULL;
  15942. }
  15943. catch (IException *E)
  15944. {
  15945. throw makeWrappedException(E);
  15946. }
  15947. }
  15948. void createDefaultLeft()
  15949. {
  15950. if (!defaultLeft)
  15951. {
  15952. if (!defaultAllocator)
  15953. defaultAllocator.setown(createRowAllocator(input->queryOutputMeta()));
  15954. RtlDynamicRowBuilder rowBuilder(defaultAllocator);
  15955. size32_t thisSize = helper.createDefaultLeft(rowBuilder);
  15956. defaultLeft.setown(rowBuilder.finalizeRowClear(thisSize));
  15957. }
  15958. }
  15959. void createDefaultRight()
  15960. {
  15961. if (!defaultRight)
  15962. {
  15963. if (!defaultAllocator)
  15964. defaultAllocator.setown(createRowAllocator(input->queryOutputMeta()));
  15965. RtlDynamicRowBuilder rowBuilder(defaultAllocator);
  15966. size32_t thisSize = helper.createDefaultRight(rowBuilder);
  15967. defaultRight.setown(rowBuilder.finalizeRowClear(thisSize));
  15968. }
  15969. }
  15970. public:
  15971. CRoxieServerSelfJoinActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _forceSpill)
  15972. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorJoinArg &)basehelper), forceSpill(_forceSpill)
  15973. {
  15974. collate = helper.queryCompareLeftRight();
  15975. eof = false;
  15976. first = true;
  15977. keepLimit = 0;
  15978. atmostLimit = 0;
  15979. atmostsTriggered = 0;
  15980. unsigned joinFlags = helper.getJoinFlags();
  15981. leftOuterJoin = (joinFlags & JFleftouter) != 0;
  15982. rightOuterJoin = (joinFlags & JFrightouter) != 0;
  15983. cloneLeft = (joinFlags & JFtransformmatchesleft) != 0;
  15984. exclude = (joinFlags & JFexclude) != 0;
  15985. abortLimit = 0;
  15986. joinLimit = 0;
  15987. assertex((joinFlags & (JFfirst | JFfirstleft | JFfirstright)) == 0); // no longer supported
  15988. getLimitType(joinFlags, limitFail, limitOnFail);
  15989. if((joinFlags & JFslidingmatch) != 0)
  15990. throw MakeStringException(ROXIE_UNIMPLEMENTED_ERROR, "Internal Error: Sliding self join not supported");
  15991. failingOuterAtmost = false;
  15992. matchedLeft = false;
  15993. leftIndex = 0;
  15994. rightIndex = 0;
  15995. rightOuterIndex = 0;
  15996. joinCounter = 0;
  15997. dualCacheInput = NULL;
  15998. }
  15999. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  16000. {
  16001. eof = false;
  16002. first = true;
  16003. failingLimit.clear();
  16004. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  16005. keepLimit = helper.getKeepLimit();
  16006. if(keepLimit == 0)
  16007. keepLimit = (unsigned)-1;
  16008. atmostsTriggered = 0;
  16009. atmostLimit = helper.getJoinLimit();
  16010. if(atmostLimit == 0)
  16011. atmostLimit = (unsigned)-1;
  16012. else
  16013. assertex(!rightOuterJoin);
  16014. abortLimit = helper.getMatchAbortLimit();
  16015. if (abortLimit == 0)
  16016. abortLimit = (unsigned)-1;
  16017. if (rightOuterJoin)
  16018. createDefaultLeft();
  16019. if (leftOuterJoin || limitOnFail)
  16020. createDefaultRight();
  16021. ICompare *compareLeft = helper.queryCompareLeft();
  16022. if (helper.isLeftAlreadySorted())
  16023. groupedInput.setown(createGroupedInputReader(inputStream, compareLeft));
  16024. else
  16025. {
  16026. bool isStable = (helper.getJoinFlags() & JFunstable) == 0;
  16027. RoxieSortAlgorithm sortAlgorithm;
  16028. if (forceSpill)
  16029. sortAlgorithm = isStable ? stableSpillingQuickSortAlgorithm : spillingQuickSortAlgorithm;
  16030. else
  16031. sortAlgorithm = isStable ? stableQuickSortAlgorithm : quickSortAlgorithm;
  16032. groupedInput.setown(createSortedGroupedInputReader(inputStream, compareLeft, createSortAlgorithm(sortAlgorithm, compareLeft, ctx->queryRowManager(), input->queryOutputMeta(), ctx->queryCodeContext(), tempDirectory, activityId)));
  16033. }
  16034. if ((helper.getJoinFlags() & JFlimitedprefixjoin) && helper.getJoinLimit())
  16035. { //limited match join (s[1..n])
  16036. dualcache.setown(new CRHDualCache());
  16037. dualcache->init(groupedInput);
  16038. dualCacheInput = dualcache->queryOut1();
  16039. failingOuterAtmost = false;
  16040. matchedLeft = false;
  16041. leftIndex = 0;
  16042. rightOuterIndex = 0;
  16043. joinCounter = 0;
  16044. limitedhelper.setown(createRHLimitedCompareHelper());
  16045. limitedhelper->init( helper.getJoinLimit(), dualcache->queryOut2(), collate, helper.queryPrefixCompare() );
  16046. }
  16047. }
  16048. virtual void reset()
  16049. {
  16050. if (atmostsTriggered)
  16051. noteStatistic(StNumAtmostTriggered, atmostsTriggered);
  16052. group.clear();
  16053. groupedInput.clear();
  16054. CRoxieServerActivity::reset();
  16055. defaultLeft.clear();
  16056. defaultRight.clear();
  16057. }
  16058. virtual const void * nextRow()
  16059. {
  16060. ActivityTimer t(totalCycles, timeActivities);
  16061. if (limitedhelper)
  16062. {
  16063. while(!eof) //limited match join
  16064. {
  16065. if (!group.isItem(rightIndex))
  16066. {
  16067. lhs.setown(dualCacheInput->nextRow());
  16068. if (lhs)
  16069. {
  16070. rightIndex = 0;
  16071. joinCounter = 0;
  16072. group.clear();
  16073. limitedhelper->getGroup(group,lhs);
  16074. }
  16075. else
  16076. {
  16077. eof = true;
  16078. }
  16079. }
  16080. if (group.isItem(rightIndex))
  16081. {
  16082. const void * rhs = group.item(rightIndex++);
  16083. if(helper.match(lhs, rhs))
  16084. {
  16085. const void * ret = joinRecords(lhs, rhs, ++joinCounter, NULL, JTFmatchedleft|JTFmatchedright);
  16086. if(ret)
  16087. {
  16088. processed++;
  16089. return ret;
  16090. }
  16091. }
  16092. }
  16093. }
  16094. return NULL;
  16095. }
  16096. else
  16097. {
  16098. if (first)
  16099. {
  16100. first = false;
  16101. fillGroup();
  16102. }
  16103. while(!eof)
  16104. {
  16105. if(failingOuterAtmost)
  16106. while(group.isItem(leftIndex))
  16107. {
  16108. const void * ret = joinRecords(group.item(leftIndex++), defaultRight, 0, NULL, JTFmatchedleft);
  16109. if(ret)
  16110. {
  16111. processed++;
  16112. return ret;
  16113. }
  16114. }
  16115. if((joinLimit == 0) || !group.isItem(rightIndex))
  16116. {
  16117. if(leftOuterJoin && !matchedLeft && !failingLimit)
  16118. {
  16119. const void * ret = joinRecords(group.item(leftIndex), defaultRight, 0, NULL, JTFmatchedleft);
  16120. if(ret)
  16121. {
  16122. matchedLeft = true;
  16123. processed++;
  16124. return ret;
  16125. }
  16126. }
  16127. leftIndex++;
  16128. matchedLeft = false;
  16129. rightIndex = 0;
  16130. joinCounter = 0;
  16131. joinLimit = keepLimit;
  16132. }
  16133. if(!group.isItem(leftIndex))
  16134. {
  16135. if(failingLimit || failingOuterAtmost)
  16136. {
  16137. const void * lhs;
  16138. while((lhs = groupedInput->nextRow()) != NULL) // dualCache never active here
  16139. {
  16140. const void * ret = joinRecords(lhs, defaultRight, 0, failingLimit, JTFmatchedleft);
  16141. ReleaseRoxieRow(lhs);
  16142. if(ret)
  16143. {
  16144. processed++;
  16145. return ret;
  16146. }
  16147. }
  16148. failingLimit.clear();
  16149. }
  16150. if(rightOuterJoin && !failingLimit)
  16151. while(group.isItem(rightOuterIndex))
  16152. if(!matchedRight.item(rightOuterIndex++))
  16153. {
  16154. const void * ret = joinRecords(defaultLeft, group.item(rightOuterIndex-1), 0, NULL, JTFmatchedright);
  16155. if(ret)
  16156. {
  16157. processed++;
  16158. return ret;
  16159. }
  16160. }
  16161. if(!fillGroup())
  16162. return NULL;
  16163. continue;
  16164. }
  16165. const void * lhs = group.item(leftIndex);
  16166. if(failingLimit)
  16167. {
  16168. leftIndex++;
  16169. const void * ret = joinRecords(lhs, defaultRight, 0, failingLimit, JTFmatchedleft);
  16170. if(ret)
  16171. {
  16172. processed++;
  16173. return ret;
  16174. }
  16175. }
  16176. else
  16177. {
  16178. const void * rhs = group.item(rightIndex++);
  16179. if(helper.match(lhs, rhs))
  16180. {
  16181. matchedLeft = true;
  16182. matchedRight.replace(true, rightIndex-1);
  16183. if(!exclude)
  16184. {
  16185. const void * ret = joinRecords(lhs, rhs, ++joinCounter, NULL, JTFmatchedleft|JTFmatchedright);
  16186. if(ret)
  16187. {
  16188. processed++;
  16189. joinLimit--;
  16190. return ret;
  16191. }
  16192. }
  16193. }
  16194. }
  16195. }
  16196. return NULL;
  16197. }
  16198. }
  16199. };
  16200. class CRoxieServerSelfJoinActivityFactory : public CRoxieServerActivityFactory
  16201. {
  16202. bool forceSpill;
  16203. public:
  16204. CRoxieServerSelfJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  16205. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  16206. {
  16207. forceSpill = queryFactory.queryOptions().allSortsMaySpill || _graphNode.getPropBool("hint[@name='spill']/@value", false);;
  16208. }
  16209. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  16210. {
  16211. return new CRoxieServerSelfJoinActivity(_ctx, this, _probeManager, forceSpill);
  16212. }
  16213. virtual const StatisticsMapping &queryStatsMapping() const
  16214. {
  16215. return joinStatistics;
  16216. }
  16217. };
  16218. IRoxieServerActivityFactory *createRoxieServerSelfJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  16219. {
  16220. return new CRoxieServerSelfJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  16221. }
  16222. //=====================================================================================================
  16223. class CRoxieServerLookupJoinActivity : public CRoxieServerTwoInputActivity
  16224. {
  16225. private:
  16226. class LookupTable : public CInterface
  16227. {
  16228. public:
  16229. LookupTable(IHThorHashJoinArg &helper)
  16230. : leftRightCompare(helper.queryCompareLeftRight()), rightCompare(helper.queryCompareRight()),
  16231. leftHash(helper.queryHashLeft()), rightHash(helper.queryHashRight())
  16232. {
  16233. size = 0;
  16234. }
  16235. virtual const void *find(const void * left) const = 0;
  16236. virtual const void *findNext(const void * left) const = 0;
  16237. protected:
  16238. ICompare * leftRightCompare;
  16239. ICompare * rightCompare;
  16240. IHash * leftHash;
  16241. IHash * rightHash;
  16242. unsigned size;
  16243. };
  16244. class DedupLookupTable : public LookupTable
  16245. {
  16246. public:
  16247. DedupLookupTable(ConstPointerArray &rightRows, IHThorHashJoinArg &helper)
  16248. : LookupTable(helper)
  16249. {
  16250. size = (4*rightRows.length())/3 + 1;
  16251. table = (const void * *)calloc(size, sizeof(void *)); // This should probably be allocated from roxiemem (and size rounded up to actual available size)
  16252. ForEachItemIn(idx, rightRows)
  16253. add(rightRows.item(idx));
  16254. }
  16255. ~DedupLookupTable()
  16256. {
  16257. roxiemem::ReleaseRoxieRowArray(size, table);
  16258. free(table);
  16259. }
  16260. virtual const void *find(const void * left) const
  16261. {
  16262. unsigned index = leftHash->hash(left) % size;
  16263. unsigned start = index;
  16264. while (table[index])
  16265. {
  16266. if(leftRightCompare->docompare(left, table[index]) == 0)
  16267. return table[index];
  16268. index++;
  16269. if (index==size)
  16270. index = 0;
  16271. if (index==start)
  16272. throw MakeStringException(ROXIE_JOIN_ERROR, "Internal error in lookup join activity (hash table full on lookup)");
  16273. }
  16274. return NULL;
  16275. }
  16276. virtual const void *findNext(const void * left) const
  16277. {
  16278. return NULL;
  16279. }
  16280. protected:
  16281. void add(const void * right)
  16282. {
  16283. unsigned index = rightHash->hash(right) % size;
  16284. unsigned start = index;
  16285. while (table[index])
  16286. {
  16287. if (rightCompare->docompare(table[index], right) == 0)
  16288. {
  16289. ReleaseRoxieRow(right);
  16290. return;
  16291. }
  16292. index++;
  16293. if (index==size)
  16294. index = 0;
  16295. if (index==start)
  16296. throw MakeStringException(ROXIE_JOIN_ERROR, "Internal error in lookup join activity (hash table full on add)");
  16297. }
  16298. table[index] = right;
  16299. }
  16300. const void * * table;
  16301. };
  16302. class FewLookupTable : public LookupTable
  16303. {
  16304. public:
  16305. FewLookupTable(ConstPointerArray &rightRows, IHThorHashJoinArg &helper)
  16306. : LookupTable(helper)
  16307. {
  16308. size = (4*rightRows.length())/3 + 1;
  16309. table = (const void * *)calloc(size, sizeof(void *)); // This should probably be allocated from roxiemem
  16310. findex = fstart = BadIndex;
  16311. ForEachItemIn(idx, rightRows)
  16312. add(rightRows.item(idx));
  16313. }
  16314. ~FewLookupTable()
  16315. {
  16316. roxiemem::ReleaseRoxieRowArray(size, table);
  16317. free(table);
  16318. }
  16319. virtual const void *find(const void * left) const
  16320. {
  16321. fstart = leftHash->hash(left) % size;
  16322. findex = fstart;
  16323. return doFind(left);
  16324. }
  16325. virtual const void *findNext(const void * left) const
  16326. {
  16327. if (findex == BadIndex)
  16328. return NULL;
  16329. advance();
  16330. return doFind(left);
  16331. }
  16332. protected:
  16333. void add(const void * right)
  16334. {
  16335. unsigned start = rightHash->hash(right) % size;
  16336. unsigned index = start;
  16337. while (table[index])
  16338. {
  16339. index++;
  16340. if (index==size)
  16341. index = 0;
  16342. if (index==start)
  16343. throwUnexpected(); //table is full, should never happen
  16344. }
  16345. table[index] = right;
  16346. }
  16347. void advance() const
  16348. {
  16349. findex++;
  16350. if(findex==size)
  16351. findex = 0;
  16352. if(findex==fstart)
  16353. throw MakeStringException(ROXIE_JOIN_ERROR, "Internal error in lookup join activity (hash table full on lookup)");
  16354. }
  16355. const void *doFind(const void * left) const
  16356. {
  16357. while(table[findex])
  16358. {
  16359. if (leftRightCompare->docompare(left, table[findex]) == 0)
  16360. return table[findex];
  16361. advance();
  16362. }
  16363. findex = BadIndex;
  16364. return NULL;
  16365. }
  16366. const void * * table;
  16367. unsigned mutable fstart;
  16368. unsigned mutable findex;
  16369. static unsigned const BadIndex;
  16370. };
  16371. class ManyLookupTable : public LookupTable
  16372. {
  16373. public:
  16374. ManyLookupTable(ConstPointerArray &rightRows, IHThorHashJoinArg &helper)
  16375. : LookupTable(helper)
  16376. {
  16377. rightRows.swapWith(rowtable);
  16378. UInt64Array groups;
  16379. unsigned numRows = rowtable.length();
  16380. if (numRows)
  16381. {
  16382. unsigned groupStart = 0;
  16383. const void *groupStartRow = rowtable.item(0);
  16384. for (unsigned i=1; i < numRows; i++)
  16385. {
  16386. const void *thisRow = rowtable.item(i);
  16387. if (rightCompare->docompare(groupStartRow, thisRow))
  16388. {
  16389. groups.append(makeint64(groupStart, i-groupStart));
  16390. groupStart = i;
  16391. groupStartRow = thisRow;
  16392. }
  16393. }
  16394. groups.append(makeint64(groupStart, numRows-groupStart));
  16395. }
  16396. size = (4*groups.length())/3 + 1;
  16397. table = (__uint64 *) calloc(size, sizeof(__uint64)); // This should probably be allocated from roxiemem
  16398. ForEachItemIn(idx, groups)
  16399. {
  16400. unsigned __int64 group = groups.item(idx);
  16401. unsigned groupstart = high(group);
  16402. const void *row = rowtable.item(groupstart);
  16403. add(row, group);
  16404. }
  16405. }
  16406. ~ManyLookupTable()
  16407. {
  16408. roxiemem::ReleaseRoxieRows(rowtable);
  16409. free(table);
  16410. }
  16411. void add(const void *row, unsigned __int64 group)
  16412. {
  16413. unsigned start = rightHash->hash(row) % size;
  16414. unsigned index = start;
  16415. while (table[index])
  16416. {
  16417. index++;
  16418. if (index==size)
  16419. index = 0;
  16420. if (index==start)
  16421. throwUnexpected(); //table is full, should never happen
  16422. }
  16423. table[index] = group;
  16424. }
  16425. virtual const void *find(const void * left) const
  16426. {
  16427. unsigned index = leftHash->hash(left) % size;
  16428. unsigned start = index;
  16429. while (table[index])
  16430. {
  16431. __uint64 group = table[index];
  16432. currentMatch = high(group);
  16433. const void *right = rowtable.item(currentMatch);
  16434. if (leftRightCompare->docompare(left, right) == 0)
  16435. {
  16436. currentMatch++;
  16437. matchCount = low(group) - 1;
  16438. return right;
  16439. }
  16440. index++;
  16441. if (index==size)
  16442. index = 0;
  16443. if (index==start)
  16444. throw MakeStringException(ROXIE_JOIN_ERROR, "Internal error in lookup join activity (hash table full on lookup)");
  16445. }
  16446. matchCount = 0;
  16447. return NULL;
  16448. }
  16449. virtual const void *findNext(const void * left) const
  16450. {
  16451. if (!matchCount)
  16452. return NULL;
  16453. matchCount--;
  16454. return rowtable.item(currentMatch++);
  16455. }
  16456. protected:
  16457. __uint64 *table;
  16458. ConstPointerArray rowtable;
  16459. mutable unsigned currentMatch = 0;
  16460. mutable unsigned matchCount = 0;
  16461. };
  16462. IHThorHashJoinArg &helper;
  16463. bool leftOuterJoin;
  16464. bool exclude;
  16465. bool eog;
  16466. bool many;
  16467. bool dedupRHS;
  16468. bool useFewTable;
  16469. bool matchedGroup;
  16470. const void *left;
  16471. OwnedConstRoxieRow defaultRight;
  16472. Owned<LookupTable> table;
  16473. unsigned keepLimit;
  16474. unsigned atmostLimit;
  16475. unsigned atmostsTriggered;
  16476. unsigned limitLimit;
  16477. unsigned joinCounter;
  16478. bool limitFail;
  16479. bool limitOnFail;
  16480. bool hasGroupLimit;
  16481. bool isSmartJoin;
  16482. unsigned keepCount;
  16483. bool gotMatch;
  16484. bool cloneLeft;
  16485. ConstPointerArray rightGroup;
  16486. aindex_t rightGroupIndex;
  16487. Owned<IException> failingLimit;
  16488. ConstPointerArray filteredRight;
  16489. ThorActivityKind activityKind;
  16490. Owned<IEngineRowAllocator> defaultRightAllocator;
  16491. void createDefaultRight()
  16492. {
  16493. if (!defaultRight)
  16494. {
  16495. if (!defaultRightAllocator)
  16496. defaultRightAllocator.setown(createRowAllocator(input1->queryOutputMeta()));
  16497. RtlDynamicRowBuilder rowBuilder(defaultRightAllocator);
  16498. size32_t thisSize = helper.createDefaultRight(rowBuilder);
  16499. defaultRight.setown(rowBuilder.finalizeRowClear(thisSize));
  16500. }
  16501. }
  16502. public:
  16503. CRoxieServerLookupJoinActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _useFewTable)
  16504. : CRoxieServerTwoInputActivity(_ctx, _factory, _probeManager), helper((IHThorHashJoinArg &)basehelper), useFewTable(_useFewTable)
  16505. {
  16506. unsigned joinFlags = helper.getJoinFlags();
  16507. leftOuterJoin = (joinFlags & JFleftouter) != 0;
  16508. assertex((joinFlags & JFrightouter) == 0);
  16509. exclude = (joinFlags & JFexclude) != 0;
  16510. many = (joinFlags & JFmanylookup) != 0;
  16511. cloneLeft = (joinFlags & JFtransformmatchesleft) != 0;
  16512. dedupRHS = (joinFlags & (JFmanylookup | JFmatchrequired | JFtransformMaySkip)) == 0; // optimisation: can implicitly dedup RHS unless is many lookup, or match required, or transform may skip
  16513. left = NULL;
  16514. activityKind = factory->getKind();
  16515. eog = false;
  16516. matchedGroup = false;
  16517. gotMatch = false;
  16518. keepLimit = 0;
  16519. keepCount = 0;
  16520. joinCounter = 0;
  16521. atmostLimit = 0;
  16522. atmostsTriggered = 0;
  16523. limitLimit = 0;
  16524. rightGroupIndex = 0;
  16525. hasGroupLimit = false;
  16526. isSmartJoin = (joinFlags & JFsmart) != 0;
  16527. getLimitType(joinFlags, limitFail, limitOnFail);
  16528. }
  16529. void loadRight()
  16530. {
  16531. ConstPointerArray rightset;
  16532. try
  16533. {
  16534. const void * next;
  16535. while(true)
  16536. {
  16537. next = inputStream1->ungroupedNextRow();
  16538. if(!next)
  16539. break;
  16540. rightset.append(next);
  16541. }
  16542. if (!dedupRHS)
  16543. {
  16544. if (useFewTable)
  16545. {
  16546. table.setown(new FewLookupTable(rightset, helper)); // NOTE - takes ownership of rightset
  16547. }
  16548. else
  16549. {
  16550. if (!helper.isRightAlreadySorted())
  16551. {
  16552. if (helper.getJoinFlags() & JFunstable)
  16553. {
  16554. qsortvec(const_cast<void * *>(rightset.getArray()), rightset.ordinality(), *helper.queryCompareRight());
  16555. }
  16556. else
  16557. {
  16558. unsigned rightord = rightset.ordinality();
  16559. MemoryAttr tempAttr(rightord*sizeof(void **)); // Temp storage for stable sort. This should probably be allocated from roxiemem
  16560. void **temp = (void **) tempAttr.bufferBase();
  16561. void **_rows = const_cast<void * *>(rightset.getArray());
  16562. msortvecstableinplace(_rows, rightord, *helper.queryCompareRight(), temp);
  16563. }
  16564. }
  16565. table.setown(new ManyLookupTable(rightset, helper)); // NOTE - takes ownership of rightset
  16566. }
  16567. }
  16568. else
  16569. {
  16570. table.setown(new DedupLookupTable(rightset, helper)); // NOTE - takes ownership of rightset
  16571. }
  16572. }
  16573. catch (...)
  16574. {
  16575. roxiemem::ReleaseRoxieRows(rightset);
  16576. throw;
  16577. }
  16578. };
  16579. virtual void reset()
  16580. {
  16581. if (atmostsTriggered)
  16582. noteStatistic(StNumAtmostTriggered, atmostsTriggered);
  16583. CRoxieServerTwoInputActivity::reset();
  16584. ReleaseClearRoxieRow(left);
  16585. defaultRight.clear();
  16586. table.clear();
  16587. }
  16588. virtual bool needsAllocator() const { return true; }
  16589. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  16590. {
  16591. eog = false;
  16592. matchedGroup = false;
  16593. left = NULL;
  16594. CRoxieServerTwoInputActivity::start(parentExtractSize, parentExtract, paused);
  16595. keepLimit = helper.getKeepLimit();
  16596. if(keepLimit==0) keepLimit = static_cast<unsigned>(-1);
  16597. atmostsTriggered = 0;
  16598. atmostLimit = helper.getJoinLimit();
  16599. limitLimit = helper.getMatchAbortLimit();
  16600. hasGroupLimit = ((atmostLimit > 0) || (limitLimit > 0));
  16601. if(atmostLimit==0) atmostLimit = static_cast<unsigned>(-1);
  16602. if(limitLimit==0) limitLimit = static_cast<unsigned>(-1);
  16603. getLimitType(helper.getJoinFlags(), limitFail, limitOnFail);
  16604. switch (activityKind)
  16605. {
  16606. case TAKlookupjoin:
  16607. case TAKlookupdenormalizegroup:
  16608. case TAKsmartjoin:
  16609. case TAKsmartdenormalizegroup:
  16610. if (leftOuterJoin)
  16611. createDefaultRight();
  16612. break;
  16613. }
  16614. if (limitOnFail)
  16615. createDefaultRight();
  16616. }
  16617. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  16618. {
  16619. if (!idx && (helper.getJoinFlags() & JFparallel) != 0)
  16620. {
  16621. puller.setown(new CRoxieServerReadAheadInput(ctx, ctx->queryOptions().parallelJoinPreload));
  16622. puller->setInput(0, _sourceIdx, _in);
  16623. _in = puller;
  16624. _sourceIdx = 0;
  16625. }
  16626. CRoxieServerTwoInputActivity::setInput(idx, _sourceIdx, _in);
  16627. }
  16628. virtual const void * nextRow()
  16629. {
  16630. ActivityTimer t(totalCycles, timeActivities);
  16631. if(!table)
  16632. loadRight();
  16633. switch (activityKind)
  16634. {
  16635. case TAKlookupjoin:
  16636. case TAKsmartjoin:
  16637. return nextRowJoin();
  16638. case TAKlookupdenormalize:
  16639. case TAKlookupdenormalizegroup:
  16640. case TAKsmartdenormalize:
  16641. case TAKsmartdenormalizegroup:
  16642. return nextRowDenormalize();
  16643. }
  16644. throwUnexpected();
  16645. }
  16646. private:
  16647. const void * nextRowJoin()
  16648. {
  16649. if(!table)
  16650. loadRight();
  16651. while(true)
  16652. {
  16653. const void * right = NULL;
  16654. if(!left)
  16655. {
  16656. left = inputStream->nextRow();
  16657. keepCount = keepLimit;
  16658. joinCounter = 0;
  16659. if(!left)
  16660. {
  16661. if (isSmartJoin)
  16662. left = inputStream->nextRow();
  16663. if (!left)
  16664. {
  16665. if(matchedGroup || eog)
  16666. {
  16667. matchedGroup = false;
  16668. eog = true;
  16669. return NULL;
  16670. }
  16671. eog = true;
  16672. continue;
  16673. }
  16674. }
  16675. eog = false;
  16676. gotMatch = false;
  16677. right = getRightFirst();
  16678. }
  16679. else
  16680. right = getRightNext();
  16681. const void * ret = NULL;
  16682. if(failingLimit)
  16683. {
  16684. ret = joinException(left, failingLimit);
  16685. }
  16686. else
  16687. {
  16688. while(right)
  16689. {
  16690. if(helper.match(left, right))
  16691. {
  16692. gotMatch = true;
  16693. if(exclude)
  16694. break;
  16695. ret = joinRecords(left, right, ++joinCounter, JTFmatchedleft|JTFmatchedright);
  16696. if(ret)
  16697. {
  16698. processed++;
  16699. break;
  16700. }
  16701. }
  16702. right = getRightNext();
  16703. ret = NULL;
  16704. }
  16705. if(leftOuterJoin && !gotMatch)
  16706. {
  16707. ret = joinRecords(left, defaultRight, 0, JTFmatchedleft);
  16708. gotMatch = true;
  16709. }
  16710. }
  16711. if(ret)
  16712. {
  16713. matchedGroup = true;
  16714. processed++;
  16715. if(!many || (--keepCount == 0) || failingLimit)
  16716. {
  16717. ReleaseClearRoxieRow(left);
  16718. failingLimit.clear();
  16719. }
  16720. return ret;
  16721. }
  16722. ReleaseClearRoxieRow(left);
  16723. }
  16724. }
  16725. const void * nextRowDenormalize()
  16726. {
  16727. while(true)
  16728. {
  16729. left = inputStream->nextRow();
  16730. if(!left)
  16731. {
  16732. if (!matchedGroup || isSmartJoin)
  16733. left = inputStream->nextRow();
  16734. if (!left)
  16735. {
  16736. matchedGroup = false;
  16737. return NULL;
  16738. }
  16739. }
  16740. gotMatch = false;
  16741. const void * right = getRightFirst();
  16742. const void * ret = NULL;
  16743. if (failingLimit)
  16744. ret = joinException(left, failingLimit);
  16745. else if (activityKind == TAKlookupdenormalize || activityKind == TAKsmartdenormalize)
  16746. {
  16747. OwnedConstRoxieRow newLeft;
  16748. newLeft.set(left);
  16749. unsigned rowSize = 0;
  16750. unsigned leftCount = 0;
  16751. keepCount = keepLimit;
  16752. while (right)
  16753. {
  16754. try
  16755. {
  16756. if (helper.match(left, right))
  16757. {
  16758. gotMatch = true;
  16759. if (exclude)
  16760. break;
  16761. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  16762. unsigned thisSize = helper.transform(rowBuilder, newLeft, right, ++leftCount, JTFmatchedleft|JTFmatchedright);
  16763. if (thisSize)
  16764. {
  16765. rowSize = thisSize;
  16766. newLeft.setown(rowBuilder.finalizeRowClear(rowSize));
  16767. }
  16768. if(!many || (--keepCount == 0))
  16769. break;
  16770. }
  16771. right = getRightNext();
  16772. }
  16773. catch (IException *E)
  16774. {
  16775. throw makeWrappedException(E);
  16776. }
  16777. }
  16778. if (rowSize)
  16779. ret = newLeft.getClear();
  16780. else if (leftOuterJoin && !gotMatch)
  16781. {
  16782. ret = left;
  16783. left = NULL;
  16784. }
  16785. }
  16786. else
  16787. {
  16788. filteredRight.kill();
  16789. keepCount = keepLimit;
  16790. while (right)
  16791. {
  16792. if (helper.match(left, right))
  16793. {
  16794. gotMatch = true;
  16795. if(exclude)
  16796. break;
  16797. filteredRight.append(right);
  16798. if(!many || (--keepCount == 0))
  16799. break;
  16800. }
  16801. right = getRightNext();
  16802. }
  16803. if((filteredRight.ordinality() > 0) || (leftOuterJoin && !gotMatch))
  16804. ret = denormalizeRecords(left, filteredRight, JTFmatchedleft);
  16805. filteredRight.kill();
  16806. }
  16807. ReleaseRoxieRow(left);
  16808. left = NULL;
  16809. failingLimit.clear();
  16810. if(ret)
  16811. {
  16812. matchedGroup = true;
  16813. processed++;
  16814. return ret;
  16815. }
  16816. }
  16817. }
  16818. const void * joinRecords(const void * left, const void * right, unsigned counter, unsigned flags)
  16819. {
  16820. if (cloneLeft)
  16821. {
  16822. LinkRoxieRow(left);
  16823. return left;
  16824. }
  16825. try
  16826. {
  16827. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  16828. unsigned outSize = helper.transform(rowBuilder, left, right, counter, flags);
  16829. if (outSize)
  16830. return rowBuilder.finalizeRowClear(outSize);
  16831. else
  16832. return NULL;
  16833. }
  16834. catch (IException *E)
  16835. {
  16836. throw makeWrappedException(E);
  16837. }
  16838. }
  16839. const void * joinException(const void * left, IException * except)
  16840. {
  16841. try
  16842. {
  16843. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  16844. unsigned outSize = helper.onFailTransform(rowBuilder, left, defaultRight, except, JTFmatchedleft);
  16845. if (outSize)
  16846. return rowBuilder.finalizeRowClear(outSize);
  16847. else
  16848. return NULL;
  16849. }
  16850. catch (IException *E)
  16851. {
  16852. throw makeWrappedException(E);
  16853. }
  16854. }
  16855. const void * denormalizeRecords(const void * left, ConstPointerArray & rows, unsigned flags)
  16856. {
  16857. try
  16858. {
  16859. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  16860. unsigned numRows = rows.ordinality();
  16861. const void * right = numRows ? rows.item(0) : defaultRight.get();
  16862. if (numRows>0)
  16863. flags |= JTFmatchedright;
  16864. unsigned outSize = helper.transform(rowBuilder, left, right, numRows, (const void * *)rows.getArray(), flags);
  16865. if (outSize)
  16866. return rowBuilder.finalizeRowClear(outSize);
  16867. else
  16868. return NULL;
  16869. }
  16870. catch (IException *E)
  16871. {
  16872. throw makeWrappedException(E);
  16873. }
  16874. }
  16875. const void * getRightFirst() { if(hasGroupLimit) return fillRightGroup(); else return table->find(left); }
  16876. const void * getRightNext() { if(hasGroupLimit) return readRightGroup(); else return table->findNext(left); }
  16877. const void * readRightGroup() { if(rightGroup.isItem(rightGroupIndex)) return rightGroup.item(rightGroupIndex++); else return NULL; }
  16878. const void *fillRightGroup()
  16879. {
  16880. rightGroup.kill();
  16881. for(const void * right = table->find(left); right; right = table->findNext(left))
  16882. {
  16883. rightGroup.append(right);
  16884. if(rightGroup.ordinality() > limitLimit)
  16885. {
  16886. if(limitFail)
  16887. failLimit();
  16888. gotMatch = true;
  16889. if (ctx->queryDebugContext())
  16890. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  16891. if(limitOnFail)
  16892. {
  16893. assertex(!failingLimit);
  16894. try
  16895. {
  16896. failLimit();
  16897. }
  16898. catch(IException * e)
  16899. {
  16900. failingLimit.setown(e);
  16901. }
  16902. assertex(failingLimit != NULL);
  16903. }
  16904. else
  16905. {
  16906. rightGroup.kill();
  16907. }
  16908. break;
  16909. }
  16910. if(rightGroup.ordinality() > atmostLimit)
  16911. {
  16912. atmostsTriggered++;
  16913. rightGroup.kill();
  16914. break;
  16915. }
  16916. }
  16917. rightGroupIndex = 0;
  16918. return readRightGroup();
  16919. }
  16920. void failLimit()
  16921. {
  16922. helper.onMatchAbortLimitExceeded();
  16923. CommonXmlWriter xmlwrite(XWFtrim|XWFopt );
  16924. if(!ctx->isBlind() && input->queryOutputMeta() && input->queryOutputMeta()->hasXML())
  16925. {
  16926. input->queryOutputMeta()->toXML(static_cast<const unsigned char *>(left), xmlwrite);
  16927. }
  16928. throw MakeStringException(ROXIE_TOO_MANY_RESULTS, "More than %u match candidates in join %d for row %s", limitLimit, queryId(), xmlwrite.str());
  16929. }
  16930. };
  16931. unsigned const CRoxieServerLookupJoinActivity::FewLookupTable::BadIndex(static_cast<unsigned>(-1));
  16932. class CRoxieServerLookupJoinActivityFactory : public CRoxieServerJoinActivityFactory
  16933. {
  16934. public:
  16935. CRoxieServerLookupJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  16936. : CRoxieServerJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  16937. {
  16938. Owned<IHThorHashJoinArg> helper = (IHThorHashJoinArg *) helperFactory();
  16939. useFewTable = _graphNode.getPropBool("hint[@name='usefewtable']/@value", false);
  16940. if((helper->getJoinFlags() & (JFfirst | JFfirstleft | JFfirstright | JFslidingmatch)) != 0)
  16941. throw MakeStringException(ROXIE_INVALID_FLAGS, "Invalid flags for lookup join activity"); // code generator should never create such an activity
  16942. }
  16943. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  16944. {
  16945. return new CRoxieServerLookupJoinActivity(_ctx, this, _probeManager, useFewTable);
  16946. }
  16947. virtual const StatisticsMapping &queryStatsMapping() const
  16948. {
  16949. return joinStatistics;
  16950. }
  16951. protected:
  16952. bool useFewTable;
  16953. };
  16954. IRoxieServerActivityFactory *createRoxieServerLookupJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  16955. {
  16956. return new CRoxieServerLookupJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  16957. }
  16958. //=====================================================================================================
  16959. class CRoxieServerAllJoinActivity : public CRoxieServerTwoInputActivity
  16960. {
  16961. private:
  16962. IHThorAllJoinArg &helper;
  16963. bool leftOuterJoin;
  16964. bool rightOuterJoin;
  16965. bool exclude;
  16966. OwnedConstRoxieRow defaultRight;
  16967. OwnedConstRoxieRow defaultLeft;
  16968. Owned<IEngineRowAllocator> defaultRightAllocator;
  16969. Owned<IEngineRowAllocator> defaultLeftAllocator;
  16970. const void *left;
  16971. unsigned countForLeft;
  16972. ConstPointerArray rightset;
  16973. BoolArray matchedRight; // MORE - could use a bitset...
  16974. unsigned keepLimit;
  16975. bool started;
  16976. bool eog;
  16977. bool eos;
  16978. bool matchedLeft;
  16979. bool matchedGroup;
  16980. bool leftIsGrouped;
  16981. bool cloneLeft;
  16982. unsigned rightIndex;
  16983. unsigned joinCounter;
  16984. unsigned rightOrdinality;
  16985. ThorActivityKind activityKind;
  16986. ConstPointerArray filteredRight;
  16987. void createDefaultLeft()
  16988. {
  16989. if (!defaultLeft)
  16990. {
  16991. if (!defaultLeftAllocator)
  16992. defaultLeftAllocator.setown(createRowAllocator(input->queryOutputMeta()));
  16993. RtlDynamicRowBuilder rowBuilder(defaultLeftAllocator);
  16994. size32_t thisSize = helper.createDefaultLeft(rowBuilder);
  16995. defaultLeft.setown(rowBuilder.finalizeRowClear(thisSize));
  16996. }
  16997. }
  16998. void createDefaultRight()
  16999. {
  17000. if (!defaultRight)
  17001. {
  17002. if (!defaultRightAllocator)
  17003. defaultRightAllocator.setown(createRowAllocator(input1->queryOutputMeta()));
  17004. RtlDynamicRowBuilder rowBuilder(defaultRightAllocator);
  17005. size32_t thisSize = helper.createDefaultRight(rowBuilder);
  17006. defaultRight.setown(rowBuilder.finalizeRowClear(thisSize));
  17007. }
  17008. }
  17009. public:
  17010. CRoxieServerAllJoinActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  17011. : CRoxieServerTwoInputActivity(_ctx, _factory, _probeManager), helper((IHThorAllJoinArg &)basehelper)
  17012. {
  17013. unsigned joinFlags = helper.getJoinFlags();
  17014. leftOuterJoin = (joinFlags & JFleftouter) != 0;
  17015. rightOuterJoin = (joinFlags & JFrightouter) != 0;
  17016. cloneLeft = (joinFlags & JFtransformmatchesleft) != 0;
  17017. keepLimit = (unsigned) -1;
  17018. exclude = (joinFlags & JFexclude) != 0;
  17019. left = NULL;
  17020. started = true;
  17021. eog = false;
  17022. eos = false;
  17023. matchedLeft = false;
  17024. matchedGroup = false;
  17025. activityKind = factory->getKind();
  17026. rightIndex = 0;
  17027. rightOrdinality = 0;
  17028. leftIsGrouped = false;
  17029. countForLeft = 0;
  17030. joinCounter = 0;
  17031. }
  17032. virtual void reset()
  17033. {
  17034. defaultRight.clear();
  17035. defaultLeft.clear();
  17036. ReleaseRoxieRows(rightset);
  17037. matchedRight.kill();
  17038. CRoxieServerTwoInputActivity::reset();
  17039. }
  17040. virtual bool needsAllocator() const { return true; }
  17041. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  17042. {
  17043. eog = false;
  17044. eos = false;
  17045. matchedLeft = false;
  17046. matchedGroup = false;
  17047. started = false;
  17048. left = NULL;
  17049. CRoxieServerTwoInputActivity::start(parentExtractSize, parentExtract, paused);
  17050. keepLimit = helper.getKeepLimit();
  17051. if(keepLimit==0)
  17052. keepLimit = (unsigned) -1;
  17053. countForLeft = keepLimit;
  17054. joinCounter = 0;
  17055. leftIsGrouped = input->queryOutputMeta()->isGrouped();
  17056. if((activityKind==TAKalljoin || activityKind==TAKalldenormalizegroup) && leftOuterJoin)
  17057. createDefaultRight();
  17058. if(rightOuterJoin)
  17059. createDefaultLeft();
  17060. }
  17061. void loadRight()
  17062. {
  17063. const void * next;
  17064. while(true)
  17065. {
  17066. next = inputStream1->ungroupedNextRow();
  17067. if(!next)
  17068. break;
  17069. rightset.append(next);
  17070. matchedRight.append(false);
  17071. }
  17072. rightIndex = 0;
  17073. joinCounter = 0;
  17074. rightOrdinality = rightset.ordinality();
  17075. }
  17076. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  17077. {
  17078. if (!idx && (helper.getJoinFlags() & JFparallel) != 0)
  17079. {
  17080. puller.setown(new CRoxieServerReadAheadInput(ctx, ctx->queryOptions().parallelJoinPreload));
  17081. puller->setInput(0, _sourceIdx, _in);
  17082. _in = puller;
  17083. _sourceIdx = 0;
  17084. }
  17085. CRoxieServerTwoInputActivity::setInput(idx, _sourceIdx, _in);
  17086. }
  17087. const void * joinRecords(const void * left, const void * right, unsigned counter, unsigned flags)
  17088. {
  17089. // MORE - could share some code with lookup join
  17090. if (cloneLeft)
  17091. {
  17092. LinkRoxieRow(left);
  17093. return left;
  17094. }
  17095. try
  17096. {
  17097. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  17098. unsigned outSize = helper.transform(rowBuilder, left, right, counter, flags);
  17099. if (outSize)
  17100. return rowBuilder.finalizeRowClear(outSize);
  17101. else
  17102. return NULL;
  17103. }
  17104. catch (IException *E)
  17105. {
  17106. throw makeWrappedException(E);
  17107. }
  17108. }
  17109. const void * denormalizeRecords(const void * curLeft, ConstPointerArray & rows, unsigned flags)
  17110. {
  17111. try
  17112. {
  17113. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  17114. unsigned numRows = rows.ordinality();
  17115. const void * right = numRows ? rows.item(0) : defaultRight.get();
  17116. if (numRows>0)
  17117. flags |= JTFmatchedright;
  17118. unsigned outSize = helper.transform(rowBuilder, curLeft, right, numRows, rows.getArray(), flags);
  17119. if (outSize)
  17120. return rowBuilder.finalizeRowClear(outSize);
  17121. else
  17122. return NULL;
  17123. }
  17124. catch (IException *E)
  17125. {
  17126. throw makeWrappedException(E);
  17127. }
  17128. }
  17129. virtual const void *nextRow()
  17130. {
  17131. ActivityTimer t(totalCycles, timeActivities);
  17132. if(!started)
  17133. {
  17134. started = true;
  17135. left = inputStream->nextRow();
  17136. matchedLeft = false;
  17137. countForLeft = keepLimit;
  17138. joinCounter = 0;
  17139. if(left == NULL)
  17140. {
  17141. eos = true;
  17142. return NULL;
  17143. }
  17144. loadRight();
  17145. }
  17146. const void * ret;
  17147. const void * right;
  17148. if(eos)
  17149. return NULL;
  17150. while(true)
  17151. {
  17152. ret = NULL;
  17153. if((rightIndex == rightOrdinality) || (countForLeft==0))
  17154. {
  17155. if(leftOuterJoin && left && !matchedLeft)
  17156. {
  17157. switch(activityKind)
  17158. {
  17159. case TAKalljoin:
  17160. ret = joinRecords(left, defaultRight, 0, JTFmatchedleft);
  17161. break;
  17162. case TAKalldenormalize:
  17163. ret = left;
  17164. left = NULL;
  17165. break;
  17166. case TAKalldenormalizegroup:
  17167. filteredRight.kill();
  17168. ret = denormalizeRecords(left, filteredRight, JTFmatchedleft);
  17169. break;
  17170. default:
  17171. throwUnexpected();
  17172. }
  17173. }
  17174. rightIndex = 0;
  17175. joinCounter = 0;
  17176. ReleaseRoxieRow(left);
  17177. left = NULL;
  17178. if(ret)
  17179. {
  17180. matchedGroup = true;
  17181. processed++;
  17182. return ret;
  17183. }
  17184. }
  17185. if(!left)
  17186. {
  17187. left = inputStream->nextRow();
  17188. matchedLeft = false;
  17189. countForLeft = keepLimit;
  17190. joinCounter = 0;
  17191. }
  17192. if(!left)
  17193. {
  17194. if(eog)
  17195. {
  17196. eos = true;
  17197. matchedGroup = false;
  17198. return NULL;
  17199. }
  17200. eog = true;
  17201. if (matchedGroup && leftIsGrouped)
  17202. {
  17203. matchedGroup = false;
  17204. return NULL;
  17205. }
  17206. matchedGroup = false;
  17207. continue;
  17208. }
  17209. eog = false;
  17210. switch(activityKind)
  17211. {
  17212. case TAKalljoin:
  17213. while(rightIndex < rightOrdinality)
  17214. {
  17215. right = rightset.item(rightIndex);
  17216. if(helper.match(left, right))
  17217. {
  17218. matchedLeft = true;
  17219. matchedRight.replace(true, rightIndex);
  17220. if(!exclude)
  17221. ret = joinRecords(left, right, ++joinCounter, JTFmatchedleft|JTFmatchedright);
  17222. }
  17223. rightIndex++;
  17224. if(ret)
  17225. {
  17226. countForLeft--;
  17227. matchedGroup = true;
  17228. processed++;
  17229. return ret;
  17230. }
  17231. }
  17232. break;
  17233. case TAKalldenormalize:
  17234. {
  17235. OwnedConstRoxieRow newLeft;
  17236. newLeft.set(left);
  17237. unsigned rowSize = 0;
  17238. unsigned leftCount = 0;
  17239. while((rightIndex < rightOrdinality) && countForLeft)
  17240. {
  17241. right = rightset.item(rightIndex);
  17242. if(helper.match(left, right))
  17243. {
  17244. matchedLeft = true;
  17245. matchedRight.replace(true, rightIndex);
  17246. if(!exclude)
  17247. {
  17248. try
  17249. {
  17250. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  17251. unsigned thisSize = helper.transform(rowBuilder, newLeft, right, ++leftCount, JTFmatchedleft|JTFmatchedright);
  17252. if(thisSize)
  17253. {
  17254. rowSize = thisSize;
  17255. newLeft.setown(rowBuilder.finalizeRowClear(rowSize));
  17256. --countForLeft;
  17257. }
  17258. }
  17259. catch (IException *e)
  17260. {
  17261. throw makeWrappedException(e);
  17262. }
  17263. }
  17264. }
  17265. rightIndex++;
  17266. }
  17267. if(rowSize)
  17268. {
  17269. processed++;
  17270. return newLeft.getClear();
  17271. }
  17272. }
  17273. break;
  17274. case TAKalldenormalizegroup:
  17275. filteredRight.kill();
  17276. while((rightIndex < rightOrdinality) && countForLeft)
  17277. {
  17278. right = rightset.item(rightIndex);
  17279. if(helper.match(left, right))
  17280. {
  17281. matchedLeft = true;
  17282. matchedRight.replace(true, rightIndex);
  17283. filteredRight.append(right);
  17284. --countForLeft;
  17285. }
  17286. ++rightIndex;
  17287. }
  17288. if(!exclude && filteredRight.ordinality())
  17289. {
  17290. ret = denormalizeRecords(left, filteredRight, JTFmatchedleft);
  17291. filteredRight.kill();
  17292. if(ret)
  17293. {
  17294. processed++;
  17295. return ret;
  17296. }
  17297. }
  17298. break;
  17299. default:
  17300. throwUnexpected();
  17301. }
  17302. }
  17303. }
  17304. };
  17305. class CRoxieServerAllJoinActivityFactory : public CRoxieServerJoinActivityFactory
  17306. {
  17307. public:
  17308. CRoxieServerAllJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  17309. : CRoxieServerJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  17310. {
  17311. Owned<IHThorAllJoinArg> helper = (IHThorAllJoinArg *) helperFactory();
  17312. if((helper->getJoinFlags() & (JFfirst | JFfirstleft | JFfirstright)) != 0)
  17313. throw MakeStringException(ROXIE_INVALID_FLAGS, "Invalid flags for join all activity"); // code generator should never create such an activity
  17314. }
  17315. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  17316. {
  17317. return new CRoxieServerAllJoinActivity(_ctx, this, _probeManager);
  17318. }
  17319. virtual const StatisticsMapping &queryStatsMapping() const
  17320. {
  17321. return joinStatistics;
  17322. }
  17323. };
  17324. IRoxieServerActivityFactory *createRoxieServerAllJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  17325. {
  17326. return new CRoxieServerAllJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  17327. }
  17328. //=====================================================================================================
  17329. class CRoxieServerTopNActivity : public CRoxieServerLateStartActivity
  17330. {
  17331. unsigned limit;
  17332. bool hasBest;
  17333. bool eoi;
  17334. const void **sorted;
  17335. unsigned sortedCount;
  17336. unsigned curIndex;
  17337. IHThorTopNArg &helper;
  17338. ICompare &compare;
  17339. public:
  17340. CRoxieServerTopNActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  17341. : CRoxieServerLateStartActivity(_ctx, _factory, _probeManager), helper((IHThorTopNArg &)basehelper), compare(*helper.queryCompare())
  17342. {
  17343. sorted = NULL;
  17344. sortedCount = 0;
  17345. curIndex = 0;
  17346. limit = 0;
  17347. eoi = false;
  17348. hasBest = false;
  17349. }
  17350. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  17351. {
  17352. assertex(sorted == NULL);
  17353. sortedCount = 0;
  17354. curIndex = 0;
  17355. eoi = false;
  17356. CRoxieServerLateStartActivity::start(parentExtractSize, parentExtract, paused);
  17357. limit = (unsigned) helper.getLimit();
  17358. hasBest = helper.hasBest();
  17359. lateStart(parentExtractSize, parentExtract, limit > 0);
  17360. // MORE - should we use an expanding array instead?
  17361. if (limit > 0)
  17362. sorted = (const void **) ctx->queryRowManager().allocate((limit+1) * sizeof(const void *), activityId);
  17363. }
  17364. virtual void reset()
  17365. {
  17366. if (sorted)
  17367. {
  17368. roxiemem::ReleaseRoxieRowRange(sorted, curIndex, sortedCount);
  17369. curIndex = 0;
  17370. sortedCount = 0;
  17371. ReleaseRoxieRow(sorted);
  17372. sorted = NULL;
  17373. }
  17374. CRoxieServerLateStartActivity::reset();
  17375. }
  17376. bool abortEarly()
  17377. {
  17378. if (hasBest && (sortedCount == limit))
  17379. {
  17380. int compare = helper.compareBest(sorted[sortedCount-1]);
  17381. if (compare == 0)
  17382. {
  17383. if (meta.isGrouped())
  17384. {
  17385. //MORE: This would be more efficient if we had a away of skipping to the end of the incoming group.
  17386. const void * next;
  17387. while ((next = inputStream->nextRow()) != NULL)
  17388. ReleaseRoxieRow(next);
  17389. }
  17390. else
  17391. eoi = true;
  17392. return true;
  17393. }
  17394. //This only checks the lowest element - we could check all elements inserted, but it would increase the number of compares
  17395. if (compare < 0)
  17396. throw MakeStringException(ROXIE_TOPN_ROW_ERROR, "TOPN: row found that exceeds the best value");
  17397. }
  17398. return false;
  17399. }
  17400. void getSorted()
  17401. {
  17402. curIndex = 0;
  17403. sortedCount = 0;
  17404. if(eoi)
  17405. return;
  17406. const void * next;
  17407. while ((next = inputStream->nextRow()) != NULL)
  17408. {
  17409. if (sortedCount < limit)
  17410. {
  17411. binary_vec_insert_stable(next, sorted, sortedCount, compare);
  17412. sortedCount++;
  17413. if(abortEarly())
  17414. return;
  17415. }
  17416. else
  17417. {
  17418. if(limit && compare.docompare(sorted[sortedCount-1], next) > 0) // MORE - if stability is an issue, need to consider whether this should be > or >=
  17419. {
  17420. binary_vec_insert_stable(next, sorted, sortedCount, compare); // MORE - not sure this is stable!
  17421. ReleaseRoxieRow(sorted[sortedCount]);
  17422. if(abortEarly())
  17423. return;
  17424. }
  17425. else
  17426. {
  17427. ReleaseRoxieRow(next); // do not bother with insertion sort if we know next will fall off the end
  17428. }
  17429. }
  17430. }
  17431. }
  17432. virtual const void * nextRow()
  17433. {
  17434. ActivityTimer t(totalCycles, timeActivities);
  17435. if (eof)
  17436. return NULL;
  17437. if (curIndex >= sortedCount)
  17438. {
  17439. bool eog = sortedCount != 0;
  17440. getSorted();
  17441. if(sortedCount == 0)
  17442. {
  17443. eof = true;
  17444. return NULL;
  17445. }
  17446. if (eog)
  17447. return NULL;
  17448. }
  17449. processed++;
  17450. return sorted[curIndex++];
  17451. }
  17452. };
  17453. class CRoxieServerTopNActivityFactory : public CRoxieServerActivityFactory
  17454. {
  17455. public:
  17456. CRoxieServerTopNActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  17457. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  17458. {
  17459. }
  17460. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  17461. {
  17462. return new CRoxieServerTopNActivity(_ctx, this, _probeManager);
  17463. }
  17464. };
  17465. IRoxieServerActivityFactory *createRoxieServerTopNActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  17466. {
  17467. return new CRoxieServerTopNActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  17468. }
  17469. //=================================================================================
  17470. class CRoxieServerLimitActivity : public CRoxieServerActivity
  17471. {
  17472. protected:
  17473. unsigned __int64 rowLimit;
  17474. IHThorLimitArg &helper;
  17475. public:
  17476. CRoxieServerLimitActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  17477. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorLimitArg &)basehelper)
  17478. {
  17479. rowLimit = 0;
  17480. }
  17481. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  17482. {
  17483. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  17484. rowLimit = helper.getRowLimit(); // could conceivably depend on context so should not compute any earlier than this
  17485. }
  17486. virtual const void *nextRow()
  17487. {
  17488. ActivityTimer t(totalCycles, timeActivities);
  17489. const void * ret = inputStream->nextRow();
  17490. if (ret)
  17491. {
  17492. processed++;
  17493. if (processed > rowLimit)
  17494. {
  17495. ReleaseRoxieRow(ret);
  17496. if (traceLevel > 4)
  17497. DBGLOG("activityid = %d line = %d", activityId, __LINE__);
  17498. helper.onLimitExceeded();
  17499. }
  17500. }
  17501. return ret;
  17502. }
  17503. virtual const void * nextRowGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  17504. {
  17505. ActivityTimer t(totalCycles, timeActivities);
  17506. const void * ret = inputStream->nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);
  17507. if (ret)
  17508. {
  17509. if (wasCompleteMatch)
  17510. processed++;
  17511. if (processed > rowLimit)
  17512. {
  17513. ReleaseRoxieRow(ret);
  17514. if (traceLevel > 4)
  17515. DBGLOG("activityid = %d line = %d", activityId, __LINE__);
  17516. helper.onLimitExceeded();
  17517. }
  17518. }
  17519. return ret;
  17520. }
  17521. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  17522. {
  17523. return input->gatherConjunctions(collector);
  17524. }
  17525. virtual void resetEOF()
  17526. {
  17527. //Do not reset the rowLimit
  17528. inputStream->resetEOF();
  17529. }
  17530. IInputSteppingMeta * querySteppingMeta()
  17531. {
  17532. return input->querySteppingMeta();
  17533. }
  17534. };
  17535. class CRoxieServerLimitActivityFactory : public CRoxieServerActivityFactory
  17536. {
  17537. public:
  17538. CRoxieServerLimitActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  17539. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  17540. {
  17541. }
  17542. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  17543. {
  17544. return new CRoxieServerLimitActivity(_ctx, this, _probeManager);
  17545. }
  17546. };
  17547. IRoxieServerActivityFactory *createRoxieServerLimitActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  17548. {
  17549. return new CRoxieServerLimitActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  17550. }
  17551. //=====================================================================================================
  17552. class CRoxieServerSkipLimitActivity : public CRoxieServerLimitActivity
  17553. {
  17554. ConstPointerArray buff;
  17555. bool started = false;
  17556. unsigned index = 0;
  17557. bool isFail = false;
  17558. public:
  17559. CRoxieServerSkipLimitActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _onFail)
  17560. : CRoxieServerLimitActivity(_ctx, _factory, _probeManager)
  17561. {
  17562. started = false;
  17563. index = 0;
  17564. isFail = _onFail;
  17565. }
  17566. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  17567. {
  17568. started = false;
  17569. index = 0;
  17570. CRoxieServerLimitActivity::start(parentExtractSize, parentExtract, paused);
  17571. }
  17572. virtual void reset()
  17573. {
  17574. roxiemem::ReleaseRoxieRowRange(buff.getArray(), index, buff.ordinality());
  17575. buff.kill();
  17576. index = 0;
  17577. started = false;
  17578. CRoxieServerLimitActivity::reset();
  17579. }
  17580. virtual const void *nextRow()
  17581. {
  17582. ActivityTimer t(totalCycles, timeActivities);
  17583. if (!started)
  17584. pullInput();
  17585. if (buff.isItem(index))
  17586. {
  17587. const void * next = buff.item(index++);
  17588. if(next)
  17589. processed++;
  17590. return next;
  17591. }
  17592. return NULL;
  17593. }
  17594. protected:
  17595. void pullInput()
  17596. {
  17597. unsigned count = 0;
  17598. for (;;)
  17599. {
  17600. const void * next = inputStream->nextRow();
  17601. if (next == NULL)
  17602. {
  17603. next = inputStream->nextRow();
  17604. if(next == NULL)
  17605. break;
  17606. buff.append(NULL);
  17607. }
  17608. count++;
  17609. if (count > rowLimit)
  17610. {
  17611. ReleaseRoxieRow(next);
  17612. ReleaseRoxieRows(buff);
  17613. if (ctx->queryDebugContext())
  17614. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  17615. if (isFail)
  17616. {
  17617. ensureRowAllocator();
  17618. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  17619. size32_t outSize = helper.transformOnLimitExceeded(rowBuilder);
  17620. if (outSize)
  17621. buff.append(rowBuilder.finalizeRowClear(outSize));
  17622. }
  17623. break;
  17624. }
  17625. buff.append(next);
  17626. }
  17627. started = true;
  17628. }
  17629. };
  17630. class CRoxieServerSkipLimitActivityFactory : public CRoxieServerActivityFactory
  17631. {
  17632. public:
  17633. CRoxieServerSkipLimitActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  17634. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  17635. {
  17636. }
  17637. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  17638. {
  17639. return new CRoxieServerSkipLimitActivity(_ctx, this, _probeManager, kind==TAKcreaterowlimit);
  17640. }
  17641. };
  17642. IRoxieServerActivityFactory *createRoxieServerSkipLimitActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  17643. {
  17644. return new CRoxieServerSkipLimitActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  17645. }
  17646. //=================================================================================
  17647. class CRoxieServerCatchActivity : public CRoxieServerActivity
  17648. {
  17649. IHThorCatchArg &helper;
  17650. public:
  17651. CRoxieServerCatchActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  17652. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorCatchArg &)basehelper)
  17653. {
  17654. }
  17655. virtual const void *nextRow()
  17656. {
  17657. ActivityTimer t(totalCycles, timeActivities);
  17658. try
  17659. {
  17660. const void *ret = inputStream->nextRow();
  17661. if (ret)
  17662. processed++;
  17663. return ret;
  17664. }
  17665. catch (IException *E)
  17666. {
  17667. E->Release();
  17668. helper.onExceptionCaught();
  17669. }
  17670. catch (...)
  17671. {
  17672. helper.onExceptionCaught();
  17673. }
  17674. throwUnexpected(); // onExceptionCaught should have thrown something
  17675. }
  17676. virtual const void * nextRowGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  17677. {
  17678. try
  17679. {
  17680. ActivityTimer t(totalCycles, timeActivities);
  17681. const void * ret = inputStream->nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);
  17682. if (ret && wasCompleteMatch)
  17683. processed++;
  17684. return ret;
  17685. }
  17686. catch (IException *E)
  17687. {
  17688. E->Release();
  17689. helper.onExceptionCaught();
  17690. }
  17691. catch (...)
  17692. {
  17693. helper.onExceptionCaught();
  17694. }
  17695. throwUnexpected(); // onExceptionCaught should have thrown something
  17696. }
  17697. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  17698. {
  17699. return input->gatherConjunctions(collector);
  17700. }
  17701. virtual void resetEOF()
  17702. {
  17703. inputStream->resetEOF(); // MORE - why not in base class?
  17704. }
  17705. IInputSteppingMeta * querySteppingMeta()
  17706. {
  17707. return input->querySteppingMeta();
  17708. }
  17709. };
  17710. class CRoxieServerSkipCatchActivity : public CRoxieServerActivity
  17711. {
  17712. ConstPointerArray buff;
  17713. bool started;
  17714. unsigned index;
  17715. IHThorCatchArg &helper;
  17716. bool createRow;
  17717. public:
  17718. CRoxieServerSkipCatchActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _createRow)
  17719. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorCatchArg &)basehelper), createRow(_createRow)
  17720. {
  17721. started = false;
  17722. index = 0;
  17723. }
  17724. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  17725. {
  17726. started = false;
  17727. index = 0;
  17728. try
  17729. {
  17730. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  17731. }
  17732. catch (IException *E)
  17733. {
  17734. onException(E);
  17735. started = true;
  17736. }
  17737. catch (...)
  17738. {
  17739. onException(MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught"));
  17740. started = true;
  17741. }
  17742. }
  17743. virtual void reset()
  17744. {
  17745. roxiemem::ReleaseRoxieRowRange(buff.getArray(), index, buff.ordinality());
  17746. buff.kill();
  17747. index = 0;
  17748. started = false;
  17749. CRoxieServerActivity::reset();
  17750. }
  17751. virtual const void *nextRow()
  17752. {
  17753. ActivityTimer t(totalCycles, timeActivities);
  17754. if (!started)
  17755. pullInput();
  17756. if (buff.isItem(index))
  17757. {
  17758. const void * next = buff.item(index++);
  17759. if(next)
  17760. processed++;
  17761. return next;
  17762. }
  17763. return NULL;
  17764. }
  17765. protected:
  17766. void onException(IException *E)
  17767. {
  17768. inputStream->stop();
  17769. ReleaseRoxieRows(buff);
  17770. if (createRow)
  17771. {
  17772. ensureRowAllocator();
  17773. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  17774. size32_t outSize = helper.transformOnExceptionCaught(rowBuilder, E);
  17775. if (outSize)
  17776. buff.append(rowBuilder.finalizeRowClear(outSize));
  17777. }
  17778. E->Release();
  17779. }
  17780. void pullInput()
  17781. {
  17782. try
  17783. {
  17784. bool EOGseen = false;
  17785. for (;;)
  17786. {
  17787. const void * next = inputStream->nextRow();
  17788. buff.append(next);
  17789. if (next == NULL)
  17790. {
  17791. if (EOGseen)
  17792. break;
  17793. EOGseen = true;
  17794. }
  17795. else
  17796. EOGseen = false;
  17797. }
  17798. }
  17799. catch (IException *E)
  17800. {
  17801. onException(E);
  17802. }
  17803. catch (...)
  17804. {
  17805. onException(MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught"));
  17806. }
  17807. started = true;
  17808. }
  17809. };
  17810. class CRoxieServerCatchActivityFactory : public CRoxieServerActivityFactory
  17811. {
  17812. public:
  17813. CRoxieServerCatchActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  17814. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  17815. {
  17816. }
  17817. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  17818. {
  17819. switch (kind)
  17820. {
  17821. case TAKcatch:
  17822. return new CRoxieServerCatchActivity(_ctx, this, _probeManager);
  17823. case TAKskipcatch:
  17824. return new CRoxieServerSkipCatchActivity(_ctx, this, _probeManager, false);
  17825. case TAKcreaterowcatch:
  17826. return new CRoxieServerSkipCatchActivity(_ctx, this, _probeManager, true);
  17827. default:
  17828. throwUnexpected();
  17829. }
  17830. }
  17831. };
  17832. IRoxieServerActivityFactory *createRoxieServerCatchActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  17833. {
  17834. return new CRoxieServerCatchActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  17835. }
  17836. //=================================================================================
  17837. class CRoxieServerPullActivity : public CRoxieServerActivity
  17838. {
  17839. ConstPointerArray buff;
  17840. bool started;
  17841. unsigned index;
  17842. public:
  17843. CRoxieServerPullActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  17844. : CRoxieServerActivity(_ctx, _factory, _probeManager)
  17845. {
  17846. started = false;
  17847. index = 0;
  17848. }
  17849. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  17850. {
  17851. started = false;
  17852. index = 0;
  17853. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  17854. }
  17855. virtual void reset()
  17856. {
  17857. while (buff.isItem(index))
  17858. ReleaseRoxieRow(buff.item(index++));
  17859. buff.kill();
  17860. started = false;
  17861. index = 0;
  17862. CRoxieServerActivity::reset();
  17863. }
  17864. virtual const void *nextRow()
  17865. {
  17866. ActivityTimer t(totalCycles, timeActivities);
  17867. if (!started)
  17868. pullInput();
  17869. if (buff.isItem(index))
  17870. {
  17871. const void * next = buff.item(index++);
  17872. if (next)
  17873. processed++;
  17874. return next;
  17875. }
  17876. return NULL;
  17877. }
  17878. protected:
  17879. void pullInput()
  17880. {
  17881. bool EOGseen = false;
  17882. for (;;)
  17883. {
  17884. const void * next = inputStream->nextRow();
  17885. buff.append(next);
  17886. if (next == NULL)
  17887. {
  17888. if (EOGseen)
  17889. break;
  17890. EOGseen = true;
  17891. }
  17892. else
  17893. EOGseen = false;
  17894. }
  17895. started = true;
  17896. }
  17897. };
  17898. class CRoxieServerPullActivityFactory : public CRoxieServerActivityFactory
  17899. {
  17900. public:
  17901. CRoxieServerPullActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  17902. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  17903. {
  17904. }
  17905. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  17906. {
  17907. return new CRoxieServerPullActivity(_ctx, this, _probeManager);
  17908. }
  17909. };
  17910. IRoxieServerActivityFactory *createRoxieServerPullActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  17911. {
  17912. return new CRoxieServerPullActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  17913. }
  17914. //=================================================================================
  17915. class CRoxieServerTraceActivity : public CRoxieServerActivity
  17916. {
  17917. public:
  17918. CRoxieServerTraceActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  17919. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorTraceArg &) basehelper),
  17920. keepLimit(0), skip(0), sample(0)
  17921. {
  17922. assertex(meta.hasXML());
  17923. traceEnabled = defaultTraceEnabled && !isBlind();
  17924. }
  17925. virtual void onCreate(IHThorArg *_colocalParent)
  17926. {
  17927. CRoxieServerActivity::onCreate(_colocalParent);
  17928. if (ctx)
  17929. traceEnabled = ctx->queryOptions().traceEnabled && !isBlind();
  17930. }
  17931. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  17932. {
  17933. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  17934. if (traceEnabled && helper.canMatchAny())
  17935. {
  17936. keepLimit = helper.getKeepLimit();
  17937. if (keepLimit==(unsigned) -1)
  17938. keepLimit = ctx->queryOptions().traceLimit;
  17939. skip = helper.getSkip();
  17940. sample = helper.getSample();
  17941. if (sample)
  17942. sample--;
  17943. name.setown(helper.getName());
  17944. if (!name)
  17945. name.set("Row");
  17946. }
  17947. else
  17948. keepLimit = 0;
  17949. }
  17950. virtual void stop()
  17951. {
  17952. name.clear();
  17953. CRoxieServerActivity::stop();
  17954. }
  17955. virtual bool isPassThrough()
  17956. {
  17957. return true;
  17958. }
  17959. virtual const void *nextRow()
  17960. {
  17961. ActivityTimer t(totalCycles, timeActivities);
  17962. const void *row = inputStream->nextRow();
  17963. if (row)
  17964. {
  17965. onTrace(row);
  17966. processed++;
  17967. }
  17968. return row;
  17969. }
  17970. virtual const void * nextRowGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  17971. {
  17972. // MORE - will need rethinking once we rethink the nextRowGE interface for global smart-stepping.
  17973. ActivityTimer t(totalCycles, timeActivities);
  17974. const void * row = inputStream->nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);
  17975. if (row)
  17976. {
  17977. onTrace(row);
  17978. processed++;
  17979. }
  17980. return row;
  17981. }
  17982. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  17983. {
  17984. return input->gatherConjunctions(collector);
  17985. }
  17986. virtual void resetEOF()
  17987. {
  17988. inputStream->resetEOF();
  17989. }
  17990. IInputSteppingMeta * querySteppingMeta()
  17991. {
  17992. return input->querySteppingMeta();
  17993. }
  17994. protected:
  17995. void onTrace(const void *row)
  17996. {
  17997. if (keepLimit && helper.isValid(row))
  17998. {
  17999. if (skip)
  18000. skip--;
  18001. else if (sample)
  18002. sample--;
  18003. else
  18004. {
  18005. CommonXmlWriter xmlwrite(XWFnoindent);
  18006. meta.toXML((const byte *) row, xmlwrite);
  18007. CTXLOG("TRACE: <%s>%s<%s>", name.get(), xmlwrite.str(), name.get());
  18008. keepLimit--;
  18009. sample = helper.getSample();
  18010. if (sample)
  18011. sample--;
  18012. }
  18013. }
  18014. }
  18015. OwnedRoxieString name;
  18016. IHThorTraceArg &helper;
  18017. unsigned keepLimit;
  18018. unsigned skip;
  18019. unsigned sample;
  18020. bool traceEnabled;
  18021. };
  18022. class CRoxieServerTraceActivityFactory : public CRoxieServerActivityFactory
  18023. {
  18024. public:
  18025. CRoxieServerTraceActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  18026. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  18027. {
  18028. }
  18029. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  18030. {
  18031. return new CRoxieServerTraceActivity(_ctx, this, _probeManager);
  18032. }
  18033. };
  18034. IRoxieServerActivityFactory *createRoxieServerTraceActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  18035. {
  18036. return new CRoxieServerTraceActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  18037. }
  18038. //=================================================================================
  18039. class CRoxieServerCaseActivity : public CRoxieServerMultiInputBaseActivity
  18040. {
  18041. IHThorCaseArg &helper;
  18042. unsigned cond;
  18043. bool unusedStopped;
  18044. IEngineRowStream *active;
  18045. public:
  18046. CRoxieServerCaseActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  18047. : CRoxieServerMultiInputBaseActivity(_ctx, _factory, _probeManager, _numInputs), helper((IHThorCaseArg &)basehelper)
  18048. {
  18049. unusedStopped = false;
  18050. cond = 0;
  18051. active = NULL;
  18052. }
  18053. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  18054. {
  18055. CRoxieServerMultiInputBaseActivity::start(parentExtractSize, parentExtract, paused);
  18056. cond = helper.getBranch();
  18057. //CHOOSE defaults to the last argument if out of range.
  18058. if (cond >= numInputs)
  18059. cond = numInputs - 1;
  18060. inputArray[cond]->start(parentExtractSize, parentExtract, paused);
  18061. startJunction(junctionArray[cond]);
  18062. assertex(numInputs==numStreams);
  18063. for (unsigned idx = 0; idx < numStreams; idx++)
  18064. {
  18065. if (idx!=cond)
  18066. streamArray[idx]->stop(); // Note: stopping unused branches early helps us avoid buffering splits too long.
  18067. }
  18068. active = streamArray[cond];
  18069. unusedStopped = true;
  18070. }
  18071. virtual void stop()
  18072. {
  18073. for (unsigned idx = 0; idx < numStreams; idx++)
  18074. {
  18075. if (idx==cond || !unusedStopped)
  18076. streamArray[idx]->stop();
  18077. }
  18078. CRoxieServerMultiInputBaseActivity::stop();
  18079. }
  18080. virtual void reset()
  18081. {
  18082. unusedStopped = false;
  18083. active = NULL;
  18084. CRoxieServerMultiInputBaseActivity::reset();
  18085. }
  18086. virtual const void *nextRow()
  18087. {
  18088. ActivityTimer t(totalCycles, timeActivities);
  18089. if (active)
  18090. {
  18091. const void *ret = active->nextRow();
  18092. if (ret)
  18093. processed++;
  18094. return ret;
  18095. }
  18096. return NULL;
  18097. }
  18098. };
  18099. class CRoxieServerCaseActivityFactory : public CRoxieServerMultiInputFactory
  18100. {
  18101. bool graphInvariant;
  18102. public:
  18103. CRoxieServerCaseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _graphInvariant)
  18104. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  18105. {
  18106. graphInvariant = _graphInvariant;
  18107. }
  18108. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  18109. {
  18110. return new CRoxieServerCaseActivity(_ctx, this, _probeManager, numInputs());
  18111. }
  18112. virtual bool isGraphInvariant() const
  18113. {
  18114. return graphInvariant;
  18115. }
  18116. };
  18117. IRoxieServerActivityFactory *createRoxieServerCaseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _graphInvariant)
  18118. {
  18119. return new CRoxieServerCaseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _graphInvariant);
  18120. }
  18121. //=================================================================================
  18122. class CRoxieServerIfActivity : public CRoxieServerActivity
  18123. {
  18124. IHThorIfArg &helper;
  18125. IFinalRoxieInput *inputTrue;
  18126. IFinalRoxieInput *inputFalse;
  18127. IEngineRowStream *streamTrue;
  18128. IEngineRowStream *streamFalse;
  18129. unsigned sourceIdxFalse = 0;
  18130. unsigned sourceIdxTrue = 0;
  18131. Owned<IStrandJunction> junctionTrue;
  18132. Owned<IStrandJunction> junctionFalse;
  18133. bool cond;
  18134. bool unusedStopped;
  18135. public:
  18136. CRoxieServerIfActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  18137. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorIfArg &)basehelper)
  18138. {
  18139. inputFalse = NULL;
  18140. inputTrue = NULL;
  18141. streamTrue = NULL;
  18142. streamFalse = NULL;
  18143. unusedStopped = false;
  18144. cond = false;
  18145. }
  18146. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  18147. {
  18148. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  18149. cond = helper.getCondition();
  18150. if (cond)
  18151. {
  18152. inputTrue->start(parentExtractSize, parentExtract, paused);
  18153. startJunction(junctionTrue);
  18154. if (streamFalse)
  18155. streamFalse->stop(); // Note: stopping unused branches early helps us avoid buffering splits too long.
  18156. }
  18157. else
  18158. {
  18159. if (inputFalse)
  18160. {
  18161. inputFalse->start(parentExtractSize, parentExtract, paused);
  18162. startJunction(junctionFalse);
  18163. }
  18164. streamTrue->stop();
  18165. }
  18166. unusedStopped = true;
  18167. }
  18168. virtual void stop()
  18169. {
  18170. if (!unusedStopped || cond)
  18171. streamTrue->stop();
  18172. if (streamFalse && (!unusedStopped || !cond))
  18173. streamFalse->stop();
  18174. CRoxieServerActivity::stop();
  18175. }
  18176. virtual unsigned __int64 queryLocalCycles() const
  18177. {
  18178. __int64 localCycles = totalCycles.totalCycles;
  18179. localCycles -= inputTrue->queryTotalCycles();
  18180. if (inputFalse)
  18181. localCycles -= inputFalse->queryTotalCycles();
  18182. if (localCycles < 0)
  18183. localCycles = 0;
  18184. return localCycles;
  18185. }
  18186. virtual IFinalRoxieInput *queryInput(unsigned idx) const
  18187. {
  18188. switch (idx)
  18189. {
  18190. case 0:
  18191. return inputTrue;
  18192. case 1:
  18193. return inputFalse;
  18194. default:
  18195. return NULL;
  18196. }
  18197. }
  18198. virtual IEngineRowStream *queryConcreteOutputStream(unsigned whichInput) { return this; }
  18199. virtual IStrandJunction *queryConcreteOutputJunction(unsigned idx) const { return nullptr; }
  18200. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  18201. {
  18202. IFinalRoxieInput *in = cond ? inputTrue : inputFalse;
  18203. if (in)
  18204. return in->queryIndexReadActivity();
  18205. return NULL;
  18206. }
  18207. virtual void reset()
  18208. {
  18209. CRoxieServerActivity::reset();
  18210. inputTrue->reset();
  18211. if (inputFalse)
  18212. inputFalse->reset();
  18213. resetJunction(junctionTrue);
  18214. resetJunction(junctionFalse);
  18215. unusedStopped = false;
  18216. }
  18217. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  18218. {
  18219. if (idx==1)
  18220. {
  18221. inputFalse = _in;
  18222. sourceIdxFalse = _sourceIdx;
  18223. }
  18224. else
  18225. {
  18226. assertex(!idx);
  18227. inputTrue = _in;
  18228. sourceIdxTrue = _sourceIdx;
  18229. }
  18230. }
  18231. virtual IStrandJunction *getOutputStreams(IRoxieSlaveContext *ctx, unsigned idx, PointerArrayOf<IEngineRowStream> &streams, const StrandOptions * consumerOptions, bool consumerOrdered, IOrderedCallbackCollection * orderedCallbacks)
  18232. {
  18233. //It should be possible to stream IF(), but the number of strands would need to match on the two branches.
  18234. streamTrue = connectSingleStream(ctx, inputTrue, sourceIdxTrue, junctionTrue, consumerOrdered);
  18235. streamFalse = connectSingleStream(ctx, inputFalse, sourceIdxFalse, junctionFalse, consumerOrdered);
  18236. return CRoxieServerActivity::getOutputStreams(ctx, idx, streams, nullptr, consumerOrdered, nullptr);
  18237. }
  18238. virtual const void *nextRow()
  18239. {
  18240. ActivityTimer t(totalCycles, timeActivities);
  18241. IEngineRowStream *in = cond ? streamTrue : streamFalse;
  18242. if (in)
  18243. {
  18244. const void * ret;
  18245. if ((ret = in->nextRow()) != NULL)
  18246. processed++;
  18247. return ret;
  18248. }
  18249. return NULL;
  18250. }
  18251. };
  18252. class CRoxieServerIfActivityFactory : public CRoxieServerActivityFactory
  18253. {
  18254. unsigned input2;
  18255. unsigned input2idx;
  18256. bool graphInvariant;
  18257. public:
  18258. CRoxieServerIfActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _graphInvariant)
  18259. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  18260. {
  18261. graphInvariant = _graphInvariant;
  18262. input2 = (unsigned)-1;
  18263. input2idx = (unsigned)-1;
  18264. }
  18265. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  18266. {
  18267. return new CRoxieServerIfActivity(_ctx, this, _probeManager);
  18268. }
  18269. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  18270. {
  18271. if (idx==1)
  18272. {
  18273. input2 = source;
  18274. input2idx = sourceidx;
  18275. }
  18276. else
  18277. CRoxieServerActivityFactory::setInput(idx, source, sourceidx);
  18278. }
  18279. virtual unsigned getInput(unsigned idx, unsigned &sourceidx) const
  18280. {
  18281. switch (idx)
  18282. {
  18283. case 1:
  18284. sourceidx = input2idx;
  18285. return input2;
  18286. case 0:
  18287. return CRoxieServerActivityFactory::getInput(idx, sourceidx);
  18288. default:
  18289. return (unsigned) -1;
  18290. }
  18291. }
  18292. virtual unsigned numInputs() const { return (input2 == (unsigned)-1) ? 1 : 2; }
  18293. virtual bool isGraphInvariant() const
  18294. {
  18295. return graphInvariant;
  18296. }
  18297. };
  18298. IRoxieServerActivityFactory *createRoxieServerIfActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _graphInvariant)
  18299. {
  18300. return new CRoxieServerIfActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _graphInvariant);
  18301. }
  18302. //=================================================================================
  18303. class CRoxieServerActionBaseActivity : public CRoxieServerActivity
  18304. {
  18305. CriticalSection ecrit;
  18306. Owned<IException> exception;
  18307. bool executed;
  18308. public:
  18309. CRoxieServerActionBaseActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  18310. : CRoxieServerActivity(_ctx, _factory, _probeManager)
  18311. {
  18312. executed = false;
  18313. }
  18314. virtual void doExecuteAction(unsigned parentExtractSize, const byte * parentExtract) = 0;
  18315. virtual void execute(unsigned parentExtractSize, const byte * parentExtract)
  18316. {
  18317. CriticalBlock b(ecrit);
  18318. if (exception)
  18319. throw(exception.getLink());
  18320. if (!executed)
  18321. {
  18322. try
  18323. {
  18324. executed = true;
  18325. start(parentExtractSize, parentExtract, false);
  18326. doExecuteAction(parentExtractSize, parentExtract);
  18327. stop();
  18328. }
  18329. catch (IException * E)
  18330. {
  18331. ctx->notifyAbort(E);
  18332. abort();
  18333. exception.set(E);
  18334. throw;
  18335. }
  18336. }
  18337. }
  18338. virtual void reset()
  18339. {
  18340. executed = false;
  18341. exception.clear();
  18342. CRoxieServerActivity::reset();
  18343. }
  18344. virtual const void *nextRow()
  18345. {
  18346. throwUnexpected(); // I am nobody's input
  18347. }
  18348. virtual IFinalRoxieInput *queryInput(unsigned idx) const
  18349. {
  18350. return NULL;
  18351. }
  18352. };
  18353. class CRoxieServerIfActionActivity : public CRoxieServerActionBaseActivity
  18354. {
  18355. IHThorIfArg &helper;
  18356. public:
  18357. CRoxieServerIfActionActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  18358. : CRoxieServerActionBaseActivity(_ctx, _factory, _probeManager), helper((IHThorIfArg &)basehelper)
  18359. {
  18360. }
  18361. virtual void doExecuteAction(unsigned parentExtractSize, const byte * parentExtract)
  18362. {
  18363. bool cond;
  18364. {
  18365. ActivityTimer t(totalCycles, timeActivities);
  18366. cond = helper.getCondition();
  18367. }
  18368. stopDependencies(parentExtractSize, parentExtract, cond ? 2 : 1);
  18369. executeDependencies(parentExtractSize, parentExtract, cond ? 1 : 2);
  18370. }
  18371. };
  18372. class CRoxieServerIfActionActivityFactory : public CRoxieServerActivityFactory
  18373. {
  18374. bool isRoot;
  18375. public:
  18376. CRoxieServerIfActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _isRoot)
  18377. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode), isRoot(_isRoot)
  18378. {
  18379. }
  18380. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  18381. {
  18382. return new CRoxieServerIfActionActivity(_ctx, this, _probeManager);
  18383. }
  18384. virtual bool isSink() const
  18385. {
  18386. return isRoot;
  18387. }
  18388. };
  18389. IRoxieServerActivityFactory *createRoxieServerIfActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _isRoot)
  18390. {
  18391. return new CRoxieServerIfActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _isRoot);
  18392. }
  18393. //=================================================================================
  18394. class CRoxieServerParallelActionActivity : public CRoxieServerActionBaseActivity
  18395. {
  18396. public:
  18397. CRoxieServerParallelActionActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  18398. : CRoxieServerActionBaseActivity(_ctx, _factory, _probeManager)
  18399. {
  18400. }
  18401. virtual void doExecuteAction(unsigned parentExtractSize, const byte * parentExtract)
  18402. {
  18403. #ifdef PARALLEL_EXECUTE
  18404. CParallelActivityExecutor afor(dependencies, parentExtractSize, parentExtract);
  18405. afor.For(dependencies.ordinality(), dependencies.ordinality(), true);
  18406. #else
  18407. ForEachItemIn(idx, dependencies)
  18408. {
  18409. dependencies.item(idx).execute(parentExtractSize, parentExtract);
  18410. }
  18411. #endif
  18412. }
  18413. };
  18414. class CRoxieServerParallelActionActivityFactory : public CRoxieServerActivityFactory
  18415. {
  18416. bool isRoot;
  18417. public:
  18418. CRoxieServerParallelActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _isRoot)
  18419. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode), isRoot(_isRoot)
  18420. {
  18421. assertex(!isRoot); // non-internal should be expanded out..
  18422. }
  18423. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  18424. {
  18425. return new CRoxieServerParallelActionActivity(_ctx, this, _probeManager);
  18426. }
  18427. virtual bool isSink() const
  18428. {
  18429. return isRoot;
  18430. }
  18431. };
  18432. IRoxieServerActivityFactory *createRoxieServerParallelActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _isRoot)
  18433. {
  18434. return new CRoxieServerParallelActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _isRoot);
  18435. }
  18436. //=================================================================================
  18437. class CRoxieServerSequentialActionActivity : public CRoxieServerActionBaseActivity
  18438. {
  18439. IHThorSequentialArg &helper;
  18440. public:
  18441. CRoxieServerSequentialActionActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  18442. : CRoxieServerActionBaseActivity(_ctx, _factory, _probeManager), helper((IHThorSequentialArg &)basehelper)
  18443. {
  18444. }
  18445. virtual void doExecuteAction(unsigned parentExtractSize, const byte * parentExtract)
  18446. {
  18447. unsigned numBranches = helper.numBranches();
  18448. for (unsigned branch=1; branch <= numBranches; branch++)
  18449. executeDependencies(parentExtractSize, parentExtract, branch);
  18450. }
  18451. };
  18452. class CRoxieServerSequentialActionActivityFactory : public CRoxieServerActivityFactory
  18453. {
  18454. bool isRoot;
  18455. public:
  18456. CRoxieServerSequentialActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _isRoot)
  18457. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode), isRoot(_isRoot)
  18458. {
  18459. }
  18460. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  18461. {
  18462. return new CRoxieServerSequentialActionActivity(_ctx, this, _probeManager);
  18463. }
  18464. virtual bool isSink() const
  18465. {
  18466. return isRoot;
  18467. }
  18468. };
  18469. IRoxieServerActivityFactory *createRoxieServerSequentialActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _isRoot)
  18470. {
  18471. return new CRoxieServerSequentialActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _isRoot);
  18472. }
  18473. //=================================================================================
  18474. class CRoxieServerWhenActivity : public CRoxieServerActivity
  18475. {
  18476. public:
  18477. CRoxieServerWhenActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  18478. : CRoxieServerActivity(_ctx, _factory, _probeManager)
  18479. {
  18480. savedExtractSize = 0;
  18481. savedExtract = NULL;
  18482. eofseen = false;
  18483. eogseen = false;
  18484. }
  18485. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  18486. {
  18487. savedExtractSize = parentExtractSize;
  18488. savedExtract = parentExtract;
  18489. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  18490. executeDependencies(parentExtractSize, parentExtract, WhenBeforeId);
  18491. executeDependencies(parentExtractSize, parentExtract, WhenParallelId); // MORE: This should probably be done in parallel!
  18492. eofseen = false;
  18493. eogseen = false;
  18494. }
  18495. virtual void stop()
  18496. {
  18497. if (state == STATEreset || (!aborted && !eofseen)) // If someone else aborted, then WHEN clauses don't trigger, whatever
  18498. {
  18499. stopDependencies(savedExtractSize, savedExtract, WhenSuccessId);
  18500. stopDependencies(savedExtractSize, savedExtract, WhenFailureId);
  18501. }
  18502. else if (state != STATEstopped)
  18503. {
  18504. stopDependencies(savedExtractSize, savedExtract, aborted ? WhenSuccessId : WhenFailureId); // These ones don't get executed
  18505. executeDependencies(savedExtractSize, savedExtract, aborted ? WhenFailureId : WhenSuccessId); // These ones do
  18506. }
  18507. CRoxieServerActivity::stop();
  18508. }
  18509. virtual const void *nextRow()
  18510. {
  18511. try
  18512. {
  18513. ActivityTimer t(totalCycles, timeActivities); // bit of a waste of time....
  18514. const void *ret = inputStream->nextRow();
  18515. if (!ret)
  18516. {
  18517. if (eogseen)
  18518. eofseen = true;
  18519. else
  18520. eogseen = true;
  18521. }
  18522. else
  18523. eogseen = false;
  18524. return ret;
  18525. }
  18526. catch (...)
  18527. {
  18528. aborted = true;
  18529. throw;
  18530. }
  18531. }
  18532. protected:
  18533. const byte *savedExtract;
  18534. unsigned savedExtractSize;
  18535. bool eofseen;
  18536. bool eogseen;
  18537. };
  18538. class CRoxieServerWhenActivityFactory : public CRoxieServerActivityFactory
  18539. {
  18540. public:
  18541. CRoxieServerWhenActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  18542. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  18543. {
  18544. }
  18545. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  18546. {
  18547. return new CRoxieServerWhenActivity(_ctx, this, _probeManager);
  18548. }
  18549. };
  18550. extern IRoxieServerActivityFactory *createRoxieServerWhenActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  18551. {
  18552. return new CRoxieServerWhenActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  18553. }
  18554. //=================================================================================
  18555. class CRoxieServerWhenActionActivity : public CRoxieServerActionBaseActivity
  18556. {
  18557. public:
  18558. CRoxieServerWhenActionActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  18559. : CRoxieServerActionBaseActivity(_ctx, _factory, _probeManager)
  18560. {
  18561. savedExtractSize = 0;
  18562. savedExtract = NULL;
  18563. }
  18564. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  18565. {
  18566. savedExtractSize = parentExtractSize;
  18567. savedExtract = parentExtract;
  18568. CRoxieServerActionBaseActivity::start(parentExtractSize, parentExtract, paused);
  18569. executeDependencies(parentExtractSize, parentExtract, WhenBeforeId);
  18570. executeDependencies(parentExtractSize, parentExtract, WhenParallelId); // MORE: This should probably be done in parallel!
  18571. }
  18572. virtual void stop()
  18573. {
  18574. if (state != STATEstopped)
  18575. {
  18576. stopDependencies(savedExtractSize, savedExtract, aborted ? WhenSuccessId : WhenFailureId); // these are NOT going to execute
  18577. executeDependencies(savedExtractSize, savedExtract, aborted ? WhenFailureId : WhenSuccessId);
  18578. }
  18579. CRoxieServerActionBaseActivity::stop();
  18580. }
  18581. virtual void doExecuteAction(unsigned parentExtractSize, const byte * parentExtract)
  18582. {
  18583. executeDependencies(parentExtractSize, parentExtract, 1);
  18584. }
  18585. protected:
  18586. unsigned savedExtractSize;
  18587. const byte *savedExtract;
  18588. };
  18589. class CRoxieServerWhenActionActivityFactory : public CRoxieServerActivityFactory
  18590. {
  18591. public:
  18592. CRoxieServerWhenActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _isRoot)
  18593. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode), isRoot(_isRoot)
  18594. {
  18595. }
  18596. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  18597. {
  18598. return new CRoxieServerWhenActionActivity(_ctx, this, _probeManager);
  18599. }
  18600. virtual bool isSink() const
  18601. {
  18602. return isRoot;
  18603. }
  18604. private:
  18605. bool isRoot;
  18606. };
  18607. extern IRoxieServerActivityFactory *createRoxieServerWhenActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _isRoot)
  18608. {
  18609. return new CRoxieServerWhenActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _isRoot);
  18610. }
  18611. //=================================================================================
  18612. class CRoxieServerStrandedParseActivity : public CRoxieServerStrandedActivity
  18613. {
  18614. INlpParseAlgorithm * algorithm;
  18615. class ParseProcessor : public StrandProcessor, implements IMatchedAction
  18616. {
  18617. protected:
  18618. IHThorParseArg &helper;
  18619. INlpParser * parser;
  18620. INlpResultIterator * rowIter;
  18621. const void * in;
  18622. char * curSearchText;
  18623. size32_t curSearchTextLen;
  18624. bool processRecord(const void * inRec)
  18625. {
  18626. if (helper.searchTextNeedsFree())
  18627. rtlFree(curSearchText);
  18628. curSearchTextLen = 0;
  18629. curSearchText = NULL;
  18630. helper.getSearchText(curSearchTextLen, curSearchText, inRec);
  18631. return parser->performMatch(*this, in, curSearchTextLen, curSearchText);
  18632. }
  18633. public:
  18634. ParseProcessor(CRoxieServerActivity &_parent, IEngineRowStream *_inputStream, IHThorParseArg &_helper, INlpParseAlgorithm * _algorithm)
  18635. : StrandProcessor(_parent, _inputStream, false), helper(_helper)
  18636. {
  18637. parser = _algorithm->createParser(parent.queryCodeContext(), parent.queryId(), helper.queryHelper(), &helper);
  18638. rowIter = parser->queryResultIter();
  18639. in = NULL;
  18640. curSearchText = NULL;
  18641. curSearchTextLen = 0;
  18642. }
  18643. ~ParseProcessor()
  18644. {
  18645. ::Release(parser);
  18646. }
  18647. virtual void start()
  18648. {
  18649. StrandProcessor::start();
  18650. numProcessedLastGroup = 0;
  18651. curSearchTextLen = 0;
  18652. curSearchText = NULL;
  18653. in = NULL;
  18654. parser->reset();
  18655. }
  18656. virtual void reset()
  18657. {
  18658. if (helper.searchTextNeedsFree())
  18659. rtlFree(curSearchText);
  18660. curSearchText = NULL;
  18661. ReleaseClearRoxieRow(in);
  18662. StrandProcessor::reset();
  18663. }
  18664. virtual const void * nextRow()
  18665. {
  18666. ActivityTimer t(totalCycles, timeActivities);
  18667. for (;;)
  18668. {
  18669. if (rowIter->isValid())
  18670. {
  18671. OwnedConstRoxieRow out = rowIter->getRow();
  18672. rowIter->next();
  18673. processed++;
  18674. return out.getClear();
  18675. }
  18676. ReleaseClearRoxieRow(in);
  18677. in = inputStream->nextRow();
  18678. if (!in)
  18679. {
  18680. if (processed == numProcessedLastGroup)
  18681. in = inputStream->nextRow();
  18682. if (!in)
  18683. {
  18684. processed = numProcessedLastGroup;
  18685. return NULL;
  18686. }
  18687. in = inputStream->nextRow();
  18688. if (!in)
  18689. return NULL;
  18690. }
  18691. processRecord(in);
  18692. rowIter->first();
  18693. }
  18694. }
  18695. virtual unsigned onMatch(ARowBuilder & self, const void * curRecord, IMatchedResults * results, IMatchWalker * walker)
  18696. {
  18697. try
  18698. {
  18699. return helper.transform(self, curRecord, results, walker);
  18700. }
  18701. catch (IException *E)
  18702. {
  18703. throw parent.makeWrappedException(E);
  18704. }
  18705. }
  18706. };
  18707. public:
  18708. CRoxieServerStrandedParseActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, INlpParseAlgorithm * _algorithm, const StrandOptions &_strandOptions)
  18709. : CRoxieServerStrandedActivity(_ctx, _factory, _probeManager, _strandOptions), algorithm(_algorithm)
  18710. {
  18711. }
  18712. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  18713. {
  18714. CRoxieServerStrandedActivity::start(parentExtractSize, parentExtract, paused);
  18715. onStartStrands();
  18716. }
  18717. virtual StrandProcessor *createStrandProcessor(IEngineRowStream *instream)
  18718. {
  18719. return new ParseProcessor(*this, instream, (IHThorParseArg &) basehelper, algorithm);
  18720. }
  18721. virtual StrandProcessor *createStrandSourceProcessor(bool inputOrdered) { throwUnexpected(); }
  18722. };
  18723. class CRoxieServerParseActivityFactory : public CRoxieServerActivityFactory
  18724. {
  18725. Owned<INlpParseAlgorithm> algorithm;
  18726. Owned<IHThorParseArg> helper;
  18727. StrandOptions strandOptions;
  18728. public:
  18729. CRoxieServerParseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, IResourceContext *rc)
  18730. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode), strandOptions(_graphNode)
  18731. {
  18732. helper.setown((IHThorParseArg *) helperFactory());
  18733. algorithm.setown(createThorParser(rc, *helper));
  18734. optStableInput = false;
  18735. }
  18736. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  18737. {
  18738. return new CRoxieServerStrandedParseActivity(_ctx, this, _probeManager, algorithm, strandOptions);
  18739. }
  18740. };
  18741. IRoxieServerActivityFactory *createRoxieServerParseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, IResourceContext *rc)
  18742. {
  18743. return new CRoxieServerParseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, rc);
  18744. }
  18745. //=====================================================================================================
  18746. class CRoxieServerWorkUnitWriteActivity : public CRoxieServerInternalSinkActivity
  18747. {
  18748. IHThorWorkUnitWriteArg &helper;
  18749. bool isReread;
  18750. bool grouped;
  18751. IRoxieServerContext *serverContext;
  18752. public:
  18753. CRoxieServerWorkUnitWriteActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _isReread, unsigned _numOutputs)
  18754. : CRoxieServerInternalSinkActivity(_ctx, _factory, _probeManager, _numOutputs), helper((IHThorWorkUnitWriteArg &)basehelper), isReread(_isReread)
  18755. {
  18756. grouped = (helper.getFlags() & POFgrouped) != 0;
  18757. serverContext = NULL;
  18758. }
  18759. virtual void onCreate(IHThorArg *_colocalParent)
  18760. {
  18761. CRoxieServerInternalSinkActivity::onCreate(_colocalParent);
  18762. serverContext = ctx->queryServerContext();
  18763. if (!serverContext)
  18764. {
  18765. throw MakeStringException(ROXIE_PIPE_ERROR, "Pipe output activity cannot be executed in slave context");
  18766. }
  18767. }
  18768. virtual bool needsAllocator() const { return true; }
  18769. virtual void onExecute()
  18770. {
  18771. int sequence = helper.getSequence();
  18772. const char *storedName = helper.queryName();
  18773. if (!storedName)
  18774. storedName = "Dataset";
  18775. MemoryBuffer result;
  18776. bool saveInContext = (int) sequence < 0 || isReread;
  18777. if (!meta.queryOriginal()) // this is a bit of a hack - don't know why no meta on an output....
  18778. meta.set(input->queryOutputMeta());
  18779. Owned<IOutputRowSerializer> rowSerializer;
  18780. Owned<IXmlWriter> xmlwriter;
  18781. bool appendRaw = false;
  18782. IHpccProtocolResultsWriter *results = NULL;
  18783. IHpccNativeProtocolResultsWriter *nativeResults = NULL;
  18784. IHpccProtocolResponse *protocol = serverContext->queryProtocol();
  18785. unsigned protocolFlags = (protocol) ? protocol->getFlags() : 0;
  18786. if ((int) sequence >= 0)
  18787. {
  18788. results = (protocol) ? protocol->queryHpccResultsSection() : NULL;
  18789. if (results)
  18790. {
  18791. nativeResults = dynamic_cast<IHpccNativeProtocolResultsWriter*>(results);
  18792. xmlwriter.setown(results->addDataset(helper.queryName(), sequence, "Dataset", appendRaw, serverContext->getXmlFlags(), (helper.getFlags() & POFextend) != 0, serverContext->queryXmlns(sequence))); //xmlwriter only returned if needed
  18793. }
  18794. }
  18795. size32_t outputLimitBytes = 0;
  18796. IConstWorkUnit *workunit = serverContext->queryWorkUnit();
  18797. if (workunit)
  18798. {
  18799. size32_t outputLimit;
  18800. if (helper.getFlags() & POFmaxsize)
  18801. outputLimit = helper.getMaxSize();
  18802. else
  18803. {
  18804. // In absense of OPT_OUTPUTLIMIT check pre 5.2 legacy name OPT_OUTPUTLIMIT_LEGACY
  18805. outputLimit = workunit->getDebugValueInt(OPT_OUTPUTLIMIT, workunit->getDebugValueInt(OPT_OUTPUTLIMIT_LEGACY, defaultDaliResultLimit));
  18806. }
  18807. if (outputLimit>defaultDaliResultOutputMax)
  18808. throw MakeStringException(0, "Dali result outputs are restricted to a maximum of %d MB, the current limit is %d MB. A huge dali result usually indicates the ECL needs altering.", defaultDaliResultOutputMax, defaultDaliResultLimit);
  18809. assertex(outputLimit<=0x1000); // 32bit limit because MemoryBuffer/CMessageBuffers involved etc.
  18810. outputLimitBytes = outputLimit * 0x100000;
  18811. }
  18812. if (workunit != NULL || (results && protocol->getFlags() & HPCC_PROTOCOL_NATIVE_RAW))
  18813. {
  18814. ensureRowAllocator();
  18815. rowSerializer.setown(rowAllocator->createDiskSerializer(ctx->queryCodeContext()));
  18816. }
  18817. __int64 initialProcessed = processed;
  18818. RtlLinkedDatasetBuilder builder(rowAllocator);
  18819. for (;;)
  18820. {
  18821. const void *row = inputStream->nextRow();
  18822. if (saveInContext)
  18823. {
  18824. if (row || grouped)
  18825. builder.append(row);
  18826. }
  18827. if (grouped && (processed != initialProcessed))
  18828. {
  18829. if (workunit)
  18830. result.append(row == NULL);
  18831. if (results)
  18832. {
  18833. if (protocolFlags & HPCC_PROTOCOL_NATIVE_RAW && nativeResults)
  18834. {
  18835. char val = (char)(row == NULL);
  18836. nativeResults->appendRaw(sequence, 1, &val);
  18837. }
  18838. else if (xmlwriter)
  18839. {
  18840. xmlwriter->outputBeginNested("Row", false);
  18841. xmlwriter->outputCString("1", "@__GroupBreak__");
  18842. xmlwriter->outputEndNested("Row");
  18843. }
  18844. }
  18845. }
  18846. if (!row)
  18847. {
  18848. row = inputStream->nextRow();
  18849. if (!row)
  18850. break;
  18851. if (saveInContext)
  18852. builder.append(row);
  18853. }
  18854. processed++;
  18855. if (workunit)
  18856. {
  18857. CThorDemoRowSerializer serializerTarget(result);
  18858. rowSerializer->serialize(serializerTarget, (const byte *) row);
  18859. }
  18860. if ((int) sequence >= 0)
  18861. {
  18862. if (appendRaw && nativeResults)
  18863. {
  18864. // MORE - should be able to serialize straight to the response...
  18865. MemoryBuffer rowbuff;
  18866. CThorDemoRowSerializer serializerTarget(rowbuff);
  18867. rowSerializer->serialize(serializerTarget, (const byte *) row);
  18868. nativeResults->appendRawRow(sequence, rowbuff.length(), rowbuff.toByteArray());
  18869. }
  18870. else if (xmlwriter)
  18871. {
  18872. xmlwriter->outputBeginNested(DEFAULTXMLROWTAG, false);
  18873. helper.serializeXml((byte *) row, *xmlwriter);
  18874. xmlwriter->outputEndNested(DEFAULTXMLROWTAG);
  18875. results->finalizeXmlRow(sequence);
  18876. }
  18877. else if (nativeResults)
  18878. {
  18879. SimpleOutputWriter x;
  18880. helper.serializeXml((byte *) row, x);
  18881. x.newline();
  18882. nativeResults->appendSimpleRow(sequence, x.str());
  18883. }
  18884. }
  18885. ReleaseRoxieRow(row);
  18886. if (outputLimitBytes && result.length() > outputLimitBytes)
  18887. {
  18888. StringBuffer errMsg("Dataset too large to output to workunit (limit ");
  18889. errMsg.append(outputLimitBytes/0x100000).append(" megabytes), in result (");
  18890. const char *name = helper.queryName();
  18891. if (name)
  18892. errMsg.append("name=").append(name);
  18893. else
  18894. errMsg.append("sequence=").append(helper.getSequence());
  18895. errMsg.append(")");
  18896. throw MakeStringExceptionDirect(0, errMsg.str());
  18897. }
  18898. }
  18899. if (xmlwriter)
  18900. xmlwriter->outputEndArray(DEFAULTXMLROWTAG);
  18901. if (saveInContext)
  18902. serverContext->appendResultDeserialized(storedName, sequence, builder.getcount(), builder.linkrows(), (helper.getFlags() & POFextend) != 0, LINK(meta.queryOriginal()));
  18903. if (workunit)
  18904. serverContext->appendResultRawContext(storedName, sequence, result.length(), result.toByteArray(), processed, (helper.getFlags() & POFextend) != 0, false); // MORE - shame to do extra copy...
  18905. }
  18906. };
  18907. class CRoxieServerWorkUnitWriteActivityFactory : public CRoxieServerInternalSinkFactory
  18908. {
  18909. bool isReread;
  18910. public:
  18911. CRoxieServerWorkUnitWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned _usageCount, bool _isRoot)
  18912. : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _usageCount, _isRoot)
  18913. {
  18914. isReread = usageCount > 0;
  18915. Owned<IHThorWorkUnitWriteArg> helper = (IHThorWorkUnitWriteArg *) helperFactory();
  18916. isInternal = (helper->getSequence()==ResultSequenceInternal);
  18917. }
  18918. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  18919. {
  18920. return new CRoxieServerWorkUnitWriteActivity(_ctx, this, _probeManager, isReread, usageCount);
  18921. }
  18922. };
  18923. IRoxieServerActivityFactory *createRoxieServerWorkUnitWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned _usageCount, bool _isRoot)
  18924. {
  18925. return new CRoxieServerWorkUnitWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _usageCount, _isRoot);
  18926. }
  18927. //=====================================================================================================
  18928. class CRoxieServerWorkUnitWriteDictActivity : public CRoxieServerInternalSinkActivity
  18929. {
  18930. IHThorDictionaryWorkUnitWriteArg &helper;
  18931. IRoxieServerContext *serverContext;
  18932. public:
  18933. CRoxieServerWorkUnitWriteDictActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _usageCount)
  18934. : CRoxieServerInternalSinkActivity(_ctx, _factory, _probeManager, _usageCount), helper((IHThorDictionaryWorkUnitWriteArg &)basehelper)
  18935. {
  18936. serverContext = NULL;
  18937. }
  18938. virtual void onCreate(IHThorArg *_colocalParent)
  18939. {
  18940. CRoxieServerInternalSinkActivity::onCreate(_colocalParent);
  18941. serverContext = ctx->queryServerContext();
  18942. if (!serverContext)
  18943. {
  18944. throw MakeStringException(ROXIE_PIPE_ERROR, "Write Dictionary activity cannot be executed in slave context");
  18945. }
  18946. }
  18947. virtual bool needsAllocator() const { return true; }
  18948. virtual void onExecute()
  18949. {
  18950. int sequence = helper.getSequence();
  18951. const char *storedName = helper.queryName();
  18952. assertex(storedName && *storedName);
  18953. assertex(sequence < 0);
  18954. RtlLinkedDictionaryBuilder builder(rowAllocator, helper.queryHashLookupInfo());
  18955. for (;;)
  18956. {
  18957. const void *row = inputStream->ungroupedNextRow();
  18958. if (!row)
  18959. break;
  18960. builder.appendOwn(row);
  18961. processed++;
  18962. }
  18963. serverContext->appendResultDeserialized(storedName, sequence, builder.getcount(), builder.linkrows(), (helper.getFlags() & POFextend) != 0, LINK(meta.queryOriginal()));
  18964. }
  18965. };
  18966. class CRoxieServerWorkUnitWriteDictActivityFactory : public CRoxieServerInternalSinkFactory
  18967. {
  18968. public:
  18969. CRoxieServerWorkUnitWriteDictActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned _usageCount, bool _isRoot)
  18970. : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _usageCount, _isRoot)
  18971. {
  18972. Owned<IHThorDictionaryWorkUnitWriteArg> helper = (IHThorDictionaryWorkUnitWriteArg *) helperFactory();
  18973. isInternal = (helper->getSequence()==ResultSequenceInternal);
  18974. }
  18975. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  18976. {
  18977. return new CRoxieServerWorkUnitWriteDictActivity(_ctx, this, _probeManager, usageCount);
  18978. }
  18979. };
  18980. IRoxieServerActivityFactory *createRoxieServerWorkUnitWriteDictActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned _usageCount, bool _isRoot)
  18981. {
  18982. return new CRoxieServerWorkUnitWriteDictActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _usageCount, _isRoot);
  18983. }
  18984. //=================================================================================
  18985. class CRoxieServerRemoteResultActivity : public CRoxieServerInternalSinkActivity
  18986. {
  18987. IHThorRemoteResultArg &helper;
  18988. public:
  18989. CRoxieServerRemoteResultActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numOutputs)
  18990. : CRoxieServerInternalSinkActivity(_ctx, _factory, _probeManager, _numOutputs), helper((IHThorRemoteResultArg &)basehelper)
  18991. {
  18992. }
  18993. virtual void onExecute()
  18994. {
  18995. OwnedConstRoxieRow row = inputStream->nextRow();
  18996. helper.sendResult(row); // should be only one row or something has gone wrong!
  18997. }
  18998. };
  18999. class CRoxieServerRemoteResultActivityFactory : public CRoxieServerInternalSinkFactory
  19000. {
  19001. public:
  19002. CRoxieServerRemoteResultActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned _usageCount, bool _isRoot)
  19003. : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _usageCount, _isRoot)
  19004. {
  19005. Owned<IHThorRemoteResultArg> helper = (IHThorRemoteResultArg *) helperFactory();
  19006. isInternal = (helper->getSequence()==ResultSequenceInternal);
  19007. }
  19008. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  19009. {
  19010. return new CRoxieServerRemoteResultActivity(_ctx, this, _probeManager, usageCount);
  19011. }
  19012. };
  19013. IRoxieServerActivityFactory *createRoxieServerRemoteResultActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, unsigned _usageCount, bool _isRoot)
  19014. {
  19015. return new CRoxieServerRemoteResultActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _usageCount, _isRoot);
  19016. }
  19017. //=================================================================================
  19018. class CRoxieServerXmlParseActivity : public CRoxieServerActivity, implements IXMLSelect
  19019. {
  19020. IHThorXmlParseArg &helper;
  19021. Owned<IXMLParse> xmlParser;
  19022. const void * in;
  19023. char * srchStr;
  19024. unsigned numProcessedLastGroup;
  19025. bool srchStrNeedsFree;
  19026. Owned<IColumnProvider> lastMatch;
  19027. public:
  19028. IMPLEMENT_IINTERFACE_USING(CRoxieServerActivity)
  19029. CRoxieServerXmlParseActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  19030. : CRoxieServerActivity(_ctx, _factory, _probeManager),
  19031. helper((IHThorXmlParseArg &)basehelper)
  19032. {
  19033. srchStrNeedsFree = helper.searchTextNeedsFree();
  19034. numProcessedLastGroup = 0;
  19035. srchStr = NULL;
  19036. in = NULL;
  19037. }
  19038. ~CRoxieServerXmlParseActivity()
  19039. {
  19040. }
  19041. virtual bool needsAllocator() const { return true; }
  19042. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  19043. {
  19044. numProcessedLastGroup = 0;
  19045. srchStr = NULL;
  19046. in = NULL;
  19047. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  19048. }
  19049. virtual void reset()
  19050. {
  19051. if (helper.searchTextNeedsFree())
  19052. rtlFree(srchStr);
  19053. srchStr = NULL;
  19054. ReleaseClearRoxieRow(in);
  19055. xmlParser.clear();
  19056. CRoxieServerActivity::reset();
  19057. }
  19058. virtual void match(IColumnProvider &entry, offset_t startOffset, offset_t endOffset)
  19059. {
  19060. lastMatch.set(&entry);
  19061. }
  19062. virtual const void *nextRow()
  19063. {
  19064. ActivityTimer t(totalCycles, timeActivities);
  19065. for (;;)
  19066. {
  19067. if(xmlParser)
  19068. {
  19069. for (;;)
  19070. {
  19071. if(!xmlParser->next())
  19072. {
  19073. if (srchStrNeedsFree)
  19074. {
  19075. rtlFree(srchStr);
  19076. srchStr = NULL;
  19077. }
  19078. xmlParser.clear();
  19079. break;
  19080. }
  19081. if(lastMatch)
  19082. {
  19083. try
  19084. {
  19085. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  19086. size32_t outSize = helper.transform(rowBuilder, in, lastMatch);
  19087. lastMatch.clear();
  19088. if (outSize)
  19089. {
  19090. processed++;
  19091. return rowBuilder.finalizeRowClear(outSize);
  19092. }
  19093. }
  19094. catch (IException *E)
  19095. {
  19096. throw makeWrappedException(E);
  19097. }
  19098. }
  19099. }
  19100. }
  19101. ReleaseClearRoxieRow(in);
  19102. in = inputStream->nextRow();
  19103. if(!in)
  19104. {
  19105. if(numProcessedLastGroup == processed)
  19106. in = inputStream->nextRow();
  19107. if(!in)
  19108. {
  19109. numProcessedLastGroup = processed;
  19110. return NULL;
  19111. }
  19112. }
  19113. size32_t srchLen;
  19114. helper.getSearchText(srchLen, srchStr, in);
  19115. OwnedRoxieString xmlIteratorPath(helper.getXmlIteratorPath());
  19116. xmlParser.setown(createXMLParse(srchStr, srchLen, xmlIteratorPath, *this));
  19117. }
  19118. }
  19119. };
  19120. class CRoxieServerXmlParseActivityFactory : public CRoxieServerActivityFactory
  19121. {
  19122. public:
  19123. CRoxieServerXmlParseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  19124. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  19125. {
  19126. }
  19127. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  19128. {
  19129. return new CRoxieServerXmlParseActivity(_ctx, this, _probeManager);
  19130. }
  19131. };
  19132. IRoxieServerActivityFactory *createRoxieServerXmlParseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  19133. {
  19134. return new CRoxieServerXmlParseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  19135. }
  19136. //=====================================================================================================
  19137. class CRoxieServerDiskReadBaseActivity : public CRoxieServerActivity, implements IRoxieServerErrorHandler, implements IIndexReadContext
  19138. {
  19139. protected:
  19140. IHThorDiskReadBaseArg &helper;
  19141. IHThorSourceLimitTransformExtra * limitTransformExtra = nullptr;
  19142. IHThorCompoundExtra * compoundHelper;
  19143. RemoteActivityId remoteId; // Note we copy it rather than reference
  19144. Owned<CSkippableRemoteResultAdaptor> remote;
  19145. unsigned numParts;
  19146. unsigned __int64 rowLimit;
  19147. unsigned __int64 stopAfter;
  19148. Linked<IInMemoryIndexManager> manager;
  19149. Owned<IInMemoryIndexCursor> cursor;
  19150. Owned<IDirectReader> reader;
  19151. CThorContiguousRowBuffer deserializeSource;
  19152. Owned<ISourceRowPrefetcher> prefetcher;
  19153. bool eof;
  19154. bool isKeyed;
  19155. bool variableFileName;
  19156. bool isOpt;
  19157. bool sorted;
  19158. bool maySkip;
  19159. bool isLocal;
  19160. bool forceRemote;
  19161. bool isGrouped = false;
  19162. CachedOutputMetaData diskSize;
  19163. Owned<const IResolvedFile> varFileInfo;
  19164. Owned<IFileIOArray> varFiles;
  19165. inline bool useRemote()
  19166. {
  19167. return remote != NULL && (forceRemote || numParts > 1);
  19168. }
  19169. public:
  19170. IMPLEMENT_IINTERFACE_USING(CRoxieServerActivity)
  19171. CRoxieServerDiskReadBaseActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, bool _sorted, bool _maySkip, IInMemoryIndexManager *_manager)
  19172. : CRoxieServerActivity(_ctx, _factory, _probeManager),
  19173. helper((IHThorDiskReadBaseArg &)basehelper),
  19174. numParts(_numParts),
  19175. remoteId(_remoteId),
  19176. manager(_manager),
  19177. isLocal(_isLocal),
  19178. sorted(_sorted),
  19179. maySkip(_maySkip),
  19180. deserializeSource(NULL)
  19181. {
  19182. forceRemote = factory->queryQueryFactory().queryOptions().disableLocalOptimizations;
  19183. if ((forceRemote || numParts != 1) && !isLocal) // NOTE : when numParts == 0 (variable case) we create, even though we may not use
  19184. remote.setown(new CSkippableRemoteResultAdaptor(_ctx, this, remoteId, meta.queryOriginal(), helper, *this, sorted, false, _maySkip));
  19185. compoundHelper = NULL;
  19186. eof = false;
  19187. rowLimit = (unsigned __int64) -1;
  19188. isKeyed = false;
  19189. stopAfter = I64C(0x7FFFFFFFFFFFFFFF);
  19190. Linked<IOutputMetaData> diskMeta(helper.queryDiskRecordSize()->querySerializedDiskMeta());
  19191. if (diskMeta->isGrouped())
  19192. {
  19193. diskMeta.setown(new CSuffixedOutputMeta(+1, diskMeta.getClear()));
  19194. isGrouped = true;
  19195. }
  19196. diskSize.set(diskMeta);
  19197. variableFileName = allFilesDynamic || factory->queryQueryFactory().isDynamic() || ((helper.getFlags() & (TDXvarfilename|TDXdynamicfilename)) != 0);
  19198. isOpt = (helper.getFlags() & TDRoptional) != 0;
  19199. }
  19200. virtual const IResolvedFile *queryVarFileInfo() const
  19201. {
  19202. return varFileInfo;
  19203. }
  19204. virtual void onCreate(IHThorArg *_colocalParent)
  19205. {
  19206. CRoxieServerActivity::onCreate(_colocalParent);
  19207. if (remote)
  19208. remote->onCreate(_colocalParent);
  19209. }
  19210. virtual bool needsAllocator() const { return true; }
  19211. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  19212. {
  19213. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  19214. if (compoundHelper)
  19215. {
  19216. rowLimit = compoundHelper->getRowLimit();
  19217. stopAfter = compoundHelper->getChooseNLimit();
  19218. }
  19219. if (!helper.canMatchAny())
  19220. eof = true;
  19221. else
  19222. {
  19223. if (variableFileName)
  19224. {
  19225. OwnedRoxieString fileName(helper.getFileName());
  19226. varFileInfo.setown(resolveLFN(fileName, isOpt));
  19227. numParts = 0;
  19228. if (varFileInfo)
  19229. {
  19230. numParts = varFileInfo->getNumParts();
  19231. const IPropertyTree *options = varFileInfo->queryProperties();
  19232. if (options)
  19233. {
  19234. isGrouped = options->getPropBool("@grouped");
  19235. if (isGrouped && !diskSize.isGrouped())
  19236. {
  19237. // We are prepared to read contents of a grouped persist ungrouped... But not vice versa
  19238. VStringBuffer msg("Published group information for file %s does not match coded information - assuming grouped", fileName.get());
  19239. WARNLOG("%s", msg.str());
  19240. ctx->queryCodeContext()->addWuException(msg.str(), ROXIE_LAYOUT_MISMATCH, SeverityError, "roxie");
  19241. Owned<IOutputMetaData> diskMeta(new CSuffixedOutputMeta(+1, LINK(diskSize.queryOriginal())));
  19242. diskSize.set(diskMeta);
  19243. }
  19244. size32_t dfsSize = options->getPropInt("@recordSize");
  19245. if (dfsSize && diskSize.isFixedSize() && dfsSize != diskSize.getFixedSize())
  19246. throw MakeStringException(ROXIE_LAYOUT_MISMATCH, "Published record size %d for file %s (%s) does not match coded record size %d", dfsSize, fileName.get(), isGrouped ? "grouped" : "ungrouped", diskSize.getFixedSize());
  19247. }
  19248. }
  19249. }
  19250. if (!numParts)
  19251. {
  19252. eof = true;
  19253. }
  19254. else if (useRemote())
  19255. {
  19256. remote->onStart(parentExtractSize, parentExtract);
  19257. remote->setLimits(rowLimit, (unsigned __int64) -1, stopAfter);
  19258. unsigned fileNo = 0;
  19259. // Translation into a message per channel done elsewhere....
  19260. remote->getMem(0, fileNo, 0);
  19261. remote->flush();
  19262. remote->senddone();
  19263. }
  19264. else
  19265. {
  19266. if (variableFileName)
  19267. {
  19268. unsigned channel = isLocal ? factory->queryQueryFactory().queryChannel() : 0;
  19269. varFiles.setown(varFileInfo->getIFileIOArray(isOpt, channel));
  19270. manager.setown(varFileInfo->getIndexManager(isOpt, channel, varFiles, diskSize, false, 0));
  19271. }
  19272. assertex(manager != NULL);
  19273. helper.createSegmentMonitors(this);
  19274. if (cursor)
  19275. {
  19276. isKeyed = cursor->selectKey();
  19277. cursor->reset();
  19278. }
  19279. if (!isKeyed)
  19280. {
  19281. reader.setown(manager->createReader(0, 0, 1));
  19282. deserializeSource.setStream(reader);
  19283. prefetcher.setown(diskSize.queryOriginal()->createDiskPrefetcher(ctx->queryCodeContext(), activityId));
  19284. }
  19285. helper.setCallback(reader ? reader->queryThorDiskCallback() : cursor);
  19286. }
  19287. }
  19288. }
  19289. virtual void append(IKeySegmentMonitor *segment)
  19290. {
  19291. if (!segment->isWild())
  19292. {
  19293. if (!cursor)
  19294. cursor.setown(manager->createCursor(diskSize.queryRecordAccessor(true)));
  19295. cursor->append(segment);
  19296. }
  19297. }
  19298. virtual unsigned ordinality() const
  19299. {
  19300. return cursor ? cursor->ordinality() : 0;
  19301. }
  19302. virtual IKeySegmentMonitor *item(unsigned idx) const
  19303. {
  19304. return cursor ? cursor->item(idx) : 0;
  19305. }
  19306. virtual void stop()
  19307. {
  19308. if (useRemote())
  19309. remote->onStop();
  19310. CRoxieServerActivity::stop();
  19311. }
  19312. virtual void reset()
  19313. {
  19314. if (useRemote())
  19315. {
  19316. processed = remote->processed;
  19317. remote->processed = 0;
  19318. remote->onReset();
  19319. }
  19320. varFileInfo.clear();
  19321. eof = false;
  19322. if (cursor)
  19323. cursor->reset();
  19324. deserializeSource.clearStream();
  19325. CRoxieServerActivity::reset();
  19326. }
  19327. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  19328. {
  19329. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  19330. }
  19331. virtual void onLimitExceeded(bool isKeyed)
  19332. {
  19333. if (traceLevel > 4)
  19334. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  19335. assertex(compoundHelper);
  19336. if (isKeyed) // MORE does this exist for diskread? should it?
  19337. {
  19338. if (helper.getFlags() & (TDRkeyedlimitskips|TDRkeyedlimitcreates))
  19339. {
  19340. if (ctx->queryDebugContext())
  19341. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  19342. throw makeLimitSkipException(true);
  19343. }
  19344. else
  19345. {
  19346. UNIMPLEMENTED;
  19347. //compoundHelper->onKeyedLimitExceeded(); Doesn't exist - though the flags do... interesting...
  19348. }
  19349. }
  19350. else
  19351. {
  19352. if (helper.getFlags() & (TDRlimitskips|TDRlimitcreates))
  19353. {
  19354. if (ctx->queryDebugContext())
  19355. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  19356. throw makeLimitSkipException(false);
  19357. }
  19358. else
  19359. compoundHelper->onLimitExceeded();
  19360. }
  19361. }
  19362. virtual const void * createLimitFailRow(bool isKeyed)
  19363. {
  19364. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  19365. assertex(limitTransformExtra);
  19366. size32_t outSize = isKeyed ? limitTransformExtra->transformOnKeyedLimitExceeded(rowBuilder) : limitTransformExtra->transformOnLimitExceeded(rowBuilder);
  19367. if (outSize)
  19368. return rowBuilder.finalizeRowClear(outSize);
  19369. return NULL;
  19370. }
  19371. virtual void gatherStats(CRuntimeStatisticCollection & merged) const override
  19372. {
  19373. CRoxieServerActivity::gatherStats(merged);
  19374. if (remote)
  19375. remote->gatherStats(merged);
  19376. }
  19377. };
  19378. class CRoxieServerDiskReadActivity : public CRoxieServerDiskReadBaseActivity
  19379. {
  19380. IHThorDiskReadArg * readHelper;
  19381. ConstPointerArray readrows;
  19382. bool readAheadDone;
  19383. bool eogPending;
  19384. unsigned readIndex;
  19385. unsigned lastGroupProcessed;
  19386. public:
  19387. CRoxieServerDiskReadActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, bool _sorted, bool _maySkip, IInMemoryIndexManager *_manager)
  19388. : CRoxieServerDiskReadBaseActivity(_ctx, _factory, _probeManager, _remoteId, _numParts, _isLocal, _sorted, _maySkip, _manager)
  19389. {
  19390. compoundHelper = (IHThorDiskReadArg *)&helper;
  19391. readHelper = (IHThorDiskReadArg *)&helper;
  19392. limitTransformExtra = readHelper;
  19393. readAheadDone = false;
  19394. readIndex = 0;
  19395. eogPending = false;
  19396. lastGroupProcessed = processed;
  19397. }
  19398. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  19399. {
  19400. rowLimit = compoundHelper->getRowLimit();
  19401. stopAfter = compoundHelper->getChooseNLimit();
  19402. CRoxieServerDiskReadBaseActivity::start(parentExtractSize, parentExtract, paused);
  19403. readAheadDone = false;
  19404. readIndex = 0;
  19405. eogPending = false;
  19406. lastGroupProcessed = processed;
  19407. }
  19408. virtual void reset()
  19409. {
  19410. roxiemem::ReleaseRoxieRowRange(readrows.getArray(), readIndex, readrows.ordinality());
  19411. readrows.kill();
  19412. readAheadDone = false;
  19413. readIndex = 0;
  19414. eogPending = false;
  19415. lastGroupProcessed = processed;
  19416. CRoxieServerDiskReadBaseActivity::reset();
  19417. }
  19418. virtual const void *nextRow()
  19419. {
  19420. ActivityTimer t(totalCycles, timeActivities);
  19421. if (eof)
  19422. return NULL;
  19423. else if (useRemote())
  19424. return remote->nextRow();
  19425. else if (maySkip)
  19426. {
  19427. if (!readAheadDone)
  19428. {
  19429. unsigned preprocessed = 0;
  19430. while (!eof)
  19431. {
  19432. const void *row = _nextRow();
  19433. if (row)
  19434. preprocessed++;
  19435. if (preprocessed > rowLimit)
  19436. {
  19437. ReleaseRoxieRow(row);
  19438. roxiemem::ReleaseRoxieRowRange(readrows.getArray(), readIndex, readrows.ordinality());
  19439. readrows.kill();
  19440. readIndex = 0;
  19441. eof = true;
  19442. if (ctx->queryDebugContext())
  19443. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  19444. if (helper.getFlags() & TDRlimitskips)
  19445. return NULL;
  19446. else if (helper.getFlags() & TDRlimitcreates)
  19447. return createLimitFailRow(false);
  19448. else
  19449. throwUnexpected();
  19450. }
  19451. if (preprocessed > stopAfter) // MORE - bit of a strange place to check
  19452. {
  19453. eof = true;
  19454. ReleaseRoxieRow(row);
  19455. break;
  19456. }
  19457. readrows.append(row);
  19458. }
  19459. readAheadDone = true;
  19460. }
  19461. if (readrows.isItem(readIndex))
  19462. {
  19463. const void *ret = readrows.item(readIndex++);
  19464. if (ret)
  19465. processed++;
  19466. return ret;
  19467. }
  19468. else
  19469. {
  19470. eof = true;
  19471. return NULL;
  19472. }
  19473. }
  19474. else
  19475. {
  19476. const void *ret = _nextRow();
  19477. if (ret)
  19478. {
  19479. processed++;
  19480. if (processed > rowLimit)
  19481. {
  19482. if (traceLevel > 4)
  19483. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  19484. ReleaseRoxieRow(ret);
  19485. compoundHelper->onLimitExceeded();
  19486. throwUnexpected(); // onLimitExceeded is not supposed to return
  19487. }
  19488. if (processed > stopAfter) // MORE - bit of a strange place to check
  19489. {
  19490. eof = true;
  19491. ReleaseRoxieRow(ret);
  19492. return NULL;
  19493. }
  19494. }
  19495. return ret;
  19496. }
  19497. }
  19498. const void *_nextRow()
  19499. {
  19500. if (eogPending && (lastGroupProcessed != processed))
  19501. {
  19502. eogPending = false;
  19503. lastGroupProcessed = processed;
  19504. return NULL;
  19505. }
  19506. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  19507. unsigned transformedSize = 0;
  19508. if (isKeyed)
  19509. {
  19510. for (;;)
  19511. {
  19512. const void *nextCandidate = cursor->nextMatch();
  19513. if (!nextCandidate)
  19514. {
  19515. eof = true;
  19516. return NULL;
  19517. }
  19518. transformedSize = readHelper->transform(rowBuilder, nextCandidate);
  19519. if (transformedSize)
  19520. break;
  19521. }
  19522. }
  19523. else // use reader...
  19524. {
  19525. assertex(reader != NULL);
  19526. for (;;)
  19527. {
  19528. if (deserializeSource.eos())
  19529. {
  19530. eof = true;
  19531. return NULL;
  19532. }
  19533. prefetcher->readAhead(deserializeSource);
  19534. const byte *nextRec = deserializeSource.queryRow();
  19535. if (cursor && cursor->isFiltered(nextRec))
  19536. transformedSize = 0;
  19537. else
  19538. transformedSize = readHelper->transform(rowBuilder, nextRec);
  19539. bool eog;
  19540. if (isGrouped)
  19541. {
  19542. size32_t sizeRead = diskSize.getRecordSize(nextRec);
  19543. eog = nextRec[sizeRead-1];
  19544. }
  19545. else
  19546. eog = false;
  19547. deserializeSource.finishedRow();
  19548. if (transformedSize)
  19549. {
  19550. if (isGrouped)
  19551. eogPending = eog;
  19552. break;
  19553. }
  19554. else
  19555. {
  19556. if (eog && (lastGroupProcessed != processed))
  19557. {
  19558. lastGroupProcessed = processed;
  19559. return NULL;
  19560. }
  19561. }
  19562. }
  19563. }
  19564. return rowBuilder.finalizeRowClear(transformedSize);
  19565. }
  19566. };
  19567. class CRoxieServerXmlReadActivity : public CRoxieServerDiskReadBaseActivity, implements IXMLSelect, implements IThorDiskCallback
  19568. {
  19569. IHThorXmlReadArg * readHelper;
  19570. Owned<IXmlToRowTransformer> rowTransformer;
  19571. Owned<IXMLParse> xmlParser;
  19572. Owned<IColumnProvider> lastMatch;
  19573. unsigned __int64 fileoffset;
  19574. public:
  19575. IMPLEMENT_IINTERFACE_USING(CRoxieServerDiskReadBaseActivity)
  19576. CRoxieServerXmlReadActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, bool _sorted, bool _maySkip, IInMemoryIndexManager *_manager)
  19577. : CRoxieServerDiskReadBaseActivity(_ctx, _factory, _probeManager, _remoteId, _numParts, _isLocal, _sorted, _maySkip, _manager)
  19578. {
  19579. compoundHelper = NULL;
  19580. readHelper = (IHThorXmlReadArg *)&helper;
  19581. fileoffset = 0;
  19582. }
  19583. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  19584. {
  19585. rowLimit = readHelper->getRowLimit();
  19586. stopAfter = readHelper->getChooseNLimit();
  19587. CRoxieServerDiskReadBaseActivity::start(parentExtractSize, parentExtract, paused);
  19588. if (!useRemote())
  19589. {
  19590. rowTransformer.set(readHelper->queryTransformer());
  19591. assertex(reader != NULL);
  19592. OwnedRoxieString xmlIterator(readHelper->getXmlIteratorPath());
  19593. if (factory->getKind()==TAKjsonread)
  19594. xmlParser.setown(createJSONParse(*reader->querySimpleStream(), xmlIterator, *this, (0 != (TDRxmlnoroot & readHelper->getFlags()))?ptr_noRoot:ptr_none, (readHelper->getFlags() & TDRusexmlcontents) != 0));
  19595. else
  19596. xmlParser.setown(createXMLParse(*reader->querySimpleStream(), xmlIterator, *this, (0 != (TDRxmlnoroot & readHelper->getFlags()))?ptr_noRoot:ptr_none, (readHelper->getFlags() & TDRusexmlcontents) != 0));
  19597. }
  19598. }
  19599. virtual void reset()
  19600. {
  19601. CRoxieServerDiskReadBaseActivity::reset();
  19602. rowTransformer.clear();
  19603. xmlParser.clear();
  19604. }
  19605. virtual void match(IColumnProvider &entry, offset_t startOffset, offset_t endOffset)
  19606. {
  19607. fileoffset = startOffset;
  19608. lastMatch.set(&entry);
  19609. }
  19610. //interface IThorDiskCallback
  19611. virtual unsigned __int64 getFilePosition(const void * row)
  19612. {
  19613. return fileoffset;
  19614. }
  19615. virtual unsigned __int64 getLocalFilePosition(const void * row)
  19616. {
  19617. return reader->makeFilePositionLocal(fileoffset);
  19618. }
  19619. virtual const char * queryLogicalFilename(const void * row)
  19620. {
  19621. return reader->queryThorDiskCallback()->queryLogicalFilename(row);
  19622. }
  19623. virtual const void *nextRow()
  19624. {
  19625. ActivityTimer t(totalCycles, timeActivities);
  19626. if (eof)
  19627. return NULL;
  19628. else if (useRemote())
  19629. return remote->nextRow();
  19630. assertex(xmlParser != NULL);
  19631. try
  19632. {
  19633. while (!eof)
  19634. {
  19635. //call to next() will callback on the IXmlSelect interface
  19636. bool gotNext = false;
  19637. gotNext = xmlParser->next();
  19638. if(!gotNext)
  19639. eof = true;
  19640. else if (lastMatch)
  19641. {
  19642. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  19643. unsigned sizeGot = rowTransformer->transform(rowBuilder, lastMatch, this);
  19644. lastMatch.clear();
  19645. fileoffset = 0;
  19646. if (sizeGot)
  19647. {
  19648. OwnedConstRoxieRow ret = rowBuilder.finalizeRowClear(sizeGot);
  19649. if (processed > rowLimit)
  19650. {
  19651. if (traceLevel > 4)
  19652. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  19653. readHelper->onLimitExceeded();
  19654. throwUnexpected(); // onLimitExceeded is not supposed to return
  19655. }
  19656. processed++;
  19657. if (processed > stopAfter) // MORE - bit of a strange place to check
  19658. {
  19659. eof = true;
  19660. return NULL;
  19661. }
  19662. return ret.getClear();
  19663. }
  19664. }
  19665. }
  19666. return NULL;
  19667. }
  19668. catch(IException *E)
  19669. {
  19670. throw makeWrappedException(E);
  19671. }
  19672. }
  19673. };
  19674. class CRoxieServerCsvReadActivity : public CRoxieServerDiskReadBaseActivity
  19675. {
  19676. IHThorCsvReadArg *readHelper;
  19677. ICsvParameters * csvInfo;
  19678. unsigned headerLines;
  19679. unsigned maxDiskSize;
  19680. CSVSplitter csvSplitter;
  19681. unsigned __int64 localOffset;
  19682. const char *quotes;
  19683. const char *separators;
  19684. const char *terminators;
  19685. const char *escapes;
  19686. size32_t maxRowSize;
  19687. public:
  19688. CRoxieServerCsvReadActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  19689. unsigned _numParts, bool _isLocal, bool _sorted, bool _maySkip, IInMemoryIndexManager *_manager,
  19690. const char *_quotes, const char *_separators, const char *_terminators, const char *_escapes, size32_t _maxRowSize)
  19691. : CRoxieServerDiskReadBaseActivity(_ctx, _factory, _probeManager, _remoteId, _numParts, _isLocal, _sorted, _maySkip, _manager),
  19692. quotes(_quotes), separators(_separators), terminators(_terminators), escapes(_escapes), maxRowSize(_maxRowSize)
  19693. {
  19694. compoundHelper = NULL;
  19695. readHelper = (IHThorCsvReadArg *)&helper;
  19696. rowLimit = readHelper->getRowLimit();
  19697. stopAfter = readHelper->getChooseNLimit();
  19698. csvInfo = readHelper->queryCsvParameters();
  19699. maxDiskSize = csvInfo->queryMaxSize();
  19700. localOffset = 0;
  19701. headerLines = 0;
  19702. }
  19703. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  19704. {
  19705. rowLimit = readHelper->getRowLimit();
  19706. stopAfter = readHelper->getChooseNLimit();
  19707. CRoxieServerDiskReadBaseActivity::start(parentExtractSize, parentExtract, paused);
  19708. if (!useRemote())
  19709. {
  19710. headerLines = csvInfo->queryHeaderLen();
  19711. if (headerLines && isLocal && reader->queryFilePart() != 1)
  19712. 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...
  19713. if (!eof)
  19714. {
  19715. if (varFileInfo)
  19716. {
  19717. const IPropertyTree *options = varFileInfo->queryProperties();
  19718. if (options)
  19719. {
  19720. quotes = options->queryProp("@csvQuote");
  19721. separators = options->queryProp("@csvSeparate");
  19722. terminators = options->queryProp("@csvTerminate");
  19723. escapes = options->queryProp("@csvEscape");
  19724. }
  19725. }
  19726. csvSplitter.init(readHelper->getMaxColumns(), csvInfo, quotes, separators, terminators, escapes);
  19727. }
  19728. }
  19729. }
  19730. virtual const void *nextRow()
  19731. {
  19732. ActivityTimer t(totalCycles, timeActivities);
  19733. if (eof)
  19734. return NULL;
  19735. else if (useRemote())
  19736. return remote->nextRow();
  19737. try
  19738. {
  19739. while (!eof)
  19740. {
  19741. if (reader->eos())
  19742. {
  19743. eof = true;
  19744. break;
  19745. }
  19746. // MORE - there are rumours of a csvSplitter that operates on a stream... if/when it exists, this should use it
  19747. size32_t rowSize = 4096; // MORE - make configurable
  19748. size32_t thisLineLength;
  19749. for (;;)
  19750. {
  19751. size32_t avail;
  19752. const void *peek = reader->peek(rowSize, avail);
  19753. thisLineLength = csvSplitter.splitLine(avail, (const byte *)peek);
  19754. if (thisLineLength < rowSize || avail < rowSize)
  19755. break;
  19756. if (rowSize == maxRowSize)
  19757. throw MakeStringException(0, "File contained a line of length greater than %d bytes.", maxRowSize);
  19758. if (rowSize >= maxRowSize/2)
  19759. rowSize = maxRowSize;
  19760. else
  19761. rowSize += rowSize;
  19762. }
  19763. if (headerLines)
  19764. {
  19765. headerLines--;
  19766. reader->skip(thisLineLength);
  19767. }
  19768. else
  19769. {
  19770. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  19771. unsigned transformedSize = readHelper->transform(rowBuilder, csvSplitter.queryLengths(), (const char * *)csvSplitter.queryData());
  19772. reader->skip(thisLineLength);
  19773. if (transformedSize)
  19774. {
  19775. OwnedConstRoxieRow ret = rowBuilder.finalizeRowClear(transformedSize);
  19776. if (processed > rowLimit)
  19777. {
  19778. readHelper->onLimitExceeded();
  19779. throwUnexpected(); // onLimitExceeded is not supposed to return
  19780. }
  19781. processed++;
  19782. if (processed > stopAfter) // MORE - bit of a strange place to check
  19783. {
  19784. eof = true;
  19785. return NULL;
  19786. }
  19787. return ret.getClear();
  19788. }
  19789. }
  19790. }
  19791. return NULL;
  19792. }
  19793. catch(IException *E)
  19794. {
  19795. throw makeWrappedException(E);
  19796. }
  19797. }
  19798. virtual void reset()
  19799. {
  19800. CRoxieServerDiskReadBaseActivity::reset();
  19801. csvSplitter.reset();
  19802. localOffset = 0;
  19803. }
  19804. virtual unsigned __int64 getFilePosition(const void * row)
  19805. {
  19806. UNIMPLEMENTED; // we know offset in the reader but not sure it helps us much
  19807. }
  19808. virtual unsigned __int64 getLocalFilePosition(const void * row)
  19809. {
  19810. UNIMPLEMENTED;
  19811. }
  19812. };
  19813. class CRoxieServerDiskNormalizeActivity : public CRoxieServerDiskReadBaseActivity
  19814. {
  19815. IHThorDiskNormalizeArg *normalizeHelper;
  19816. bool firstPending;
  19817. public:
  19818. CRoxieServerDiskNormalizeActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, bool _sorted, IInMemoryIndexManager *_manager)
  19819. : CRoxieServerDiskReadBaseActivity(_ctx, _factory, _probeManager, _remoteId, _numParts, _isLocal, _sorted, false, _manager)
  19820. {
  19821. compoundHelper = (IHThorDiskNormalizeArg *)&helper;
  19822. normalizeHelper = (IHThorDiskNormalizeArg *)&helper;
  19823. limitTransformExtra = normalizeHelper;
  19824. firstPending = true;
  19825. }
  19826. virtual void reset()
  19827. {
  19828. firstPending = true;
  19829. CRoxieServerDiskReadBaseActivity::reset();
  19830. }
  19831. virtual const void *nextRow()
  19832. {
  19833. ActivityTimer t(totalCycles, timeActivities);
  19834. if (eof)
  19835. return NULL;
  19836. else if (useRemote())
  19837. return remote->nextRow();
  19838. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  19839. unsigned transformedSize = 0;
  19840. if (isKeyed)
  19841. {
  19842. for (;;)
  19843. {
  19844. while (firstPending)
  19845. {
  19846. const void *nextCandidate = cursor->nextMatch();
  19847. if (!nextCandidate)
  19848. {
  19849. eof = true;
  19850. return NULL;
  19851. }
  19852. if (normalizeHelper->first(nextCandidate))
  19853. {
  19854. firstPending = false;
  19855. break;
  19856. }
  19857. }
  19858. transformedSize = normalizeHelper->transform(rowBuilder);
  19859. firstPending = !normalizeHelper->next();
  19860. if (transformedSize)
  19861. break;
  19862. }
  19863. }
  19864. else
  19865. {
  19866. assertex(reader != NULL);
  19867. for (;;)
  19868. {
  19869. while (firstPending)
  19870. {
  19871. if (deserializeSource.eos())
  19872. {
  19873. eof = true;
  19874. return NULL;
  19875. }
  19876. prefetcher->readAhead(deserializeSource);
  19877. const byte *nextRec = deserializeSource.queryRow();
  19878. if (!cursor || !cursor->isFiltered(nextRec))
  19879. {
  19880. if (normalizeHelper->first(nextRec))
  19881. firstPending = false;
  19882. }
  19883. deserializeSource.finishedRow();
  19884. }
  19885. transformedSize = normalizeHelper->transform(rowBuilder);
  19886. firstPending = !normalizeHelper->next();
  19887. if (transformedSize)
  19888. break;
  19889. }
  19890. }
  19891. OwnedConstRoxieRow recBuffer = rowBuilder.finalizeRowClear(transformedSize);
  19892. processed++;
  19893. if (processed > rowLimit)
  19894. {
  19895. compoundHelper->onLimitExceeded();
  19896. throwUnexpected(); // onLimitExceeded is not supposed to return
  19897. }
  19898. if (processed > stopAfter) // MORE - bit of a strange place to check
  19899. {
  19900. eof = true;
  19901. return NULL;
  19902. }
  19903. return recBuffer.getClear();
  19904. }
  19905. };
  19906. class CRoxieServerDiskAggregateBaseActivity : public CRoxieServerDiskReadBaseActivity
  19907. {
  19908. protected:
  19909. bool done;
  19910. public:
  19911. CRoxieServerDiskAggregateBaseActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, IInMemoryIndexManager *_manager)
  19912. : CRoxieServerDiskReadBaseActivity(_ctx, _factory, _probeManager, _remoteId, _numParts, _isLocal, false, false, _manager),
  19913. done(false)
  19914. {
  19915. }
  19916. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  19917. {
  19918. done = false;
  19919. CRoxieServerDiskReadBaseActivity::start(parentExtractSize, parentExtract, paused);
  19920. }
  19921. virtual IFinalRoxieInput *queryOutput(unsigned idx)
  19922. {
  19923. if (idx==(unsigned)-1)
  19924. idx = 0;
  19925. return idx ? NULL: this;
  19926. }
  19927. };
  19928. class CRoxieServerDiskCountActivity : public CRoxieServerDiskAggregateBaseActivity
  19929. {
  19930. IHThorDiskCountArg & countHelper;
  19931. unsigned __int64 choosenLimit;
  19932. unsigned __int64 getSkippedCount()
  19933. {
  19934. unsigned flags = countHelper.getFlags();
  19935. if (flags & TDRlimitskips)
  19936. return 0;
  19937. else if (flags & TDRlimitcreates)
  19938. return 1;
  19939. else
  19940. {
  19941. if (traceLevel > 4)
  19942. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  19943. countHelper.onLimitExceeded();
  19944. throwUnexpected(); // onLimitExceeded should always throw exception
  19945. }
  19946. }
  19947. public:
  19948. CRoxieServerDiskCountActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, IInMemoryIndexManager *_manager)
  19949. : CRoxieServerDiskAggregateBaseActivity(_ctx, _factory, _probeManager, _remoteId, _numParts, _isLocal, _manager),
  19950. countHelper((IHThorDiskCountArg &)basehelper)
  19951. {
  19952. choosenLimit = 0;
  19953. }
  19954. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  19955. {
  19956. choosenLimit = countHelper.getChooseNLimit();
  19957. rowLimit = countHelper.getRowLimit();
  19958. // keyedLimit = countHelper->getKeyedLimit(); // more - should there be one?
  19959. CRoxieServerDiskAggregateBaseActivity::start(parentExtractSize, parentExtract, paused);
  19960. }
  19961. virtual const void *nextRow()
  19962. {
  19963. ActivityTimer t(totalCycles, timeActivities);
  19964. if (done) return NULL;
  19965. done = true;
  19966. unsigned __int64 totalCount = 0;
  19967. if (helper.canMatchAny() && !eof)
  19968. {
  19969. if (useRemote())
  19970. {
  19971. for (;;)
  19972. {
  19973. const void * next = remote->nextRow();
  19974. if (!next)
  19975. break;
  19976. if (meta.getFixedSize() == 1)
  19977. totalCount += *(byte *)next;
  19978. else
  19979. totalCount += *(unsigned __int64 *)next;
  19980. ReleaseRoxieRow(next);
  19981. if (totalCount > rowLimit)
  19982. {
  19983. totalCount = getSkippedCount();
  19984. break;
  19985. }
  19986. else if (totalCount >= choosenLimit)
  19987. {
  19988. totalCount = choosenLimit;
  19989. break;
  19990. }
  19991. }
  19992. }
  19993. else
  19994. {
  19995. if (isKeyed)
  19996. {
  19997. for (;;)
  19998. {
  19999. const void *nextCandidate = cursor->nextMatch();
  20000. if (!nextCandidate)
  20001. break;
  20002. totalCount += countHelper.numValid(nextCandidate);
  20003. if (totalCount > rowLimit)
  20004. {
  20005. totalCount = getSkippedCount();
  20006. break;
  20007. }
  20008. else if (totalCount >= choosenLimit)
  20009. {
  20010. totalCount = choosenLimit;
  20011. break;
  20012. }
  20013. }
  20014. }
  20015. else
  20016. {
  20017. assertex(reader != NULL);
  20018. while (!deserializeSource.eos())
  20019. {
  20020. prefetcher->readAhead(deserializeSource);
  20021. const byte *nextRec = deserializeSource.queryRow();
  20022. if (!cursor || !cursor->isFiltered(nextRec))
  20023. {
  20024. totalCount += countHelper.numValid(nextRec);
  20025. }
  20026. deserializeSource.finishedRow();
  20027. if (totalCount > rowLimit)
  20028. {
  20029. totalCount = getSkippedCount();
  20030. break;
  20031. }
  20032. else if (totalCount >= choosenLimit)
  20033. {
  20034. totalCount = choosenLimit;
  20035. break;
  20036. }
  20037. }
  20038. }
  20039. }
  20040. }
  20041. size32_t rowSize = meta.getFixedSize();
  20042. void * result = rowAllocator->createRow();
  20043. if (rowSize == 1)
  20044. *(byte *)result = (byte)totalCount;
  20045. else
  20046. {
  20047. assertex(rowSize == sizeof(unsigned __int64));
  20048. *(unsigned __int64 *)result = totalCount;
  20049. }
  20050. return rowAllocator->finalizeRow(rowSize, result, rowSize);
  20051. }
  20052. };
  20053. class CRoxieServerDiskAggregateActivity : public CRoxieServerDiskAggregateBaseActivity
  20054. {
  20055. IHThorCompoundAggregateExtra & aggregateHelper;
  20056. public:
  20057. CRoxieServerDiskAggregateActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  20058. unsigned _numParts, bool _isLocal, IInMemoryIndexManager *_manager)
  20059. : CRoxieServerDiskAggregateBaseActivity(_ctx, _factory, _probeManager, _remoteId, _numParts, _isLocal, _manager),
  20060. aggregateHelper((IHThorDiskAggregateArg &)basehelper)
  20061. {
  20062. }
  20063. const void * gatherMerged()
  20064. {
  20065. RtlDynamicRowBuilder rowBuilder(rowAllocator, false);
  20066. size32_t finalSize = 0;
  20067. if (useRemote())
  20068. {
  20069. const void * firstRow = remote->nextRow();
  20070. if (!firstRow)
  20071. {
  20072. rowBuilder.ensureRow();
  20073. finalSize = aggregateHelper.clearAggregate(rowBuilder);
  20074. }
  20075. else
  20076. {
  20077. // NOTE need to clone this because going to modify below, could special case 1 row only
  20078. finalSize = cloneRow(rowBuilder, firstRow, meta);
  20079. ReleaseRoxieRow(firstRow);
  20080. }
  20081. for (;;)
  20082. {
  20083. const void * next = remote->nextRow();
  20084. if (!next)
  20085. break;
  20086. finalSize = aggregateHelper.mergeAggregate(rowBuilder, next);
  20087. ReleaseRoxieRow(next);
  20088. }
  20089. }
  20090. else
  20091. {
  20092. aggregateHelper.clearAggregate(rowBuilder);
  20093. if (helper.canMatchAny() && !eof)
  20094. {
  20095. if (isKeyed)
  20096. {
  20097. for (;;)
  20098. {
  20099. const void *next = cursor->nextMatch();
  20100. if (!next)
  20101. break;
  20102. aggregateHelper.processRow(rowBuilder, next);
  20103. }
  20104. }
  20105. else
  20106. {
  20107. assertex(reader != NULL);
  20108. while (!deserializeSource.eos())
  20109. {
  20110. prefetcher->readAhead(deserializeSource);
  20111. const byte *nextRec = deserializeSource.queryRow();
  20112. if (!cursor || !cursor->isFiltered(nextRec))
  20113. {
  20114. aggregateHelper.processRow(rowBuilder, nextRec);
  20115. }
  20116. deserializeSource.finishedRow();
  20117. }
  20118. }
  20119. }
  20120. finalSize = meta.getRecordSize(rowBuilder.getSelf());
  20121. }
  20122. return rowBuilder.finalizeRowClear(finalSize);
  20123. }
  20124. virtual const void *nextRow()
  20125. {
  20126. ActivityTimer t(totalCycles, timeActivities);
  20127. if (done) return NULL;
  20128. const void * ret = gatherMerged();
  20129. done = true;
  20130. return ret;
  20131. }
  20132. };
  20133. class CRoxieServerDiskGroupAggregateActivity : public CRoxieServerDiskAggregateBaseActivity
  20134. {
  20135. IHThorDiskGroupAggregateArg & aggregateHelper;
  20136. RowAggregator resultAggregator;
  20137. bool gathered;
  20138. public:
  20139. CRoxieServerDiskGroupAggregateActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, IInMemoryIndexManager *_manager)
  20140. : CRoxieServerDiskAggregateBaseActivity(_ctx, _factory, _probeManager, _remoteId, _numParts, _isLocal, _manager),
  20141. aggregateHelper((IHThorDiskGroupAggregateArg &)basehelper),
  20142. resultAggregator(aggregateHelper, aggregateHelper),
  20143. gathered(false)
  20144. {
  20145. }
  20146. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  20147. {
  20148. gathered= false;
  20149. CRoxieServerDiskAggregateBaseActivity::start(parentExtractSize, parentExtract, paused);
  20150. resultAggregator.start(rowAllocator);
  20151. }
  20152. virtual void reset()
  20153. {
  20154. resultAggregator.reset();
  20155. CRoxieServerDiskAggregateBaseActivity::reset();
  20156. }
  20157. void gatherMerged()
  20158. {
  20159. if (useRemote())
  20160. {
  20161. for (;;)
  20162. {
  20163. const void * next = remote->nextRow();
  20164. if (!next)
  20165. break;
  20166. resultAggregator.mergeElement(next);
  20167. ReleaseRoxieRow(next);
  20168. }
  20169. }
  20170. else
  20171. {
  20172. if (helper.canMatchAny() && !eof)
  20173. {
  20174. Owned<IInMemoryFileProcessor> processor = isKeyed ?
  20175. createKeyedGroupAggregateRecordProcessor(cursor, resultAggregator, aggregateHelper) :
  20176. createUnkeyedGroupAggregateRecordProcessor(cursor, resultAggregator, aggregateHelper, manager->createReader(0, 0, 1),
  20177. ctx->queryCodeContext(), activityId);
  20178. processor->doQuery(NULL, 0, 0, 0);
  20179. }
  20180. }
  20181. gathered = true;
  20182. }
  20183. virtual const void *nextRow()
  20184. {
  20185. ActivityTimer t(totalCycles, timeActivities);
  20186. if (done)
  20187. return NULL;
  20188. if (!gathered)
  20189. gatherMerged();
  20190. Owned<AggregateRowBuilder> next = resultAggregator.nextResult();
  20191. if (next)
  20192. {
  20193. processed++;
  20194. return next->finalizeRowClear();
  20195. }
  20196. done = true;
  20197. return NULL;
  20198. }
  20199. };
  20200. class CRoxieServerDiskReadActivityFactory : public CRoxieServerActivityFactory
  20201. {
  20202. public:
  20203. RemoteActivityId remoteId;
  20204. bool isLocal;
  20205. bool sorted;
  20206. bool maySkip;
  20207. bool variableFileName;
  20208. Owned<IFileIOArray> files;
  20209. Owned<IInMemoryIndexManager> manager;
  20210. Owned<const IResolvedFile> datafile;
  20211. const char *quotes;
  20212. const char *separators;
  20213. const char *terminators;
  20214. const char *escapes;
  20215. size32_t maxCsvRowSize;
  20216. CRoxieServerDiskReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, const RemoteActivityId &_remoteId)
  20217. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode), remoteId(_remoteId)
  20218. {
  20219. isLocal = _graphNode.getPropBool("att[@name='local']/@value") && queryFactory.queryChannel()!=0;
  20220. Owned<IHThorDiskReadBaseArg> helper = (IHThorDiskReadBaseArg *) helperFactory();
  20221. sorted = (helper->getFlags() & TDRunsorted) == 0;
  20222. variableFileName = allFilesDynamic || _queryFactory.isDynamic() || ((helper->getFlags() & (TDXvarfilename|TDXdynamicfilename)) != 0);
  20223. maySkip = (helper->getFlags() & (TDRkeyedlimitskips|TDRkeyedlimitcreates|TDRlimitskips|TDRlimitcreates)) != 0;
  20224. quotes = separators = terminators = escapes = NULL;
  20225. if (!variableFileName)
  20226. {
  20227. bool isOpt = (helper->getFlags() & TDRoptional) != 0;
  20228. OwnedRoxieString fileName(helper->getFileName());
  20229. datafile.setown(_queryFactory.queryPackage().lookupFileName(fileName, isOpt, true, true, _queryFactory.queryWorkUnit(), true));
  20230. Linked<IOutputMetaData> diskMeta(helper->queryDiskRecordSize()->querySerializedDiskMeta());
  20231. if (diskMeta->isGrouped())
  20232. diskMeta.setown(new CSuffixedOutputMeta(+1, diskMeta.getClear()));
  20233. if (datafile)
  20234. {
  20235. const IPropertyTree *options = datafile->queryProperties();
  20236. if (options)
  20237. {
  20238. bool isGrouped = options->getPropBool("@grouped");
  20239. if (isGrouped && !diskMeta->isGrouped())
  20240. {
  20241. // We are prepared to read contents of a grouped persist ungrouped... But not vice versa
  20242. WARNLOG("Published group information for file %s does not match coded information - assuming grouped", fileName.get());
  20243. diskMeta.setown(new CSuffixedOutputMeta(+1, diskMeta.getClear()));
  20244. }
  20245. size32_t dfsSize = options->getPropInt("@recordSize");
  20246. if (dfsSize && diskMeta->isFixedSize() && dfsSize != diskMeta->getFixedSize())
  20247. throw MakeStringException(ROXIE_LAYOUT_MISMATCH, "Published record size %d for file %s (%s) does not match coded record size %d", dfsSize, fileName.get(), isGrouped ? "grouped" : "ungrouped", diskMeta->getFixedSize());
  20248. }
  20249. }
  20250. bool isSimple = (datafile && datafile->getNumParts()==1 && !_queryFactory.queryOptions().disableLocalOptimizations);
  20251. if (isLocal || isSimple)
  20252. {
  20253. if (datafile)
  20254. {
  20255. unsigned channel = isLocal ? queryFactory.queryChannel() : 0;
  20256. files.setown(datafile->getIFileIOArray(isOpt, channel));
  20257. manager.setown(datafile->getIndexManager(isOpt, channel, files, diskMeta, _graphNode.getPropBool("att[@name=\"preload\"]/@value", false), _graphNode.getPropInt("att[@name=\"_preloadSize\"]/@value", 0)));
  20258. const IPropertyTree *options = datafile->queryProperties();
  20259. if (options)
  20260. {
  20261. quotes = options->queryProp("@csvQuote");
  20262. separators = options->queryProp("@csvSeparate");
  20263. terminators = options->queryProp("@csvTerminate");
  20264. escapes = options->queryProp("@csvEscape");
  20265. }
  20266. }
  20267. else
  20268. manager.setown(getEmptyIndexManager());
  20269. }
  20270. }
  20271. switch (kind)
  20272. {
  20273. case TAKcsvread:
  20274. {
  20275. maxCsvRowSize = defaultMaxCsvRowSize * 1024 * 1024;
  20276. IConstWorkUnit *workunit = _queryFactory.queryWorkUnit();
  20277. if (workunit)
  20278. maxCsvRowSize = workunit->getDebugValueInt(OPT_MAXCSVROWSIZE, defaultMaxCsvRowSize) * 1024 * 1024;
  20279. break;
  20280. }
  20281. default:
  20282. maxCsvRowSize = 0; // unused
  20283. }
  20284. }
  20285. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  20286. {
  20287. unsigned numParts = datafile ? datafile->getNumParts() : 0;
  20288. switch (kind)
  20289. {
  20290. case TAKcsvread:
  20291. return new CRoxieServerCsvReadActivity(_ctx, this, _probeManager, remoteId, numParts, isLocal, sorted, maySkip, manager,
  20292. quotes, separators, terminators, escapes, maxCsvRowSize);
  20293. case TAKxmlread:
  20294. case TAKjsonread:
  20295. return new CRoxieServerXmlReadActivity(_ctx, this, _probeManager, remoteId, numParts, isLocal, sorted, maySkip, manager);
  20296. case TAKdiskread:
  20297. return new CRoxieServerDiskReadActivity(_ctx, this, _probeManager, remoteId, numParts, isLocal, sorted, maySkip, manager);
  20298. case TAKdisknormalize:
  20299. return new CRoxieServerDiskNormalizeActivity(_ctx, this, _probeManager, remoteId, numParts, isLocal, sorted, manager);
  20300. case TAKdiskcount:
  20301. return new CRoxieServerDiskCountActivity(_ctx, this, _probeManager, remoteId, numParts, isLocal, manager);
  20302. case TAKdiskaggregate:
  20303. return new CRoxieServerDiskAggregateActivity(_ctx, this, _probeManager, remoteId, numParts, isLocal, manager);
  20304. case TAKdiskgroupaggregate:
  20305. return new CRoxieServerDiskGroupAggregateActivity(_ctx, this, _probeManager, remoteId, numParts, isLocal, manager);
  20306. }
  20307. throwUnexpected();
  20308. }
  20309. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  20310. {
  20311. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for %s activity", getActivityText(kind));
  20312. }
  20313. virtual void getXrefInfo(IPropertyTree &reply, const IRoxieContextLogger &logctx) const
  20314. {
  20315. if (datafile)
  20316. addXrefFileInfo(reply, datafile);
  20317. else
  20318. {
  20319. // Temporarily resolve the file
  20320. Owned<IHThorDiskReadBaseArg> helper = (IHThorDiskReadBaseArg *) helperFactory();
  20321. if ((helper->getFlags() & (TDXvarfilename|TDXdynamicfilename)) == 0)
  20322. {
  20323. OwnedRoxieString fileName(helper->getFileName());
  20324. Owned<const IResolvedFile> temp = queryFactory.queryPackage().lookupFileName(fileName, true, true, false, queryFactory.queryWorkUnit(), true);
  20325. if (temp)
  20326. addXrefFileInfo(reply, temp);
  20327. }
  20328. }
  20329. }
  20330. virtual const StatisticsMapping &queryStatsMapping() const
  20331. {
  20332. return diskStatistics;
  20333. }
  20334. };
  20335. IRoxieServerActivityFactory *createRoxieServerDiskReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, const RemoteActivityId &_remoteId)
  20336. {
  20337. return new CRoxieServerDiskReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _remoteId);
  20338. }
  20339. //=================================================================================
  20340. class CRoxieServerIndexActivity : public CRoxieServerActivity, implements IRoxieServerErrorHandler
  20341. {
  20342. protected:
  20343. IHThorIndexReadBaseArg &indexHelper;
  20344. IHThorSteppedSourceExtra *steppedExtra;
  20345. Linked<IKeyArray> keySet;
  20346. Linked<TranslatorArray> translators;
  20347. CSkippableRemoteResultAdaptor remote;
  20348. CIndexTransformCallback callback;
  20349. bool sorted;
  20350. bool variableFileName;
  20351. bool variableInfoPending;
  20352. bool isOpt;
  20353. bool isLocal;
  20354. unsigned __int64 rowLimit;
  20355. unsigned __int64 keyedLimit;
  20356. unsigned __int64 choosenLimit;
  20357. unsigned accepted;
  20358. unsigned rejected;
  20359. unsigned seekGEOffset;
  20360. Owned<IKeyManager> tlk;
  20361. Owned<const IResolvedFile> varFileInfo;
  20362. const RemoteActivityId &remoteId;
  20363. void setVariableFileInfo()
  20364. {
  20365. OwnedRoxieString indexName(indexHelper.getFileName());
  20366. varFileInfo.setown(resolveLFN(indexName, isOpt));
  20367. if (varFileInfo)
  20368. {
  20369. translators.setown(new TranslatorArray) ;
  20370. keySet.setown(varFileInfo->getKeyArray(factory->queryActivityMeta(), translators, isOpt, isLocal ? factory->queryQueryFactory().queryChannel() : 0, factory->queryQueryFactory().queryOptions().enableFieldTranslation));
  20371. }
  20372. variableInfoPending = false;
  20373. }
  20374. public:
  20375. CRoxieServerIndexActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  20376. IKeyArray * _keySet, TranslatorArray *_translators, bool _sorted, bool _isLocal, bool _maySkip)
  20377. : CRoxieServerActivity(_ctx, _factory, _probeManager),
  20378. keySet(_keySet),
  20379. translators(_translators),
  20380. indexHelper((IHThorIndexReadBaseArg &)basehelper),
  20381. remote(_ctx, this, _remoteId, meta.queryOriginal(), indexHelper, *this, _sorted, false, _maySkip),
  20382. remoteId(_remoteId),
  20383. sorted(_sorted),
  20384. isLocal(_isLocal)
  20385. {
  20386. indexHelper.setCallback(&callback);
  20387. steppedExtra = indexHelper.querySteppingExtra();
  20388. variableFileName = allFilesDynamic || factory->queryQueryFactory().isDynamic() || ((indexHelper.getFlags() & (TIRvarfilename|TIRdynamicfilename)) != 0);
  20389. variableInfoPending = false;
  20390. isOpt = (indexHelper.getFlags() & TIRoptional) != 0;
  20391. seekGEOffset = 0;
  20392. // started = false;
  20393. rejected = accepted = 0;
  20394. rowLimit = choosenLimit = keyedLimit = 0;
  20395. }
  20396. virtual const IResolvedFile *queryVarFileInfo() const
  20397. {
  20398. return varFileInfo;
  20399. }
  20400. virtual void onCreate(IHThorArg *_colocalParent)
  20401. {
  20402. CRoxieServerActivity::onCreate(_colocalParent);
  20403. remote.onCreate(_colocalParent);
  20404. }
  20405. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  20406. {
  20407. accepted = 0;
  20408. rejected = 0;
  20409. rowLimit = (unsigned __int64) -1;
  20410. keyedLimit = (unsigned __int64 ) -1;
  20411. choosenLimit = I64C(0x7fffffffffffffff);
  20412. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  20413. remote.onStart(parentExtractSize, parentExtract);
  20414. variableInfoPending = variableFileName;
  20415. }
  20416. void processAllKeys()
  20417. {
  20418. try
  20419. {
  20420. if (indexHelper.canMatchAny())
  20421. {
  20422. if (variableInfoPending)
  20423. setVariableFileInfo();
  20424. remote.setLimits(rowLimit, keyedLimit, choosenLimit);
  20425. if (keySet)
  20426. {
  20427. // MORE - this recreates the segmonitors per part but not per fileno (which is a little backwards).
  20428. // 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
  20429. // However order is probably better to iterate fileno's inside partnos
  20430. // MORE - also not properly supporting STEPPED I fear.
  20431. // A superkey that mixes single and multipart or tlk and roroot keys might be hard
  20432. for (unsigned partNo = 0; partNo < keySet->length(); partNo++)
  20433. {
  20434. IKeyIndexBase *thisBase = keySet->queryKeyPart(partNo);
  20435. if (thisBase)
  20436. {
  20437. unsigned fileNo = 0;
  20438. IKeyIndex *thisKey = thisBase->queryPart(fileNo);
  20439. if (!thisKey->isTopLevelKey())
  20440. {
  20441. if (keyedLimit != (unsigned __int64) -1)
  20442. {
  20443. if ((indexHelper.getFlags() & TIRcountkeyedlimit) != 0)
  20444. {
  20445. Owned<IKeyManager> countKey;
  20446. countKey.setown(createLocalKeyManager(indexHelper.queryDiskRecordSize()->queryRecordAccessor(true), thisKey, this));
  20447. countKey->setLayoutTranslator(translators->item(fileNo));
  20448. createSegmentMonitors(countKey);
  20449. unsigned __int64 count = countKey->checkCount(keyedLimit);
  20450. if (count > keyedLimit)
  20451. {
  20452. if (traceLevel > 4)
  20453. DBGLOG("activityid = %d line = %d", activityId, __LINE__);
  20454. onLimitExceeded(true);
  20455. }
  20456. }
  20457. }
  20458. }
  20459. if (seekGEOffset && !thisKey->isTopLevelKey())
  20460. {
  20461. tlk.setown(createSingleKeyMerger(indexHelper.queryDiskRecordSize()->queryRecordAccessor(true), thisKey, seekGEOffset, this));
  20462. }
  20463. else
  20464. {
  20465. tlk.setown(createLocalKeyManager(indexHelper.queryDiskRecordSize()->queryRecordAccessor(true), thisKey, this));
  20466. if (!thisKey->isTopLevelKey())
  20467. tlk->setLayoutTranslator(translators->item(fileNo));
  20468. else
  20469. tlk->setLayoutTranslator(nullptr);
  20470. }
  20471. createSegmentMonitors(tlk);
  20472. if (queryTraceLevel() > 3 || ctx->queryProbeManager())
  20473. {
  20474. StringBuffer out;
  20475. printKeyedValues(out, tlk, indexHelper.queryDiskRecordSize());
  20476. CTXLOG("Using filter %s", out.str());
  20477. if (ctx->queryProbeManager())
  20478. ctx->queryProbeManager()->setNodeProperty(this, "filter", out.str());
  20479. }
  20480. tlk->reset();
  20481. for (;;) // for each file part
  20482. {
  20483. //block for TransformCallbackAssociation
  20484. {
  20485. TransformCallbackAssociation associate(callback, tlk);
  20486. if (thisKey->isTopLevelKey())
  20487. {
  20488. if (thisKey->isFullySorted())
  20489. {
  20490. while (tlk->lookup(false))
  20491. {
  20492. unsigned slavePart = (unsigned)extractFpos(tlk);
  20493. if (slavePart)
  20494. {
  20495. accepted++;
  20496. remote.getMem(slavePart, fileNo, 0); // the cached context is all we need to send
  20497. if (sorted && numChannels>1)
  20498. remote.flush(); // don't combine parts if we need result sorted, except on a 1-way
  20499. }
  20500. }
  20501. }
  20502. else
  20503. {
  20504. // MORE - we could check whether there are any matching parts if we wanted.
  20505. // If people are in the habit of sending null values that would be worthwhile
  20506. remote.getMem(0, fileNo, 0);
  20507. }
  20508. }
  20509. else
  20510. {
  20511. if (processSingleKey(thisKey, translators->item(fileNo)))
  20512. break;
  20513. }
  20514. }
  20515. if (++fileNo < thisBase->numParts())
  20516. {
  20517. thisKey = thisBase->queryPart(fileNo);
  20518. tlk->setKey(thisKey);
  20519. if (!thisKey->isTopLevelKey())
  20520. tlk->setLayoutTranslator(translators->item(fileNo));
  20521. else
  20522. tlk->setLayoutTranslator(nullptr);
  20523. tlk->reset();
  20524. }
  20525. else
  20526. break;
  20527. }
  20528. tlk->releaseSegmentMonitors();
  20529. tlk->setKey(NULL);
  20530. }
  20531. }
  20532. }
  20533. }
  20534. remote.flush();
  20535. remote.senddone();
  20536. }
  20537. catch (IException *E)
  20538. {
  20539. remote.setException(E);
  20540. }
  20541. }
  20542. virtual void createSegmentMonitors(IKeyManager *key)
  20543. {
  20544. indexHelper.createSegmentMonitors(key);
  20545. key->finishSegmentMonitors();
  20546. }
  20547. virtual bool processSingleKey(IKeyIndex *key, IRecordLayoutTranslator * trans) = 0;
  20548. virtual void reset()
  20549. {
  20550. if (accepted)
  20551. noteStatistic(StNumIndexAccepted, accepted);
  20552. if (rejected)
  20553. noteStatistic(StNumIndexRejected, rejected);
  20554. remote.onReset();
  20555. CRoxieServerActivity::reset();
  20556. if (varFileInfo)
  20557. {
  20558. keySet.clear();
  20559. varFileInfo.clear();
  20560. }
  20561. variableInfoPending = false;
  20562. }
  20563. virtual void stop()
  20564. {
  20565. remote.onStop();
  20566. CRoxieServerActivity::stop();
  20567. }
  20568. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  20569. {
  20570. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  20571. }
  20572. virtual void gatherStats(CRuntimeStatisticCollection & merged) const override
  20573. {
  20574. CRoxieServerActivity::gatherStats(merged);
  20575. remote.gatherStats(merged);
  20576. }
  20577. };
  20578. class CRoxieServerIndexReadBaseActivity : public CRoxieServerIndexActivity
  20579. {
  20580. protected:
  20581. IHThorSourceLimitTransformExtra * limitTransformExtra = nullptr;
  20582. public:
  20583. CRoxieServerIndexReadBaseActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  20584. IKeyArray * _keySet, TranslatorArray *_translators, bool _sorted, bool _isLocal, bool _maySkip)
  20585. : CRoxieServerIndexActivity(_ctx, _factory, _probeManager, _remoteId, _keySet, _translators, _sorted, _isLocal, _maySkip)
  20586. {
  20587. }
  20588. virtual void reset()
  20589. {
  20590. remote.onReset();
  20591. CRoxieServerIndexActivity::reset();
  20592. }
  20593. virtual const void *nextRow()
  20594. {
  20595. ActivityTimer t(totalCycles, timeActivities);
  20596. try
  20597. {
  20598. const void *ret = remote.nextRow();
  20599. if (ret)
  20600. processed++;
  20601. return ret;
  20602. }
  20603. catch (IException *E)
  20604. {
  20605. throw makeWrappedException(E);
  20606. }
  20607. }
  20608. protected:
  20609. virtual const void * createLimitFailRow(bool isKeyed)
  20610. {
  20611. ensureRowAllocator();
  20612. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  20613. assertex(limitTransformExtra);
  20614. size32_t outSize = isKeyed ? limitTransformExtra->transformOnKeyedLimitExceeded(rowBuilder) : limitTransformExtra->transformOnLimitExceeded(rowBuilder);
  20615. if (outSize)
  20616. return rowBuilder.finalizeRowClear(outSize);
  20617. return NULL;
  20618. }
  20619. };
  20620. class CRoxieServerIndexReadActivity : public CRoxieServerIndexReadBaseActivity, implements IIndexReadActivityInfo
  20621. {
  20622. protected:
  20623. IHThorIndexReadArg & readHelper;
  20624. ISteppingMeta *rawMeta = nullptr;
  20625. CSteppingMeta steppingMeta;
  20626. unsigned * seekSizes = nullptr;
  20627. bool optimizeSteppedPostFilter;
  20628. ISteppingMeta * projectedMeta = nullptr;
  20629. unsigned maxSeekLookahead;
  20630. public:
  20631. CRoxieServerIndexReadActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  20632. IKeyArray * _keySet, TranslatorArray *_translators, bool _sorted, bool _isLocal, bool _maySkip, unsigned _maxSeekLookahead)
  20633. : CRoxieServerIndexReadBaseActivity(_ctx, _factory, _probeManager, _remoteId, _keySet, _translators, _sorted, _isLocal, _maySkip),
  20634. readHelper((IHThorIndexReadArg &)basehelper)
  20635. {
  20636. limitTransformExtra = &readHelper;
  20637. rawMeta = readHelper.queryRawSteppingMeta();
  20638. unsigned flags = indexHelper.getFlags();
  20639. optimizeSteppedPostFilter = (flags & TIRunfilteredtransform) != 0;
  20640. seekSizes = NULL;
  20641. maxSeekLookahead = _maxSeekLookahead;
  20642. if (rawMeta)
  20643. {
  20644. const CFieldOffsetSize * fields = rawMeta->queryFields();
  20645. unsigned maxFields = rawMeta->getNumFields();
  20646. seekGEOffset = fields[0].offset;
  20647. seekSizes = new unsigned[maxFields];
  20648. seekSizes[0] = fields[0].size;
  20649. for (unsigned i=1; i < maxFields; i++)
  20650. seekSizes[i] = seekSizes[i-1] + fields[i].size;
  20651. projectedMeta = readHelper.queryProjectedSteppingMeta();
  20652. ISteppingMeta *useMeta = projectedMeta ? projectedMeta : rawMeta;
  20653. remote.setMergeInfo(useMeta); // also need to consider superfile case where there is a mix of multiway and singleparts.. ?
  20654. bool hasPostFilter = readHelper.transformMayFilter() && optimizeSteppedPostFilter;
  20655. steppingMeta.init(useMeta, hasPostFilter);
  20656. }
  20657. }
  20658. ~CRoxieServerIndexReadActivity()
  20659. {
  20660. delete [] seekSizes;
  20661. }
  20662. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  20663. {
  20664. CRoxieServerIndexReadBaseActivity::start(parentExtractSize, parentExtract, paused);
  20665. steppingMeta.setDistributed();
  20666. if (steppedExtra)
  20667. steppingMeta.setExtra(steppedExtra);
  20668. rowLimit = readHelper.getRowLimit();
  20669. keyedLimit = readHelper.getKeyedLimit();
  20670. choosenLimit = readHelper.getChooseNLimit();
  20671. if (!paused)
  20672. processAllKeys();
  20673. }
  20674. class LazyLocalKeyReader : implements IMessageUnpackCursor, implements IMessageResult, public CInterface
  20675. {
  20676. public:
  20677. IMPLEMENT_IINTERFACE;
  20678. virtual IMessageUnpackCursor *getCursor(roxiemem::IRowManager *rowMgr) const
  20679. {
  20680. Link();
  20681. return const_cast<LazyLocalKeyReader*> (this);
  20682. }
  20683. virtual const void *getMessageHeader(unsigned &length) const
  20684. {
  20685. length = 0;
  20686. return NULL;
  20687. }
  20688. virtual const void *getMessageMetadata(unsigned &length) const
  20689. {
  20690. length = 0;
  20691. return NULL;
  20692. }
  20693. virtual void discard() const
  20694. {
  20695. // nothing to do.
  20696. }
  20697. unsigned keyedCount;
  20698. unsigned matched;
  20699. bool EOFseen;
  20700. Owned<IKeyIndexSet> keySet;
  20701. Owned<IKeyManager> tlk;
  20702. CRoxieServerIndexReadActivity &owner;
  20703. LazyLocalKeyReader(CRoxieServerIndexReadActivity &_owner, IKeyIndex *key, IRecordLayoutTranslator * trans)
  20704. : owner(_owner)
  20705. {
  20706. keyedCount = 0;
  20707. matched = 0;
  20708. EOFseen = false;
  20709. keySet.setown(createKeyIndexSet());
  20710. keySet->addIndex(LINK(key));
  20711. if (owner.seekGEOffset)
  20712. tlk.setown(createKeyMerger(owner.indexHelper.queryDiskRecordSize()->queryRecordAccessor(true), keySet, owner.seekGEOffset, &owner));
  20713. else
  20714. tlk.setown(createLocalKeyManager(owner.indexHelper.queryDiskRecordSize()->queryRecordAccessor(true), keySet->queryPart(0), &owner));
  20715. if (!key->isTopLevelKey())
  20716. tlk->setLayoutTranslator(trans);
  20717. owner.indexHelper.createSegmentMonitors(tlk);
  20718. tlk->finishSegmentMonitors();
  20719. tlk->reset();
  20720. }
  20721. virtual const void *getNext(int length)
  20722. {
  20723. TransformCallbackAssociation associate(owner.callback, tlk);
  20724. while (tlk->lookup(true))
  20725. {
  20726. keyedCount++;
  20727. if (keyedCount > owner.keyedLimit)
  20728. {
  20729. owner.onLimitExceeded(true); // Should throw exception
  20730. throwUnexpected();
  20731. }
  20732. size32_t transformedSize;
  20733. RtlDynamicRowBuilder rowBuilder(owner.rowAllocator);
  20734. byte const * keyRow = tlk->queryKeyBuffer();
  20735. try
  20736. {
  20737. transformedSize = owner.readHelper.transform(rowBuilder, keyRow);
  20738. owner.callback.finishedRow();
  20739. }
  20740. catch (IException *E)
  20741. {
  20742. throw owner.makeWrappedException(E);
  20743. }
  20744. if (transformedSize)
  20745. {
  20746. OwnedConstRoxieRow result = rowBuilder.finalizeRowClear(transformedSize);
  20747. matched++;
  20748. if (matched > owner.rowLimit)
  20749. {
  20750. owner.onLimitExceeded(false); // Should throw exception
  20751. throwUnexpected();
  20752. }
  20753. if (matched > owner.choosenLimit) // MORE - bit of a strange place to check
  20754. {
  20755. break;
  20756. }
  20757. owner.accepted++;
  20758. return result.getClear();
  20759. }
  20760. else
  20761. owner.rejected++;
  20762. }
  20763. EOFseen = true;
  20764. return NULL;
  20765. }
  20766. virtual bool atEOF() const
  20767. {
  20768. return EOFseen;
  20769. }
  20770. virtual bool isSerialized() const
  20771. {
  20772. return false;
  20773. }
  20774. };
  20775. virtual bool processSingleKey(IKeyIndex *key, IRecordLayoutTranslator * trans)
  20776. {
  20777. ensureRowAllocator();
  20778. remote.injectResult(new LazyLocalKeyReader(*this, key, trans));
  20779. return false;
  20780. }
  20781. virtual void onLimitExceeded(bool isKeyed)
  20782. {
  20783. if (traceLevel > 4)
  20784. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  20785. if (isKeyed)
  20786. {
  20787. if (indexHelper.getFlags() & (TIRkeyedlimitskips|TIRkeyedlimitcreates))
  20788. {
  20789. if (ctx->queryDebugContext())
  20790. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  20791. throw makeLimitSkipException(true);
  20792. }
  20793. else
  20794. readHelper.onKeyedLimitExceeded();
  20795. }
  20796. else
  20797. {
  20798. if (indexHelper.getFlags() & (TIRlimitskips|TIRlimitcreates))
  20799. {
  20800. if (ctx->queryDebugContext())
  20801. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  20802. throw makeLimitSkipException(false);
  20803. }
  20804. else
  20805. readHelper.onLimitExceeded();
  20806. }
  20807. }
  20808. virtual void serializeSkipInfo(MemoryBuffer &out, unsigned seekLen, const void *rawSeek, unsigned numFields, const void * seek, const SmartStepExtra &stepExtra) const
  20809. {
  20810. out.append((unsigned short) numFields);
  20811. out.append((unsigned short) seekLen);
  20812. out.append((unsigned short) stepExtra.queryFlags());
  20813. IMultipleStepSeekInfo *seeks = stepExtra.queryExtraSeeks();
  20814. if (seeks)
  20815. {
  20816. unsigned lookahead = 40000/seekLen;
  20817. if (maxSeekLookahead && (lookahead > maxSeekLookahead))
  20818. lookahead = maxSeekLookahead;
  20819. seeks->ensureFilled(seek, numFields, lookahead);
  20820. out.append(lookahead != seeks->ordinality()); // seeksAreEof flag
  20821. unsigned serialized = 1; // rawseek is always serialized...
  20822. unsigned patchLength = out.length();
  20823. out.append(serialized); // NOTE - we come back and patch with the actual value...
  20824. out.append(seekLen, rawSeek);
  20825. if (seeks->ordinality())
  20826. {
  20827. const void *lastSeek = rawSeek;
  20828. byte *nextSeek = NULL;
  20829. if (projectedMeta)
  20830. nextSeek = (byte *) alloca(seekLen);
  20831. for (unsigned i = 0; i < seeks->ordinality(); i++)
  20832. {
  20833. if (projectedMeta)
  20834. {
  20835. RtlStaticRowBuilder rowBuilder(nextSeek-seekGEOffset, seekGEOffset+seekLen);
  20836. readHelper.mapOutputToInput(rowBuilder, seeks->querySeek(i), numFields); // NOTE - weird interface to mapOutputToInput means that it STARTS writing at seekGEOffset...
  20837. }
  20838. else
  20839. nextSeek = (byte *) seeks->querySeek(i)+seekGEOffset;
  20840. int diff = memcmp(nextSeek, lastSeek, seekLen);
  20841. if (diff > 0)
  20842. {
  20843. serialized++;
  20844. out.append(seekLen, nextSeek);
  20845. lastSeek = (const byte *) out.reserve(0) - seekLen;
  20846. }
  20847. }
  20848. unsigned length = out.length();
  20849. out.setWritePos(patchLength);
  20850. out.append(serialized);
  20851. out.setWritePos(length);
  20852. }
  20853. }
  20854. else
  20855. {
  20856. out.append(false);
  20857. out.append(1);
  20858. out.append(seekLen, rawSeek);
  20859. }
  20860. }
  20861. virtual const void * nextRowGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  20862. {
  20863. ActivityTimer t(totalCycles, timeActivities);
  20864. try
  20865. {
  20866. unsigned seeklen = 0;
  20867. const void *rawSeek = NULL;
  20868. if (seek && numFields)
  20869. {
  20870. seeklen = seekSizes[numFields-1];
  20871. rawSeek = (const byte *)seek + seekGEOffset;
  20872. if (projectedMeta)
  20873. {
  20874. byte * temp = (byte *) alloca(seeklen);
  20875. RtlStaticRowBuilder rawBuilder(temp-seekGEOffset, seekGEOffset+seeklen);
  20876. readHelper.mapOutputToInput(rawBuilder, seek, numFields); // NOTE - weird interface to mapOutputToInput means that it STARTS writing at seekGEOffset...
  20877. rawSeek = (byte *)temp;
  20878. }
  20879. }
  20880. const void *ret = remote.nextRowGE(seek, rawSeek, numFields, seeklen, wasCompleteMatch, stepExtra);
  20881. if (ret && wasCompleteMatch) // GH pleas confirm the wasCompleteMatch I just added here is right
  20882. processed++;
  20883. return ret;
  20884. }
  20885. catch (IException *E)
  20886. {
  20887. throw makeWrappedException(E);
  20888. }
  20889. }
  20890. virtual IInputSteppingMeta * querySteppingMeta()
  20891. {
  20892. if (rawMeta && steppingEnabled && ((indexHelper.getFlags() & (TIRlimitskips|TIRlimitcreates|TIRkeyedlimitskips|TIRkeyedlimitcreates)) == 0))
  20893. return &steppingMeta;
  20894. return NULL;
  20895. }
  20896. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  20897. {
  20898. if (variableInfoPending)
  20899. setVariableFileInfo();
  20900. return this;
  20901. }
  20902. virtual IKeyArray *getKeySet() const
  20903. {
  20904. return keySet.getLink();
  20905. }
  20906. virtual const IResolvedFile *getVarFileInfo() const
  20907. {
  20908. return varFileInfo.getLink();
  20909. }
  20910. virtual TranslatorArray *getTranslators() const
  20911. {
  20912. return translators.getLink();
  20913. }
  20914. virtual void mergeSegmentMonitors(IIndexReadContext *irc) const
  20915. {
  20916. indexHelper.createSegmentMonitors(irc); // NOTE: they will merge
  20917. }
  20918. virtual IRoxieServerActivity *queryActivity() { return this; }
  20919. virtual const RemoteActivityId& queryRemoteId() const
  20920. {
  20921. return remoteId;
  20922. }
  20923. };
  20924. class CRoxieServerSimpleIndexReadActivity : public CRoxieServerActivity, implements IIndexReadActivityInfo
  20925. {
  20926. IHThorIndexReadArg & indexHelper;
  20927. IHThorSteppedSourceExtra * steppedExtra;
  20928. bool eof;
  20929. Linked<IKeyArray>keySet;
  20930. Owned<IKeyIndexSet>keyIndexSet;
  20931. Owned<IKeyManager> tlk;
  20932. Linked<TranslatorArray> translators;
  20933. CIndexTransformCallback callback;
  20934. unsigned __int64 keyedLimit;
  20935. unsigned rowLimit;
  20936. unsigned chooseNLimit;
  20937. unsigned accepted;
  20938. unsigned rejected;
  20939. unsigned keyedCount;
  20940. ISteppingMeta * rawMeta;
  20941. ISteppingMeta * projectedMeta;
  20942. size32_t seekGEOffset;
  20943. unsigned * seekSizes;
  20944. CSteppingMeta steppingMeta;
  20945. Owned<const IResolvedFile> varFileInfo;
  20946. const RemoteActivityId &remoteId;
  20947. bool firstRead;
  20948. bool variableFileName;
  20949. bool variableInfoPending;
  20950. bool isOpt;
  20951. bool isLocal;
  20952. bool optimizeSteppedPostFilter;
  20953. // MORE there may be enough in common between this and CRoxieServerIndexActivity to warrant some refactoring
  20954. void initKeySet()
  20955. {
  20956. if ((keySet->length() > 1 || rawMeta != NULL) && translators->needsTranslation())
  20957. {
  20958. throw MakeStringException(ROXIE_UNIMPLEMENTED_ERROR, "Layout translation is not available when merging key parts or smart-stepping, as it may change record order");
  20959. }
  20960. keyIndexSet.setown(createKeyIndexSet());
  20961. for (unsigned part = 0; part < keySet->length(); part++)
  20962. {
  20963. IKeyIndexBase *kib = keySet->queryKeyPart(part);
  20964. if (kib)
  20965. {
  20966. for (unsigned subpart = 0; subpart < kib->numParts(); subpart++)
  20967. {
  20968. IKeyIndex *k = kib->queryPart(subpart);
  20969. if (k)
  20970. {
  20971. assertex(!k->isTopLevelKey());
  20972. keyIndexSet->addIndex(LINK(k));
  20973. }
  20974. }
  20975. }
  20976. }
  20977. }
  20978. void setVariableFileInfo()
  20979. {
  20980. OwnedRoxieString indexName(indexHelper.getFileName());
  20981. varFileInfo.setown(resolveLFN(indexName, isOpt));
  20982. translators.setown(new TranslatorArray) ;
  20983. keySet.setown(varFileInfo->getKeyArray(factory->queryActivityMeta(), translators, isOpt, isLocal ? factory->queryQueryFactory().queryChannel() : 0, factory->queryQueryFactory().queryOptions().enableFieldTranslation));
  20984. initKeySet();
  20985. variableInfoPending = false;
  20986. }
  20987. void onEOF()
  20988. {
  20989. callback.setManager(NULL);
  20990. eof = true;
  20991. tlk.clear();
  20992. }
  20993. public:
  20994. CRoxieServerSimpleIndexReadActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  20995. IKeyArray *_keyArray, TranslatorArray *_translatorArray, bool _isLocal)
  20996. : CRoxieServerActivity(_ctx, _factory, _probeManager),
  20997. indexHelper((IHThorIndexReadArg &)basehelper),
  20998. translators(_translatorArray),
  20999. keySet(_keyArray),
  21000. isLocal(_isLocal),
  21001. remoteId(_remoteId)
  21002. {
  21003. rowLimit = 0;
  21004. keyedLimit = 0;
  21005. chooseNLimit = 0;
  21006. indexHelper.setCallback(&callback);
  21007. steppedExtra = indexHelper.querySteppingExtra();
  21008. unsigned flags = indexHelper.getFlags();
  21009. variableFileName = allFilesDynamic || factory->queryQueryFactory().isDynamic() || ((flags & (TIRvarfilename|TIRdynamicfilename)) != 0);
  21010. variableInfoPending = false;
  21011. isOpt = (flags & TIRoptional) != 0;
  21012. optimizeSteppedPostFilter = (flags & TIRunfilteredtransform) != 0;
  21013. firstRead = true;
  21014. accepted = 0;
  21015. rejected = 0;
  21016. keyedCount = 0;
  21017. eof = false;
  21018. rawMeta = indexHelper.queryRawSteppingMeta();
  21019. projectedMeta = indexHelper.queryProjectedSteppingMeta();
  21020. seekGEOffset = 0;
  21021. seekSizes = NULL;
  21022. if (rawMeta)
  21023. {
  21024. // MORE - should check all keys in maxFields list can actually be keyed.
  21025. const CFieldOffsetSize * fields = rawMeta->queryFields();
  21026. unsigned maxFields = rawMeta->getNumFields();
  21027. seekGEOffset = fields[0].offset;
  21028. seekSizes = new unsigned[maxFields];
  21029. seekSizes[0] = fields[0].size;
  21030. for (unsigned i=1; i < maxFields; i++)
  21031. seekSizes[i] = seekSizes[i-1] + fields[i].size;
  21032. bool hasPostFilter = indexHelper.transformMayFilter() && optimizeSteppedPostFilter;
  21033. if (projectedMeta)
  21034. steppingMeta.init(projectedMeta, hasPostFilter);
  21035. else
  21036. steppingMeta.init(rawMeta, hasPostFilter);
  21037. }
  21038. }
  21039. virtual const IResolvedFile *queryVarFileInfo() const
  21040. {
  21041. return varFileInfo;
  21042. }
  21043. ~CRoxieServerSimpleIndexReadActivity()
  21044. {
  21045. delete [] seekSizes;
  21046. }
  21047. virtual bool needsAllocator() const { return true; }
  21048. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  21049. {
  21050. firstRead = true;
  21051. accepted = 0;
  21052. rejected = 0;
  21053. keyedCount = 0;
  21054. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  21055. if (steppedExtra)
  21056. steppingMeta.setExtra(steppedExtra);
  21057. eof = !indexHelper.canMatchAny();
  21058. if (variableFileName)
  21059. variableInfoPending = true;
  21060. else
  21061. {
  21062. variableInfoPending = false;
  21063. if (!keyIndexSet)
  21064. initKeySet();
  21065. }
  21066. }
  21067. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  21068. {
  21069. if (variableInfoPending)
  21070. setVariableFileInfo();
  21071. return this;
  21072. }
  21073. virtual IKeyArray *getKeySet() const
  21074. {
  21075. return keySet.getLink();
  21076. }
  21077. virtual const IResolvedFile *getVarFileInfo() const
  21078. {
  21079. return varFileInfo.getLink();
  21080. }
  21081. virtual TranslatorArray *getTranslators() const
  21082. {
  21083. return translators.getLink();
  21084. }
  21085. virtual void mergeSegmentMonitors(IIndexReadContext *irc) const
  21086. {
  21087. indexHelper.createSegmentMonitors(irc); // NOTE: they will merge
  21088. }
  21089. virtual IRoxieServerActivity *queryActivity() { return this; }
  21090. virtual const RemoteActivityId& queryRemoteId() const
  21091. {
  21092. return remoteId;
  21093. }
  21094. const void *nextRow()
  21095. {
  21096. bool matched = true;
  21097. return nextRowGE(NULL, 0, matched, dummySmartStepExtra);
  21098. }
  21099. unsigned __int64 checkCount(unsigned __int64 limit)
  21100. {
  21101. unsigned numParts = keyIndexSet->numParts();
  21102. unsigned __int64 result = 0;
  21103. for (unsigned i = 0; i < numParts; i++)
  21104. {
  21105. Owned<IKeyManager> countTlk = createLocalKeyManager(indexHelper.queryDiskRecordSize()->queryRecordAccessor(true), keyIndexSet->queryPart(i), this);
  21106. countTlk->setLayoutTranslator(translators->item(i));
  21107. indexHelper.createSegmentMonitors(countTlk);
  21108. countTlk->finishSegmentMonitors();
  21109. result += countTlk->checkCount(limit-result);
  21110. if (result > limit)
  21111. break;
  21112. }
  21113. return result;
  21114. }
  21115. virtual const void *nextRowGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  21116. {
  21117. ActivityTimer t(totalCycles, timeActivities);
  21118. if (eof)
  21119. return NULL;
  21120. if (firstRead)
  21121. {
  21122. if (variableInfoPending)
  21123. setVariableFileInfo();
  21124. rowLimit = (unsigned) indexHelper.getRowLimit();
  21125. chooseNLimit = (unsigned) indexHelper.getChooseNLimit();
  21126. unsigned numParts = keyIndexSet->numParts();
  21127. if (!numParts)
  21128. {
  21129. onEOF();
  21130. return NULL;
  21131. }
  21132. if (numParts > 1 || seekGEOffset)
  21133. {
  21134. tlk.setown(createKeyMerger(indexHelper.queryDiskRecordSize()->queryRecordAccessor(true), keyIndexSet, seekGEOffset, this));
  21135. // note that we don't set up translator because we don't support it. If that ever changes...
  21136. }
  21137. else
  21138. {
  21139. tlk.setown(createLocalKeyManager(indexHelper.queryDiskRecordSize()->queryRecordAccessor(true), keyIndexSet->queryPart(0), this));
  21140. tlk->setLayoutTranslator(translators->item(0));
  21141. }
  21142. indexHelper.createSegmentMonitors(tlk);
  21143. tlk->finishSegmentMonitors();
  21144. if (queryTraceLevel() > 3 || ctx->queryProbeManager())
  21145. {
  21146. StringBuffer out;
  21147. printKeyedValues(out, tlk, indexHelper.queryDiskRecordSize());
  21148. CTXLOG("Using filter %s", out.str());
  21149. if (ctx->queryProbeManager())
  21150. ctx->queryProbeManager()->setNodeProperty(this, "filter", out.str());
  21151. }
  21152. tlk->reset();
  21153. callback.setManager(tlk);
  21154. keyedLimit = indexHelper.getKeyedLimit();
  21155. if (keyedLimit != (unsigned __int64) -1)
  21156. {
  21157. if ((indexHelper.getFlags() & TIRcountkeyedlimit) != 0)
  21158. {
  21159. unsigned __int64 count = checkCount(keyedLimit);
  21160. if (count > keyedLimit)
  21161. {
  21162. if ((indexHelper.getFlags() & (TIRkeyedlimitskips|TIRkeyedlimitcreates)) == 0)
  21163. indexHelper.onKeyedLimitExceeded();
  21164. const void * ret = NULL;
  21165. if (indexHelper.getFlags() & TIRkeyedlimitcreates)
  21166. ret = createKeyedLimitOnFailRow();
  21167. onEOF();
  21168. return ret;
  21169. }
  21170. keyedLimit = (unsigned __int64) -1;
  21171. }
  21172. }
  21173. firstRead = false;
  21174. }
  21175. if (accepted == chooseNLimit)
  21176. {
  21177. onEOF();
  21178. return NULL;
  21179. }
  21180. const byte * rawSeek = NULL;
  21181. unsigned seekSize = 0;
  21182. if (seek)
  21183. {
  21184. seekSize = seekSizes[numFields-1];
  21185. rawSeek = (const byte *)seek + seekGEOffset;
  21186. if (projectedMeta)
  21187. {
  21188. byte *temp = (byte *) alloca(seekSize);
  21189. RtlStaticRowBuilder rawBuilder(temp-seekGEOffset, seekGEOffset+seekSize);
  21190. indexHelper.mapOutputToInput(rawBuilder, seek, numFields);// NOTE - weird interface to mapOutputToInput means that it STARTS writing at seekGEOffset...
  21191. rawSeek = (byte *)temp;
  21192. }
  21193. #ifdef _DEBUG
  21194. // StringBuffer seekStr;
  21195. // for (unsigned i = 0; i < seekSize; i++)
  21196. // {
  21197. // seekStr.appendf("%02x ", ((unsigned char *) rawSeek)[i]);
  21198. // }
  21199. // DBGLOG("nextRowGE can skip offset %d size %d value %s", seekGEOffset, seekSize, seekStr.str());
  21200. #endif
  21201. }
  21202. const byte * originalRawSeek = rawSeek;
  21203. RtlDynamicRowBuilder rowBuilder(rowAllocator, false);
  21204. while (rawSeek ? tlk->lookupSkip(rawSeek, seekGEOffset, seekSize) : tlk->lookup(true))
  21205. {
  21206. checkAbort();
  21207. keyedCount++;
  21208. if (keyedCount > keyedLimit)
  21209. {
  21210. indexHelper.onKeyedLimitExceeded();
  21211. break;
  21212. }
  21213. byte const * keyRow = tlk->queryKeyBuffer();
  21214. #ifdef _DEBUG
  21215. // StringBuffer recstr;
  21216. // unsigned size = (tlk->queryRecordSize()<80) ? tlk->queryRecordSize() : 80;
  21217. // for (unsigned i = 0; i < size; i++)
  21218. // {
  21219. // recstr.appendf("%02x ", ((unsigned char *) keyRow)[i]);
  21220. // }
  21221. // DBGLOG("nextRowGE Got %s", recstr.str());
  21222. if (originalRawSeek && memcmp(keyRow + seekGEOffset, originalRawSeek, seekSize) < 0)
  21223. assertex(!"smart seek failure");
  21224. #endif
  21225. size32_t transformedSize;
  21226. rowBuilder.ensureRow();
  21227. try
  21228. {
  21229. transformedSize =indexHelper.transform(rowBuilder, keyRow);
  21230. //if the post filter causes a mismatch, and the stepping condition no longer matches
  21231. //then return a mismatch record - so the join code can start seeking on the other input.
  21232. if (transformedSize == 0 && optimizeSteppedPostFilter && stepExtra.returnMismatches())
  21233. {
  21234. if (memcmp(keyRow + seekGEOffset, originalRawSeek, seekSize) != 0)
  21235. {
  21236. transformedSize = indexHelper.unfilteredTransform(rowBuilder, keyRow);
  21237. if (transformedSize != 0)
  21238. wasCompleteMatch = false;
  21239. }
  21240. }
  21241. callback.finishedRow();
  21242. }
  21243. catch (IException *E)
  21244. {
  21245. throw makeWrappedException(E);
  21246. }
  21247. if (transformedSize)
  21248. {
  21249. accepted++;
  21250. if (accepted > rowLimit)
  21251. {
  21252. if ((indexHelper.getFlags() & (TIRlimitskips|TIRlimitcreates)) != 0)
  21253. {
  21254. throwUnexpected(); // should not have used simple variant if maySkip set...
  21255. }
  21256. if (traceLevel > 4)
  21257. DBGLOG("activityid = %d line = %d", activityId, __LINE__);
  21258. indexHelper.onLimitExceeded();
  21259. break;
  21260. }
  21261. processed++;
  21262. #ifdef _DEBUG
  21263. // const byte *ret = (const byte *) out.get();
  21264. // CommonXmlWriter xmlwrite(XWFnoindent|XWFtrim|XWFopt);
  21265. // queryOutputMeta()->toXML(ret, xmlwrite);
  21266. // DBGLOG("ROW: {%p} %s", ret, xmlwrite.str());
  21267. #endif
  21268. return rowBuilder.finalizeRowClear(transformedSize);
  21269. }
  21270. else
  21271. rejected++;
  21272. rawSeek = NULL;
  21273. }
  21274. onEOF();
  21275. return NULL;
  21276. }
  21277. virtual void reset()
  21278. {
  21279. onEOF();
  21280. if (accepted)
  21281. noteStatistic(StNumIndexAccepted, accepted);
  21282. if (rejected)
  21283. noteStatistic(StNumIndexRejected, rejected);
  21284. if (variableFileName)
  21285. {
  21286. varFileInfo.clear();
  21287. translators.clear();
  21288. }
  21289. variableInfoPending = false;
  21290. CRoxieServerActivity::reset();
  21291. }
  21292. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  21293. {
  21294. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  21295. }
  21296. virtual IInputSteppingMeta * querySteppingMeta()
  21297. {
  21298. if (rawMeta && steppingEnabled && ((indexHelper.getFlags() & (TIRlimitskips|TIRlimitcreates|TIRkeyedlimitskips|TIRkeyedlimitcreates)) == 0))
  21299. return &steppingMeta;
  21300. return NULL;
  21301. }
  21302. protected:
  21303. const void * createKeyedLimitOnFailRow()
  21304. {
  21305. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  21306. size32_t outSize = indexHelper.transformOnKeyedLimitExceeded(rowBuilder);
  21307. if (outSize)
  21308. return rowBuilder.finalizeRowClear(outSize);
  21309. return NULL;
  21310. }
  21311. };
  21312. class CRoxieServerBaseIndexActivityFactory : public CRoxieServerActivityFactory
  21313. {
  21314. public:
  21315. Owned<IKeyArray> keySet;
  21316. Owned<TranslatorArray> translatorArray;
  21317. Owned<IDefRecordMeta> activityMeta;
  21318. RemoteActivityId remoteId;
  21319. bool isSimple;
  21320. bool isLocal;
  21321. bool maySkip;
  21322. bool sorted;
  21323. bool variableFileName;
  21324. IRecordLayoutTranslator::Mode enableFieldTranslation;
  21325. unsigned maxSeekLookahead;
  21326. Owned<const IResolvedFile> indexfile;
  21327. CRoxieServerSideCache *cache;
  21328. CRoxieServerBaseIndexActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, const RemoteActivityId &_remoteId)
  21329. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode), remoteId(_remoteId)
  21330. {
  21331. Owned<IHThorIndexReadBaseArg> indexHelper = (IHThorIndexReadBaseArg *) helperFactory();
  21332. unsigned flags = indexHelper->getFlags();
  21333. sorted = (flags & TIRunordered) == 0;
  21334. isLocal = _graphNode.getPropBool("att[@name='local']/@value") && queryFactory.queryChannel()!=0;
  21335. rtlDataAttr indexLayoutMeta;
  21336. size32_t indexLayoutSize = 0;
  21337. if(indexHelper->getIndexLayout(indexLayoutSize, indexLayoutMeta.refdata()))
  21338. {
  21339. MemoryBuffer m;
  21340. m.setBuffer(indexLayoutSize, indexLayoutMeta.getdata());
  21341. activityMeta.setown(deserializeRecordMeta(m, true));
  21342. }
  21343. else
  21344. assertex(indexLayoutSize==0);
  21345. enableFieldTranslation = queryFactory.queryOptions().enableFieldTranslation;
  21346. translatorArray.setown(new TranslatorArray);
  21347. variableFileName = allFilesDynamic || _queryFactory.isDynamic() || ((flags & (TIRvarfilename|TIRdynamicfilename)) != 0);
  21348. if (!variableFileName)
  21349. {
  21350. bool isOpt = (flags & TIRoptional) != 0;
  21351. OwnedRoxieString indexName(indexHelper->getFileName());
  21352. indexfile.setown(queryFactory.queryPackage().lookupFileName(indexName, isOpt, true, true, queryFactory.queryWorkUnit(), true));
  21353. if (indexfile)
  21354. keySet.setown(indexfile->getKeyArray(activityMeta, translatorArray, isOpt, isLocal ? queryFactory.queryChannel() : 0, enableFieldTranslation));
  21355. }
  21356. isSimple = isLocal;
  21357. maySkip = (flags & (TIRkeyedlimitskips|TIRlimitskips|TIRlimitcreates|TIRkeyedlimitcreates)) != 0;
  21358. if (keySet && keySet->length()==1 && !isLocal && (flags & (TIRlimitskips|TIRlimitcreates|TIRkeyedlimitskips|TIRkeyedlimitcreates))==0)
  21359. {
  21360. IKeyIndexBase *thisBase = keySet->queryKeyPart(0);
  21361. if (thisBase->numParts()==1 && !thisBase->queryPart(0)->isTopLevelKey() && !_queryFactory.queryOptions().disableLocalOptimizations)
  21362. isSimple = true;
  21363. }
  21364. int cacheSize = _graphNode.getPropInt("hint[@name='cachehits']/@value", serverSideCacheSize);
  21365. cache = cacheSize ? new CRoxieServerSideCache(cacheSize) : NULL;
  21366. maxSeekLookahead = _graphNode.getPropInt("hint[@name='maxseeklookahead']/@value", 0);
  21367. }
  21368. ~CRoxieServerBaseIndexActivityFactory()
  21369. {
  21370. delete cache;
  21371. }
  21372. virtual void getXrefInfo(IPropertyTree &reply, const IRoxieContextLogger &logctx) const
  21373. {
  21374. if (indexfile)
  21375. addXrefFileInfo(reply, indexfile);
  21376. else
  21377. {
  21378. Owned<IHThorIndexReadBaseArg> indexHelper = (IHThorIndexReadBaseArg *) helperFactory();
  21379. if ((indexHelper->getFlags() & (TIRvarfilename|TIRdynamicfilename)) == 0)
  21380. {
  21381. OwnedRoxieString indexName(indexHelper->getFileName());
  21382. Owned<const IResolvedFile> temp = queryFactory.queryPackage().lookupFileName(indexName, true, true, false, queryFactory.queryWorkUnit(), true);
  21383. if (temp)
  21384. addXrefFileInfo(reply, temp);
  21385. }
  21386. }
  21387. }
  21388. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  21389. {
  21390. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for indexread activity");
  21391. }
  21392. virtual IRoxieServerSideCache *queryServerSideCache() const
  21393. {
  21394. return cache;
  21395. }
  21396. virtual bool getEnableFieldTranslation() const
  21397. {
  21398. return enableFieldTranslation;
  21399. }
  21400. virtual IDefRecordMeta *queryActivityMeta() const
  21401. {
  21402. return activityMeta;
  21403. }
  21404. virtual const StatisticsMapping &queryStatsMapping() const
  21405. {
  21406. return indexStatistics;
  21407. }
  21408. };
  21409. class CRoxieServerIndexReadActivityFactory : public CRoxieServerBaseIndexActivityFactory
  21410. {
  21411. public:
  21412. CRoxieServerIndexReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, const RemoteActivityId &_remoteId)
  21413. : CRoxieServerBaseIndexActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _remoteId)
  21414. {
  21415. }
  21416. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  21417. {
  21418. if (!variableFileName && (keySet==NULL || keySet->length()==0))
  21419. return new CRoxieServerNullActivity(_ctx, this, _probeManager);
  21420. else if (isSimple && !maySkip)
  21421. return new CRoxieServerSimpleIndexReadActivity(_ctx, this, _probeManager, remoteId, keySet, translatorArray, isLocal);
  21422. else
  21423. return new CRoxieServerIndexReadActivity(_ctx, this, _probeManager, remoteId, keySet, translatorArray, sorted, isLocal, maySkip, maxSeekLookahead);
  21424. }
  21425. };
  21426. IRoxieServerActivityFactory *createRoxieServerIndexReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, const RemoteActivityId &_remoteId)
  21427. {
  21428. return new CRoxieServerIndexReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _remoteId);
  21429. }
  21430. //--------------------------------------------------------------------------------------------------------------------------
  21431. class CRoxieServerNullCountActivity : public CRoxieServerActivity
  21432. {
  21433. bool done;
  21434. public:
  21435. CRoxieServerNullCountActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  21436. : CRoxieServerActivity(_ctx, _factory, _probeManager)
  21437. {
  21438. done = false;
  21439. }
  21440. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  21441. {
  21442. done = false;
  21443. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  21444. }
  21445. virtual bool needsAllocator() const { return true; }
  21446. virtual const void *nextRow()
  21447. {
  21448. ActivityTimer t(totalCycles, timeActivities);
  21449. if (done) return NULL;
  21450. done = true;
  21451. size32_t rowSize = meta.getFixedSize();
  21452. void * nullRow = rowAllocator->createRow();
  21453. if (rowSize == 1)
  21454. *(byte *)nullRow = 0;
  21455. else
  21456. {
  21457. assertex(rowSize == sizeof(unsigned __int64));
  21458. *(unsigned __int64 *)nullRow = 0;
  21459. }
  21460. return rowAllocator->finalizeRow(rowSize, nullRow, rowSize);
  21461. }
  21462. };
  21463. class CRoxieServerIndexCountActivity : public CRoxieServerIndexActivity
  21464. {
  21465. IHThorIndexCountArg & countHelper;
  21466. bool done;
  21467. public:
  21468. CRoxieServerIndexCountActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, IKeyArray * _keySet, TranslatorArray *_translators, bool _isLocal)
  21469. : CRoxieServerIndexActivity(_ctx, _factory, _probeManager, _remoteId, _keySet, _translators, false, _isLocal, false),
  21470. countHelper((IHThorIndexCountArg &)basehelper),
  21471. done(false)
  21472. {
  21473. }
  21474. virtual bool needsAllocator() const { return true; }
  21475. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  21476. {
  21477. done = false;
  21478. CRoxieServerIndexActivity::start(parentExtractSize, parentExtract, paused);
  21479. choosenLimit = countHelper.getChooseNLimit();
  21480. rowLimit = countHelper.getRowLimit();
  21481. keyedLimit = countHelper.getKeyedLimit();
  21482. if (!paused)
  21483. processAllKeys();
  21484. }
  21485. virtual bool processSingleKey(IKeyIndex *key, IRecordLayoutTranslator * trans)
  21486. {
  21487. unsigned __int64 count = 0;
  21488. if (countHelper.hasFilter())
  21489. {
  21490. while (tlk->lookup(true))
  21491. {
  21492. try
  21493. {
  21494. count += countHelper.numValid(tlk->queryKeyBuffer());
  21495. callback.finishedRow();
  21496. }
  21497. catch (IException *E)
  21498. {
  21499. throw makeWrappedException(E);
  21500. }
  21501. accepted++;
  21502. if (count >= choosenLimit) // MORE - what about limit?
  21503. break;
  21504. }
  21505. }
  21506. else
  21507. count = tlk->getCount(); //MORE: GH->RKC There should be value in providing a max limit to getCount()
  21508. if (count)
  21509. {
  21510. Owned<CRowArrayMessageResult> result = new CRowArrayMessageResult(ctx->queryRowManager(), false);
  21511. if (count > choosenLimit)
  21512. count = choosenLimit;
  21513. void * recBuffer = rowAllocator->createRow();
  21514. if (meta.getFixedSize() == 1)
  21515. *(byte *)recBuffer = (byte)count;
  21516. else
  21517. {
  21518. assertex(meta.getFixedSize() == sizeof(unsigned __int64));
  21519. *(unsigned __int64 *)recBuffer = count;
  21520. }
  21521. recBuffer = rowAllocator->finalizeRow(meta.getFixedSize(), recBuffer, meta.getFixedSize());
  21522. result->append(recBuffer);
  21523. remote.injectResult(result.getClear());
  21524. //GH->RKC for count(,choosen)/exists passing in the previous count would short-circuit this much earlier
  21525. if (count >= choosenLimit)
  21526. return true;
  21527. }
  21528. return false;
  21529. }
  21530. virtual void onLimitExceeded(bool isKeyed)
  21531. {
  21532. if (traceLevel > 4)
  21533. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  21534. if (isKeyed)
  21535. {
  21536. if (indexHelper.getFlags() & (TIRkeyedlimitskips|TIRkeyedlimitcreates))
  21537. {
  21538. if (ctx->queryDebugContext())
  21539. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  21540. throw makeLimitSkipException(true);
  21541. }
  21542. else
  21543. {
  21544. countHelper.onKeyedLimitExceeded();
  21545. }
  21546. }
  21547. else
  21548. {
  21549. if (indexHelper.getFlags() & (TIRlimitskips|TIRlimitcreates))
  21550. {
  21551. if (ctx->queryDebugContext())
  21552. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  21553. throw makeLimitSkipException(false);
  21554. }
  21555. else
  21556. {
  21557. countHelper.onLimitExceeded();
  21558. }
  21559. }
  21560. }
  21561. virtual const void *createLimitFailRow(bool isKeyed)
  21562. {
  21563. throwUnexpected();
  21564. }
  21565. virtual const void *nextRow()
  21566. {
  21567. ActivityTimer t(totalCycles, timeActivities);
  21568. if (done) return NULL;
  21569. done = true;
  21570. unsigned __int64 totalCount = 0;
  21571. bool hasLimit = rowLimit != (unsigned __int64) -1;
  21572. try
  21573. {
  21574. for (;;)
  21575. {
  21576. const void * next = remote.nextRow();
  21577. if (!next)
  21578. break;
  21579. if (meta.getFixedSize() == 1)
  21580. totalCount += *(byte *)next;
  21581. else
  21582. totalCount += *(unsigned __int64 *) next;
  21583. ReleaseRoxieRow(next);
  21584. if (totalCount > rowLimit || (totalCount > choosenLimit && !hasLimit)) // can't break out early if there is a possibility of later slave throwing limit exception
  21585. break;
  21586. }
  21587. if (totalCount > rowLimit)
  21588. {
  21589. unsigned flags = indexHelper.getFlags();
  21590. if (flags & TIRlimitskips)
  21591. totalCount = 0;
  21592. else if (flags & TIRlimitcreates)
  21593. totalCount = 1;
  21594. else
  21595. countHelper.onLimitExceeded();
  21596. }
  21597. else if (totalCount > choosenLimit)
  21598. totalCount = choosenLimit;
  21599. }
  21600. catch (IException *E)
  21601. {
  21602. if (QUERYINTERFACE(E, LimitSkipException))
  21603. {
  21604. totalCount = 0;
  21605. unsigned flags = indexHelper.getFlags();
  21606. if (E->errorCode() == KeyedLimitSkipErrorCode)
  21607. {
  21608. if (flags & TIRkeyedlimitcreates)
  21609. totalCount++;
  21610. }
  21611. else
  21612. {
  21613. if (flags & TIRlimitcreates)
  21614. totalCount++;
  21615. }
  21616. if (totalCount > choosenLimit)
  21617. totalCount = choosenLimit; // would have to be weird code (and escape the optimizer...)
  21618. E->Release();
  21619. }
  21620. else
  21621. throw ;
  21622. }
  21623. void * result = rowAllocator->createRow();
  21624. if (meta.getFixedSize() == 1)
  21625. *(byte *)result = (byte)totalCount;
  21626. else
  21627. {
  21628. assertex(meta.getFixedSize() == sizeof(unsigned __int64));
  21629. *(unsigned __int64 *)result = totalCount;
  21630. }
  21631. return rowAllocator->finalizeRow(meta.getFixedSize(), result, meta.getFixedSize());
  21632. }
  21633. };
  21634. class CRoxieServerIndexCountActivityFactory : public CRoxieServerBaseIndexActivityFactory
  21635. {
  21636. public:
  21637. CRoxieServerIndexCountActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, const RemoteActivityId &_remoteId)
  21638. : CRoxieServerBaseIndexActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _remoteId)
  21639. {
  21640. }
  21641. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  21642. {
  21643. if (!variableFileName && (keySet==NULL || keySet->length()==0))
  21644. return new CRoxieServerNullCountActivity(_ctx, this, _probeManager);
  21645. // else if (isSimple)
  21646. // return new CRoxieServerSimpleIndexCountActivity(this, keySet->queryKeyPart(0)->queryPart(0));
  21647. else
  21648. return new CRoxieServerIndexCountActivity(_ctx, this, _probeManager, remoteId, keySet, translatorArray, isLocal);
  21649. }
  21650. };
  21651. IRoxieServerActivityFactory *createRoxieServerIndexCountActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, const RemoteActivityId &_remoteId)
  21652. {
  21653. return new CRoxieServerIndexCountActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _remoteId);
  21654. }
  21655. //--------------------------------------------------------------------------------------------------------------------------
  21656. class CRoxieServerNullIndexAggregateActivity : public CRoxieServerActivity
  21657. {
  21658. IHThorIndexAggregateArg &aggregateHelper;
  21659. bool done;
  21660. public:
  21661. CRoxieServerNullIndexAggregateActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  21662. : CRoxieServerActivity(_ctx, _factory, _probeManager),
  21663. aggregateHelper((IHThorIndexAggregateArg &)basehelper)
  21664. {
  21665. done = false;
  21666. }
  21667. virtual bool needsAllocator() const { return true; }
  21668. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  21669. {
  21670. done = false;
  21671. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  21672. }
  21673. virtual const void *nextRow()
  21674. {
  21675. ActivityTimer t(totalCycles, timeActivities);
  21676. if (done) return NULL;
  21677. done = true;
  21678. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  21679. size32_t thisSize = aggregateHelper.clearAggregate(rowBuilder);
  21680. return rowBuilder.finalizeRowClear(thisSize);
  21681. }
  21682. };
  21683. class CRoxieServerIndexAggregateActivity : public CRoxieServerIndexActivity
  21684. {
  21685. IHThorCompoundAggregateExtra & aggregateHelper;
  21686. bool done;
  21687. public:
  21688. CRoxieServerIndexAggregateActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  21689. IKeyArray * _keySet, TranslatorArray *_translators, bool _isLocal)
  21690. : CRoxieServerIndexActivity(_ctx, _factory, _probeManager, _remoteId, _keySet, _translators, false, _isLocal, false),
  21691. aggregateHelper((IHThorIndexAggregateArg &)basehelper),
  21692. done(false)
  21693. {
  21694. }
  21695. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  21696. {
  21697. done = false;
  21698. CRoxieServerIndexActivity::start(parentExtractSize, parentExtract, paused);
  21699. if (!paused)
  21700. processAllKeys();
  21701. }
  21702. virtual bool needsAllocator() const { return true; }
  21703. virtual bool processSingleKey(IKeyIndex *key, IRecordLayoutTranslator * trans)
  21704. {
  21705. RtlDynamicRowBuilder rowBuilder(rowAllocator, false);
  21706. while (tlk->lookup(true))
  21707. {
  21708. if (!rowBuilder.exists())
  21709. {
  21710. rowBuilder.ensureRow();
  21711. aggregateHelper.clearAggregate(rowBuilder);
  21712. }
  21713. try
  21714. {
  21715. aggregateHelper.processRow(rowBuilder, tlk->queryKeyBuffer());
  21716. callback.finishedRow();
  21717. }
  21718. catch (IException *E)
  21719. {
  21720. throw makeWrappedException(E);
  21721. }
  21722. accepted++;
  21723. }
  21724. if (aggregateHelper.processedAnyRows())
  21725. {
  21726. size32_t size = meta.getRecordSize(rowBuilder.getSelf());
  21727. const void * recBuffer = rowBuilder.finalizeRowClear(size);
  21728. Owned<CRowArrayMessageResult> result = new CRowArrayMessageResult(ctx->queryRowManager(), meta.isVariableSize());
  21729. result->append(recBuffer);
  21730. remote.injectResult(result.getClear());
  21731. }
  21732. return false;
  21733. }
  21734. virtual void onLimitExceeded(bool isKeyed)
  21735. {
  21736. if (traceLevel > 4)
  21737. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  21738. throwUnexpected();
  21739. }
  21740. virtual const void *createLimitFailRow(bool isKeyed)
  21741. {
  21742. throwUnexpected();
  21743. }
  21744. const void * gatherMerged()
  21745. {
  21746. RtlDynamicRowBuilder rowBuilder(rowAllocator, false);
  21747. const void * firstRow = remote.nextRow();
  21748. size32_t finalSize = 0;
  21749. if (!firstRow)
  21750. {
  21751. rowBuilder.ensureRow();
  21752. finalSize = aggregateHelper.clearAggregate(rowBuilder);
  21753. }
  21754. else
  21755. {
  21756. // NOTE need to clone this because going to modify below, could special case 1 row only
  21757. finalSize = cloneRow(rowBuilder, firstRow, meta);
  21758. ReleaseRoxieRow(firstRow);
  21759. }
  21760. for (;;)
  21761. {
  21762. const void * next = remote.nextRow();
  21763. if (!next)
  21764. break;
  21765. finalSize = aggregateHelper.mergeAggregate(rowBuilder, next);
  21766. ReleaseRoxieRow(next);
  21767. }
  21768. return rowBuilder.finalizeRowClear(finalSize);
  21769. }
  21770. virtual const void *nextRow()
  21771. {
  21772. ActivityTimer t(totalCycles, timeActivities);
  21773. if (done) return NULL;
  21774. const void * ret = gatherMerged();
  21775. done = true;
  21776. return ret;
  21777. }
  21778. };
  21779. class CRoxieServerIndexAggregateActivityFactory : public CRoxieServerBaseIndexActivityFactory
  21780. {
  21781. public:
  21782. CRoxieServerIndexAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, const RemoteActivityId &_remoteId)
  21783. : CRoxieServerBaseIndexActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _remoteId)
  21784. {
  21785. }
  21786. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  21787. {
  21788. if (!variableFileName && (keySet==NULL || keySet->length()==0))
  21789. return new CRoxieServerNullIndexAggregateActivity(_ctx, this, _probeManager);
  21790. // else if (isSimple)
  21791. // return new CRoxieServerSimpleIndexAggregateActivity(this, keySet->queryKeyPart(0)->queryPart(0));
  21792. else
  21793. return new CRoxieServerIndexAggregateActivity(_ctx, this, _probeManager, remoteId, keySet, translatorArray, isLocal);
  21794. }
  21795. };
  21796. IRoxieServerActivityFactory *createRoxieServerIndexAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, const RemoteActivityId &_remoteId)
  21797. {
  21798. return new CRoxieServerIndexAggregateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _remoteId);
  21799. }
  21800. //--------------------------------------------------------------------------------------------------------------------------
  21801. class CRoxieServerIndexGroupAggregateActivity : public CRoxieServerIndexActivity, implements IHThorGroupAggregateCallback
  21802. {
  21803. IHThorCompoundGroupAggregateExtra & aggregateHelper;
  21804. RowAggregator singleAggregator;
  21805. RowAggregator resultAggregator;
  21806. unsigned groupSegCount;
  21807. bool gathered;
  21808. bool eof;
  21809. public:
  21810. CRoxieServerIndexGroupAggregateActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  21811. IKeyArray * _keySet, TranslatorArray *_translators, bool _isLocal)
  21812. : CRoxieServerIndexActivity(_ctx, _factory, _probeManager, _remoteId, _keySet, _translators, false, _isLocal, false),
  21813. aggregateHelper((IHThorIndexGroupAggregateArg &)basehelper),
  21814. singleAggregator(aggregateHelper, aggregateHelper),
  21815. resultAggregator(aggregateHelper, aggregateHelper),
  21816. gathered(false), eof(true)
  21817. {
  21818. groupSegCount = 0;
  21819. }
  21820. IMPLEMENT_IINTERFACE_USING(CRoxieServerIndexActivity)
  21821. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  21822. {
  21823. eof = false;
  21824. gathered= false;
  21825. CRoxieServerIndexActivity::start(parentExtractSize, parentExtract, paused);
  21826. groupSegCount = 0;
  21827. if (!paused)
  21828. processAllKeys();
  21829. resultAggregator.start(rowAllocator);
  21830. }
  21831. virtual bool needsAllocator() const { return true; }
  21832. virtual void reset()
  21833. {
  21834. resultAggregator.reset();
  21835. CRoxieServerIndexActivity::reset();
  21836. }
  21837. virtual void processRow(const void * next)
  21838. {
  21839. singleAggregator.addRow(next);
  21840. }
  21841. virtual void createSegmentMonitors(IKeyManager *key)
  21842. {
  21843. unsigned groupSegSize;
  21844. ThorActivityKind kind = factory->getKind();
  21845. if ((kind==TAKindexgroupcount || kind==TAKindexgroupexists))
  21846. groupSegSize = aggregateHelper.getGroupSegmentMonitorsSize();
  21847. else
  21848. groupSegSize = 0;
  21849. if (groupSegSize)
  21850. {
  21851. CRoxieServerIndexActivity::createSegmentMonitors(key);
  21852. unsigned numSegs = tlk->ordinality();
  21853. for (unsigned segNo = 0; segNo < numSegs; segNo++)
  21854. {
  21855. IKeySegmentMonitor *seg = tlk->item(segNo);
  21856. if (seg->getOffset()+seg->getSize()==groupSegSize)
  21857. {
  21858. groupSegCount = segNo+1;
  21859. break;
  21860. }
  21861. }
  21862. assertex(groupSegCount);
  21863. }
  21864. else
  21865. CRoxieServerIndexActivity::createSegmentMonitors(key);
  21866. }
  21867. virtual bool processSingleKey(IKeyIndex *key, IRecordLayoutTranslator * trans)
  21868. {
  21869. Owned<CRowArrayMessageResult> result = new CRowArrayMessageResult(ctx->queryRowManager(), meta.isVariableSize());
  21870. singleAggregator.start(rowAllocator);
  21871. ThorActivityKind kind = factory->getKind();
  21872. while (tlk->lookup(true))
  21873. {
  21874. try
  21875. {
  21876. if (groupSegCount && !trans)
  21877. {
  21878. AggregateRowBuilder &rowBuilder = singleAggregator.addRow(tlk->queryKeyBuffer());
  21879. callback.finishedRow();
  21880. if (kind==TAKindexgroupcount)
  21881. {
  21882. unsigned __int64 count = tlk->getCurrentRangeCount(groupSegCount);
  21883. aggregateHelper.processCountGrouping(rowBuilder, count-1);
  21884. }
  21885. if (!tlk->nextRange(groupSegCount))
  21886. break;
  21887. }
  21888. else
  21889. {
  21890. aggregateHelper.processRow(tlk->queryKeyBuffer(), this);
  21891. callback.finishedRow();
  21892. }
  21893. }
  21894. catch (IException *E)
  21895. {
  21896. throw makeWrappedException(E);
  21897. }
  21898. accepted++;
  21899. }
  21900. for (;;)
  21901. {
  21902. Owned<AggregateRowBuilder> next = singleAggregator.nextResult();
  21903. if (!next)
  21904. break;
  21905. size32_t size = next->querySize();
  21906. result->append(next->finalizeRowClear());
  21907. }
  21908. remote.injectResult(result.getClear());
  21909. singleAggregator.reset();
  21910. return false;
  21911. }
  21912. virtual void onLimitExceeded(bool isKeyed)
  21913. {
  21914. if (traceLevel > 4)
  21915. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  21916. throwUnexpected();
  21917. }
  21918. virtual const void *createLimitFailRow(bool isKeyed)
  21919. {
  21920. throwUnexpected();
  21921. }
  21922. void gatherMerged()
  21923. {
  21924. gathered = true;
  21925. for (;;)
  21926. {
  21927. const void * next = remote.nextRow();
  21928. if (!next)
  21929. break;
  21930. resultAggregator.mergeElement(next);
  21931. ReleaseRoxieRow(next);
  21932. }
  21933. }
  21934. virtual const void *nextRow()
  21935. {
  21936. ActivityTimer t(totalCycles, timeActivities);
  21937. if (eof)
  21938. return NULL;
  21939. if (!gathered)
  21940. gatherMerged();
  21941. Owned<AggregateRowBuilder> next = resultAggregator.nextResult();
  21942. if (next)
  21943. {
  21944. processed++;
  21945. return next->finalizeRowClear();
  21946. }
  21947. eof = true;
  21948. return NULL;
  21949. }
  21950. };
  21951. class CRoxieServerIndexGroupAggregateActivityFactory : public CRoxieServerBaseIndexActivityFactory
  21952. {
  21953. public:
  21954. CRoxieServerIndexGroupAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, const RemoteActivityId &_remoteId)
  21955. : CRoxieServerBaseIndexActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _remoteId)
  21956. {
  21957. }
  21958. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  21959. {
  21960. if (!variableFileName && (keySet==NULL || keySet->length()==0))
  21961. return new CRoxieServerNullActivity(_ctx, this, _probeManager);
  21962. // else if (isSimple)
  21963. // return new CRoxieServerSimpleIndexGroupAggregateActivity(this, keySet->queryKeyPart(0)->queryPart(0));
  21964. else
  21965. return new CRoxieServerIndexGroupAggregateActivity(_ctx, this, _probeManager, remoteId, keySet, translatorArray, isLocal);
  21966. }
  21967. };
  21968. IRoxieServerActivityFactory *createRoxieServerIndexGroupAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, const RemoteActivityId &_remoteId)
  21969. {
  21970. return new CRoxieServerIndexGroupAggregateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _remoteId);
  21971. }
  21972. //--------------------------------------------------------------------------------------------------------------------------
  21973. class CRoxieServerIndexNormalizeActivity : public CRoxieServerIndexReadBaseActivity
  21974. {
  21975. IHThorIndexNormalizeArg & readHelper;
  21976. public:
  21977. CRoxieServerIndexNormalizeActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  21978. IKeyArray * _keySet, TranslatorArray *_translators, bool _sorted, bool _isLocal)
  21979. : CRoxieServerIndexReadBaseActivity(_ctx, _factory, _probeManager, _remoteId, _keySet, _translators, _sorted, _isLocal, false),
  21980. readHelper((IHThorIndexNormalizeArg &)basehelper)
  21981. {
  21982. limitTransformExtra = &readHelper;
  21983. }
  21984. virtual bool needsAllocator() const { return true; }
  21985. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  21986. {
  21987. CRoxieServerIndexReadBaseActivity::start(parentExtractSize, parentExtract, paused);
  21988. rowLimit = readHelper.getRowLimit();
  21989. keyedLimit = readHelper.getKeyedLimit();
  21990. choosenLimit = readHelper.getChooseNLimit();
  21991. if (!paused)
  21992. processAllKeys();
  21993. }
  21994. virtual bool processSingleKey(IKeyIndex *key, IRecordLayoutTranslator * trans)
  21995. {
  21996. unsigned keyedCount = 0;
  21997. RtlDynamicRowBuilder rowBuilder(rowAllocator, false);
  21998. while (tlk->lookup(true))
  21999. {
  22000. keyedCount++;
  22001. if (keyedCount > keyedLimit)
  22002. {
  22003. if (traceLevel > 4)
  22004. DBGLOG("activityid = %d line = %d", activityId, __LINE__);
  22005. onLimitExceeded(true);
  22006. break;
  22007. }
  22008. size32_t transformedSize;
  22009. if (readHelper.first(tlk->queryKeyBuffer()))
  22010. {
  22011. Owned<CRowArrayMessageResult> result = new CRowArrayMessageResult(ctx->queryRowManager(), meta.isVariableSize());
  22012. do
  22013. {
  22014. if (accepted>=choosenLimit)
  22015. break;
  22016. rowBuilder.ensureRow();
  22017. try
  22018. {
  22019. transformedSize = readHelper.transform(rowBuilder);
  22020. }
  22021. catch (IException *E)
  22022. {
  22023. throw makeWrappedException(E);
  22024. }
  22025. if (transformedSize)
  22026. {
  22027. // MORE - would be a good idea to stop these asap if rowlimit exceeded
  22028. result->append(rowBuilder.finalizeRowClear(transformedSize));
  22029. accepted++;
  22030. }
  22031. else
  22032. rejected++;
  22033. } while (readHelper.next());
  22034. remote.injectResult(result.getClear());
  22035. callback.finishedRow();
  22036. if (accepted>=choosenLimit)
  22037. return true;
  22038. }
  22039. }
  22040. return false;
  22041. }
  22042. virtual void onLimitExceeded(bool isKeyed)
  22043. {
  22044. if (traceLevel > 4)
  22045. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  22046. if (isKeyed)
  22047. {
  22048. if (indexHelper.getFlags() & (TIRkeyedlimitskips|TIRkeyedlimitcreates))
  22049. {
  22050. if (ctx->queryDebugContext())
  22051. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  22052. throw makeLimitSkipException(true);
  22053. }
  22054. else
  22055. readHelper.onKeyedLimitExceeded();
  22056. }
  22057. else
  22058. {
  22059. if (indexHelper.getFlags() & (TIRlimitskips||TIRlimitcreates))
  22060. {
  22061. if (ctx->queryDebugContext())
  22062. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  22063. throw makeLimitSkipException(false);
  22064. }
  22065. else
  22066. readHelper.onLimitExceeded();
  22067. }
  22068. }
  22069. virtual const void *createLimitFailRow(bool isKeyed)
  22070. {
  22071. UNIMPLEMENTED;
  22072. }
  22073. };
  22074. class CRoxieServerIndexNormalizeActivityFactory : public CRoxieServerBaseIndexActivityFactory
  22075. {
  22076. public:
  22077. CRoxieServerIndexNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, const RemoteActivityId &_remoteId)
  22078. : CRoxieServerBaseIndexActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _remoteId)
  22079. {
  22080. }
  22081. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  22082. {
  22083. if (!variableFileName && (keySet==NULL || keySet->length()==0))
  22084. return new CRoxieServerNullActivity(_ctx, this, _probeManager);
  22085. else
  22086. return new CRoxieServerIndexNormalizeActivity(_ctx, this, _probeManager, remoteId, keySet, translatorArray, sorted, isLocal);
  22087. }
  22088. };
  22089. IRoxieServerActivityFactory *createRoxieServerIndexNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, const RemoteActivityId &_remoteId)
  22090. {
  22091. return new CRoxieServerIndexNormalizeActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _remoteId);
  22092. }
  22093. //=================================================================================
  22094. class CRoxieServerFetchActivity : public CRoxieServerActivity, implements IRecordPullerCallback, implements IRoxieServerErrorHandler
  22095. {
  22096. IHThorFetchBaseArg &helper;
  22097. Linked<IFilePartMap> map;
  22098. CRemoteResultAdaptor remote;
  22099. RecordPullerThread puller;
  22100. bool needsRHS;
  22101. bool variableFileName;
  22102. bool isOpt;
  22103. Owned<const IResolvedFile> varFileInfo;
  22104. public:
  22105. CRoxieServerFetchActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, IFilePartMap *_map)
  22106. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorFetchBaseArg &)basehelper), map(_map), remote(_ctx, this, _remoteId, meta.queryOriginal(), helper, *this, true, true), puller(false)
  22107. {
  22108. needsRHS = helper.transformNeedsRhs();
  22109. variableFileName = allFilesDynamic || factory->queryQueryFactory().isDynamic() || ((helper.getFetchFlags() & (FFvarfilename|FFdynamicfilename)) != 0);
  22110. isOpt = (helper.getFetchFlags() & FFdatafileoptional) != 0;
  22111. }
  22112. virtual const IResolvedFile *queryVarFileInfo() const
  22113. {
  22114. return varFileInfo;
  22115. }
  22116. virtual void onCreate(IHThorArg *_colocalParent)
  22117. {
  22118. CRoxieServerActivity::onCreate(_colocalParent);
  22119. remote.onCreate(_colocalParent);
  22120. }
  22121. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  22122. {
  22123. if (idx)
  22124. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", sanitizeSourceFile(__FILE__), __LINE__);
  22125. puller.setInput(this, _sourceIdx, _in);
  22126. }
  22127. virtual IStrandJunction *getOutputStreams(IRoxieSlaveContext *ctx, unsigned idx, PointerArrayOf<IEngineRowStream> &streams, const StrandOptions * consumerOptions, bool consumerOrdered, IOrderedCallbackCollection * orderedCallbacks)
  22128. {
  22129. puller.connectInputStreams(ctx, consumerOrdered);
  22130. return CRoxieServerActivity::getOutputStreams(ctx, idx, streams, consumerOptions, consumerOrdered, orderedCallbacks);
  22131. }
  22132. virtual IFinalRoxieInput *queryInput(unsigned idx) const
  22133. {
  22134. if (idx==0)
  22135. return puller.queryInput();
  22136. else
  22137. return NULL;
  22138. }
  22139. virtual void gatherStats(CRuntimeStatisticCollection & merged) const override
  22140. {
  22141. CRoxieServerActivity::gatherStats(merged);
  22142. remote.gatherStats(merged);
  22143. }
  22144. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  22145. {
  22146. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  22147. remote.onStart(parentExtractSize, parentExtract);
  22148. remote.setLimits(helper.getRowLimit(), (unsigned __int64) -1, I64C(0x7FFFFFFFFFFFFFFF));
  22149. if (variableFileName)
  22150. {
  22151. OwnedRoxieString fname(helper.getFileName());
  22152. varFileInfo.setown(resolveLFN(fname, isOpt));
  22153. if (varFileInfo)
  22154. map.setown(varFileInfo->getFileMap());
  22155. }
  22156. puller.start(parentExtractSize, parentExtract, paused, ctx->queryOptions().fetchPreload, false, ctx);
  22157. }
  22158. virtual void stop()
  22159. {
  22160. // Called from remote, so no need to call back to it....
  22161. puller.stop();
  22162. CRoxieServerActivity::stop();
  22163. }
  22164. virtual void reset()
  22165. {
  22166. processed = remote.processed;
  22167. remote.processed = 0;
  22168. puller.reset();
  22169. if (variableFileName)
  22170. {
  22171. varFileInfo.clear();
  22172. map.clear();
  22173. }
  22174. CRoxieServerActivity::reset();
  22175. }
  22176. virtual IFinalRoxieInput *queryOutput(unsigned idx)
  22177. {
  22178. if (idx==(unsigned)-1)
  22179. idx = 0;
  22180. return idx ? NULL : &remote;
  22181. }
  22182. virtual void processRow(const void *row)
  22183. {
  22184. // called from puller thread
  22185. offset_t rp = helper.extractPosition(row);
  22186. unsigned partNo;
  22187. if (isLocalFpos(rp))
  22188. partNo = getLocalFposPart(rp) + 1;
  22189. else
  22190. partNo = map->mapOffset(rp);
  22191. if (needsRHS)
  22192. {
  22193. Owned<IEngineRowAllocator> extractAllocator = createRowAllocator(helper.queryExtractedSize());
  22194. RtlDynamicRowBuilder rb(extractAllocator, true);
  22195. unsigned rhsSize = helper.extractJoinFields(rb, row);
  22196. char * block = (char *) remote.getMem(partNo, 0, sizeof(rp) + sizeof(rhsSize) + rhsSize); // MORE - superfiles
  22197. *(offset_t *) block = rp;
  22198. block += sizeof(rp);
  22199. *(unsigned *) block = rhsSize;
  22200. block += sizeof(rhsSize);
  22201. memcpy(block, rb.row(), rhsSize);
  22202. }
  22203. else
  22204. *(offset_t *) remote.getMem(partNo, 0, sizeof(rp)) = rp; // MORE - superfiles
  22205. ReleaseRoxieRow(row);
  22206. }
  22207. void processEOG()
  22208. {
  22209. #ifdef FETCH_PRESERVES_GROUPING
  22210. UNIMPLEMENTED;
  22211. #endif
  22212. // else discard is correct
  22213. }
  22214. void processGroup(const ConstPointerArray &)
  22215. {
  22216. throwUnexpected();
  22217. }
  22218. void processDone()
  22219. {
  22220. // called from puller thread
  22221. remote.flush();
  22222. remote.senddone();
  22223. }
  22224. virtual bool fireException(IException *e)
  22225. {
  22226. return remote.fireException(e);
  22227. }
  22228. virtual void onLimitExceeded(bool isKeyed)
  22229. {
  22230. if (traceLevel > 4)
  22231. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  22232. if (isKeyed)
  22233. throwUnexpected();
  22234. helper.onLimitExceeded();
  22235. }
  22236. virtual const void *createLimitFailRow(bool isKeyed)
  22237. {
  22238. UNIMPLEMENTED;
  22239. }
  22240. virtual const void *nextRow()
  22241. {
  22242. throwUnexpected(); // I am nobody's input
  22243. }
  22244. };
  22245. class CRoxieServerFetchActivityFactory : public CRoxieServerActivityFactory
  22246. {
  22247. RemoteActivityId remoteId;
  22248. Owned<IFilePartMap> map;
  22249. bool variableFileName;
  22250. Owned<const IResolvedFile> datafile;
  22251. public:
  22252. CRoxieServerFetchActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, const RemoteActivityId &_remoteId)
  22253. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode), remoteId(_remoteId)
  22254. {
  22255. Owned<IHThorFetchBaseArg> helper = (IHThorFetchBaseArg *) helperFactory();
  22256. variableFileName = allFilesDynamic || _queryFactory.isDynamic() || ((helper->getFetchFlags() & (FFvarfilename|FFdynamicfilename)) != 0);
  22257. if (!variableFileName)
  22258. {
  22259. OwnedRoxieString fname(helper->getFileName());
  22260. datafile.setown(_queryFactory.queryPackage().lookupFileName(fname,
  22261. (helper->getFetchFlags() & FFdatafileoptional) != 0,
  22262. true, true,
  22263. _queryFactory.queryWorkUnit(), true));
  22264. if (datafile)
  22265. map.setown(datafile->getFileMap());
  22266. }
  22267. }
  22268. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  22269. {
  22270. return new CRoxieServerFetchActivity(_ctx, this, _probeManager, remoteId, map);
  22271. }
  22272. virtual void getXrefInfo(IPropertyTree &reply, const IRoxieContextLogger &logctx) const
  22273. {
  22274. if (datafile)
  22275. addXrefFileInfo(reply, datafile);
  22276. else
  22277. {
  22278. // Temporarily resolve the file
  22279. Owned<IHThorFetchBaseArg> helper = (IHThorFetchBaseArg *) helperFactory();
  22280. if ((helper->getFetchFlags() & (FFvarfilename|FFdynamicfilename)) == 0)
  22281. {
  22282. OwnedRoxieString fileName(helper->getFileName());
  22283. Owned<const IResolvedFile> temp = queryFactory.queryPackage().lookupFileName(fileName, true, true, false, queryFactory.queryWorkUnit(), true);
  22284. if (temp)
  22285. addXrefFileInfo(reply, temp);
  22286. }
  22287. }
  22288. }
  22289. virtual const StatisticsMapping &queryStatsMapping() const
  22290. {
  22291. return diskStatistics;
  22292. }
  22293. };
  22294. IRoxieServerActivityFactory *createRoxieServerFetchActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, const RemoteActivityId &_remoteId)
  22295. {
  22296. return new CRoxieServerFetchActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _remoteId);
  22297. }
  22298. // MORE - is there any point keeping this now?
  22299. class CRoxieServerDummyActivityFactory : public CRoxieServerActivityFactory // not a real activity - just used to properly link files
  22300. {
  22301. public:
  22302. Owned<const IResolvedFile> indexfile;
  22303. Owned<const IResolvedFile> datafile;
  22304. StringAttr fileName;
  22305. StringAttr indexName;
  22306. Owned<IKeyArray> keySet;
  22307. Owned<IFileIOArray> files;
  22308. TranslatorArray layoutTranslators;
  22309. CRoxieServerDummyActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool isLoadDataOnly)
  22310. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  22311. {
  22312. try // does not want any missing file errors to be fatal, or throw traps - just log it
  22313. {
  22314. if (_graphNode.getPropBool("att[@name='_isSpill']/@value", false) || _graphNode.getPropBool("att[@name='_isSpillGlobal']/@value", false))
  22315. return; // ignore 'spills'
  22316. bool isLocal = _graphNode.getPropBool("att[@name='local']/@value") && queryFactory.queryChannel()!=0;
  22317. ThorActivityKind kind = getActivityKind(_graphNode);
  22318. if (kind != TAKdiskwrite && kind != TAKindexwrite && kind != TAKpiperead && kind != TAKpipewrite)
  22319. {
  22320. fileName.set(queryNodeFileName(_graphNode, kind));
  22321. indexName.set(queryNodeIndexName(_graphNode, kind));
  22322. if (indexName && !allFilesDynamic && !queryFactory.isDynamic())
  22323. {
  22324. bool isOpt = pretendAllOpt || _graphNode.getPropBool("att[@name='_isIndexOpt']/@value");
  22325. indexfile.setown(queryFactory.queryPackage().lookupFileName(indexName, isOpt, true, true, queryFactory.queryWorkUnit(), true));
  22326. if (indexfile)
  22327. keySet.setown(indexfile->getKeyArray(NULL, &layoutTranslators, isOpt, isLocal ? queryFactory.queryChannel() : 0, IRecordLayoutTranslator::NoTranslation));
  22328. }
  22329. if (fileName && !allFilesDynamic && !queryFactory.isDynamic())
  22330. {
  22331. bool isOpt = pretendAllOpt || _graphNode.getPropBool("att[@name='_isOpt']/@value");
  22332. datafile.setown(_queryFactory.queryPackage().lookupFileName(fileName, isOpt, true, true, queryFactory.queryWorkUnit(), true));
  22333. if (datafile)
  22334. {
  22335. if (isLocal)
  22336. files.setown(datafile->getIFileIOArray(isOpt, queryFactory.queryChannel()));
  22337. }
  22338. }
  22339. }
  22340. }
  22341. catch(IException *E)
  22342. {
  22343. StringBuffer errors;
  22344. E->errorMessage(errors);
  22345. DBGLOG("%s File error = %s", (isLoadDataOnly) ? "LOADDATAONLY" : "SUSPENDED QUERY", errors.str());
  22346. E->Release();
  22347. }
  22348. }
  22349. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, 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(), sanitizeSourceFile(__FILE__), __LINE__); }
  22350. virtual void getXrefInfo(IPropertyTree &reply, const IRoxieContextLogger &logctx) const
  22351. {
  22352. if (!allFilesDynamic)
  22353. {
  22354. if (datafile)
  22355. addXrefFileInfo(reply, datafile);
  22356. if (indexfile)
  22357. addXrefFileInfo(reply, indexfile);
  22358. }
  22359. else
  22360. {
  22361. Owned<const IResolvedFile> temp;
  22362. if (fileName.length())
  22363. {
  22364. temp.setown(queryFactory.queryPackage().lookupFileName(fileName, true, true, false, queryFactory.queryWorkUnit(), true));
  22365. if (temp)
  22366. addXrefFileInfo(reply, temp);
  22367. }
  22368. if (indexName.length())
  22369. {
  22370. temp.setown(queryFactory.queryPackage().lookupFileName(indexName, true, true, false, queryFactory.queryWorkUnit(), true));
  22371. if (temp)
  22372. addXrefFileInfo(reply, temp);
  22373. }
  22374. }
  22375. }
  22376. };
  22377. IRoxieServerActivityFactory *createRoxieServerDummyActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool isLoadDataOnly)
  22378. {
  22379. return new CRoxieServerDummyActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, isLoadDataOnly);
  22380. }
  22381. //=====================================================================================================
  22382. // Keyed joins...
  22383. //
  22384. // Input records are pulled by a puller thread, which checks each LHS record to determine which (if any) channels it
  22385. // may have RHS matches on, and sends the relevant fields to the relevant slaves.
  22386. // 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
  22387. // the transform and returns rows that are created.
  22388. // 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)
  22389. //
  22390. //=====================================================================================================
  22391. class CJoinGroup;
  22392. interface IJoinProcessor
  22393. {
  22394. virtual void processEOG() = 0;
  22395. virtual CJoinGroup *createJoinGroup(const void *row) = 0;
  22396. virtual void noteEndReceived(CJoinGroup *jg, unsigned candidateCount) = 0;
  22397. virtual bool fireException(IException *E) = 0;
  22398. virtual void processCompletedGroups() = 0;
  22399. };
  22400. //------------------------------------------------------------------------------------------------------
  22401. // Class CJoinGroup has a record per LHS row, plus (if preserving grouping) a 'head of group' record
  22402. // It gathers all the corresponding RHS rows, keeping track of how may slave transactions are pending in endMarkersPending
  22403. // If preserving groups, the 'head of group' record keeps track of how many LHS records in the group are still incomplete.
  22404. // CJoinGroup records are allocated out of the Roxie row memory manager by overloading operator new, so that they are included in the
  22405. // per-query limits etc (Note that the pointer array block is not though).
  22406. // Because of that, the exact size is significant - especially whether fit just under or just over a chunking threshold...
  22407. //
  22408. // There are two phases to the life of a JoinGroup - it is created by the puller thread that is also firing off slave requests
  22409. // notePending will be called once for every slave request. Puller thread calls noteEndReceived(0) once when done - this corresponds to the
  22410. // initial count when created.
  22411. // Slave replies and are noted by the consumer thread calling addRightMatch() and noteEndReceived(n).
  22412. // Once endMarkersPending reaches 0, JoinGroup is complete. Last thread to call noteEndReceived will process the rows and destroy the group.
  22413. // There is no need for a critsec because although multiple threads will access at different times, only the consumer thread will
  22414. // access any modifiable member variables while endMarkersPending != 0 (i.e. complete() is false). Once complete returns true there is a single
  22415. // remaining reference and the JoinGroup will be processed and destroyed.
  22416. //
  22417. //------------------------------------------------------------------------------------------------------
  22418. class CJoinGroup : public CInterface
  22419. {
  22420. protected:
  22421. const void *left; // LHS row
  22422. PointerArrayOf<KeyedJoinHeader> rows; // matching RHS rows
  22423. atomic_t endMarkersPending; // How many slave responses still waiting for
  22424. CJoinGroup *groupStart; // Head of group, or NULL if not grouping
  22425. unsigned lastPartNo;
  22426. unsigned pos;
  22427. unsigned candidates; // Number of RHS keyed candidates - note this may not be the same as rows.ordinality()
  22428. public:
  22429. #undef new
  22430. void *operator new(size_t size, IRowManager *a, unsigned activityId)
  22431. {
  22432. return a->allocate(size, activityId);
  22433. }
  22434. #if defined(_DEBUG) && defined(_WIN32) && !defined(USING_MPATROL)
  22435. #define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
  22436. #endif
  22437. void operator delete(void *ptr, IRowManager *a, unsigned activityId)
  22438. {
  22439. ReleaseRoxieRow(ptr);
  22440. }
  22441. void operator delete(void *ptr)
  22442. {
  22443. ReleaseRoxieRow(ptr);
  22444. }
  22445. public:
  22446. CJoinGroup(const void *_left, CJoinGroup *_groupStart)
  22447. {
  22448. #ifdef TRACE_JOINGROUPS
  22449. DBGLOG("Creating joinGroup %p, groupstart %p", this, _groupStart);
  22450. #endif
  22451. candidates = 0;
  22452. lastPartNo = 0;
  22453. pos = 0;
  22454. left = _left;
  22455. groupStart = _groupStart;
  22456. if (_groupStart)
  22457. {
  22458. atomic_inc(&_groupStart->endMarkersPending);
  22459. }
  22460. atomic_set(&endMarkersPending, 1);
  22461. }
  22462. ~CJoinGroup()
  22463. {
  22464. #ifdef TRACE_JOINGROUPS
  22465. DBGLOG("Destroying joinGroup %p", this);
  22466. #endif
  22467. if (left)
  22468. {
  22469. ReleaseRoxieRow(left);
  22470. roxiemem::ReleaseRoxieRowArray(rows.ordinality(), (const void * *)rows.getArray());
  22471. rows.kill();
  22472. }
  22473. }
  22474. inline bool isHeadRecord() const
  22475. {
  22476. return left==NULL;
  22477. }
  22478. inline bool complete() const
  22479. {
  22480. return atomic_read(&endMarkersPending) == 0;
  22481. }
  22482. #ifdef TRACE_JOINGROUPS
  22483. inline void notePending(unsigned lineNo)
  22484. #else
  22485. inline void notePending()
  22486. #endif
  22487. {
  22488. assert(!complete());
  22489. atomic_inc(&endMarkersPending);
  22490. #ifdef TRACE_JOINGROUPS
  22491. DBGLOG("CJoinGroup::notePending %p from %d, count became %d group count %d", this, lineNo, atomic_read(&endMarkersPending), groupStart ? atomic_read(&groupStart->endMarkersPending) : 0);
  22492. #endif
  22493. }
  22494. inline bool inGroup(CJoinGroup *leader) const
  22495. {
  22496. return groupStart==leader;
  22497. }
  22498. inline const KeyedJoinHeader *queryRow(unsigned idx) const
  22499. {
  22500. // Single threaded by now
  22501. assert(complete());
  22502. return rows.item(idx);
  22503. }
  22504. #ifdef TRACE_JOINGROUPS
  22505. bool noteEndReceived(unsigned candidateCount, unsigned lineNo)
  22506. #else
  22507. bool noteEndReceived(unsigned candidateCount)
  22508. #endif
  22509. {
  22510. assert(!complete());
  22511. if (candidateCount)
  22512. {
  22513. candidates += candidateCount;
  22514. }
  22515. #ifdef TRACE_JOINGROUPS
  22516. 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);
  22517. #endif
  22518. // NOTE - as soon as endMarkersPending and groupStart->endMarkersPending are decremented to zero this object may get released asynchronously by other threads
  22519. // There must therefore be nothing in this method after them that acceses member variables. Think of it as a delete this...
  22520. // In particular, we can't safely reference groupStart after the dec_and_test of endMarkersPending, hence copy local first
  22521. CJoinGroup *localGroupStart = groupStart;
  22522. if (atomic_dec_and_test(&endMarkersPending))
  22523. {
  22524. if (localGroupStart)
  22525. return atomic_dec_and_test(&localGroupStart->endMarkersPending);
  22526. else
  22527. return true;
  22528. }
  22529. else
  22530. return false;
  22531. }
  22532. inline const void *queryLeft() const
  22533. {
  22534. return left;
  22535. }
  22536. void addRightMatch(KeyedJoinHeader *right)
  22537. {
  22538. assert(!complete());
  22539. unsigned short partNo = right->partNo;
  22540. if (partNo != lastPartNo)
  22541. {
  22542. // MORE - should we binchop? If we did we would need to be careful to find LAST match
  22543. if (partNo > lastPartNo)
  22544. pos = rows.length();
  22545. while (pos>0)
  22546. {
  22547. if (rows.item(pos-1)->partNo <= partNo)
  22548. break;
  22549. pos--;
  22550. }
  22551. lastPartNo = partNo;
  22552. }
  22553. rows.add(right, pos);
  22554. pos++;
  22555. }
  22556. inline unsigned rowsSeen() const
  22557. {
  22558. assert(complete());
  22559. return rows.length();
  22560. }
  22561. inline unsigned candidateCount() const
  22562. {
  22563. assert(complete());
  22564. return candidates;
  22565. }
  22566. };
  22567. #ifdef TRACE_JOINGROUPS
  22568. #define notePending() notePending(__LINE__)
  22569. #define noteEndReceived(a) noteEndReceived(a, __LINE__)
  22570. #endif
  22571. class KeyedJoinRemoteAdaptor : public CRemoteResultAdaptor // MORE - not sure it should be derived from this - makes processed all wrong, for example
  22572. {
  22573. private:
  22574. SafeQueueOf<const void, true> ready;
  22575. public:
  22576. IHThorKeyedJoinArg &helper;
  22577. unsigned joinProcessed;
  22578. bool isFullKey;
  22579. bool eof;
  22580. bool isSimple;
  22581. bool allPulled;
  22582. ActivityTimeAccumulator totalCycles;
  22583. unsigned activityId;
  22584. RecordPullerThread &puller;
  22585. SafeQueueOf<const void, true> injected; // Used in isSimple mode
  22586. Owned<IEngineRowAllocator> ccdRecordAllocator;
  22587. IJoinProcessor &processor;
  22588. KeyedJoinRemoteAdaptor(IRoxieSlaveContext *_ctx, IRoxieServerErrorHandler *_errorHandler, const RemoteActivityId &_remoteId, IHThorKeyedJoinArg &_helper,
  22589. IRoxieServerActivity &_activity, bool _isFullKey, bool _isSimple,
  22590. RecordPullerThread &_puller, IJoinProcessor &_processor)
  22591. : helper(_helper),
  22592. CRemoteResultAdaptor(_ctx, _errorHandler, _remoteId, 0, _helper, _activity, true, true),
  22593. isFullKey(_isFullKey),
  22594. isSimple(_isSimple),
  22595. puller(_puller),
  22596. processor(_processor),
  22597. activityId(_activity.queryId())
  22598. {
  22599. joinProcessed = 0;
  22600. allPulled = false;
  22601. eof = false;
  22602. }
  22603. virtual void onCreate(IHThorArg *_colocalArg)
  22604. {
  22605. CRemoteResultAdaptor::onCreate(_colocalArg);
  22606. ccdRecordAllocator.setown(activity.createRowAllocator(helper.queryJoinFieldsRecordSize()));
  22607. }
  22608. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  22609. {
  22610. eof = false;
  22611. joinProcessed = 0;
  22612. totalCycles.totalCycles = 0;
  22613. allPulled = false;
  22614. assertex(ready.ordinality()==0);
  22615. CRemoteResultAdaptor::start(parentExtractSize, parentExtract, paused);
  22616. }
  22617. virtual void reset()
  22618. {
  22619. CRemoteResultAdaptor::reset();
  22620. while (ready.ordinality())
  22621. {
  22622. const void *goer = ready.dequeue();
  22623. if (goer)
  22624. ReleaseRoxieRow(goer);
  22625. }
  22626. while (injected.ordinality())
  22627. {
  22628. const void *goer = injected.dequeue();
  22629. if (goer)
  22630. ReleaseRoxieRow(goer);
  22631. }
  22632. }
  22633. inline void addResult(const void *row)
  22634. {
  22635. ready.enqueue(row);
  22636. }
  22637. virtual unsigned __int64 queryTotalCycles() const
  22638. {
  22639. return totalCycles.totalCycles;
  22640. }
  22641. virtual const void *nextRow()
  22642. {
  22643. ActivityTimer t(totalCycles, timeActivities);
  22644. for (;;)
  22645. {
  22646. if (eof)
  22647. return NULL;
  22648. processSlaveResults();
  22649. if (ready.ordinality())
  22650. {
  22651. const void *result = ready.dequeue();
  22652. if (result)
  22653. joinProcessed++;
  22654. return result;
  22655. }
  22656. else
  22657. eof = true;
  22658. }
  22659. }
  22660. void gatherStats(CRuntimeStatisticCollection & merged) const
  22661. {
  22662. CRemoteResultAdaptor::gatherStats(merged);
  22663. if (ccdRecordAllocator)
  22664. ccdRecordAllocator->gatherStats(merged);
  22665. }
  22666. private:
  22667. void processSlaveResults()
  22668. {
  22669. while (!ready.ordinality())
  22670. {
  22671. KeyedJoinHeader *fetchedData;
  22672. if (isSimple)
  22673. {
  22674. while (!allPulled && !injected.ordinality())
  22675. {
  22676. if (!puller.pullRecords(1))
  22677. {
  22678. puller.done();
  22679. allPulled = true;
  22680. }
  22681. }
  22682. fetchedData = (KeyedJoinHeader *) injected.dequeue();
  22683. }
  22684. else
  22685. fetchedData = (KeyedJoinHeader *) CRemoteResultAdaptor::nextRow();
  22686. if (fetchedData)
  22687. {
  22688. CJoinGroup *thisGroup = fetchedData->thisGroup;
  22689. if (fetchedData->partNo == (unsigned short) -1)
  22690. {
  22691. #ifdef TRACE_JOINGROUPS
  22692. CTXLOG("Got end for group %p", thisGroup);
  22693. #endif
  22694. unsigned candidateCount = (unsigned) fetchedData->fpos;
  22695. ReleaseRoxieRow(fetchedData);
  22696. processor.noteEndReceived(thisGroup, candidateCount); // note - this can throw exception. So release fetchdata before calling
  22697. }
  22698. else
  22699. {
  22700. #ifdef TRACE_JOINGROUPS
  22701. CTXLOG("Reading another %d bytes for group %p data", ccdRecordSize, thisGroup);
  22702. #endif
  22703. thisGroup->addRightMatch(fetchedData);
  22704. if (isFullKey)
  22705. {
  22706. #ifdef TRACE_JOINGROUPS
  22707. CTXLOG("Calling noteEndReceived for record returned from FETCH of full keyed join");
  22708. #endif
  22709. processor.noteEndReceived(thisGroup, 0); // note - this can throw exception. So release fetchdata before calling
  22710. }
  22711. }
  22712. }
  22713. else
  22714. break;
  22715. }
  22716. }
  22717. };
  22718. class CRoxieServerFullKeyedJoinHead: public CRoxieServerActivity, implements IRecordPullerCallback, implements IRoxieServerErrorHandler
  22719. {
  22720. IHThorKeyedJoinArg &helper;
  22721. Owned<IKeyManager> tlk;
  22722. Linked<IKeyArray> keySet;
  22723. Linked<TranslatorArray> translators;
  22724. CRemoteResultAdaptor remote;
  22725. RecordPullerThread puller;
  22726. IOutputMetaData *indexReadMeta;
  22727. IJoinProcessor *joinHandler;
  22728. bool variableIndexFileName;
  22729. bool indexReadInputRecordVariable;
  22730. bool isLocal;
  22731. Owned<IEngineRowAllocator> indexReadAllocator;
  22732. Owned<const IResolvedFile> varFileInfo;
  22733. IFinalRoxieInput *indexReadInput;
  22734. unsigned indexReadIdx = 0;
  22735. IIndexReadActivityInfo *rootIndex;
  22736. public:
  22737. CRoxieServerFullKeyedJoinHead(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, IKeyArray * _keySet, TranslatorArray *_translators, IOutputMetaData *_indexReadMeta, IJoinProcessor *_joinHandler, bool _isLocal)
  22738. : CRoxieServerActivity(_ctx, _factory, _probeManager),
  22739. helper((IHThorKeyedJoinArg &)basehelper),
  22740. tlk(createLocalKeyManager(helper.queryIndexRecordSize()->queryRecordAccessor(true), NULL, this)),
  22741. translators(_translators),
  22742. keySet(_keySet),
  22743. remote(_ctx, this, _remoteId, 0, helper, *this, true, true),
  22744. indexReadMeta(_indexReadMeta),
  22745. joinHandler(_joinHandler),
  22746. puller(false),
  22747. isLocal(_isLocal)
  22748. {
  22749. variableIndexFileName = allFilesDynamic || factory->queryQueryFactory().isDynamic() || ((helper.getJoinFlags() & (JFvarindexfilename|JFdynamicindexfilename|JFindexfromactivity)) != 0);
  22750. indexReadInputRecordVariable = indexReadMeta->isVariableSize();
  22751. indexReadInput = NULL;
  22752. rootIndex = NULL;
  22753. }
  22754. virtual const IResolvedFile *queryVarFileInfo() const
  22755. {
  22756. return varFileInfo;
  22757. }
  22758. virtual void onCreate(IHThorArg *_colocalParent)
  22759. {
  22760. CRoxieServerActivity::onCreate(_colocalParent);
  22761. remote.onCreate(_colocalParent);
  22762. indexReadAllocator.setown(createRowAllocator(indexReadMeta));
  22763. }
  22764. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  22765. {
  22766. if (!idx)
  22767. puller.setInput(this, _sourceIdx, _in);
  22768. else if (idx==1)
  22769. {
  22770. indexReadInput = _in;
  22771. indexReadIdx = _sourceIdx;
  22772. }
  22773. else
  22774. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", sanitizeSourceFile(__FILE__), __LINE__);
  22775. }
  22776. virtual IStrandJunction *getOutputStreams(IRoxieSlaveContext *ctx, unsigned idx, PointerArrayOf<IEngineRowStream> &streams, const StrandOptions * consumerOptions, bool consumerOrdered, IOrderedCallbackCollection * orderedCallbacks)
  22777. {
  22778. puller.connectInputStreams(ctx, consumerOrdered);
  22779. //No rows are read from indexReadInput, so no need to extract the streams
  22780. return CRoxieServerActivity::getOutputStreams(ctx, idx, streams, consumerOptions, consumerOrdered, orderedCallbacks);
  22781. }
  22782. virtual IFinalRoxieInput *queryInput(unsigned idx) const
  22783. {
  22784. switch (idx)
  22785. {
  22786. case 0:
  22787. return puller.queryInput();
  22788. case 1:
  22789. return indexReadInput;
  22790. default:
  22791. return NULL;
  22792. }
  22793. }
  22794. virtual void serializeExtra(MemoryBuffer &out)
  22795. {
  22796. if (helper.getJoinFlags() & JFindexfromactivity)
  22797. {
  22798. assertex(rootIndex);
  22799. const RemoteActivityId& indexId = rootIndex->queryRemoteId();
  22800. indexId.serialize(out);
  22801. // could mess about reserving space for length then patching it again, to avoid copy, but probably not worth it
  22802. MemoryBuffer tmp;
  22803. rootIndex->queryActivity()->serializeCreateStartContext(tmp);
  22804. if (rootIndex->queryActivity()->queryVarFileInfo())
  22805. {
  22806. rootIndex->queryActivity()->queryVarFileInfo()->queryTimeStamp().serialize(tmp);
  22807. tmp.append(rootIndex->queryActivity()->queryVarFileInfo()->queryCheckSum());
  22808. }
  22809. unsigned ctxlen = tmp.length();
  22810. out.append(ctxlen).append(tmp);
  22811. }
  22812. }
  22813. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  22814. {
  22815. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  22816. if (indexReadInput)
  22817. {
  22818. indexReadInput->start(parentExtractSize, parentExtract, true); // paused=true because we don't want to actually run the index read
  22819. rootIndex = indexReadInput->queryIndexReadActivity();
  22820. if (!rootIndex)
  22821. throw MakeStringException(ROXIE_INTERNAL_ERROR,"Index in keyed join %d could not be resolved", queryId());
  22822. }
  22823. remote.onStart(parentExtractSize, parentExtract);
  22824. remote.setLimits(helper.getRowLimit(), (unsigned __int64) -1, I64C(0x7FFFFFFFFFFFFFFF));
  22825. if (rootIndex)
  22826. {
  22827. varFileInfo.setown(rootIndex->getVarFileInfo());
  22828. translators.setown(rootIndex->getTranslators());
  22829. keySet.setown(rootIndex->getKeySet());
  22830. }
  22831. else if (variableIndexFileName)
  22832. {
  22833. OwnedRoxieString indexFileName(helper.getIndexFileName());
  22834. varFileInfo.setown(resolveLFN(indexFileName, (helper.getJoinFlags() & JFindexoptional) != 0));
  22835. if (varFileInfo)
  22836. {
  22837. translators.setown(new TranslatorArray);
  22838. keySet.setown(varFileInfo->getKeyArray(factory->queryActivityMeta(), translators, false, isLocal ? factory->queryQueryFactory().queryChannel() : 0, factory->queryQueryFactory().queryOptions().enableFieldTranslation)); // MORE - isLocal?
  22839. }
  22840. }
  22841. puller.start(parentExtractSize, parentExtract, paused, ctx->queryOptions().fullKeyedJoinPreload, false, ctx);
  22842. }
  22843. virtual void stop()
  22844. {
  22845. puller.stop();
  22846. CRoxieServerActivity::stop();
  22847. }
  22848. virtual void reset()
  22849. {
  22850. CRoxieServerActivity::reset();
  22851. puller.reset();
  22852. if (varFileInfo)
  22853. {
  22854. keySet.clear();
  22855. varFileInfo.clear();
  22856. }
  22857. }
  22858. virtual IFinalRoxieInput *queryOutput(unsigned idx)
  22859. {
  22860. if (idx==(unsigned)-1)
  22861. idx = 0;
  22862. return idx ? NULL : &remote;
  22863. }
  22864. virtual void processRow(const void *row)
  22865. {
  22866. // MORE - this code seems to be pretty much duplicated below in half-keyed....
  22867. // called from front puller thread
  22868. // buffer up an IndexRead request
  22869. if (keySet && helper.leftCanMatch(row))
  22870. {
  22871. RtlDynamicRowBuilder extractedBuilder(indexReadAllocator);
  22872. unsigned indexReadSize = helper.extractIndexReadFields(extractedBuilder, row);
  22873. OwnedConstRoxieRow extracted;
  22874. if (indexReadSize)
  22875. extracted.setown(extractedBuilder.finalizeRowClear(indexReadSize));
  22876. CJoinGroup *jg = joinHandler->createJoinGroup(row);
  22877. for (unsigned partNo = 0; partNo < keySet->length(); partNo++)
  22878. {
  22879. IKeyIndexBase *thisBase = keySet->queryKeyPart(partNo);
  22880. if (thisBase)
  22881. {
  22882. unsigned fileNo = 0;
  22883. IKeyIndex *thisKey = thisBase->queryPart(fileNo);
  22884. try
  22885. {
  22886. tlk->setKey(thisKey);
  22887. if (!thisKey->isTopLevelKey())
  22888. tlk->setLayoutTranslator(translators->item(fileNo));
  22889. else
  22890. tlk->setLayoutTranslator(nullptr);
  22891. helper.createSegmentMonitors(tlk, extracted);
  22892. if (rootIndex)
  22893. rootIndex->mergeSegmentMonitors(tlk);
  22894. tlk->finishSegmentMonitors();
  22895. tlk->reset();
  22896. for (;;)
  22897. {
  22898. typedef const void * cvp;
  22899. if (thisKey->isTopLevelKey())
  22900. {
  22901. bool locallySorted = !thisKey->isFullySorted();
  22902. while (locallySorted || tlk->lookup(false))
  22903. {
  22904. unsigned slavePart = locallySorted ? 0 : (unsigned)extractFpos(tlk);
  22905. if (locallySorted || slavePart)
  22906. {
  22907. cvp *outputBuffer = (cvp *) remote.getMem(slavePart, fileNo, indexReadSize + sizeof(cvp) + (indexReadInputRecordVariable ? sizeof(unsigned) : 0));
  22908. *outputBuffer++ = jg;
  22909. if (indexReadInputRecordVariable)
  22910. {
  22911. *(unsigned *) outputBuffer = indexReadSize;
  22912. outputBuffer = (cvp*) (((unsigned *) outputBuffer) + 1);
  22913. }
  22914. jg->notePending();
  22915. memcpy(outputBuffer, extracted, indexReadSize);
  22916. if (locallySorted)
  22917. {
  22918. for (unsigned i = 1; i < numChannels; i++)
  22919. jg->notePending();
  22920. break;
  22921. }
  22922. }
  22923. }
  22924. }
  22925. else
  22926. {
  22927. // MORE - this code seems to be duplicated in half keyed
  22928. unsigned accepted = 0;
  22929. unsigned rejected = 0;
  22930. Owned<CRowArrayMessageResult> result = new CRowArrayMessageResult(ctx->queryRowManager(), true);
  22931. jg->notePending();
  22932. unsigned candidateCount = 0;
  22933. while (tlk->lookup(true))
  22934. {
  22935. candidateCount++;
  22936. atomic_inc(&indexRecordsRead);
  22937. KLBlobProviderAdapter adapter(tlk);
  22938. const byte *indexRow = tlk->queryKeyBuffer();
  22939. size_t fposOffset = tlk->queryRowSize() - sizeof(offset_t);
  22940. offset_t fpos = rtlReadBigUInt8(indexRow + fposOffset);
  22941. if (helper.indexReadMatch(extracted, indexRow, &adapter))
  22942. {
  22943. KeyedJoinHeader *rhs = (KeyedJoinHeader *) ctx->queryRowManager().allocate(KEYEDJOIN_RECORD_SIZE(0), activityId);
  22944. rhs->fpos = fpos;
  22945. rhs->thisGroup = jg;
  22946. rhs->partNo = partNo;
  22947. result->append(rhs);
  22948. }
  22949. else
  22950. {
  22951. rejected++;
  22952. atomic_inc(&postFiltered);
  22953. }
  22954. }
  22955. // output an end marker for the matches to this group
  22956. KeyedJoinHeader *endMarker = (KeyedJoinHeader *) ctx->queryRowManager().allocate(KEYEDJOIN_RECORD_SIZE(0), activityId);
  22957. endMarker->fpos = (offset_t) candidateCount;
  22958. endMarker->thisGroup = jg;
  22959. endMarker->partNo = (unsigned short) -1;
  22960. result->append(endMarker);
  22961. remote.injectResult(result.getClear());
  22962. if (accepted)
  22963. noteStatistic(StNumIndexAccepted, accepted);
  22964. if (rejected)
  22965. noteStatistic(StNumIndexRejected, rejected);
  22966. }
  22967. if (++fileNo < thisBase->numParts())
  22968. {
  22969. thisKey = thisBase->queryPart(fileNo);
  22970. tlk->setKey(thisKey);
  22971. if (!thisKey->isTopLevelKey())
  22972. tlk->setLayoutTranslator(translators->item(fileNo));
  22973. else
  22974. tlk->setLayoutTranslator(nullptr);
  22975. tlk->reset();
  22976. }
  22977. else
  22978. break;
  22979. }
  22980. tlk->releaseSegmentMonitors();
  22981. tlk->setKey(NULL);
  22982. }
  22983. catch (...)
  22984. {
  22985. tlk->releaseSegmentMonitors();
  22986. tlk->setKey(NULL);
  22987. throw;
  22988. }
  22989. }
  22990. }
  22991. joinHandler->noteEndReceived(jg, 0);
  22992. }
  22993. else
  22994. {
  22995. joinHandler->noteEndReceived(joinHandler->createJoinGroup(row), 0);
  22996. }
  22997. }
  22998. void processGroup(const ConstPointerArray &)
  22999. {
  23000. throwUnexpected();
  23001. }
  23002. virtual void processEOG()
  23003. {
  23004. joinHandler->processEOG();
  23005. }
  23006. virtual void processDone()
  23007. {
  23008. // called from puller thread
  23009. remote.flush();
  23010. remote.senddone();
  23011. }
  23012. virtual void onLimitExceeded(bool isKeyed)
  23013. {
  23014. if (traceLevel > 4)
  23015. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  23016. if (isKeyed)
  23017. throwUnexpected();
  23018. helper.onLimitExceeded();
  23019. }
  23020. virtual const void *createLimitFailRow(bool isKeyed)
  23021. {
  23022. throwUnexpected();
  23023. }
  23024. virtual bool fireException(IException *e)
  23025. {
  23026. // called from puller thread on failure
  23027. remote.fireException(LINK(e));
  23028. return joinHandler->fireException(e);
  23029. }
  23030. virtual const void *nextRow()
  23031. {
  23032. throwUnexpected(); // I am nobody's input
  23033. }
  23034. virtual void gatherStats(CRuntimeStatisticCollection & merged) const override
  23035. {
  23036. CRoxieServerActivity::gatherStats(merged);
  23037. remote.gatherStats(merged);
  23038. if (indexReadAllocator)
  23039. indexReadAllocator->gatherStats(merged);
  23040. }
  23041. };
  23042. class CRoxieServerKeyedJoinBase : public CRoxieServerActivity, implements IRecordPullerCallback, implements IRoxieServerErrorHandler, implements IJoinProcessor
  23043. {
  23044. protected:
  23045. IHThorKeyedJoinArg &helper;
  23046. KeyedJoinRemoteAdaptor remote;
  23047. RecordPullerThread puller;
  23048. OwnedConstRoxieRow defaultRight;
  23049. Owned<IEngineRowAllocator> defaultRightAllocator;
  23050. unsigned joinFlags;
  23051. unsigned atMost;
  23052. unsigned atmostsTriggered;
  23053. unsigned abortLimit;
  23054. unsigned keepLimit;
  23055. bool limitFail;
  23056. bool limitOnFail;
  23057. bool preserveGroups;
  23058. bool cloneLeft;
  23059. bool isSimple;
  23060. bool isLocal;
  23061. ThorActivityKind activityKind;
  23062. CJoinGroup *groupStart;
  23063. CriticalSection groupsCrit;
  23064. QueueOf<CJoinGroup, false> groups;
  23065. IFinalRoxieInput *indexReadInput;
  23066. unsigned indexReadIdx = 0;
  23067. Owned<IStrandJunction> indexReadJunction;
  23068. IEngineRowStream *indexReadStream = NULL; // Never actually pulled
  23069. IIndexReadActivityInfo *rootIndex;
  23070. void createDefaultRight()
  23071. {
  23072. if (!defaultRight)
  23073. {
  23074. if (!defaultRightAllocator)
  23075. defaultRightAllocator.setown(createRowAllocator(helper.queryJoinFieldsRecordSize()));
  23076. RtlDynamicRowBuilder rowBuilder(defaultRightAllocator);
  23077. size32_t thisSize = helper.createDefaultRight(rowBuilder);
  23078. defaultRight.setown(rowBuilder.finalizeRowClear(thisSize));
  23079. }
  23080. }
  23081. public:
  23082. CRoxieServerKeyedJoinBase(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _joinFlags
  23083. , bool isFull, bool _isSimple, bool _isLocal)
  23084. : CRoxieServerActivity(_ctx, _factory, _probeManager),
  23085. helper((IHThorKeyedJoinArg &)basehelper),
  23086. remote(_ctx, this, _remoteId, helper, *this, isFull, _isSimple, puller, *this),
  23087. joinFlags(_joinFlags),
  23088. preserveGroups(meta.isGrouped()),
  23089. puller(false),
  23090. isSimple(_isSimple),
  23091. isLocal(_isLocal),
  23092. abortLimit(0),
  23093. keepLimit(0),
  23094. atMost(0),
  23095. limitFail(false),
  23096. limitOnFail(false),
  23097. cloneLeft(false)
  23098. {
  23099. groupStart = NULL;
  23100. activityKind = _factory->getKind();
  23101. indexReadInput = NULL;
  23102. rootIndex = NULL;
  23103. atmostsTriggered = 0;
  23104. // MORE - code would be easier to read if I got more values from helper rather than passing from factory
  23105. }
  23106. virtual void onCreate(IHThorArg *_colocalParent)
  23107. {
  23108. CRoxieServerActivity::onCreate(_colocalParent);
  23109. remote.onCreate(_colocalParent);
  23110. }
  23111. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  23112. {
  23113. if (!idx)
  23114. puller.setInput(this, _sourceIdx, _in);
  23115. else if (idx==1)
  23116. {
  23117. indexReadInput = _in;
  23118. indexReadIdx = _sourceIdx;
  23119. }
  23120. else
  23121. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", sanitizeSourceFile(__FILE__), __LINE__);
  23122. }
  23123. virtual void connectInputStreams(bool consumerOrdered)
  23124. {
  23125. CRoxieServerActivity::connectInputStreams(consumerOrdered);
  23126. puller.connectInputStreams(ctx, consumerOrdered);
  23127. if (indexReadInput)
  23128. indexReadStream = connectSingleStream(ctx, indexReadInput, indexReadIdx, indexReadJunction, consumerOrdered); // We never actually pull the stream
  23129. }
  23130. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  23131. {
  23132. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  23133. if (indexReadInput)
  23134. {
  23135. indexReadInput->start(parentExtractSize, parentExtract, true); // paused=true because we don't want to actually run the index read
  23136. rootIndex = indexReadInput->queryIndexReadActivity();
  23137. if (!rootIndex)
  23138. throw MakeStringException(ROXIE_INTERNAL_ERROR,"Index in keyed join %d could not be resolved", queryId());
  23139. }
  23140. remote.onStart(parentExtractSize, parentExtract);
  23141. remote.setLimits(helper.getRowLimit(), (unsigned __int64) -1, I64C(0x7FFFFFFFFFFFFFFF));
  23142. atmostsTriggered = 0;
  23143. atMost = helper.getJoinLimit();
  23144. if (atMost == 0) atMost = (unsigned)-1;
  23145. abortLimit = helper.getMatchAbortLimit();
  23146. if (abortLimit == 0 || atMost != (unsigned) -1) abortLimit = (unsigned)-1;
  23147. keepLimit = helper.getKeepLimit();
  23148. if (keepLimit == 0) keepLimit = (unsigned)-1;
  23149. getLimitType(joinFlags, limitFail, limitOnFail);
  23150. cloneLeft = (joinFlags & JFtransformmatchesleft) != 0;
  23151. if (joinFlags & JFleftouter || limitOnFail)
  23152. createDefaultRight();
  23153. }
  23154. virtual void stop()
  23155. {
  23156. puller.stop();
  23157. if (indexReadStream)
  23158. indexReadStream->stop(); // Could probably do this as soon as re have fetched rootIndex?
  23159. CRoxieServerActivity::stop();
  23160. }
  23161. virtual unsigned __int64 queryLocalCycles() const
  23162. {
  23163. __int64 localCycles = remote.totalCycles.totalCycles;
  23164. localCycles -= puller.queryTotalCycles(); // MORE - debatable... but probably fair.
  23165. if (localCycles < 0)
  23166. localCycles = 0;
  23167. return localCycles;
  23168. }
  23169. virtual void gatherStats(CRuntimeStatisticCollection & merged) const override
  23170. {
  23171. CRoxieServerActivity::gatherStats(merged);
  23172. remote.gatherStats(merged);
  23173. }
  23174. virtual IFinalRoxieInput *queryInput(unsigned idx) const
  23175. {
  23176. if (idx==0)
  23177. return puller.queryInput();
  23178. else if (idx==1)
  23179. return indexReadInput;
  23180. else
  23181. return NULL;
  23182. }
  23183. virtual void reset()
  23184. {
  23185. totalCycles.totalCycles = remote.totalCycles.totalCycles;
  23186. remote.totalCycles.totalCycles = 0;
  23187. processed = remote.joinProcessed;
  23188. remote.joinProcessed = 0;
  23189. defaultRight.clear();
  23190. if (indexReadInput)
  23191. indexReadInput->reset();
  23192. if (atmostsTriggered)
  23193. noteStatistic(StNumAtmostTriggered, atmostsTriggered);
  23194. CRoxieServerActivity::reset();
  23195. puller.reset();
  23196. while (groups.ordinality())
  23197. {
  23198. ::Release(groups.dequeue());
  23199. }
  23200. }
  23201. virtual IFinalRoxieInput *queryOutput(unsigned idx)
  23202. {
  23203. if (idx==(unsigned)-1)
  23204. idx = 0;
  23205. return idx ? NULL : &remote;
  23206. }
  23207. #undef new
  23208. virtual CJoinGroup *createJoinGroup(const void *row)
  23209. {
  23210. // NOTE - we need to protect access to queue, since it's also modified by consumer thread. Groupstart is only modified by puller thread.
  23211. CriticalBlock c(groupsCrit);
  23212. if (preserveGroups && !groupStart)
  23213. {
  23214. groupStart = new (&ctx->queryRowManager(), activityId) CJoinGroup(NULL, NULL);
  23215. groups.enqueue(groupStart);
  23216. }
  23217. CJoinGroup *jg = new (&ctx->queryRowManager(), activityId) CJoinGroup(row, groupStart);
  23218. groups.enqueue(jg);
  23219. return jg;
  23220. }
  23221. #if defined(_DEBUG) && defined(_WIN32) && !defined(USING_MPATROL)
  23222. #define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
  23223. #endif
  23224. void endGroup()
  23225. {
  23226. CriticalBlock c(groupsCrit);
  23227. if (groupStart)
  23228. noteEndReceived(groupStart, 0);
  23229. groupStart = NULL;
  23230. }
  23231. virtual void noteEndReceived(CJoinGroup *jg, unsigned candidateCount)
  23232. {
  23233. if (jg->noteEndReceived(candidateCount))
  23234. processCompletedGroups();
  23235. }
  23236. void processCompletedGroups()
  23237. {
  23238. CriticalBlock c(groupsCrit);
  23239. while (groups.ordinality())
  23240. {
  23241. if (!groups.head()->complete())
  23242. break;
  23243. Owned<CJoinGroup> head = groups.dequeue();
  23244. if (preserveGroups)
  23245. {
  23246. assert(head->isHeadRecord());
  23247. assert(groups.head()->inGroup(head));
  23248. unsigned joinGroupSize = 0;
  23249. while (groups.ordinality() && groups.head()->inGroup(head))
  23250. {
  23251. Owned<CJoinGroup> finger = groups.dequeue();
  23252. joinGroupSize += doJoinGroup(finger);
  23253. }
  23254. if (joinGroupSize)
  23255. remote.addResult(NULL);
  23256. }
  23257. else
  23258. doJoinGroup(head);
  23259. }
  23260. }
  23261. void failLimit(const void * left)
  23262. {
  23263. helper.onMatchAbortLimitExceeded();
  23264. CommonXmlWriter xmlwrite(0);
  23265. if (input && input->queryOutputMeta() && input->queryOutputMeta()->hasXML())
  23266. {
  23267. input->queryOutputMeta()->toXML((byte *) left, xmlwrite);
  23268. }
  23269. throw MakeStringException(ROXIE_JOIN_ERROR, "More than %d match candidates in keyed join %d for row %s", abortLimit, queryId(), xmlwrite.str());
  23270. }
  23271. virtual bool needsAllocator() const { return true; }
  23272. unsigned doTransform(const void *left, const void *right, offset_t fpos_or_count, IException *except, const void **group, unsigned counter)
  23273. {
  23274. if (cloneLeft && !except)
  23275. {
  23276. LinkRoxieRow(left);
  23277. remote.addResult((void *) left);
  23278. return 1;
  23279. }
  23280. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  23281. unsigned outSize;
  23282. try
  23283. {
  23284. outSize = except ? helper.onFailTransform(rowBuilder, left, right, fpos_or_count, except) :
  23285. (activityKind == TAKkeyeddenormalizegroup) ? helper.transform(rowBuilder, left, right, (unsigned)fpos_or_count, group) :
  23286. helper.transform(rowBuilder, left, right, fpos_or_count, counter);
  23287. }
  23288. catch (IException *E)
  23289. {
  23290. throw makeWrappedException(E);
  23291. }
  23292. if (outSize)
  23293. {
  23294. const void *shrunk = rowBuilder.finalizeRowClear(outSize);
  23295. remote.addResult(shrunk);
  23296. return 1;
  23297. }
  23298. else
  23299. return 0;
  23300. }
  23301. unsigned doJoinGroup(CJoinGroup *jg)
  23302. {
  23303. unsigned matched = jg->rowsSeen();
  23304. unsigned added = 0;
  23305. const void *left = jg->queryLeft();
  23306. if (jg->candidateCount() > abortLimit)
  23307. {
  23308. if (limitFail)
  23309. failLimit(left);
  23310. if (ctx->queryDebugContext())
  23311. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  23312. if (limitOnFail)
  23313. {
  23314. Owned<IException> except;
  23315. try
  23316. {
  23317. failLimit(left);
  23318. }
  23319. catch(IException * e)
  23320. {
  23321. except.setown(e);
  23322. }
  23323. added = doTransform(left, defaultRight, 0, except, NULL, 0);
  23324. }
  23325. }
  23326. else if (!matched || jg->candidateCount() > atMost)
  23327. {
  23328. if (jg->candidateCount() > atMost)
  23329. atmostsTriggered++;
  23330. switch (joinFlags & JFtypemask)
  23331. {
  23332. case JFleftouter:
  23333. case JFleftonly:
  23334. switch (activityKind)
  23335. {
  23336. case TAKkeyedjoin:
  23337. case TAKkeyeddenormalizegroup:
  23338. added = doTransform(left, defaultRight, 0, NULL, NULL, 0);
  23339. break;
  23340. case TAKkeyeddenormalize:
  23341. LinkRoxieRow(left);
  23342. remote.addResult((void *) left);
  23343. added++;
  23344. break;
  23345. }
  23346. break;
  23347. }
  23348. }
  23349. else if (!(joinFlags & JFexclude))
  23350. {
  23351. unsigned idx = 0;
  23352. switch (activityKind)
  23353. {
  23354. case TAKkeyedjoin:
  23355. while (idx < matched)
  23356. {
  23357. const KeyedJoinHeader *rhs = jg->queryRow(idx);
  23358. added += doTransform(left, &rhs->rhsdata, 0, NULL, NULL, idx+1);
  23359. if (added==keepLimit)
  23360. break;
  23361. idx++;
  23362. }
  23363. break;
  23364. case TAKkeyeddenormalize:
  23365. {
  23366. OwnedConstRoxieRow newLeft;
  23367. newLeft.set(left);
  23368. unsigned rowSize = 0;
  23369. unsigned rightAdded = 0;
  23370. while (idx < matched)
  23371. {
  23372. const KeyedJoinHeader *rhs = jg->queryRow(idx);
  23373. try
  23374. {
  23375. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  23376. size32_t transformedSize = helper.transform(rowBuilder, newLeft, &rhs->rhsdata, rhs->fpos, idx+1);
  23377. if (transformedSize)
  23378. {
  23379. rowSize = transformedSize;
  23380. newLeft.setown(rowBuilder.finalizeRowClear(rowSize));
  23381. rightAdded++;
  23382. if (rightAdded==keepLimit)
  23383. break;
  23384. }
  23385. idx++;
  23386. }
  23387. catch (IException *E)
  23388. {
  23389. throw makeWrappedException(E);
  23390. }
  23391. }
  23392. if (rowSize)
  23393. {
  23394. remote.addResult(newLeft.getClear());
  23395. added++;
  23396. }
  23397. }
  23398. break;
  23399. case TAKkeyeddenormalizegroup:
  23400. {
  23401. ConstPointerArray extractedRows;
  23402. while (idx < matched && idx < keepLimit)
  23403. {
  23404. const KeyedJoinHeader *rhs = jg->queryRow(idx);
  23405. extractedRows.append((void *) &rhs->rhsdata);
  23406. idx++;
  23407. }
  23408. added += doTransform(left, extractedRows.item(0), extractedRows.ordinality(), NULL, (const void * *)extractedRows.getArray(), 0);
  23409. }
  23410. break;
  23411. }
  23412. }
  23413. return added;
  23414. }
  23415. virtual void processDone()
  23416. {
  23417. // called from puller thread
  23418. remote.flush();
  23419. remote.senddone();
  23420. }
  23421. virtual void onLimitExceeded(bool isKeyed)
  23422. {
  23423. if (traceLevel > 4)
  23424. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  23425. if (isKeyed)
  23426. throwUnexpected();
  23427. helper.onLimitExceeded();
  23428. }
  23429. virtual const void *createLimitFailRow(bool isKeyed)
  23430. {
  23431. throwUnexpected();
  23432. }
  23433. virtual bool fireException(IException *e)
  23434. {
  23435. // called from puller thread on failure
  23436. return remote.fireException(e);
  23437. }
  23438. virtual const void *nextRow()
  23439. {
  23440. throwUnexpected(); // I am nobody's input
  23441. }
  23442. };
  23443. #ifdef _MSC_VER
  23444. #pragma warning ( push )
  23445. #pragma warning ( disable: 4355 )
  23446. #endif
  23447. class CRoxieServerKeyedJoinActivity : public CRoxieServerKeyedJoinBase
  23448. {
  23449. CRoxieServerFullKeyedJoinHead head;
  23450. Owned<IEngineRowAllocator> fetchInputAllocator;
  23451. Linked<IFilePartMap> map;
  23452. bool variableFetchFileName;
  23453. Owned<const IResolvedFile> varFetchFileInfo;
  23454. CachedOutputMetaData fetchInputFields;
  23455. public:
  23456. CRoxieServerKeyedJoinActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_headId, IKeyArray * _key, TranslatorArray *_translators, IOutputMetaData *_indexReadMeta,
  23457. const RemoteActivityId &_tailId, IFilePartMap *_map, unsigned _joinFlags, bool _isLocal)
  23458. : CRoxieServerKeyedJoinBase(_ctx, _factory, _probeManager, _tailId, _joinFlags, true, false, _isLocal),
  23459. head(_ctx, _factory, _probeManager, _headId, _key, _translators, _indexReadMeta, this, _isLocal),
  23460. map(_map)
  23461. {
  23462. CRoxieServerKeyedJoinBase::setInput(0, 0, head.queryOutput(0));
  23463. variableFetchFileName = allFilesDynamic || factory->queryQueryFactory().isDynamic() || ((helper.getFetchFlags() & (FFvarfilename|FFdynamicfilename)) != 0);
  23464. }
  23465. virtual const IResolvedFile *queryVarFileInfo() const
  23466. {
  23467. return varFetchFileInfo;
  23468. }
  23469. virtual void onCreate(IHThorArg *_colocalParent)
  23470. {
  23471. CRoxieServerKeyedJoinBase::onCreate(_colocalParent);
  23472. head.onCreate(_colocalParent);
  23473. fetchInputFields.set(helper.queryFetchInputRecordSize());
  23474. fetchInputAllocator.setown(createRowAllocator(helper.queryFetchInputRecordSize()));
  23475. }
  23476. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  23477. {
  23478. CRoxieServerKeyedJoinBase::start(parentExtractSize, parentExtract, paused);
  23479. if (variableFetchFileName)
  23480. {
  23481. bool isFetchOpt = (helper.getFetchFlags() & FFdatafileoptional) != 0;
  23482. OwnedRoxieString fname(helper.getFileName());
  23483. varFetchFileInfo.setown(resolveLFN(fname, isFetchOpt));
  23484. if (varFetchFileInfo)
  23485. map.setown(varFetchFileInfo->getFileMap());
  23486. }
  23487. puller.start(parentExtractSize, parentExtract, paused, ctx->queryOptions().keyedJoinPreload, false, ctx);
  23488. }
  23489. virtual void setInput(unsigned idx, unsigned _sourceIdx, IFinalRoxieInput *_in)
  23490. {
  23491. head.setInput(idx, _sourceIdx, _in);
  23492. }
  23493. virtual IStrandJunction *getOutputStreams(IRoxieSlaveContext *ctx, unsigned idx, PointerArrayOf<IEngineRowStream> &streams, const StrandOptions * consumerOptions, bool consumerOrdered, IOrderedCallbackCollection * orderedCallbacks)
  23494. {
  23495. connectInputStreams(consumerOrdered);
  23496. return head.getOutputStreams(ctx, idx, streams, consumerOptions, consumerOrdered, orderedCallbacks);
  23497. }
  23498. virtual IFinalRoxieInput *queryInput(unsigned idx) const
  23499. {
  23500. return head.queryInput(idx);
  23501. }
  23502. virtual void processRow(const void *_rhs)
  23503. {
  23504. // called from puller thread
  23505. KeyedJoinHeader *rhs = (KeyedJoinHeader *) _rhs;
  23506. CJoinGroup *jg = rhs->thisGroup;
  23507. if (rhs->partNo != (unsigned short) -1)
  23508. {
  23509. unsigned partNo = map->mapOffset(rhs->fpos);
  23510. RtlDynamicRowBuilder fetchBuilder(fetchInputAllocator, true);
  23511. size32_t fisize = helper.extractFetchFields(fetchBuilder, jg->queryLeft());
  23512. if (fetchInputFields.isVariableSize())
  23513. {
  23514. KeyedJoinHeader *outRow = (KeyedJoinHeader *) remote.getMem(partNo, 0, KEYEDJOIN_RECORD_SIZE(fisize + sizeof(fisize)));
  23515. memcpy(outRow, rhs, KEYEDJOIN_RECORD_SIZE(0)); // MORE - copy constructor might be more appropriate....
  23516. ReleaseRoxieRow(rhs);
  23517. jg->notePending();
  23518. memcpy(&outRow->rhsdata, &fisize, sizeof(fisize));
  23519. memcpy((&outRow->rhsdata)+sizeof(fisize), fetchBuilder.row(), fisize);
  23520. }
  23521. else
  23522. {
  23523. KeyedJoinHeader *outRow = (KeyedJoinHeader *) remote.getMem(partNo, 0, KEYEDJOIN_RECORD_SIZE(fisize));
  23524. memcpy(outRow, rhs, KEYEDJOIN_RECORD_SIZE(0)); // MORE - copy constructor might be more appropriate....
  23525. ReleaseRoxieRow(rhs);
  23526. jg->notePending();
  23527. memcpy(&outRow->rhsdata, fetchBuilder.row(), fisize);
  23528. }
  23529. }
  23530. else
  23531. {
  23532. unsigned candidateCount = (unsigned) rhs->fpos;
  23533. // CTXLOG("Full keyed join - all results back from index");
  23534. ReleaseRoxieRow(rhs);
  23535. noteEndReceived(jg, candidateCount); // may throw exception - so release row before calling
  23536. }
  23537. }
  23538. virtual void processEOG()
  23539. {
  23540. // called from front puller thread
  23541. if (preserveGroups)
  23542. endGroup();
  23543. }
  23544. void processGroup(const ConstPointerArray &)
  23545. {
  23546. throwUnexpected();
  23547. }
  23548. virtual void gatherStats(CRuntimeStatisticCollection & merged) const override
  23549. {
  23550. CRoxieServerKeyedJoinBase::gatherStats(merged);
  23551. if (fetchInputAllocator)
  23552. fetchInputAllocator->gatherStats(merged);
  23553. }
  23554. };
  23555. #ifdef _MSC_VER
  23556. #pragma warning ( pop )
  23557. #endif
  23558. class CRoxieServerHalfKeyedJoinActivity : public CRoxieServerKeyedJoinBase
  23559. {
  23560. IOutputMetaData *indexReadMeta;
  23561. Owned<IEngineRowAllocator> indexReadAllocator;
  23562. Owned<IKeyManager> tlk;
  23563. bool variableIndexFileName;
  23564. bool indexReadInputRecordVariable;
  23565. Owned<const IResolvedFile> varFileInfo;
  23566. Linked<TranslatorArray> translators;
  23567. Linked<IKeyArray> keySet;
  23568. Owned<IOutputMetaData> joinPrefixedMeta;
  23569. Owned<IEngineRowAllocator> joinFieldsAllocator;
  23570. public:
  23571. CRoxieServerHalfKeyedJoinActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, IKeyArray * _keySet, TranslatorArray *_translators,
  23572. IOutputMetaData *_indexReadMeta, unsigned _joinFlags, bool _isSimple, bool _isLocal)
  23573. : CRoxieServerKeyedJoinBase(_ctx, _factory, _probeManager, _remoteId, _joinFlags, false, _isSimple, _isLocal),
  23574. indexReadMeta(_indexReadMeta),
  23575. tlk(createLocalKeyManager(helper.queryIndexRecordSize()->queryRecordAccessor(true), NULL, this)),
  23576. keySet(_keySet),
  23577. translators(_translators)
  23578. {
  23579. variableIndexFileName = allFilesDynamic || factory->queryQueryFactory().isDynamic() || ((helper.getJoinFlags() & (JFvarindexfilename|JFdynamicindexfilename|JFindexfromactivity)) != 0);
  23580. indexReadInputRecordVariable = indexReadMeta->isVariableSize();
  23581. }
  23582. virtual void serializeExtra(MemoryBuffer &out)
  23583. {
  23584. if (helper.getJoinFlags() & JFindexfromactivity)
  23585. {
  23586. assertex(rootIndex);
  23587. const RemoteActivityId& indexId = rootIndex->queryRemoteId();
  23588. indexId.serialize(out);
  23589. // could mess about reserving space for length then patching it again, to avoid copy, but probably not worth it
  23590. MemoryBuffer tmp;
  23591. rootIndex->queryActivity()->serializeCreateStartContext(tmp);
  23592. if (rootIndex->queryActivity()->queryVarFileInfo())
  23593. {
  23594. rootIndex->queryActivity()->queryVarFileInfo()->queryTimeStamp().serialize(tmp);
  23595. tmp.append(rootIndex->queryActivity()->queryVarFileInfo()->queryCheckSum());
  23596. }
  23597. unsigned ctxlen = tmp.length();
  23598. out.append(ctxlen).append(tmp);
  23599. }
  23600. }
  23601. virtual void onCreate(IHThorArg *_colocalParent)
  23602. {
  23603. CRoxieServerKeyedJoinBase::onCreate(_colocalParent);
  23604. indexReadAllocator.setown(createRowAllocator(indexReadMeta));
  23605. IOutputMetaData *joinFieldsMeta = helper.queryJoinFieldsRecordSize();
  23606. joinPrefixedMeta.setown(new CPrefixedOutputMeta(KEYEDJOIN_RECORD_SIZE(0), joinFieldsMeta)); // MORE - not sure if we really need this
  23607. joinFieldsAllocator.setown(createRowAllocator(joinPrefixedMeta));
  23608. }
  23609. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  23610. {
  23611. CRoxieServerKeyedJoinBase::start(parentExtractSize, parentExtract, paused);
  23612. if (rootIndex)
  23613. {
  23614. varFileInfo.setown(rootIndex->getVarFileInfo());
  23615. translators.setown(rootIndex->getTranslators());
  23616. keySet.setown(rootIndex->getKeySet());
  23617. }
  23618. else if (variableIndexFileName)
  23619. {
  23620. OwnedRoxieString indexFileName(helper.getIndexFileName());
  23621. varFileInfo.setown(resolveLFN(indexFileName, (helper.getJoinFlags() & JFindexoptional) != 0));
  23622. if (varFileInfo)
  23623. {
  23624. translators.setown(new TranslatorArray);
  23625. keySet.setown(varFileInfo->getKeyArray(factory->queryActivityMeta(), translators, false, isLocal ? factory->queryQueryFactory().queryChannel() : 0, factory->queryQueryFactory().queryOptions().enableFieldTranslation));
  23626. }
  23627. }
  23628. puller.start(parentExtractSize, parentExtract, paused, ctx->queryOptions().keyedJoinPreload, isSimple, ctx);
  23629. }
  23630. virtual const IResolvedFile *queryVarFileInfo() const
  23631. {
  23632. return varFileInfo;
  23633. }
  23634. virtual void reset()
  23635. {
  23636. CRoxieServerKeyedJoinBase::reset();
  23637. if (varFileInfo)
  23638. {
  23639. keySet.clear();
  23640. varFileInfo.clear();
  23641. }
  23642. }
  23643. virtual void processRow(const void *row)
  23644. {
  23645. // called from front puller thread
  23646. // buffer up an IndexRead request
  23647. if (keySet && helper.leftCanMatch(row))
  23648. {
  23649. RtlDynamicRowBuilder extractBuilder(indexReadAllocator);
  23650. unsigned indexReadRecordSize = helper.extractIndexReadFields(extractBuilder, row);
  23651. OwnedConstRoxieRow extracted;
  23652. if (indexReadRecordSize)
  23653. extracted.setown(extractBuilder.finalizeRowClear(indexReadRecordSize));
  23654. CJoinGroup *jg = createJoinGroup(row);
  23655. for (unsigned partNo = 0; partNo < keySet->length(); partNo++)
  23656. {
  23657. IKeyIndexBase *thisBase = keySet->queryKeyPart(partNo);
  23658. if (thisBase)
  23659. {
  23660. unsigned fileNo = 0;
  23661. IKeyIndex *thisKey = thisBase->queryPart(fileNo);
  23662. tlk->setKey(thisKey);
  23663. if (thisKey && !thisKey->isTopLevelKey())
  23664. tlk->setLayoutTranslator(translators->item(fileNo));
  23665. else
  23666. tlk->setLayoutTranslator(nullptr);
  23667. helper.createSegmentMonitors(tlk, extracted);
  23668. if (rootIndex)
  23669. rootIndex->mergeSegmentMonitors(tlk);
  23670. tlk->finishSegmentMonitors();
  23671. try
  23672. {
  23673. tlk->reset();
  23674. for (;;)
  23675. {
  23676. typedef const void * cvp;
  23677. if (thisKey && thisKey->isTopLevelKey())
  23678. {
  23679. bool locallySorted = (!thisKey->isFullySorted());
  23680. while (locallySorted || tlk->lookup(false))
  23681. {
  23682. unsigned slavePart = locallySorted ? 0 : (unsigned)extractFpos(tlk);
  23683. if (locallySorted || slavePart)
  23684. {
  23685. cvp *outputBuffer = (cvp *) remote.getMem(slavePart, fileNo, indexReadRecordSize + sizeof(cvp) + (indexReadInputRecordVariable ? sizeof(unsigned) : 0));
  23686. *outputBuffer++ = jg;
  23687. if (indexReadInputRecordVariable)
  23688. {
  23689. *(unsigned *) outputBuffer = indexReadRecordSize;
  23690. outputBuffer = (cvp *) (((unsigned *) outputBuffer) + 1);
  23691. }
  23692. jg->notePending();
  23693. memcpy(outputBuffer, extracted, indexReadRecordSize);
  23694. if (locallySorted)
  23695. {
  23696. for (unsigned i = 1; i < numChannels; i++)
  23697. jg->notePending();
  23698. break;
  23699. }
  23700. }
  23701. }
  23702. }
  23703. else
  23704. {
  23705. unsigned accepted = 0;
  23706. unsigned rejected = 0;
  23707. Owned<CRowArrayMessageResult> result;
  23708. if (!isSimple)
  23709. result.setown(new CRowArrayMessageResult(ctx->queryRowManager(), true));
  23710. // MORE - This code seems to be duplicated in keyedJoinHead
  23711. jg->notePending();
  23712. unsigned candidateCount = 0;
  23713. while (tlk->lookup(true))
  23714. {
  23715. candidateCount++;
  23716. atomic_inc(&indexRecordsRead);
  23717. KLBlobProviderAdapter adapter(tlk);
  23718. const byte *indexRow = tlk->queryKeyBuffer();
  23719. size_t fposOffset = tlk->queryRowSize() - sizeof(offset_t);
  23720. offset_t fpos = rtlReadBigUInt8(indexRow + fposOffset);
  23721. if (helper.indexReadMatch(extracted, indexRow, &adapter))
  23722. {
  23723. RtlDynamicRowBuilder rb(joinFieldsAllocator, true);
  23724. CPrefixedRowBuilder pb(KEYEDJOIN_RECORD_SIZE(0), rb);
  23725. accepted++;
  23726. KLBlobProviderAdapter adapter(tlk);
  23727. size32_t joinFieldsSize = helper.extractJoinFields(pb, indexRow, &adapter);
  23728. KeyedJoinHeader *rec = (KeyedJoinHeader *) rb.getUnfinalizedClear(); // lack of finalize ok as unserialized data here.
  23729. rec->fpos = fpos;
  23730. rec->thisGroup = jg;
  23731. rec->partNo = partNo;
  23732. if (isSimple)
  23733. remote.injected.enqueue(rec);
  23734. else
  23735. result->append(rec);
  23736. }
  23737. else
  23738. {
  23739. rejected++;
  23740. atomic_inc(&postFiltered);
  23741. }
  23742. }
  23743. // output an end marker for the matches to this group
  23744. KeyedJoinHeader *rec = (KeyedJoinHeader *) ctx->queryRowManager().allocate(KEYEDJOIN_RECORD_SIZE(0), activityId);
  23745. rec->fpos = (offset_t) candidateCount;
  23746. rec->thisGroup = jg;
  23747. rec->partNo = (unsigned short) -1;
  23748. if (isSimple)
  23749. remote.injected.enqueue(rec);
  23750. else
  23751. {
  23752. result->append(rec);
  23753. remote.injectResult(result.getClear());
  23754. }
  23755. if (accepted)
  23756. noteStatistic(StNumIndexAccepted, accepted);
  23757. if (rejected)
  23758. noteStatistic(StNumIndexRejected, rejected);
  23759. }
  23760. if (++fileNo < thisBase->numParts())
  23761. {
  23762. thisKey = thisBase->queryPart(fileNo);
  23763. tlk->setKey(thisKey);
  23764. if (thisKey && !thisKey->isTopLevelKey())
  23765. tlk->setLayoutTranslator(translators->item(fileNo));
  23766. else
  23767. tlk->setLayoutTranslator(nullptr);
  23768. tlk->reset();
  23769. }
  23770. else
  23771. break;
  23772. }
  23773. tlk->releaseSegmentMonitors();
  23774. tlk->setKey(NULL);
  23775. }
  23776. catch (...)
  23777. {
  23778. tlk->releaseSegmentMonitors();
  23779. tlk->setKey(NULL);
  23780. throw;
  23781. }
  23782. }
  23783. }
  23784. noteEndReceived(jg, 0);
  23785. }
  23786. else
  23787. {
  23788. noteEndReceived(createJoinGroup(row), 0);
  23789. }
  23790. }
  23791. virtual void processEOG()
  23792. {
  23793. // called from front puller thread
  23794. if (preserveGroups)
  23795. endGroup();
  23796. }
  23797. void processGroup(const ConstPointerArray &)
  23798. {
  23799. throwUnexpected();
  23800. }
  23801. virtual void gatherStats(CRuntimeStatisticCollection & merged) const override
  23802. {
  23803. CRoxieServerKeyedJoinBase::gatherStats(merged);
  23804. if (indexReadAllocator)
  23805. indexReadAllocator->gatherStats(merged);
  23806. if (joinFieldsAllocator)
  23807. joinFieldsAllocator->gatherStats(merged);
  23808. }
  23809. };
  23810. class CRoxieServerKeyedJoinActivityFactory : public CRoxieServerMultiInputFactory
  23811. {
  23812. Owned<const IResolvedFile> indexfile;
  23813. Owned<const IResolvedFile> datafile;
  23814. Owned<IKeyArray> keySet;
  23815. Owned<TranslatorArray> translatorArray;
  23816. Owned<IDefRecordMeta> activityMeta;
  23817. RemoteActivityId headId;
  23818. RemoteActivityId tailId;
  23819. IOutputMetaData *indexReadMeta;
  23820. Owned<IFilePartMap> map;
  23821. Owned<IFileIOArray> files;
  23822. unsigned joinFlags;
  23823. bool isHalfKeyed;
  23824. bool isLocal;
  23825. IRecordLayoutTranslator::Mode enableFieldTranslation;
  23826. bool variableFetchFileName;
  23827. bool variableIndexFileName;
  23828. bool isSimple;
  23829. public:
  23830. CRoxieServerKeyedJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, const RemoteActivityId &_headId, const RemoteActivityId &_tailId)
  23831. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode), headId(_headId), tailId(_tailId)
  23832. {
  23833. Owned<IHThorKeyedJoinArg> helper = (IHThorKeyedJoinArg *) helperFactory();
  23834. isLocal = _graphNode.getPropBool("att[@name='local']/@value") && queryFactory.queryChannel()!=0;
  23835. isSimple = isLocal;
  23836. rtlDataAttr indexLayoutMeta;
  23837. size32_t indexLayoutSize = 0;
  23838. if(!helper->getIndexLayout(indexLayoutSize, indexLayoutMeta.refdata()))
  23839. assertex(indexLayoutSize== 0);
  23840. MemoryBuffer m;
  23841. m.setBuffer(indexLayoutSize, indexLayoutMeta.getdata());
  23842. activityMeta.setown(deserializeRecordMeta(m, true));
  23843. enableFieldTranslation = queryFactory.queryOptions().enableFieldTranslation;
  23844. translatorArray.setown(new TranslatorArray);
  23845. joinFlags = helper->getJoinFlags();
  23846. variableIndexFileName = allFilesDynamic || _queryFactory.isDynamic() || ((joinFlags & (JFvarindexfilename|JFdynamicindexfilename|JFindexfromactivity)) != 0);
  23847. variableFetchFileName = allFilesDynamic || _queryFactory.isDynamic() || ((helper->getFetchFlags() & (FFvarfilename|FFdynamicfilename)) != 0);
  23848. if (!variableIndexFileName)
  23849. {
  23850. bool isOpt = (joinFlags & JFindexoptional) != 0;
  23851. OwnedRoxieString indexFileName(helper->getIndexFileName());
  23852. indexfile.setown(queryFactory.queryPackage().lookupFileName(indexFileName, isOpt, true, true, queryFactory.queryWorkUnit(), true));
  23853. if (indexfile)
  23854. keySet.setown(indexfile->getKeyArray(activityMeta, translatorArray, isOpt, isLocal ? queryFactory.queryChannel() : 0, enableFieldTranslation));
  23855. }
  23856. if (keySet && keySet->length()==1 && !isSimple)
  23857. {
  23858. IKeyIndexBase *thisBase = keySet->queryKeyPart(0);
  23859. if (thisBase->numParts()==1 && !thisBase->queryPart(0)->isTopLevelKey() && !_queryFactory.queryOptions().disableLocalOptimizations)
  23860. isSimple = true;
  23861. // MORE - if it's a variable filename then it MAY be simple, we don't know. Tough.
  23862. }
  23863. if (!simpleLocalKeyedJoins)
  23864. isSimple = false;
  23865. isHalfKeyed = !helper->diskAccessRequired();
  23866. indexReadMeta = QUERYINTERFACE(helper->queryIndexReadInputRecordSize(), IOutputMetaData);
  23867. if (!isHalfKeyed && !variableFetchFileName)
  23868. {
  23869. bool isFetchOpt = (helper->getFetchFlags() & FFdatafileoptional) != 0;
  23870. datafile.setown(_queryFactory.queryPackage().lookupFileName(queryNodeFileName(_graphNode, _kind), isFetchOpt, true, true, _queryFactory.queryWorkUnit(), true));
  23871. if (datafile)
  23872. {
  23873. if (isLocal)
  23874. files.setown(datafile->getIFileIOArray(isFetchOpt, queryFactory.queryChannel()));
  23875. else
  23876. map.setown(datafile->getFileMap());
  23877. }
  23878. }
  23879. }
  23880. virtual bool getEnableFieldTranslation() const
  23881. {
  23882. return enableFieldTranslation;
  23883. }
  23884. virtual IDefRecordMeta *queryActivityMeta() const
  23885. {
  23886. return activityMeta;
  23887. }
  23888. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  23889. {
  23890. if (isHalfKeyed)
  23891. return new CRoxieServerHalfKeyedJoinActivity(_ctx, this, _probeManager,
  23892. headId, keySet, translatorArray, indexReadMeta, joinFlags, isSimple, isLocal);
  23893. else
  23894. return new CRoxieServerKeyedJoinActivity(_ctx, this, _probeManager,
  23895. headId, keySet, translatorArray, indexReadMeta,
  23896. tailId, map, joinFlags, isLocal);
  23897. }
  23898. virtual const StatisticsMapping &queryStatsMapping() const
  23899. {
  23900. return keyedJoinStatistics;
  23901. }
  23902. virtual void getXrefInfo(IPropertyTree &reply, const IRoxieContextLogger &logctx) const
  23903. {
  23904. if (datafile)
  23905. addXrefFileInfo(reply, datafile);
  23906. if (indexfile)
  23907. addXrefFileInfo(reply, indexfile);
  23908. }
  23909. };
  23910. IRoxieServerActivityFactory *createRoxieServerKeyedJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, const RemoteActivityId &_remoteId, const RemoteActivityId &_remoteId2)
  23911. {
  23912. return new CRoxieServerKeyedJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _remoteId, _remoteId2);
  23913. }
  23914. //=================================================================================
  23915. class CRoxieServerSoapActivityBase : public CRoxieServerActivity, implements ISoapCallRowProvider, implements IRoxieAbortMonitor
  23916. {
  23917. protected:
  23918. Owned<ISoapCallHelper> soaphelper;
  23919. IHThorSoapActionArg & helper;
  23920. StringBuffer authToken;
  23921. bool eof;
  23922. CriticalSection crit;
  23923. ClientCertificate *pClientCert;
  23924. public:
  23925. IMPLEMENT_IINTERFACE_USING(CRoxieServerActivity)
  23926. CRoxieServerSoapActivityBase(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  23927. : CRoxieServerActivity(_ctx, _factory, _probeManager), helper((IHThorSoapActionArg &)basehelper)
  23928. {
  23929. eof = false;
  23930. if (clientCert.certificate.length() > 0 && clientCert.privateKey.length() > 0 && clientCert.passphrase.length() > 0)
  23931. pClientCert = &clientCert;
  23932. else
  23933. pClientCert = NULL;
  23934. }
  23935. // ISoapCallRowProvider
  23936. virtual IHThorSoapActionArg * queryActionHelper() { return &helper; };
  23937. virtual IHThorSoapCallArg * queryCallHelper() { return NULL; };
  23938. virtual const void * getNextRow() { return NULL; };
  23939. virtual void releaseRow(const void * r) { ReleaseRoxieRow(r); };
  23940. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  23941. {
  23942. eof = false;
  23943. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  23944. authToken.append(ctx->queryAuthToken());
  23945. }
  23946. virtual void reset()
  23947. {
  23948. // MORE - Shouldn't we make sure thread is stopped etc???
  23949. soaphelper.clear();
  23950. CRoxieServerActivity::reset();
  23951. }
  23952. // IRoxieAbortMonitor
  23953. virtual void checkForAbort() { checkAbort(); }
  23954. };
  23955. //---------------------------------------------------------------------------
  23956. class CRoxieServerSoapRowCallActivity : public CRoxieServerSoapActivityBase
  23957. {
  23958. IHThorSoapCallArg & callHelper;
  23959. public:
  23960. CRoxieServerSoapRowCallActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  23961. : CRoxieServerSoapActivityBase(_ctx, _factory, _probeManager), callHelper((IHThorSoapCallArg &)basehelper)
  23962. {
  23963. }
  23964. virtual IHThorSoapCallArg * queryCallHelper()
  23965. {
  23966. return &callHelper;
  23967. }
  23968. virtual bool needsAllocator() const { return true; }
  23969. virtual const void *nextRow()
  23970. {
  23971. ActivityTimer t(totalCycles, timeActivities);
  23972. if(eof) return NULL;
  23973. if (soaphelper == NULL)
  23974. {
  23975. if (factory->getKind()==TAKhttp_rowdataset)
  23976. soaphelper.setown(createHttpCallHelper(this, rowAllocator, authToken.str(), SCrow, pClientCert, *this, this));
  23977. else
  23978. soaphelper.setown(createSoapCallHelper(this, rowAllocator, authToken.str(), SCrow, pClientCert, *this, this));
  23979. soaphelper->start();
  23980. }
  23981. OwnedConstRoxieRow ret = soaphelper->getRow();
  23982. if (!ret)
  23983. {
  23984. eof = true;
  23985. return NULL;
  23986. }
  23987. ++processed;
  23988. return ret.getClear();
  23989. }
  23990. };
  23991. class CRoxieServerSoapRowCallActivityFactory : public CRoxieServerActivityFactory
  23992. {
  23993. public:
  23994. CRoxieServerSoapRowCallActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  23995. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  23996. {
  23997. }
  23998. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  23999. {
  24000. return new CRoxieServerSoapRowCallActivity(_ctx, this, _probeManager);
  24001. }
  24002. virtual const StatisticsMapping &queryStatsMapping() const
  24003. {
  24004. return soapStatistics;
  24005. }
  24006. };
  24007. IRoxieServerActivityFactory *createRoxieServerSoapRowCallActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  24008. {
  24009. return new CRoxieServerSoapRowCallActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  24010. }
  24011. //---------------------------------------------------------------------------
  24012. class CRoxieServerSoapRowActionActivity : public CRoxieServerSoapActivityBase
  24013. {
  24014. public:
  24015. CRoxieServerSoapRowActionActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  24016. : CRoxieServerSoapActivityBase(_ctx, _factory, _probeManager)
  24017. {}
  24018. virtual void execute(unsigned parentExtractSize, const byte * parentExtract)
  24019. {
  24020. //MORE: parentExtract not passed to start - although shouldn't be a problem.
  24021. soaphelper.setown(createSoapCallHelper(this, NULL, ctx->queryAuthToken(), SCrow, pClientCert, *this, this));
  24022. soaphelper->start();
  24023. soaphelper->waitUntilDone();
  24024. IException *e = soaphelper->getError();
  24025. soaphelper.clear();
  24026. if (e)
  24027. throw e;
  24028. }
  24029. virtual IFinalRoxieInput *queryOutput(unsigned idx)
  24030. {
  24031. return NULL;
  24032. }
  24033. virtual const void *nextRow()
  24034. {
  24035. throwUnexpected(); // I am nobody's input
  24036. }
  24037. };
  24038. class CRoxieServerSoapRowActionActivityFactory : public CRoxieServerActivityFactory
  24039. {
  24040. bool isRoot;
  24041. public:
  24042. CRoxieServerSoapRowActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _isRoot)
  24043. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode), isRoot(_isRoot)
  24044. {
  24045. }
  24046. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  24047. {
  24048. return new CRoxieServerSoapRowActionActivity(_ctx, this, _probeManager);
  24049. }
  24050. virtual bool isSink() const
  24051. {
  24052. return isRoot;
  24053. }
  24054. virtual const StatisticsMapping &queryStatsMapping() const
  24055. {
  24056. return soapStatistics;
  24057. }
  24058. };
  24059. IRoxieServerActivityFactory *createRoxieServerSoapRowActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _isRoot)
  24060. {
  24061. return new CRoxieServerSoapRowActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _isRoot);
  24062. }
  24063. //---------------------------------------------------------------------------
  24064. class CRoxieServerSoapDatasetCallActivity : public CRoxieServerSoapActivityBase
  24065. {
  24066. IHThorSoapCallArg & callHelper;
  24067. public:
  24068. CRoxieServerSoapDatasetCallActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  24069. : CRoxieServerSoapActivityBase(_ctx, _factory, _probeManager), callHelper((IHThorSoapCallArg &)basehelper)
  24070. {
  24071. }
  24072. virtual IHThorSoapCallArg * queryCallHelper()
  24073. {
  24074. return &callHelper;
  24075. }
  24076. virtual const void *getNextRow()
  24077. {
  24078. CriticalBlock b(crit); // MORE - why ?
  24079. return inputStream->ungroupedNextRow();
  24080. }
  24081. virtual bool needsAllocator() const { return true; }
  24082. virtual const void *nextRow()
  24083. {
  24084. ActivityTimer t(totalCycles, timeActivities);
  24085. if(eof) return NULL;
  24086. if (soaphelper == NULL)
  24087. {
  24088. soaphelper.setown(createSoapCallHelper(this, rowAllocator, authToken.str(), SCdataset, pClientCert, *this, this));
  24089. soaphelper->start();
  24090. }
  24091. OwnedConstRoxieRow ret = soaphelper->getRow();
  24092. if (!ret)
  24093. {
  24094. eof = true;
  24095. return NULL;
  24096. }
  24097. ++processed;
  24098. return ret.getClear();
  24099. }
  24100. };
  24101. class CRoxieServerSoapDatasetCallActivityFactory : public CRoxieServerActivityFactory
  24102. {
  24103. public:
  24104. CRoxieServerSoapDatasetCallActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  24105. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode)
  24106. {
  24107. }
  24108. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  24109. {
  24110. return new CRoxieServerSoapDatasetCallActivity(_ctx, this, _probeManager);
  24111. }
  24112. virtual const StatisticsMapping &queryStatsMapping() const
  24113. {
  24114. return soapStatistics;
  24115. }
  24116. };
  24117. IRoxieServerActivityFactory *createRoxieServerSoapDatasetCallActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  24118. {
  24119. return new CRoxieServerSoapDatasetCallActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  24120. }
  24121. //---------------------------------------------------------------------------
  24122. class CRoxieServerSoapDatasetActionActivity : public CRoxieServerSoapActivityBase
  24123. {
  24124. public:
  24125. CRoxieServerSoapDatasetActionActivity(IRoxieSlaveContext *_ctx, const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  24126. : CRoxieServerSoapActivityBase(_ctx, _factory, _probeManager)
  24127. {}
  24128. virtual const void *getNextRow()
  24129. {
  24130. CriticalBlock b(crit); // MORE - Why?
  24131. const void *nextrec = inputStream->ungroupedNextRow();
  24132. if (nextrec)
  24133. processed++;
  24134. return nextrec;
  24135. }
  24136. virtual void execute(unsigned parentExtractSize, const byte * parentExtract)
  24137. {
  24138. try
  24139. {
  24140. start(parentExtractSize, parentExtract, false);
  24141. soaphelper.setown(createSoapCallHelper(this, NULL, ctx->queryAuthToken(), SCdataset, pClientCert, *this, this));
  24142. soaphelper->start();
  24143. soaphelper->waitUntilDone();
  24144. IException *e = soaphelper->getError();
  24145. soaphelper.clear();
  24146. if (e)
  24147. throw e;
  24148. stop();
  24149. }
  24150. catch (IException *E)
  24151. {
  24152. ctx->notifyAbort(E);
  24153. abort();
  24154. throw;
  24155. }
  24156. catch(...)
  24157. {
  24158. Owned<IException> E = MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught at %s:%d", sanitizeSourceFile(__FILE__), __LINE__);
  24159. ctx->notifyAbort(E);
  24160. abort();
  24161. throw;
  24162. }
  24163. }
  24164. virtual IFinalRoxieInput *queryOutput(unsigned idx)
  24165. {
  24166. return NULL;
  24167. }
  24168. virtual const void *nextRow()
  24169. {
  24170. throwUnexpected(); // I am nobody's input
  24171. }
  24172. };
  24173. class CRoxieServerSoapDatasetActionActivityFactory : public CRoxieServerActivityFactory
  24174. {
  24175. bool isRoot;
  24176. public:
  24177. CRoxieServerSoapDatasetActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _isRoot)
  24178. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode), isRoot(_isRoot)
  24179. {
  24180. }
  24181. virtual IRoxieServerActivity *createActivity(IRoxieSlaveContext *_ctx, IProbeManager *_probeManager) const
  24182. {
  24183. return new CRoxieServerSoapDatasetActionActivity(_ctx, this, _probeManager);
  24184. }
  24185. virtual bool isSink() const
  24186. {
  24187. return isRoot;
  24188. }
  24189. virtual const StatisticsMapping &queryStatsMapping() const
  24190. {
  24191. return soapStatistics;
  24192. }
  24193. };
  24194. IRoxieServerActivityFactory *createRoxieServerSoapDatasetActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool _isRoot)
  24195. {
  24196. return new CRoxieServerSoapDatasetActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, _isRoot);
  24197. }
  24198. //=====================================================================================================
  24199. class CGraphResults : implements IRoxieGraphResults, public CInterface
  24200. {
  24201. IArrayOf<IGraphResult> results;
  24202. CriticalSection cs;
  24203. IGraphResult & select(unsigned idx)
  24204. {
  24205. CriticalBlock procedure(cs);
  24206. if (idx >= results.ordinality())
  24207. throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Error reading graph result %d before it is calculated", idx);
  24208. return results.item(idx);
  24209. }
  24210. public:
  24211. IMPLEMENT_IINTERFACE
  24212. void clear()
  24213. {
  24214. CriticalBlock procedure(cs);
  24215. results.kill();
  24216. }
  24217. virtual IEngineRowStream * createIterator(unsigned id)
  24218. {
  24219. return select(id).createIterator();
  24220. }
  24221. virtual void getLinkedResult(unsigned & count, const byte * * & ret, unsigned id) override
  24222. {
  24223. select(id).getLinkedResult(count, ret);
  24224. }
  24225. virtual void getDictionaryResult(unsigned & count, const byte * * & ret, unsigned id) override
  24226. {
  24227. select(id).getLinkedResult(count, ret);
  24228. }
  24229. virtual const void * getLinkedRowResult(unsigned id)
  24230. {
  24231. return select(id).getLinkedRowResult();
  24232. }
  24233. void setResult(unsigned id, IGraphResult * result)
  24234. {
  24235. CriticalBlock procedure(cs);
  24236. if (results.ordinality() <= id)
  24237. {
  24238. while (results.ordinality() < id)
  24239. results.append(*new CGraphResult);
  24240. results.append(*LINK(result));
  24241. }
  24242. else
  24243. results.replace(*LINK(result), id);
  24244. }
  24245. void appendResult(IGraphResult * result)
  24246. {
  24247. CriticalBlock procedure(cs);
  24248. results.append(*LINK(result));
  24249. }
  24250. };
  24251. //===================================================================================================================
  24252. class CPseudoArg : implements CThorSinkArgOf<IHThorArg>
  24253. {
  24254. };
  24255. class CPseudoActivity : public CRoxieServerActivity
  24256. {
  24257. public:
  24258. CPseudoActivity(IRoxieSlaveContext *_ctx, IHThorArg & _helper) : CRoxieServerActivity(_ctx, _helper) {}
  24259. virtual const void *nextRow()
  24260. {
  24261. throwUnexpected(); // I am nobody's input
  24262. }
  24263. };
  24264. class CActivityGraph : implements IActivityGraph, implements IThorChildGraph, implements ILocalGraphEx, implements IRoxieServerChildGraph, public CInterface
  24265. {
  24266. protected:
  24267. class ActivityGraphSlaveContext : public IndirectSlaveContext
  24268. {
  24269. SpinLock abortLock;
  24270. bool aborted;
  24271. Owned<IException> exception;
  24272. public:
  24273. ActivityGraphSlaveContext(IRoxieSlaveContext *_ctx, const IRoxieContextLogger &_logctx) : IndirectSlaveContext(_ctx), logctx(_logctx), loopCounter(0), codeContext(NULL)
  24274. {
  24275. aborted = false;
  24276. }
  24277. // Note - we must track exceptions at the child level in case there is a CATCH in parent
  24278. virtual void notifyAbort(IException *E)
  24279. {
  24280. SpinBlock b(abortLock);
  24281. if (!aborted && QUERYINTERFACE(E, InterruptedSemaphoreException) == NULL)
  24282. {
  24283. aborted = true;
  24284. exception.set(E);
  24285. }
  24286. }
  24287. virtual void checkAbort()
  24288. {
  24289. if (aborted) // NOTE - don't bother getting lock before reading this (for speed) - a false read is very unlikely and not a problem
  24290. {
  24291. SpinBlock b(abortLock);
  24292. if (!exception)
  24293. exception.setown(MakeStringException(ROXIE_INTERNAL_ERROR, "Query was aborted"));
  24294. throw exception.getLink();
  24295. }
  24296. IndirectSlaveContext::checkAbort();
  24297. }
  24298. virtual ICodeContext *queryCodeContext()
  24299. {
  24300. return codeContext;
  24301. }
  24302. void setCodeContext(ICodeContext * _codeContext)
  24303. {
  24304. codeContext = _codeContext;
  24305. }
  24306. void setLoopCounter(unsigned _loopCounter)
  24307. {
  24308. loopCounter = _loopCounter;
  24309. }
  24310. virtual void noteChildGraph(unsigned id, IActivityGraph *childGraph)
  24311. {
  24312. childGraphs.setValue(id, childGraph);
  24313. }
  24314. virtual IActivityGraph * queryChildGraph(unsigned id)
  24315. {
  24316. if (queryTraceLevel() > 10)
  24317. CTXLOG("resolveChildGraph %d", id);
  24318. IActivityGraph *childGraph = childGraphs.getValue(id);
  24319. assertex(childGraph);
  24320. return childGraph;
  24321. }
  24322. // 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
  24323. virtual StringBuffer &getLogPrefix(StringBuffer &ret) const
  24324. {
  24325. logctx.getLogPrefix(ret);
  24326. if (loopCounter)
  24327. ret.appendf("{%u}", loopCounter);
  24328. return ret;
  24329. }
  24330. protected:
  24331. const IRoxieContextLogger &logctx;
  24332. unsigned loopCounter;
  24333. ICodeContext * codeContext;
  24334. MapXToMyClass<unsigned, unsigned, IActivityGraph> childGraphs;
  24335. } graphSlaveContext;
  24336. class ActivityGraphCodeContext : public IndirectCodeContext
  24337. {
  24338. public:
  24339. virtual IEclGraphResults * resolveLocalQuery(__int64 activityId)
  24340. {
  24341. if ((unsigned) activityId == container->queryId())
  24342. return container;
  24343. IActivityGraph * match = slaveContext->queryChildGraph((unsigned) activityId);
  24344. if (match)
  24345. return match->queryLocalGraph();
  24346. return IndirectCodeContext::resolveLocalQuery(activityId);
  24347. }
  24348. virtual IThorChildGraph * resolveChildQuery(__int64 activityId, IHThorArg * colocal)
  24349. {
  24350. IActivityGraph * match = slaveContext->queryChildGraph((unsigned) activityId);
  24351. return LINK(match->queryChildGraph());
  24352. }
  24353. virtual unsigned getGraphLoopCounter() const
  24354. {
  24355. return container->queryLoopCounter(); // only called if value is valid
  24356. }
  24357. void setContainer(IRoxieSlaveContext * _slaveContext, CActivityGraph * _container)
  24358. {
  24359. slaveContext = _slaveContext;
  24360. container = _container;
  24361. }
  24362. protected:
  24363. IRoxieSlaveContext * slaveContext;
  24364. CActivityGraph * container;
  24365. } graphCodeContext;
  24366. // NOTE - destructor order is significant - need to destroy graphCodeContext and graphSlaveContext last
  24367. IArrayOf<IRoxieServerActivity> activities;
  24368. IArrayOf<IRoxieProbe> probes;
  24369. IRoxieServerActivityCopyArray sinks;
  24370. StringAttr graphName;
  24371. Owned<CGraphResults> results;
  24372. CGraphResults graphLoopResults;
  24373. const ActivityArray & graphDefinition;
  24374. CriticalSection evaluateCrit;
  24375. IProbeManager *probeManager;
  24376. unsigned id;
  24377. unsigned loopCounter;
  24378. public:
  24379. IMPLEMENT_IINTERFACE;
  24380. CActivityGraph(IRoxieSlaveContext *_ctx, const char *_graphName, unsigned _id, const ActivityArray &x, IProbeManager *_probeManager, const IRoxieContextLogger &_logctx)
  24381. : probeManager(_probeManager), graphDefinition(x), graphName(_graphName), graphSlaveContext(_ctx, _logctx)
  24382. {
  24383. id = x.getLibraryGraphId();
  24384. if (!id)
  24385. id = _id;
  24386. loopCounter = 0;
  24387. graphSlaveContext.setCodeContext(&graphCodeContext);
  24388. graphCodeContext.setContainer(&graphSlaveContext, this);
  24389. }
  24390. ~CActivityGraph()
  24391. {
  24392. if (probeManager)
  24393. probeManager->deleteGraph((IArrayOf<IActivityBase>*)&activities, (IArrayOf<IInputBase>*)&probes);
  24394. }
  24395. virtual const char *queryName() const
  24396. {
  24397. return graphName.get();
  24398. }
  24399. void createGraph(IRoxieSlaveContext *_ctx)
  24400. {
  24401. if (graphDefinition.isMultiInstance())
  24402. {
  24403. graphCodeContext.set(_ctx->queryCodeContext());
  24404. _ctx = &graphSlaveContext;
  24405. }
  24406. ForEachItemIn(idx, graphDefinition)
  24407. {
  24408. IRoxieServerActivityFactory &donor = graphDefinition.serverItem(idx);
  24409. IRoxieServerActivity &activity = *donor.createActivity(_ctx, probeManager);
  24410. activities.append(activity);
  24411. if (donor.isSink())
  24412. {
  24413. sinks.append(activity);
  24414. if (probeManager)
  24415. probeManager->noteSink(&activity);
  24416. }
  24417. }
  24418. ForEachItemIn(idx1, graphDefinition)
  24419. {
  24420. IRoxieServerActivityFactory &donor = graphDefinition.serverItem(idx1);
  24421. IRoxieServerActivity &activity = activities.item(idx1);
  24422. unsigned inputidx = 0;
  24423. for (;;)
  24424. {
  24425. unsigned outputidx;
  24426. unsigned source = donor.getInput(inputidx, outputidx);
  24427. if (source==(unsigned) -1)
  24428. break;
  24429. connectInput(idx1, inputidx, source, outputidx, 0);
  24430. inputidx++;
  24431. }
  24432. IntArray &dependencies = donor.queryDependencies();
  24433. IntArray &dependencyIndexes = donor.queryDependencyIndexes();
  24434. IntArray &dependencyControlIds = donor.queryDependencyControlIds();
  24435. StringArray &dependencyEdgeIds = donor.queryDependencyEdgeIds();
  24436. ForEachItemIn(idx2, dependencies)
  24437. {
  24438. IRoxieServerActivity &dependencySourceActivity = activities.item(dependencies.item(idx2));
  24439. unsigned dependencySourceIndex = dependencyIndexes.item(idx2);
  24440. unsigned dependencyControlId = dependencyControlIds.item(idx2);
  24441. activity.addDependency(dependencySourceActivity, dependencySourceIndex, dependencyControlId);
  24442. if (probeManager)
  24443. probeManager->noteDependency( &dependencySourceActivity, dependencySourceIndex, dependencyControlId, dependencyEdgeIds.item(idx2), &activity);
  24444. }
  24445. }
  24446. ForEachItemIn(idx2, sinks)
  24447. {
  24448. IRoxieServerActivity &sink = sinks.item(idx2);
  24449. sink.connectInputStreams(true);
  24450. }
  24451. }
  24452. void connectInput(unsigned target, unsigned targetIdx, unsigned source, unsigned sourceIdx, unsigned iteration)
  24453. {
  24454. IRoxieServerActivity &targetActivity = activities.item(target);
  24455. IRoxieServerActivity &sourceActivity = activities.item(source);
  24456. IFinalRoxieInput * output = sourceActivity.queryOutput(sourceIdx);
  24457. if (probeManager)
  24458. {
  24459. IRoxieProbe * inputProbe = probeManager->createProbe(static_cast<IInputBase*>(output), &sourceActivity, &targetActivity, sourceIdx, targetIdx, iteration);
  24460. probes.append(*LINK(inputProbe));
  24461. output = &dynamic_cast<IFinalRoxieInput &>(inputProbe->queryInput());
  24462. }
  24463. targetActivity.setInput(targetIdx, sourceIdx, output);
  24464. }
  24465. virtual void onCreate(IHThorArg *_colocalParent)
  24466. {
  24467. ForEachItemIn(idx, activities)
  24468. {
  24469. IRoxieServerActivity *activity = &activities.item(idx);
  24470. if (activity)
  24471. activity->onCreate(_colocalParent);
  24472. }
  24473. }
  24474. virtual void abort()
  24475. {
  24476. ForEachItemIn(idx, sinks)
  24477. {
  24478. IRoxieServerActivity &sink = sinks.item(idx);
  24479. sink.abort();
  24480. }
  24481. }
  24482. virtual void reset()
  24483. {
  24484. ForEachItemIn(idx, sinks)
  24485. {
  24486. IRoxieServerActivity &sink = sinks.item(idx);
  24487. sink.reset();
  24488. }
  24489. }
  24490. Linked<IException> exception;
  24491. CriticalSection eCrit;
  24492. virtual void noteException(IException *E)
  24493. {
  24494. CriticalBlock b(eCrit);
  24495. if (!exception)
  24496. {
  24497. if (graphSlaveContext.queryDebugContext())
  24498. {
  24499. graphSlaveContext.queryDebugContext()->checkBreakpoint(DebugStateException, NULL, exception);
  24500. }
  24501. exception.set(E);
  24502. }
  24503. }
  24504. virtual void checkAbort()
  24505. {
  24506. CriticalBlock b(eCrit);
  24507. if (exception)
  24508. throw exception.getLink();
  24509. }
  24510. virtual void execute()
  24511. {
  24512. results.setown(new CGraphResults);
  24513. doExecute(0, NULL);
  24514. }
  24515. //New child query code...
  24516. virtual IThorChildGraph * queryChildGraph()
  24517. {
  24518. return this;
  24519. }
  24520. virtual IEclGraphResults * queryLocalGraph()
  24521. {
  24522. return this;
  24523. }
  24524. virtual IRoxieServerChildGraph * queryLoopGraph()
  24525. {
  24526. return this;
  24527. }
  24528. inline unsigned queryId() const
  24529. {
  24530. return id;
  24531. }
  24532. inline unsigned queryLoopCounter() const
  24533. {
  24534. return loopCounter;
  24535. }
  24536. void doExecute(unsigned parentExtractSize, const byte * parentExtract)
  24537. {
  24538. if (sinks.ordinality()==1)
  24539. sinks.item(0).execute(parentExtractSize, parentExtract);
  24540. #ifdef PARALLEL_EXECUTE
  24541. else if (!probeManager && !graphDefinition.isSequential())
  24542. {
  24543. class casyncfor: public CAsyncFor
  24544. {
  24545. public:
  24546. IActivityGraph &parent;
  24547. unsigned parentExtractSize;
  24548. const byte * parentExtract;
  24549. casyncfor(IRoxieServerActivityCopyArray &_sinks, IActivityGraph &_parent, unsigned _parentExtractSize, const byte * _parentExtract) :
  24550. sinks(_sinks), parent(_parent), parentExtractSize(_parentExtractSize), parentExtract(_parentExtract) { }
  24551. void Do(unsigned i)
  24552. {
  24553. try
  24554. {
  24555. sinks.item(i).execute(parentExtractSize, parentExtract);
  24556. }
  24557. catch (IException *E)
  24558. {
  24559. parent.noteException(E);
  24560. throw;
  24561. }
  24562. }
  24563. private:
  24564. IRoxieServerActivityCopyArray &sinks;
  24565. } afor(sinks, *this, parentExtractSize, parentExtract);
  24566. afor.For(sinks.ordinality(), sinks.ordinality());
  24567. }
  24568. #endif
  24569. else
  24570. {
  24571. ForEachItemIn(idx, sinks)
  24572. {
  24573. IRoxieServerActivity &sink = sinks.item(idx);
  24574. sink.execute(parentExtractSize, parentExtract);
  24575. }
  24576. }
  24577. }
  24578. virtual IEclGraphResults *evaluate(unsigned parentExtractSize, const byte * parentExtract)
  24579. {
  24580. CriticalBlock block(evaluateCrit);
  24581. results.setown(new CGraphResults);
  24582. try
  24583. {
  24584. doExecute(parentExtractSize, parentExtract);
  24585. }
  24586. catch (...)
  24587. {
  24588. DBGLOG("Exception thrown in child query - cleaning up");
  24589. reset();
  24590. throw;
  24591. }
  24592. reset();
  24593. return results.getClear();
  24594. }
  24595. virtual void updateFactoryStatistics() const override
  24596. {
  24597. ForEachItemIn(i, activities)
  24598. activities.item(i).updateFactoryStatistics();
  24599. }
  24600. //interface IRoxieServerChildGraph
  24601. virtual void beforeExecute()
  24602. {
  24603. results.setown(new CGraphResults);
  24604. }
  24605. virtual IFinalRoxieInput * startOutput(unsigned id, unsigned parentExtractSize, const byte *parentExtract, bool paused)
  24606. {
  24607. IFinalRoxieInput * ret = selectOutput(id);
  24608. ret->start(parentExtractSize, parentExtract, paused);
  24609. return ret;
  24610. }
  24611. virtual IFinalRoxieInput * selectOutput(unsigned id)
  24612. {
  24613. ForEachItemIn(i, sinks)
  24614. {
  24615. IFinalRoxieInput * ret = sinks.item(i).querySelectOutput(id);
  24616. if (ret)
  24617. return ret;
  24618. }
  24619. throwUnexpected();
  24620. return NULL;
  24621. }
  24622. virtual void setInputResult(unsigned id, IGraphResult * result)
  24623. {
  24624. results->setResult(id, result);
  24625. }
  24626. virtual bool querySetInputResult(unsigned id, unsigned _sourceIdx, IFinalRoxieInput * input)
  24627. {
  24628. ForEachItemIn(i, activities)
  24629. {
  24630. if (activities.item(i).querySetStreamInput(id, _sourceIdx, input))
  24631. return true;
  24632. }
  24633. return false;
  24634. }
  24635. virtual void stopUnusedOutputs()
  24636. {
  24637. //Hmm not sure how to do this...
  24638. }
  24639. virtual void afterExecute()
  24640. {
  24641. ForEachItemIn(i, sinks)
  24642. {
  24643. sinks.item(i).stop();
  24644. }
  24645. if (graphSlaveContext.queryDebugContext())
  24646. {
  24647. graphSlaveContext.queryDebugContext()->checkBreakpoint(DebugStateGraphFinished, NULL, NULL);
  24648. }
  24649. reset();
  24650. }
  24651. virtual IRoxieGraphResults * execute(size32_t parentExtractSize, const byte *parentExtract)
  24652. {
  24653. doExecute(parentExtractSize, parentExtract);
  24654. return LINK(results);
  24655. }
  24656. virtual void getLinkedResult(unsigned & count, const byte * * & ret, unsigned id) override
  24657. {
  24658. results->getLinkedResult(count, ret, id);
  24659. }
  24660. virtual void getDictionaryResult(unsigned & count, const byte * * & ret, unsigned id) override
  24661. {
  24662. results->getLinkedResult(count, ret, id);
  24663. }
  24664. virtual const void * getLinkedRowResult(unsigned id)
  24665. {
  24666. return results->getLinkedRowResult(id);
  24667. }
  24668. virtual void setResult(unsigned id, IGraphResult * result)
  24669. {
  24670. results->setResult(id, result);
  24671. }
  24672. virtual IEngineRowStream * createResultIterator(unsigned id)
  24673. {
  24674. return results->createIterator(id);
  24675. }
  24676. virtual void setGraphLoopResult(IGraphResult * result)
  24677. {
  24678. graphLoopResults.appendResult(result);
  24679. }
  24680. virtual IEngineRowStream * createGraphLoopResultIterator(unsigned id)
  24681. {
  24682. try
  24683. {
  24684. return graphLoopResults.createIterator(id);
  24685. }
  24686. catch (IException * e)
  24687. {
  24688. e->Release();
  24689. throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Error reading graph result %d before it is calculated", id);
  24690. }
  24691. }
  24692. virtual void clearGraphLoopResults()
  24693. {
  24694. graphLoopResults.clear();
  24695. }
  24696. virtual void executeGraphLoop(size32_t parentExtractSize, const byte *parentExtract)
  24697. {
  24698. doExecute(parentExtractSize, parentExtract);
  24699. }
  24700. virtual void setGraphLoopResult(unsigned id, IGraphResult * result)
  24701. {
  24702. graphLoopResults.setResult(id, result);
  24703. }
  24704. virtual IEngineRowStream * getGraphLoopResult(unsigned id)
  24705. {
  24706. return graphLoopResults.createIterator(id);
  24707. }
  24708. virtual void getProbeResponse(IPropertyTree *query)
  24709. {
  24710. if (probeManager)
  24711. probeManager->getProbeResponse(query);
  24712. }
  24713. virtual IRoxieServerChildGraph * createGraphLoopInstance(IRoxieSlaveContext *ctx, unsigned loopCounter, unsigned parentExtractSize, const byte * parentExtract, const IRoxieContextLogger &logctx)
  24714. {
  24715. throwUnexpected();
  24716. }
  24717. virtual CGraphIterationInfo *selectGraphLoopOutput()
  24718. {
  24719. return NULL;
  24720. }
  24721. virtual void gatherIterationUsage(IRoxieServerLoopResultProcessor & processor)
  24722. {
  24723. throwUnexpected();
  24724. }
  24725. virtual void associateIterationOutputs(IRoxieServerLoopResultProcessor & processor)
  24726. {
  24727. throwUnexpected();
  24728. }
  24729. };
  24730. class CProxyActivityGraph : implements IActivityGraph, implements IThorChildGraph, public CInterface
  24731. {
  24732. public:
  24733. IMPLEMENT_IINTERFACE;
  24734. CProxyActivityGraph(IRoxieSlaveContext *_ctx, const char *_graphName, unsigned _id, ActivityArray &_graphDefinition, const IRoxieContextLogger &_logctx, unsigned _numParallel)
  24735. : ctx(_ctx), graphName(_graphName), id(_id), graphDefinition(_graphDefinition), logctx(_logctx), numParallel(_numParallel)
  24736. {
  24737. }
  24738. virtual void abort() override { throwUnexpected(); }
  24739. virtual void reset() override { throwUnexpected(); }
  24740. virtual void execute() override { throwUnexpected(); }
  24741. virtual void getProbeResponse(IPropertyTree *query) override { throwUnexpected(); }
  24742. virtual void onCreate(IHThorArg *_colocalArg) override
  24743. {
  24744. colocalArg = _colocalArg;
  24745. }
  24746. virtual void noteException(IException *E) override { throwUnexpected(); }
  24747. virtual void checkAbort() override { throwUnexpected(); }
  24748. virtual IThorChildGraph * queryChildGraph() override { return this; }
  24749. virtual IEclGraphResults * queryLocalGraph() override { throwUnexpected(); }
  24750. virtual IRoxieServerChildGraph * queryLoopGraph() override { throwUnexpected(); }
  24751. virtual IRoxieServerChildGraph * createGraphLoopInstance(IRoxieSlaveContext *ctx, unsigned loopCounter, unsigned parentExtractSize, const byte * parentExtract, const IRoxieContextLogger &logctx) override { throwUnexpected(); }
  24752. virtual const char *queryName() const override { throwUnexpected(); }
  24753. virtual void updateFactoryStatistics() const override
  24754. {
  24755. CriticalBlock b(graphCrit);
  24756. ForEachItemIn(i, stack)
  24757. stack.item(i).updateFactoryStatistics();
  24758. }
  24759. virtual IEclGraphResults * evaluate(unsigned parentExtractSize, const byte * parentExtract) override
  24760. {
  24761. Owned<CActivityGraph> realGraph;
  24762. {
  24763. CriticalBlock b(graphCrit);
  24764. if (stack.length())
  24765. realGraph.setown(&stack.popGet());
  24766. }
  24767. if (!realGraph)
  24768. {
  24769. realGraph.setown(new CActivityGraph(ctx, graphName, id, graphDefinition, NULL, logctx));
  24770. realGraph->createGraph(ctx);
  24771. realGraph->onCreate(colocalArg);
  24772. }
  24773. Owned<IEclGraphResults> results = realGraph->evaluate(parentExtractSize, parentExtract);
  24774. {
  24775. CriticalBlock b(graphCrit);
  24776. stack.append(*realGraph.getClear());
  24777. }
  24778. return results.getClear();
  24779. }
  24780. protected:
  24781. IRoxieSlaveContext *ctx;
  24782. StringAttr graphName;
  24783. unsigned id;
  24784. ActivityArray &graphDefinition;
  24785. const IRoxieContextLogger &logctx;
  24786. unsigned numParallel;
  24787. IHThorArg *colocalArg = nullptr;
  24788. mutable CriticalSection graphCrit;
  24789. CIArrayOf<CActivityGraph> stack;
  24790. };
  24791. class CIterationActivityGraph : public CActivityGraph
  24792. {
  24793. IHThorArg * colocalParent;
  24794. unsigned fixedParentExtractSize;
  24795. const byte * fixedParentExtract;
  24796. unsigned graphOutputActivityIndex;
  24797. public:
  24798. CIterationActivityGraph(const char *_graphName, unsigned _id, ActivityArray &x, IProbeManager *_probeManager,
  24799. unsigned _loopCounter, IRoxieSlaveContext *_ctx, IHThorArg * _colocalParent, unsigned parentExtractSize, const byte * parentExtract, const IRoxieContextLogger &_logctx)
  24800. : CActivityGraph(_ctx, _graphName, _id, x, _probeManager, _logctx)
  24801. {
  24802. graphOutputActivityIndex = 0;
  24803. loopCounter = _loopCounter;
  24804. colocalParent = _colocalParent;
  24805. graphSlaveContext.setLoopCounter(loopCounter);
  24806. graphCodeContext.set(_ctx->queryCodeContext());
  24807. fixedParentExtractSize = parentExtractSize;
  24808. fixedParentExtract = parentExtract;
  24809. }
  24810. void createIterationGraph(IRoxieSlaveContext *_ctx)
  24811. {
  24812. Owned<IRoxieServerActivity> pseudoActivity = new CPseudoActivity(_ctx, *new CPseudoArg);
  24813. ForEachItemIn(idx1, graphDefinition)
  24814. activities.append(*LINK(pseudoActivity));
  24815. graphOutputActivityIndex = queryGraphOutputIndex();
  24816. recursiveCreateGraph(_ctx, graphOutputActivityIndex);
  24817. }
  24818. unsigned queryGraphOutputIndex() const
  24819. {
  24820. ForEachItemIn(i, graphDefinition)
  24821. if (graphDefinition.serverItem(i).getKind() == TAKgraphloopresultwrite)
  24822. return i;
  24823. throwUnexpected();
  24824. }
  24825. void recursiveCreateGraph(IRoxieSlaveContext *_ctx, unsigned whichActivity)
  24826. {
  24827. //Check to see if already created
  24828. IRoxieServerActivity & prevActivity = activities.item(whichActivity);
  24829. if (prevActivity.queryId() != 0)
  24830. {
  24831. prevActivity.noteOutputUsed(); //We need to patch up the number of outputs for splitters.
  24832. return;
  24833. }
  24834. IRoxieServerActivityFactory &donor = graphDefinition.serverItem(whichActivity);
  24835. IRoxieServerActivity * activity = NULL;
  24836. if (donor.isGraphInvariant())
  24837. {
  24838. ThorActivityKind kind = donor.getKind();
  24839. switch (kind)
  24840. {
  24841. case TAKif:
  24842. case TAKchildif:
  24843. case TAKcase:
  24844. case TAKchildcase: // MORE RKC->GH - what about FILTER with a graph-invariant condition and other latestart activities?
  24845. {
  24846. Owned<IHThorArg> helper = &donor.getHelper();
  24847. helper->onCreate(&graphCodeContext, colocalParent, NULL);
  24848. helper->onStart(fixedParentExtract, NULL);
  24849. unsigned branch;
  24850. switch (kind)
  24851. {
  24852. case TAKif: case TAKchildif:
  24853. branch = static_cast<IHThorIfArg *>(helper.get())->getCondition() ? 0 : 1;
  24854. break;
  24855. case TAKcase: case TAKchildcase:
  24856. branch = static_cast<IHThorCaseArg *>(helper.get())->getBranch();
  24857. if (branch >= donor.numInputs())
  24858. branch = donor.numInputs() - 1;
  24859. break;
  24860. default:
  24861. throwUnexpected();
  24862. }
  24863. helper.clear();
  24864. unsigned outputidx;
  24865. unsigned source = donor.getInput(branch, outputidx);
  24866. if (source ==(unsigned) -1)
  24867. activity = createRoxieServerNullActivity(&graphSlaveContext, &donor, probeManager);
  24868. else
  24869. activity = createRoxieServerPassThroughActivity(&graphSlaveContext, &donor, probeManager);
  24870. activities.replace(*activity, whichActivity);
  24871. activity->onCreate(colocalParent);
  24872. if (source ==(unsigned) -1)
  24873. return;
  24874. recursiveCreateGraph(_ctx, source);
  24875. connectInput(whichActivity, 0, source, outputidx, loopCounter);
  24876. break;
  24877. }
  24878. }
  24879. }
  24880. if (!activity)
  24881. {
  24882. activity = donor.createActivity(&graphSlaveContext, probeManager);
  24883. activities.replace(*activity, whichActivity);
  24884. activity->onCreate(colocalParent);
  24885. activity->resetOutputsUsed();
  24886. unsigned inputidx = 0;
  24887. for (;;)
  24888. {
  24889. unsigned outputidx;
  24890. unsigned source = donor.getInput(inputidx, outputidx);
  24891. if (source==(unsigned) -1)
  24892. break;
  24893. recursiveCreateGraph(_ctx, source);
  24894. connectInput(whichActivity, inputidx, source, outputidx, loopCounter);
  24895. inputidx++;
  24896. }
  24897. }
  24898. IntArray &dependencies = donor.queryDependencies();
  24899. IntArray &dependencyIndexes = donor.queryDependencyIndexes();
  24900. IntArray &dependencyControlIds = donor.queryDependencyControlIds();
  24901. ForEachItemIn(idx2, dependencies)
  24902. {
  24903. unsigned input = dependencies.item(idx2);
  24904. recursiveCreateGraph(_ctx, input);
  24905. activity->addDependency(activities.item(input),dependencyIndexes.item(idx2),dependencyControlIds.item(idx2));
  24906. }
  24907. }
  24908. virtual CGraphIterationInfo *selectGraphLoopOutput()
  24909. {
  24910. IRoxieServerActivity &sourceActivity = activities.item(graphOutputActivityIndex);
  24911. IFinalRoxieInput *sourceInput = sourceActivity.queryOutput(0);
  24912. return new CGraphIterationInfo(&sourceActivity, sourceInput, 0, loopCounter);
  24913. }
  24914. virtual void gatherIterationUsage(IRoxieServerLoopResultProcessor & processor)
  24915. {
  24916. ForEachItemIn(i, activities)
  24917. activities.item(i).gatherIterationUsage(processor, fixedParentExtractSize, fixedParentExtract);
  24918. }
  24919. virtual void associateIterationOutputs(IRoxieServerLoopResultProcessor & processor)
  24920. {
  24921. ForEachItemIn(i, activities)
  24922. activities.item(i).associateIterationOutputs(processor, fixedParentExtractSize, fixedParentExtract, probeManager, probes);
  24923. }
  24924. };
  24925. class CDelayedActivityGraph : implements IActivityGraph, public CInterface
  24926. {
  24927. StringAttr graphName;
  24928. ActivityArray & graphDefinition;
  24929. IProbeManager *probeManager;
  24930. unsigned id;
  24931. IRoxieSlaveContext * ctx;
  24932. IHThorArg * colocalParent;
  24933. public:
  24934. IMPLEMENT_IINTERFACE;
  24935. CDelayedActivityGraph(const char *_graphName, unsigned _id, ActivityArray &x, IProbeManager *_probeManager)
  24936. : probeManager(_probeManager), graphDefinition(x)
  24937. {
  24938. graphName.set(_graphName);
  24939. id = _id;
  24940. ctx = NULL;
  24941. colocalParent = NULL;
  24942. }
  24943. virtual const char *queryName() const override { return graphName.get(); }
  24944. virtual void abort() override { throwUnexpected(); }
  24945. virtual void reset() override { }
  24946. virtual void execute() override { throwUnexpected(); }
  24947. virtual void getProbeResponse(IPropertyTree *query) override { throwUnexpected(); }
  24948. virtual void noteException(IException *E) override { throwUnexpected(); }
  24949. virtual void checkAbort() override { throwUnexpected(); }
  24950. virtual IThorChildGraph * queryChildGraph() override { throwUnexpected(); }
  24951. virtual IEclGraphResults * queryLocalGraph() override { throwUnexpected(); }
  24952. virtual IRoxieServerChildGraph * queryLoopGraph() override { throwUnexpected(); }
  24953. virtual void updateFactoryStatistics() const override { }
  24954. virtual void onCreate(IHThorArg *_colocalParent) override
  24955. {
  24956. colocalParent = _colocalParent;
  24957. }
  24958. virtual IRoxieServerChildGraph * createGraphLoopInstance(IRoxieSlaveContext *ctx, unsigned loopCounter, unsigned parentExtractSize, const byte * parentExtract, const IRoxieContextLogger &logctx) override
  24959. {
  24960. Owned<CIterationActivityGraph> ret = new CIterationActivityGraph(graphName, id, graphDefinition, probeManager, loopCounter, ctx, colocalParent, parentExtractSize, parentExtract, logctx);
  24961. ret->createIterationGraph(ctx);
  24962. return ret.getClear();
  24963. }
  24964. };
  24965. IActivityGraph *createActivityGraph(IRoxieSlaveContext *ctx, const char *_graphName, unsigned id, ActivityArray &childFactories, IRoxieServerActivity *parentActivity, IProbeManager *_probeManager, const IRoxieContextLogger &_logctx, unsigned numParallel)
  24966. {
  24967. if (childFactories.isDelayed())
  24968. {
  24969. assertex(numParallel==1);
  24970. return new CDelayedActivityGraph(_graphName, id, childFactories, _probeManager);
  24971. }
  24972. else
  24973. {
  24974. if (numParallel==1 || _probeManager != nullptr)
  24975. {
  24976. Owned<IProbeManager> childProbe;
  24977. if (_probeManager)
  24978. childProbe.setown(_probeManager->startChildGraph(id, parentActivity));
  24979. Owned<CActivityGraph> ret = new CActivityGraph(ctx, _graphName, id, childFactories, childProbe, _logctx);
  24980. ret->createGraph(ctx);
  24981. if (_probeManager)
  24982. _probeManager->endChildGraph(childProbe, parentActivity);
  24983. return ret.getClear();
  24984. }
  24985. else
  24986. return new CProxyActivityGraph(ctx, _graphName, id, childFactories, _logctx, numParallel);
  24987. }
  24988. }
  24989. //================================================================================================================
  24990. #ifdef _USE_CPPUNIT
  24991. #include "unittests.hpp"
  24992. // 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...
  24993. #if _MSC_VER==1200
  24994. #undef protected
  24995. #endif
  24996. static const char *sortAlgorithm;
  24997. class TestMetaData : public CInterface, implements IOutputMetaData
  24998. {
  24999. public:
  25000. IMPLEMENT_IINTERFACE;
  25001. virtual size32_t getRecordSize(const void *) { return 10; }
  25002. virtual size32_t getMinRecordSize() const { return 10; }
  25003. virtual size32_t getFixedSize() const { return 10; }
  25004. virtual void toXML(const byte * self, IXmlWriter & out) {}
  25005. virtual unsigned getVersion() const { return OUTPUTMETADATA_VERSION; }
  25006. virtual unsigned getMetaFlags() { return 0; }
  25007. virtual void destruct(byte * self) {}
  25008. virtual IOutputRowSerializer * createDiskSerializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
  25009. virtual IOutputRowDeserializer * createDiskDeserializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
  25010. virtual ISourceRowPrefetcher * createDiskPrefetcher(ICodeContext * ctx, unsigned activityId) { return NULL; }
  25011. virtual IOutputMetaData * querySerializedDiskMeta() { return NULL; }
  25012. virtual IOutputRowSerializer * createInternalSerializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
  25013. virtual IOutputRowDeserializer * createInternalDeserializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
  25014. virtual void walkIndirectMembers(const byte * self, IIndirectMemberVisitor & visitor) {}
  25015. virtual IOutputMetaData * queryChildMeta(unsigned i) { return NULL; }
  25016. virtual const RtlRecord &queryRecordAccessor(bool expand) const { throwUnexpected(); }
  25017. } testMeta;
  25018. class TestInput : public CInterface, implements IFinalRoxieInput, implements IEngineRowStream
  25019. {
  25020. char const * const *input;
  25021. IRoxieSlaveContext *ctx;
  25022. unsigned endSeen;
  25023. bool eof;
  25024. unsigned count;
  25025. ActivityTimeAccumulator totalCycles;
  25026. size32_t recordSize;
  25027. unsigned activityId;
  25028. public:
  25029. enum { STATEreset, STATEstarted, STATEstopped } state;
  25030. bool allRead;
  25031. unsigned repeat;
  25032. IMPLEMENT_IINTERFACE;
  25033. TestInput(IRoxieSlaveContext *_ctx, char const * const *_input)
  25034. {
  25035. ctx = _ctx;
  25036. input = _input;
  25037. count = 0;
  25038. eof = false;
  25039. allRead = false;
  25040. endSeen = 0;
  25041. recordSize = testMeta.getFixedSize();
  25042. state = STATEreset;
  25043. activityId = 1;
  25044. repeat = 0;
  25045. }
  25046. virtual IOutputMetaData * queryOutputMeta() const { return &testMeta; }
  25047. virtual void prestart(unsigned parentExtractSize, const byte *parentExtract)
  25048. {
  25049. ASSERT(state == STATEreset);
  25050. }
  25051. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  25052. {
  25053. ASSERT(state == STATEreset);
  25054. state = STATEstarted;
  25055. }
  25056. virtual IStrandJunction *getOutputStreams(IRoxieSlaveContext *ctx, unsigned idx, PointerArrayOf<IEngineRowStream> &streams, const StrandOptions * consumerOptions, bool consumerOrdered, IOrderedCallbackCollection * orderedCallbacks)
  25057. {
  25058. streams.append(this);
  25059. return NULL;
  25060. }
  25061. virtual IEngineRowStream *queryConcreteOutputStream(unsigned whichInput) { assertex(whichInput==0); return this; }
  25062. virtual IStrandJunction *queryConcreteOutputJunction(unsigned idx) const { assertex(idx==0); return nullptr; }
  25063. virtual IRoxieServerActivity *queryActivity()
  25064. {
  25065. throwUnexpected();
  25066. }
  25067. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  25068. {
  25069. throwUnexpected();
  25070. }
  25071. virtual void stop()
  25072. {
  25073. state = STATEstopped;
  25074. }
  25075. virtual void reset()
  25076. {
  25077. ASSERT(state == STATEstopped);
  25078. eof = false; count = 0; endSeen = 0; allRead = false; state = STATEreset;
  25079. }
  25080. virtual void resetEOF()
  25081. {
  25082. throwUnexpected();
  25083. }
  25084. virtual void checkAbort() {}
  25085. virtual unsigned queryId() const { return activityId; };
  25086. virtual const void *nextRow()
  25087. {
  25088. ActivityTimer t(totalCycles, ctx->queryOptions().timeActivities);
  25089. ASSERT(state == STATEstarted);
  25090. ASSERT(allRead || !eof);
  25091. if (eof)
  25092. return NULL;
  25093. again:
  25094. const char *nextSource = input[count++];
  25095. if (nextSource)
  25096. {
  25097. endSeen = 0;
  25098. void *ret = ctx->queryRowManager().ALLOCATE(recordSize);
  25099. memset(ret, 0, recordSize);
  25100. strncpy((char *) ret, nextSource, recordSize);
  25101. return ret;
  25102. }
  25103. else if (repeat)
  25104. {
  25105. repeat--;
  25106. count = 0;
  25107. goto again;
  25108. }
  25109. else
  25110. {
  25111. endSeen++;
  25112. if (endSeen==2)
  25113. eof = true;
  25114. return NULL;
  25115. }
  25116. }
  25117. virtual bool nextGroup(ConstPointerArray & group)
  25118. {
  25119. const void * next;
  25120. while ((next = nextRow()) != NULL)
  25121. group.append(next);
  25122. if (group.ordinality())
  25123. return true;
  25124. return false;
  25125. }
  25126. virtual unsigned __int64 queryTotalCycles() const { return totalCycles.totalCycles; }
  25127. virtual unsigned __int64 queryLocalCycles() const { return totalCycles.totalCycles; }
  25128. virtual IFinalRoxieInput *queryInput(unsigned idx) const
  25129. {
  25130. return NULL;
  25131. }
  25132. };
  25133. struct SortActivityTest : public CThorSortArg {
  25134. public:
  25135. struct CompareClass : public ICompare {
  25136. virtual int docompare(const void * _left, const void * _right) const {
  25137. return memcmp(_left, _right, 5);
  25138. }
  25139. } compare;
  25140. virtual ICompare * queryCompare() { return &compare; }
  25141. virtual IOutputMetaData * queryOutputMeta()
  25142. {
  25143. return &testMeta;
  25144. }
  25145. virtual unsigned getAlgorithmFlags() { return TAFunstable; }
  25146. virtual const char * getAlgorithm() { return sortAlgorithm; }
  25147. };
  25148. extern "C" IHThorArg * sortActivityTestFactory() { return new SortActivityTest; }
  25149. struct MergeActivityTest : public CThorMergeArg {
  25150. static bool isDedup;
  25151. public:
  25152. struct CompareClass : public ICompare {
  25153. virtual int docompare(const void * _left, const void * _right) const {
  25154. return memcmp(_left, _right, 5);
  25155. }
  25156. } compare;
  25157. virtual ICompare * queryCompare() { return &compare; }
  25158. virtual IOutputMetaData * queryOutputMeta()
  25159. {
  25160. return &testMeta;
  25161. }
  25162. virtual bool dedup() { return isDedup; }
  25163. };
  25164. bool MergeActivityTest::isDedup = false;
  25165. extern "C" IHThorArg * mergeActivityTestFactory() { return new MergeActivityTest; }
  25166. struct SplitActivityTest : public CThorSplitArg {
  25167. public:
  25168. virtual unsigned numBranches() { return 2; }
  25169. virtual IOutputMetaData * queryOutputMeta()
  25170. {
  25171. return &testMeta;
  25172. }
  25173. };
  25174. extern "C" IHThorArg * splitActivityTestFactory() { return new SplitActivityTest; }
  25175. class CcdServerTest : public CppUnit::TestFixture
  25176. {
  25177. CPPUNIT_TEST_SUITE(CcdServerTest);
  25178. CPPUNIT_TEST(testSetup);
  25179. CPPUNIT_TEST(testHeapSort);
  25180. CPPUNIT_TEST(testQuickSort);
  25181. CPPUNIT_TEST(testMerge);
  25182. CPPUNIT_TEST(testMergeDedup);
  25183. CPPUNIT_TEST(testMiscellaneous);
  25184. CPPUNIT_TEST(testSplitter);
  25185. CPPUNIT_TEST(testCleanup);
  25186. CPPUNIT_TEST_SUITE_END();
  25187. protected:
  25188. SlaveContextLogger logctx;
  25189. Owned<const IQueryDll> queryDll;
  25190. Owned<IRoxiePackage> package;
  25191. Owned<IPropertyTree> stateInfo;
  25192. Owned<IQueryFactory> queryFactory;
  25193. Owned<IRoxieSlaveContext> ctx;
  25194. void testSetup()
  25195. {
  25196. selfTestMode = true;
  25197. roxiemem::setTotalMemoryLimit(false, true, false, 100 * 1024 * 1024, 0, NULL, NULL);
  25198. }
  25199. void testCleanup()
  25200. {
  25201. roxiemem::releaseRoxieHeap();
  25202. }
  25203. void init()
  25204. {
  25205. package.setown(createRoxiePackage(NULL, NULL));
  25206. queryDll.setown(createExeQueryDll("roxie"));
  25207. stateInfo.setown(createPTreeFromXMLString("<test memoryLimit='50000000'/>"));
  25208. queryFactory.setown(createServerQueryFactory("test", queryDll.getLink(), *package, stateInfo, false, false));
  25209. ctx.setown(createSlaveContext(queryFactory, logctx, NULL, false));
  25210. queryActiveTimer()->reset();
  25211. }
  25212. void testActivity(IRoxieServerActivity *activity, char const * const *input, char const * const *output)
  25213. {
  25214. testActivity(activity, input, NULL, output);
  25215. }
  25216. void testActivity(IRoxieServerActivity *activity, char const * const *input, char const * const *input2, char const * const *output, unsigned outputIdx = 0)
  25217. {
  25218. TestInput in(ctx, input);
  25219. TestInput in2(ctx, input2);
  25220. activity->setInput(0, 0, &in);
  25221. if (input2)
  25222. activity->setInput(1, 0, &in2);
  25223. IFinalRoxieInput *out = activity->queryOutput(outputIdx);
  25224. IEngineRowStream *outStream = connectSingleStream(ctx, out, outputIdx, true);
  25225. IOutputMetaData *meta = out->queryOutputMeta();
  25226. void *buf = alloca(meta->getFixedSize());
  25227. for (unsigned iteration = 0; iteration < 8; iteration++)
  25228. {
  25229. // 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)
  25230. // This should be true whether we read all, some, or none of the data.
  25231. // Should not matter if an activity is not started
  25232. if (iteration % 4 == 0)
  25233. activity->onCreate(NULL);
  25234. unsigned count = 0;
  25235. if (iteration % 4 != 3)
  25236. {
  25237. activity->start(0, NULL, false);
  25238. ASSERT(in.state == TestInput::STATEstarted);
  25239. ASSERT(!input2 || in2.state == TestInput::STATEstarted);
  25240. for (;;)
  25241. {
  25242. const void *next = outStream->nextRow();
  25243. if (!next)
  25244. {
  25245. ASSERT(output[count++] == NULL);
  25246. next = outStream->nextRow();
  25247. if (!next)
  25248. {
  25249. ASSERT(output[count++] == NULL);
  25250. break;
  25251. }
  25252. }
  25253. ASSERT(output[count] != NULL);
  25254. unsigned outsize = meta->getRecordSize(next);
  25255. memset(buf, 0, outsize);
  25256. strncpy((char *) buf, output[count++], outsize);
  25257. ASSERT(memcmp(next, buf, outsize) == 0);
  25258. ReleaseRoxieRow(next);
  25259. if (iteration % 4 == 2)
  25260. break;
  25261. }
  25262. if (iteration % 4 != 2)
  25263. {
  25264. // Check that reading after end is harmless
  25265. in.allRead = true;
  25266. const void *next = outStream->nextRow();
  25267. ASSERT(next == NULL);
  25268. }
  25269. }
  25270. activity->stop();
  25271. ASSERT(in.state == TestInput::STATEstopped);
  25272. ASSERT(!input2 || in2.state == TestInput::STATEstopped);
  25273. activity->reset();
  25274. ASSERT(in.state == TestInput::STATEreset);
  25275. ASSERT(!input2 || in2.state == TestInput::STATEreset);
  25276. ctx->queryRowManager().reportLeaks();
  25277. ASSERT(ctx->queryRowManager().numPagesAfterCleanup(true) == 0);
  25278. }
  25279. }
  25280. void testSplitActivity(IRoxieServerActivityFactory *factory, char const * const *input, char const * const *output, unsigned numOutputs, unsigned repeat)
  25281. {
  25282. Owned <IRoxieServerActivity> activity = factory->createActivity(ctx, NULL);
  25283. TestInput in(ctx, input);
  25284. in.repeat = repeat;
  25285. activity->setInput(0, 0, &in);
  25286. ArrayOf<IFinalRoxieInput *> out;
  25287. for (unsigned i = 0; i < numOutputs; i++)
  25288. {
  25289. out.append(activity->queryOutput(i));
  25290. }
  25291. activity->onCreate(NULL);
  25292. class casyncfor: public CAsyncFor
  25293. {
  25294. public:
  25295. casyncfor(CcdServerTest *_parent, IRoxieServerActivity *_activity, ArrayOf<IFinalRoxieInput *> &_outputs, char const * const *_input, char const * const *_output, unsigned _repeat)
  25296. : parent(_parent), activity(_activity), outputs(_outputs), input(_input), output(_output), repeat(_repeat)
  25297. {}
  25298. void Do(unsigned i)
  25299. {
  25300. IFinalRoxieInput *out = outputs.item(i);
  25301. IEngineRowStream *outStream = connectSingleStream(NULL, out, 0, true);
  25302. out->start(0, NULL, false);
  25303. IOutputMetaData *meta = out->queryOutputMeta();
  25304. void *buf = alloca(meta->getFixedSize());
  25305. unsigned count = 0;
  25306. unsigned repeats = repeat;
  25307. for (;;)
  25308. {
  25309. const void *next = outStream->nextRow();
  25310. if (!next)
  25311. {
  25312. ASSERT(repeats==0);
  25313. ASSERT(output[count] == NULL);
  25314. count++;
  25315. next = outStream->nextRow();
  25316. if (!next)
  25317. {
  25318. ASSERT(output[count] == NULL);
  25319. count++;
  25320. break;
  25321. }
  25322. }
  25323. if (output[count] == NULL && repeats)
  25324. {
  25325. repeats--;
  25326. count = 0;
  25327. }
  25328. ASSERT(output[count] != NULL);
  25329. unsigned outsize = meta->getRecordSize(next);
  25330. memset(buf, 0, outsize);
  25331. strncpy((char *) buf, output[count++], outsize);
  25332. ASSERT(memcmp(next, buf, outsize) == 0);
  25333. ReleaseRoxieRow(next);
  25334. }
  25335. outStream->stop();
  25336. }
  25337. private:
  25338. IRoxieServerActivity *activity;
  25339. ArrayOf<IFinalRoxieInput *> &outputs;
  25340. char const * const *input;
  25341. char const * const *output;
  25342. unsigned repeat;
  25343. CcdServerTest *parent;
  25344. } afor(this, activity, out, input, output, repeat);
  25345. afor.For(numOutputs, numOutputs);
  25346. ASSERT(in.state == TestInput::STATEstopped);
  25347. for (unsigned i2 = 0; i2 < numOutputs; i2++)
  25348. {
  25349. out.item(i2)->reset();
  25350. }
  25351. ASSERT(in.state == TestInput::STATEreset);
  25352. ctx->queryRowManager().reportLeaks();
  25353. ASSERT(ctx->queryRowManager().numPagesAfterCleanup(true) == 0);
  25354. }
  25355. static int compareFunc(const void *l, const void *r)
  25356. {
  25357. return strcmp(*(char **) l, *(char **) r);
  25358. }
  25359. void testSort(unsigned type)
  25360. {
  25361. init();
  25362. sortAlgorithm = NULL;
  25363. if (type==2)
  25364. sortAlgorithm = "heapSort";
  25365. else
  25366. sortAlgorithm = "quickSort";
  25367. DBGLOG("Testing %s activity", sortAlgorithm);
  25368. Owned<IPropertyTree> dummyNode = createPTree("node");
  25369. Owned <IRoxieServerActivityFactory> factory = createRoxieServerSortActivityFactory(1, 1, *queryFactory, sortActivityTestFactory, TAKsort, *dummyNode);
  25370. Owned <IRoxieServerActivity> activity = factory->createActivity(ctx, NULL);
  25371. const char * test[] = { NULL, NULL };
  25372. const char * test12345[] = { "1", "2", "3", "4", "5", NULL, NULL };
  25373. const char * test54321[] = { "5", "4", "3", "2", "1", NULL, NULL };
  25374. const char * test11111[] = { "1", "1", "1", "1", "1", NULL, NULL };
  25375. const char * test11111_12345[] = { "1", "1", "1", "1", "1", NULL, "1", "2", "3", "4", "5", NULL, NULL };
  25376. const char * test11111_54321[] = { "1", "1", "1", "1", "1", NULL, "5", "4", "3", "2", "1", NULL, NULL };
  25377. const char * test54321_54321[] = { "5", "4", "3", "2", "1", NULL, "5", "4", "3", "2", "1", NULL, NULL };
  25378. const char * test12345_12345[] = { "1", "2", "3", "4", "5", NULL, "1", "2", "3", "4", "5", NULL, NULL };
  25379. testActivity(activity, test, test);
  25380. testActivity(activity, test12345, test12345);
  25381. testActivity(activity, test54321, test12345);
  25382. testActivity(activity, test11111, test11111);
  25383. testActivity(activity, test11111_12345, test11111_12345);
  25384. testActivity(activity, test11111_54321, test11111_12345);
  25385. testActivity(activity, test54321_54321, test12345_12345);
  25386. // A few larger tests
  25387. char *input[2002];
  25388. char *output[2002];
  25389. input[2000] = input[2001] = output[2000] = output[2001] = NULL;
  25390. unsigned i;
  25391. // identical
  25392. for (i=0; i<2000; i++)
  25393. {
  25394. input[i] = new char[11];
  25395. output[i] = new char[11];
  25396. sprintf(input[i], "1");
  25397. sprintf(output[i], "1");
  25398. }
  25399. testActivity(activity, input, output);
  25400. // Ascending
  25401. for (i=0; i<2000; i++)
  25402. {
  25403. sprintf(input[i], "%04d", i);
  25404. sprintf(output[i], "%04d", i);
  25405. }
  25406. testActivity(activity, input, output);
  25407. // Almost sorted
  25408. for (i=0; i<20; i++)
  25409. {
  25410. unsigned h = i*100;
  25411. sprintf(input[h], "%04d", 1900-h);
  25412. }
  25413. testActivity(activity, input, output);
  25414. // Descending
  25415. for (i=0; i<2000; i++)
  25416. {
  25417. sprintf(input[i], "%04d", 1999-i);
  25418. sprintf(output[i], "%04d", i);
  25419. }
  25420. testActivity(activity, input, output);
  25421. // Random
  25422. for (i=0; i<2000; i++)
  25423. {
  25424. unsigned r = fastRand() % 1500;
  25425. sprintf(input[i], "%04d", r);
  25426. sprintf(output[i], "%04d", r);
  25427. }
  25428. qsort(output, 2000, sizeof(output[0]), compareFunc);
  25429. testActivity(activity, input, output);
  25430. unsigned __int64 us = factory->queryLocalTimeNs();
  25431. DBGLOG("Simple %s sorts: activity time %u.%u ms", type==2?"Heap" : (type==1 ? "Insertion" : "Quick"), (int)(us/1000), (int)(us%1000));
  25432. factory->resetNodeProgressInfo();
  25433. if (type)
  25434. {
  25435. // Other than quicksort, it's supposed to be stable. Let's check that it is
  25436. // All sort identical
  25437. for (i=0; i<2000; i++)
  25438. {
  25439. sprintf(input[i], "1 %d", i);
  25440. sprintf(output[i], "1 %d", i);
  25441. }
  25442. testActivity(activity, input, output);
  25443. // Already sorted
  25444. for (i=0; i<2000; i++)
  25445. {
  25446. sprintf(input[i], "%04d %d", i / 10, i);
  25447. sprintf(output[i], "%04d %d", i / 10, i);
  25448. }
  25449. testActivity(activity, input, output);
  25450. // Reverse order
  25451. for (i=0; i<2000; i++)
  25452. {
  25453. sprintf(input[i], "%04d %d", 199 - (i / 10), i%10);
  25454. sprintf(output[i], "%04d %d", i / 10, i%10);
  25455. }
  25456. testActivity(activity, input, output);
  25457. }
  25458. for (i=0; i<2000; i++)
  25459. {
  25460. delete [] input[i];
  25461. delete [] output[i];
  25462. }
  25463. DBGLOG("Finished testing %s sort", type==2?"Heap" : (type==1 ? "Insertion" : "Quick"));
  25464. }
  25465. void testQuickSort()
  25466. {
  25467. testSort(0);
  25468. }
  25469. void testHeapSort()
  25470. {
  25471. testSort(2);
  25472. }
  25473. void testMerge()
  25474. {
  25475. DBGLOG("testMerge");
  25476. init();
  25477. Owned<IPropertyTree> splitterNode = createPTree();
  25478. Owned <IRoxieServerActivityFactory> factory = createRoxieServerMergeActivityFactory(1, 1, *queryFactory, mergeActivityTestFactory, TAKmerge, *splitterNode);
  25479. factory->setInput(0,0,0);
  25480. factory->setInput(1,0,0);
  25481. Owned <IRoxieServerActivity> activity = factory->createActivity(ctx, NULL);
  25482. const char * test[] = { NULL, NULL };
  25483. const char * test12345[] = { "1", "2", "3", "4", "5", NULL, NULL };
  25484. const char * test1122334455[] = { "1", "1", "2", "2", "3", "3", "4", "4", "5", "5", NULL, NULL };
  25485. const char * test11111[] = { "1", "1", "1", "1", "1", NULL, NULL };
  25486. const char * test1111111111[] = { "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", NULL, NULL };
  25487. const char * test11111_12345[] = { "1", "1", "1", "1", "1", NULL, "1", "2", "3", "4", "5", NULL, NULL };
  25488. const char * test1111112345[] = { "1", "1", "1", "1", "1", "1", "2", "3", "4", "5", NULL, NULL };
  25489. 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 };
  25490. testActivity(activity, test, test, test);
  25491. testActivity(activity, test12345, test, test12345);
  25492. testActivity(activity, test, test12345, test12345);
  25493. testActivity(activity, test12345, test12345, test1122334455);
  25494. testActivity(activity, test11111, test, test11111);
  25495. testActivity(activity, test, test11111, test11111);
  25496. testActivity(activity, test11111, test11111, test1111111111);
  25497. testActivity(activity, test11111_12345, test, test1111112345);
  25498. testActivity(activity, test11111_12345, test11111_12345, test11111111111122334455);
  25499. // Should really test WHICH side gets kept...
  25500. // Should test with more than 2 inputs...
  25501. DBGLOG("testMerge done");
  25502. }
  25503. void testMergeDedup()
  25504. {
  25505. DBGLOG("testMergeDedup");
  25506. init();
  25507. MergeActivityTest::isDedup = true;
  25508. Owned<IPropertyTree> splitterNode = createPTree();
  25509. Owned <IRoxieServerActivityFactory> factory = createRoxieServerMergeActivityFactory(1, 1, *queryFactory, mergeActivityTestFactory, TAKmerge, *splitterNode);
  25510. factory->setInput(0,0,0);
  25511. factory->setInput(1,0,0);
  25512. Owned <IRoxieServerActivity> activity = factory->createActivity(ctx, NULL);
  25513. const char * test[] = { NULL, NULL };
  25514. const char * test12345[] = { "1", "2", "3", "4", "5", NULL, NULL };
  25515. const char * test11111[] = { "1", "1", "1", "1", "1", NULL, NULL };
  25516. const char * test11111_12345[] = { "1", "1", "1", "1", "1", NULL, "1", "2", "3", "4", "5", NULL, NULL };
  25517. const char * test1111112345[] = { "1", "1", "1", "1", "1", "1", "2", "3", "4", "5", NULL, NULL };
  25518. testActivity(activity, test11111, test, test11111); // No dedup within a stream
  25519. testActivity(activity, test11111, test11111, test11111); // No dedup within a stream
  25520. testActivity(activity, test, test11111, test11111);
  25521. testActivity(activity, test, test, test);
  25522. testActivity(activity, test12345, test, test12345);
  25523. testActivity(activity, test, test12345, test12345);
  25524. testActivity(activity, test12345, test12345, test12345);
  25525. testActivity(activity, test11111_12345, test, test1111112345);
  25526. testActivity(activity, test11111_12345, test11111_12345, test1111112345);
  25527. // Should really test WHICH side gets kept...
  25528. // Should test with more than 2 inputs...
  25529. DBGLOG("testMergeDedup done");
  25530. }
  25531. void doTestSplitter(unsigned numOutputs)
  25532. {
  25533. DBGLOG("testSplit %d", numOutputs);
  25534. init();
  25535. Owned<IPropertyTree> splitterNode = createPTree();
  25536. Owned <IRoxieServerActivityFactory> factory = createRoxieServerThroughSpillActivityFactory(*queryFactory, splitActivityTestFactory, numOutputs, *splitterNode);
  25537. factory->setInput(0,0,0);
  25538. Owned <IRoxieServerActivity> activity = factory->createActivity(ctx, NULL);
  25539. const char * test[] = { NULL, NULL };
  25540. const char * test12345[] = { "1", "2", "3", "4", "5", NULL, NULL };
  25541. unsigned start = msTick();
  25542. testSplitActivity(factory, test, test, numOutputs, 0);
  25543. testSplitActivity(factory, test12345, test12345, numOutputs, 0);
  25544. testSplitActivity(factory, test12345, test12345, numOutputs, 100);
  25545. unsigned elapsed = msTick() - start;
  25546. DBGLOG("testSplit %d done in %dms", numOutputs, elapsed);
  25547. }
  25548. void testSplitter()
  25549. {
  25550. doTestSplitter(1);
  25551. doTestSplitter(2);
  25552. doTestSplitter(3);
  25553. doTestSplitter(10);
  25554. }
  25555. void testMiscellaneous()
  25556. {
  25557. DBGLOG("sizeof(CriticalSection)=%u", (unsigned) sizeof(CriticalSection));
  25558. DBGLOG("sizeof(SpinLock)=%u", (unsigned) sizeof(SpinLock));
  25559. DBGLOG("sizeof(CJoinGroup)=%u", (unsigned) sizeof(CJoinGroup));
  25560. ASSERT(sizeof(CJoinGroup) <= 120);
  25561. }
  25562. };
  25563. CPPUNIT_TEST_SUITE_REGISTRATION( CcdServerTest );
  25564. CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( CcdServerTest, "CcdServerTest" );
  25565. #endif