ccdserver.cpp 896 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137151381513915140151411514215143151441514515146151471514815149151501515115152151531515415155151561515715158151591516015161151621516315164151651516615167151681516915170151711517215173151741517515176151771517815179151801518115182151831518415185151861518715188151891519015191151921519315194151951519615197151981519915200152011520215203152041520515206152071520815209152101521115212152131521415215152161521715218152191522015221152221522315224152251522615227152281522915230152311523215233152341523515236152371523815239152401524115242152431524415245152461524715248152491525015251152521525315254152551525615257152581525915260152611526215263152641526515266152671526815269152701527115272152731527415275152761527715278152791528015281152821528315284152851528615287152881528915290152911529215293152941529515296152971529815299153001530115302153031530415305153061530715308153091531015311153121531315314153151531615317153181531915320153211532215323153241532515326153271532815329153301533115332153331533415335153361533715338153391534015341153421534315344153451534615347153481534915350153511535215353153541535515356153571535815359153601536115362153631536415365153661536715368153691537015371153721537315374153751537615377153781537915380153811538215383153841538515386153871538815389153901539115392153931539415395153961539715398153991540015401154021540315404154051540615407154081540915410154111541215413154141541515416154171541815419154201542115422154231542415425154261542715428154291543015431154321543315434154351543615437154381543915440154411544215443154441544515446154471544815449154501545115452154531545415455154561545715458154591546015461154621546315464154651546615467154681546915470154711547215473154741547515476154771547815479154801548115482154831548415485154861548715488154891549015491154921549315494154951549615497154981549915500155011550215503155041550515506155071550815509155101551115512155131551415515155161551715518155191552015521155221552315524155251552615527155281552915530155311553215533155341553515536155371553815539155401554115542155431554415545155461554715548155491555015551155521555315554155551555615557155581555915560155611556215563155641556515566155671556815569155701557115572155731557415575155761557715578155791558015581155821558315584155851558615587155881558915590155911559215593155941559515596155971559815599156001560115602156031560415605156061560715608156091561015611156121561315614156151561615617156181561915620156211562215623156241562515626156271562815629156301563115632156331563415635156361563715638156391564015641156421564315644156451564615647156481564915650156511565215653156541565515656156571565815659156601566115662156631566415665156661566715668156691567015671156721567315674156751567615677156781567915680156811568215683156841568515686156871568815689156901569115692156931569415695156961569715698156991570015701157021570315704157051570615707157081570915710157111571215713157141571515716157171571815719157201572115722157231572415725157261572715728157291573015731157321573315734157351573615737157381573915740157411574215743157441574515746157471574815749157501575115752157531575415755157561575715758157591576015761157621576315764157651576615767157681576915770157711577215773157741577515776157771577815779157801578115782157831578415785157861578715788157891579015791157921579315794157951579615797157981579915800158011580215803158041580515806158071580815809158101581115812158131581415815158161581715818158191582015821158221582315824158251582615827158281582915830158311583215833158341583515836158371583815839158401584115842158431584415845158461584715848158491585015851158521585315854158551585615857158581585915860158611586215863158641586515866158671586815869158701587115872158731587415875158761587715878158791588015881158821588315884158851588615887158881588915890158911589215893158941589515896158971589815899159001590115902159031590415905159061590715908159091591015911159121591315914159151591615917159181591915920159211592215923159241592515926159271592815929159301593115932159331593415935159361593715938159391594015941159421594315944159451594615947159481594915950159511595215953159541595515956159571595815959159601596115962159631596415965159661596715968159691597015971159721597315974159751597615977159781597915980159811598215983159841598515986159871598815989159901599115992159931599415995159961599715998159991600016001160021600316004160051600616007160081600916010160111601216013160141601516016160171601816019160201602116022160231602416025160261602716028160291603016031160321603316034160351603616037160381603916040160411604216043160441604516046160471604816049160501605116052160531605416055160561605716058160591606016061160621606316064160651606616067160681606916070160711607216073160741607516076160771607816079160801608116082160831608416085160861608716088160891609016091160921609316094160951609616097160981609916100161011610216103161041610516106161071610816109161101611116112161131611416115161161611716118161191612016121161221612316124161251612616127161281612916130161311613216133161341613516136161371613816139161401614116142161431614416145161461614716148161491615016151161521615316154161551615616157161581615916160161611616216163161641616516166161671616816169161701617116172161731617416175161761617716178161791618016181161821618316184161851618616187161881618916190161911619216193161941619516196161971619816199162001620116202162031620416205162061620716208162091621016211162121621316214162151621616217162181621916220162211622216223162241622516226162271622816229162301623116232162331623416235162361623716238162391624016241162421624316244162451624616247162481624916250162511625216253162541625516256162571625816259162601626116262162631626416265162661626716268162691627016271162721627316274162751627616277162781627916280162811628216283162841628516286162871628816289162901629116292162931629416295162961629716298162991630016301163021630316304163051630616307163081630916310163111631216313163141631516316163171631816319163201632116322163231632416325163261632716328163291633016331163321633316334163351633616337163381633916340163411634216343163441634516346163471634816349163501635116352163531635416355163561635716358163591636016361163621636316364163651636616367163681636916370163711637216373163741637516376163771637816379163801638116382163831638416385163861638716388163891639016391163921639316394163951639616397163981639916400164011640216403164041640516406164071640816409164101641116412164131641416415164161641716418164191642016421164221642316424164251642616427164281642916430164311643216433164341643516436164371643816439164401644116442164431644416445164461644716448164491645016451164521645316454164551645616457164581645916460164611646216463164641646516466164671646816469164701647116472164731647416475164761647716478164791648016481164821648316484164851648616487164881648916490164911649216493164941649516496164971649816499165001650116502165031650416505165061650716508165091651016511165121651316514165151651616517165181651916520165211652216523165241652516526165271652816529165301653116532165331653416535165361653716538165391654016541165421654316544165451654616547165481654916550165511655216553165541655516556165571655816559165601656116562165631656416565165661656716568165691657016571165721657316574165751657616577165781657916580165811658216583165841658516586165871658816589165901659116592165931659416595165961659716598165991660016601166021660316604166051660616607166081660916610166111661216613166141661516616166171661816619166201662116622166231662416625166261662716628166291663016631166321663316634166351663616637166381663916640166411664216643166441664516646166471664816649166501665116652166531665416655166561665716658166591666016661166621666316664166651666616667166681666916670166711667216673166741667516676166771667816679166801668116682166831668416685166861668716688166891669016691166921669316694166951669616697166981669916700167011670216703167041670516706167071670816709167101671116712167131671416715167161671716718167191672016721167221672316724167251672616727167281672916730167311673216733167341673516736167371673816739167401674116742167431674416745167461674716748167491675016751167521675316754167551675616757167581675916760167611676216763167641676516766167671676816769167701677116772167731677416775167761677716778167791678016781167821678316784167851678616787167881678916790167911679216793167941679516796167971679816799168001680116802168031680416805168061680716808168091681016811168121681316814168151681616817168181681916820168211682216823168241682516826168271682816829168301683116832168331683416835168361683716838168391684016841168421684316844168451684616847168481684916850168511685216853168541685516856168571685816859168601686116862168631686416865168661686716868168691687016871168721687316874168751687616877168781687916880168811688216883168841688516886168871688816889168901689116892168931689416895168961689716898168991690016901169021690316904169051690616907169081690916910169111691216913169141691516916169171691816919169201692116922169231692416925169261692716928169291693016931169321693316934169351693616937169381693916940169411694216943169441694516946169471694816949169501695116952169531695416955169561695716958169591696016961169621696316964169651696616967169681696916970169711697216973169741697516976169771697816979169801698116982169831698416985169861698716988169891699016991169921699316994169951699616997169981699917000170011700217003170041700517006170071700817009170101701117012170131701417015170161701717018170191702017021170221702317024170251702617027170281702917030170311703217033170341703517036170371703817039170401704117042170431704417045170461704717048170491705017051170521705317054170551705617057170581705917060170611706217063170641706517066170671706817069170701707117072170731707417075170761707717078170791708017081170821708317084170851708617087170881708917090170911709217093170941709517096170971709817099171001710117102171031710417105171061710717108171091711017111171121711317114171151711617117171181711917120171211712217123171241712517126171271712817129171301713117132171331713417135171361713717138171391714017141171421714317144171451714617147171481714917150171511715217153171541715517156171571715817159171601716117162171631716417165171661716717168171691717017171171721717317174171751717617177171781717917180171811718217183171841718517186171871718817189171901719117192171931719417195171961719717198171991720017201172021720317204172051720617207172081720917210172111721217213172141721517216172171721817219172201722117222172231722417225172261722717228172291723017231172321723317234172351723617237172381723917240172411724217243172441724517246172471724817249172501725117252172531725417255172561725717258172591726017261172621726317264172651726617267172681726917270172711727217273172741727517276172771727817279172801728117282172831728417285172861728717288172891729017291172921729317294172951729617297172981729917300173011730217303173041730517306173071730817309173101731117312173131731417315173161731717318173191732017321173221732317324173251732617327173281732917330173311733217333173341733517336173371733817339173401734117342173431734417345173461734717348173491735017351173521735317354173551735617357173581735917360173611736217363173641736517366173671736817369173701737117372173731737417375173761737717378173791738017381173821738317384173851738617387173881738917390173911739217393173941739517396173971739817399174001740117402174031740417405174061740717408174091741017411174121741317414174151741617417174181741917420174211742217423174241742517426174271742817429174301743117432174331743417435174361743717438174391744017441174421744317444174451744617447174481744917450174511745217453174541745517456174571745817459174601746117462174631746417465174661746717468174691747017471174721747317474174751747617477174781747917480174811748217483174841748517486174871748817489174901749117492174931749417495174961749717498174991750017501175021750317504175051750617507175081750917510175111751217513175141751517516175171751817519175201752117522175231752417525175261752717528175291753017531175321753317534175351753617537175381753917540175411754217543175441754517546175471754817549175501755117552175531755417555175561755717558175591756017561175621756317564175651756617567175681756917570175711757217573175741757517576175771757817579175801758117582175831758417585175861758717588175891759017591175921759317594175951759617597175981759917600176011760217603176041760517606176071760817609176101761117612176131761417615176161761717618176191762017621176221762317624176251762617627176281762917630176311763217633176341763517636176371763817639176401764117642176431764417645176461764717648176491765017651176521765317654176551765617657176581765917660176611766217663176641766517666176671766817669176701767117672176731767417675176761767717678176791768017681176821768317684176851768617687176881768917690176911769217693176941769517696176971769817699177001770117702177031770417705177061770717708177091771017711177121771317714177151771617717177181771917720177211772217723177241772517726177271772817729177301773117732177331773417735177361773717738177391774017741177421774317744177451774617747177481774917750177511775217753177541775517756177571775817759177601776117762177631776417765177661776717768177691777017771177721777317774177751777617777177781777917780177811778217783177841778517786177871778817789177901779117792177931779417795177961779717798177991780017801178021780317804178051780617807178081780917810178111781217813178141781517816178171781817819178201782117822178231782417825178261782717828178291783017831178321783317834178351783617837178381783917840178411784217843178441784517846178471784817849178501785117852178531785417855178561785717858178591786017861178621786317864178651786617867178681786917870178711787217873178741787517876178771787817879178801788117882178831788417885178861788717888178891789017891178921789317894178951789617897178981789917900179011790217903179041790517906179071790817909179101791117912179131791417915179161791717918179191792017921179221792317924179251792617927179281792917930179311793217933179341793517936179371793817939179401794117942179431794417945179461794717948179491795017951179521795317954179551795617957179581795917960179611796217963179641796517966179671796817969179701797117972179731797417975179761797717978179791798017981179821798317984179851798617987179881798917990179911799217993179941799517996179971799817999180001800118002180031800418005180061800718008180091801018011180121801318014180151801618017180181801918020180211802218023180241802518026180271802818029180301803118032180331803418035180361803718038180391804018041180421804318044180451804618047180481804918050180511805218053180541805518056180571805818059180601806118062180631806418065180661806718068180691807018071180721807318074180751807618077180781807918080180811808218083180841808518086180871808818089180901809118092180931809418095180961809718098180991810018101181021810318104181051810618107181081810918110181111811218113181141811518116181171811818119181201812118122181231812418125181261812718128181291813018131181321813318134181351813618137181381813918140181411814218143181441814518146181471814818149181501815118152181531815418155181561815718158181591816018161181621816318164181651816618167181681816918170181711817218173181741817518176181771817818179181801818118182181831818418185181861818718188181891819018191181921819318194181951819618197181981819918200182011820218203182041820518206182071820818209182101821118212182131821418215182161821718218182191822018221182221822318224182251822618227182281822918230182311823218233182341823518236182371823818239182401824118242182431824418245182461824718248182491825018251182521825318254182551825618257182581825918260182611826218263182641826518266182671826818269182701827118272182731827418275182761827718278182791828018281182821828318284182851828618287182881828918290182911829218293182941829518296182971829818299183001830118302183031830418305183061830718308183091831018311183121831318314183151831618317183181831918320183211832218323183241832518326183271832818329183301833118332183331833418335183361833718338183391834018341183421834318344183451834618347183481834918350183511835218353183541835518356183571835818359183601836118362183631836418365183661836718368183691837018371183721837318374183751837618377183781837918380183811838218383183841838518386183871838818389183901839118392183931839418395183961839718398183991840018401184021840318404184051840618407184081840918410184111841218413184141841518416184171841818419184201842118422184231842418425184261842718428184291843018431184321843318434184351843618437184381843918440184411844218443184441844518446184471844818449184501845118452184531845418455184561845718458184591846018461184621846318464184651846618467184681846918470184711847218473184741847518476184771847818479184801848118482184831848418485184861848718488184891849018491184921849318494184951849618497184981849918500185011850218503185041850518506185071850818509185101851118512185131851418515185161851718518185191852018521185221852318524185251852618527185281852918530185311853218533185341853518536185371853818539185401854118542185431854418545185461854718548185491855018551185521855318554185551855618557185581855918560185611856218563185641856518566185671856818569185701857118572185731857418575185761857718578185791858018581185821858318584185851858618587185881858918590185911859218593185941859518596185971859818599186001860118602186031860418605186061860718608186091861018611186121861318614186151861618617186181861918620186211862218623186241862518626186271862818629186301863118632186331863418635186361863718638186391864018641186421864318644186451864618647186481864918650186511865218653186541865518656186571865818659186601866118662186631866418665186661866718668186691867018671186721867318674186751867618677186781867918680186811868218683186841868518686186871868818689186901869118692186931869418695186961869718698186991870018701187021870318704187051870618707187081870918710187111871218713187141871518716187171871818719187201872118722187231872418725187261872718728187291873018731187321873318734187351873618737187381873918740187411874218743187441874518746187471874818749187501875118752187531875418755187561875718758187591876018761187621876318764187651876618767187681876918770187711877218773187741877518776187771877818779187801878118782187831878418785187861878718788187891879018791187921879318794187951879618797187981879918800188011880218803188041880518806188071880818809188101881118812188131881418815188161881718818188191882018821188221882318824188251882618827188281882918830188311883218833188341883518836188371883818839188401884118842188431884418845188461884718848188491885018851188521885318854188551885618857188581885918860188611886218863188641886518866188671886818869188701887118872188731887418875188761887718878188791888018881188821888318884188851888618887188881888918890188911889218893188941889518896188971889818899189001890118902189031890418905189061890718908189091891018911189121891318914189151891618917189181891918920189211892218923189241892518926189271892818929189301893118932189331893418935189361893718938189391894018941189421894318944189451894618947189481894918950189511895218953189541895518956189571895818959189601896118962189631896418965189661896718968189691897018971189721897318974189751897618977189781897918980189811898218983189841898518986189871898818989189901899118992189931899418995189961899718998189991900019001190021900319004190051900619007190081900919010190111901219013190141901519016190171901819019190201902119022190231902419025190261902719028190291903019031190321903319034190351903619037190381903919040190411904219043190441904519046190471904819049190501905119052190531905419055190561905719058190591906019061190621906319064190651906619067190681906919070190711907219073190741907519076190771907819079190801908119082190831908419085190861908719088190891909019091190921909319094190951909619097190981909919100191011910219103191041910519106191071910819109191101911119112191131911419115191161911719118191191912019121191221912319124191251912619127191281912919130191311913219133191341913519136191371913819139191401914119142191431914419145191461914719148191491915019151191521915319154191551915619157191581915919160191611916219163191641916519166191671916819169191701917119172191731917419175191761917719178191791918019181191821918319184191851918619187191881918919190191911919219193191941919519196191971919819199192001920119202192031920419205192061920719208192091921019211192121921319214192151921619217192181921919220192211922219223192241922519226192271922819229192301923119232192331923419235192361923719238192391924019241192421924319244192451924619247192481924919250192511925219253192541925519256192571925819259192601926119262192631926419265192661926719268192691927019271192721927319274192751927619277192781927919280192811928219283192841928519286192871928819289192901929119292192931929419295192961929719298192991930019301193021930319304193051930619307193081930919310193111931219313193141931519316193171931819319193201932119322193231932419325193261932719328193291933019331193321933319334193351933619337193381933919340193411934219343193441934519346193471934819349193501935119352193531935419355193561935719358193591936019361193621936319364193651936619367193681936919370193711937219373193741937519376193771937819379193801938119382193831938419385193861938719388193891939019391193921939319394193951939619397193981939919400194011940219403194041940519406194071940819409194101941119412194131941419415194161941719418194191942019421194221942319424194251942619427194281942919430194311943219433194341943519436194371943819439194401944119442194431944419445194461944719448194491945019451194521945319454194551945619457194581945919460194611946219463194641946519466194671946819469194701947119472194731947419475194761947719478194791948019481194821948319484194851948619487194881948919490194911949219493194941949519496194971949819499195001950119502195031950419505195061950719508195091951019511195121951319514195151951619517195181951919520195211952219523195241952519526195271952819529195301953119532195331953419535195361953719538195391954019541195421954319544195451954619547195481954919550195511955219553195541955519556195571955819559195601956119562195631956419565195661956719568195691957019571195721957319574195751957619577195781957919580195811958219583195841958519586195871958819589195901959119592195931959419595195961959719598195991960019601196021960319604196051960619607196081960919610196111961219613196141961519616196171961819619196201962119622196231962419625196261962719628196291963019631196321963319634196351963619637196381963919640196411964219643196441964519646196471964819649196501965119652196531965419655196561965719658196591966019661196621966319664196651966619667196681966919670196711967219673196741967519676196771967819679196801968119682196831968419685196861968719688196891969019691196921969319694196951969619697196981969919700197011970219703197041970519706197071970819709197101971119712197131971419715197161971719718197191972019721197221972319724197251972619727197281972919730197311973219733197341973519736197371973819739197401974119742197431974419745197461974719748197491975019751197521975319754197551975619757197581975919760197611976219763197641976519766197671976819769197701977119772197731977419775197761977719778197791978019781197821978319784197851978619787197881978919790197911979219793197941979519796197971979819799198001980119802198031980419805198061980719808198091981019811198121981319814198151981619817198181981919820198211982219823198241982519826198271982819829198301983119832198331983419835198361983719838198391984019841198421984319844198451984619847198481984919850198511985219853198541985519856198571985819859198601986119862198631986419865198661986719868198691987019871198721987319874198751987619877198781987919880198811988219883198841988519886198871988819889198901989119892198931989419895198961989719898198991990019901199021990319904199051990619907199081990919910199111991219913199141991519916199171991819919199201992119922199231992419925199261992719928199291993019931199321993319934199351993619937199381993919940199411994219943199441994519946199471994819949199501995119952199531995419955199561995719958199591996019961199621996319964199651996619967199681996919970199711997219973199741997519976199771997819979199801998119982199831998419985199861998719988199891999019991199921999319994199951999619997199981999920000200012000220003200042000520006200072000820009200102001120012200132001420015200162001720018200192002020021200222002320024200252002620027200282002920030200312003220033200342003520036200372003820039200402004120042200432004420045200462004720048200492005020051200522005320054200552005620057200582005920060200612006220063200642006520066200672006820069200702007120072200732007420075200762007720078200792008020081200822008320084200852008620087200882008920090200912009220093200942009520096200972009820099201002010120102201032010420105201062010720108201092011020111201122011320114201152011620117201182011920120201212012220123201242012520126201272012820129201302013120132201332013420135201362013720138201392014020141201422014320144201452014620147201482014920150201512015220153201542015520156201572015820159201602016120162201632016420165201662016720168201692017020171201722017320174201752017620177201782017920180201812018220183201842018520186201872018820189201902019120192201932019420195201962019720198201992020020201202022020320204202052020620207202082020920210202112021220213202142021520216202172021820219202202022120222202232022420225202262022720228202292023020231202322023320234202352023620237202382023920240202412024220243202442024520246202472024820249202502025120252202532025420255202562025720258202592026020261202622026320264202652026620267202682026920270202712027220273202742027520276202772027820279202802028120282202832028420285202862028720288202892029020291202922029320294202952029620297202982029920300203012030220303203042030520306203072030820309203102031120312203132031420315203162031720318203192032020321203222032320324203252032620327203282032920330203312033220333203342033520336203372033820339203402034120342203432034420345203462034720348203492035020351203522035320354203552035620357203582035920360203612036220363203642036520366203672036820369203702037120372203732037420375203762037720378203792038020381203822038320384203852038620387203882038920390203912039220393203942039520396203972039820399204002040120402204032040420405204062040720408204092041020411204122041320414204152041620417204182041920420204212042220423204242042520426204272042820429204302043120432204332043420435204362043720438204392044020441204422044320444204452044620447204482044920450204512045220453204542045520456204572045820459204602046120462204632046420465204662046720468204692047020471204722047320474204752047620477204782047920480204812048220483204842048520486204872048820489204902049120492204932049420495204962049720498204992050020501205022050320504205052050620507205082050920510205112051220513205142051520516205172051820519205202052120522205232052420525205262052720528205292053020531205322053320534205352053620537205382053920540205412054220543205442054520546205472054820549205502055120552205532055420555205562055720558205592056020561205622056320564205652056620567205682056920570205712057220573205742057520576205772057820579205802058120582205832058420585205862058720588205892059020591205922059320594205952059620597205982059920600206012060220603206042060520606206072060820609206102061120612206132061420615206162061720618206192062020621206222062320624206252062620627206282062920630206312063220633206342063520636206372063820639206402064120642206432064420645206462064720648206492065020651206522065320654206552065620657206582065920660206612066220663206642066520666206672066820669206702067120672206732067420675206762067720678206792068020681206822068320684206852068620687206882068920690206912069220693206942069520696206972069820699207002070120702207032070420705207062070720708207092071020711207122071320714207152071620717207182071920720207212072220723207242072520726207272072820729207302073120732207332073420735207362073720738207392074020741207422074320744207452074620747207482074920750207512075220753207542075520756207572075820759207602076120762207632076420765207662076720768207692077020771207722077320774207752077620777207782077920780207812078220783207842078520786207872078820789207902079120792207932079420795207962079720798207992080020801208022080320804208052080620807208082080920810208112081220813208142081520816208172081820819208202082120822208232082420825208262082720828208292083020831208322083320834208352083620837208382083920840208412084220843208442084520846208472084820849208502085120852208532085420855208562085720858208592086020861208622086320864208652086620867208682086920870208712087220873208742087520876208772087820879208802088120882208832088420885208862088720888208892089020891208922089320894208952089620897208982089920900209012090220903209042090520906209072090820909209102091120912209132091420915209162091720918209192092020921209222092320924209252092620927209282092920930209312093220933209342093520936209372093820939209402094120942209432094420945209462094720948209492095020951209522095320954209552095620957209582095920960209612096220963209642096520966209672096820969209702097120972209732097420975209762097720978209792098020981209822098320984209852098620987209882098920990209912099220993209942099520996209972099820999210002100121002210032100421005210062100721008210092101021011210122101321014210152101621017210182101921020210212102221023210242102521026210272102821029210302103121032210332103421035210362103721038210392104021041210422104321044210452104621047210482104921050210512105221053210542105521056210572105821059210602106121062210632106421065210662106721068210692107021071210722107321074210752107621077210782107921080210812108221083210842108521086210872108821089210902109121092210932109421095210962109721098210992110021101211022110321104211052110621107211082110921110211112111221113211142111521116211172111821119211202112121122211232112421125211262112721128211292113021131211322113321134211352113621137211382113921140211412114221143211442114521146211472114821149211502115121152211532115421155211562115721158211592116021161211622116321164211652116621167211682116921170211712117221173211742117521176211772117821179211802118121182211832118421185211862118721188211892119021191211922119321194211952119621197211982119921200212012120221203212042120521206212072120821209212102121121212212132121421215212162121721218212192122021221212222122321224212252122621227212282122921230212312123221233212342123521236212372123821239212402124121242212432124421245212462124721248212492125021251212522125321254212552125621257212582125921260212612126221263212642126521266212672126821269212702127121272212732127421275212762127721278212792128021281212822128321284212852128621287212882128921290212912129221293212942129521296212972129821299213002130121302213032130421305213062130721308213092131021311213122131321314213152131621317213182131921320213212132221323213242132521326213272132821329213302133121332213332133421335213362133721338213392134021341213422134321344213452134621347213482134921350213512135221353213542135521356213572135821359213602136121362213632136421365213662136721368213692137021371213722137321374213752137621377213782137921380213812138221383213842138521386213872138821389213902139121392213932139421395213962139721398213992140021401214022140321404214052140621407214082140921410214112141221413214142141521416214172141821419214202142121422214232142421425214262142721428214292143021431214322143321434214352143621437214382143921440214412144221443214442144521446214472144821449214502145121452214532145421455214562145721458214592146021461214622146321464214652146621467214682146921470214712147221473214742147521476214772147821479214802148121482214832148421485214862148721488214892149021491214922149321494214952149621497214982149921500215012150221503215042150521506215072150821509215102151121512215132151421515215162151721518215192152021521215222152321524215252152621527215282152921530215312153221533215342153521536215372153821539215402154121542215432154421545215462154721548215492155021551215522155321554215552155621557215582155921560215612156221563215642156521566215672156821569215702157121572215732157421575215762157721578215792158021581215822158321584215852158621587215882158921590215912159221593215942159521596215972159821599216002160121602216032160421605216062160721608216092161021611216122161321614216152161621617216182161921620216212162221623216242162521626216272162821629216302163121632216332163421635216362163721638216392164021641216422164321644216452164621647216482164921650216512165221653216542165521656216572165821659216602166121662216632166421665216662166721668216692167021671216722167321674216752167621677216782167921680216812168221683216842168521686216872168821689216902169121692216932169421695216962169721698216992170021701217022170321704217052170621707217082170921710217112171221713217142171521716217172171821719217202172121722217232172421725217262172721728217292173021731217322173321734217352173621737217382173921740217412174221743217442174521746217472174821749217502175121752217532175421755217562175721758217592176021761217622176321764217652176621767217682176921770217712177221773217742177521776217772177821779217802178121782217832178421785217862178721788217892179021791217922179321794217952179621797217982179921800218012180221803218042180521806218072180821809218102181121812218132181421815218162181721818218192182021821218222182321824218252182621827218282182921830218312183221833218342183521836218372183821839218402184121842218432184421845218462184721848218492185021851218522185321854218552185621857218582185921860218612186221863218642186521866218672186821869218702187121872218732187421875218762187721878218792188021881218822188321884218852188621887218882188921890218912189221893218942189521896218972189821899219002190121902219032190421905219062190721908219092191021911219122191321914219152191621917219182191921920219212192221923219242192521926219272192821929219302193121932219332193421935219362193721938219392194021941219422194321944219452194621947219482194921950219512195221953219542195521956219572195821959219602196121962219632196421965219662196721968219692197021971219722197321974219752197621977219782197921980219812198221983219842198521986219872198821989219902199121992219932199421995219962199721998219992200022001220022200322004220052200622007220082200922010220112201222013220142201522016220172201822019220202202122022220232202422025220262202722028220292203022031220322203322034220352203622037220382203922040220412204222043220442204522046220472204822049220502205122052220532205422055220562205722058220592206022061220622206322064220652206622067220682206922070220712207222073220742207522076220772207822079220802208122082220832208422085220862208722088220892209022091220922209322094220952209622097220982209922100221012210222103221042210522106221072210822109221102211122112221132211422115221162211722118221192212022121221222212322124221252212622127221282212922130221312213222133221342213522136221372213822139221402214122142221432214422145221462214722148221492215022151221522215322154221552215622157221582215922160221612216222163221642216522166221672216822169221702217122172221732217422175221762217722178221792218022181221822218322184221852218622187221882218922190221912219222193221942219522196221972219822199222002220122202222032220422205222062220722208222092221022211222122221322214222152221622217222182221922220222212222222223222242222522226222272222822229222302223122232222332223422235222362223722238222392224022241222422224322244222452224622247222482224922250222512225222253222542225522256222572225822259222602226122262222632226422265222662226722268222692227022271222722227322274222752227622277222782227922280222812228222283222842228522286222872228822289222902229122292222932229422295222962229722298222992230022301223022230322304223052230622307223082230922310223112231222313223142231522316223172231822319223202232122322223232232422325223262232722328223292233022331223322233322334223352233622337223382233922340223412234222343223442234522346223472234822349223502235122352223532235422355223562235722358223592236022361223622236322364223652236622367223682236922370223712237222373223742237522376223772237822379223802238122382223832238422385223862238722388223892239022391223922239322394223952239622397223982239922400224012240222403224042240522406224072240822409224102241122412224132241422415224162241722418224192242022421224222242322424224252242622427224282242922430224312243222433224342243522436224372243822439224402244122442224432244422445224462244722448224492245022451224522245322454224552245622457224582245922460224612246222463224642246522466224672246822469224702247122472224732247422475224762247722478224792248022481224822248322484224852248622487224882248922490224912249222493224942249522496224972249822499225002250122502225032250422505225062250722508225092251022511225122251322514225152251622517225182251922520225212252222523225242252522526225272252822529225302253122532225332253422535225362253722538225392254022541225422254322544225452254622547225482254922550225512255222553225542255522556225572255822559225602256122562225632256422565225662256722568225692257022571225722257322574225752257622577225782257922580225812258222583225842258522586225872258822589225902259122592225932259422595225962259722598225992260022601226022260322604226052260622607226082260922610226112261222613226142261522616226172261822619226202262122622226232262422625226262262722628226292263022631226322263322634226352263622637226382263922640226412264222643226442264522646226472264822649226502265122652226532265422655226562265722658226592266022661226622266322664226652266622667226682266922670226712267222673226742267522676226772267822679226802268122682226832268422685226862268722688226892269022691226922269322694226952269622697226982269922700227012270222703227042270522706227072270822709227102271122712227132271422715227162271722718227192272022721227222272322724227252272622727227282272922730227312273222733227342273522736227372273822739227402274122742227432274422745227462274722748227492275022751227522275322754227552275622757227582275922760227612276222763227642276522766227672276822769227702277122772227732277422775227762277722778227792278022781227822278322784227852278622787227882278922790227912279222793227942279522796227972279822799228002280122802228032280422805228062280722808228092281022811228122281322814228152281622817228182281922820228212282222823228242282522826228272282822829228302283122832228332283422835228362283722838228392284022841228422284322844228452284622847228482284922850228512285222853228542285522856228572285822859228602286122862228632286422865228662286722868228692287022871228722287322874228752287622877228782287922880228812288222883228842288522886228872288822889228902289122892228932289422895228962289722898228992290022901229022290322904229052290622907229082290922910229112291222913229142291522916229172291822919229202292122922229232292422925229262292722928229292293022931229322293322934229352293622937229382293922940229412294222943229442294522946229472294822949229502295122952229532295422955229562295722958229592296022961229622296322964229652296622967229682296922970229712297222973229742297522976229772297822979229802298122982229832298422985229862298722988229892299022991229922299322994229952299622997229982299923000230012300223003230042300523006230072300823009230102301123012230132301423015230162301723018230192302023021230222302323024230252302623027230282302923030230312303223033230342303523036230372303823039230402304123042230432304423045230462304723048230492305023051230522305323054230552305623057230582305923060230612306223063230642306523066230672306823069230702307123072230732307423075230762307723078230792308023081230822308323084230852308623087230882308923090230912309223093230942309523096230972309823099231002310123102231032310423105231062310723108231092311023111231122311323114231152311623117231182311923120231212312223123231242312523126231272312823129231302313123132231332313423135231362313723138231392314023141231422314323144231452314623147231482314923150231512315223153231542315523156231572315823159231602316123162231632316423165231662316723168231692317023171231722317323174231752317623177231782317923180231812318223183231842318523186231872318823189231902319123192231932319423195231962319723198231992320023201232022320323204232052320623207232082320923210232112321223213232142321523216232172321823219232202322123222232232322423225232262322723228232292323023231232322323323234232352323623237232382323923240232412324223243232442324523246232472324823249232502325123252232532325423255232562325723258232592326023261232622326323264232652326623267232682326923270232712327223273232742327523276232772327823279232802328123282232832328423285232862328723288232892329023291232922329323294232952329623297232982329923300233012330223303233042330523306233072330823309233102331123312233132331423315233162331723318233192332023321233222332323324233252332623327233282332923330233312333223333233342333523336233372333823339233402334123342233432334423345233462334723348233492335023351233522335323354233552335623357233582335923360233612336223363233642336523366233672336823369233702337123372233732337423375233762337723378233792338023381233822338323384233852338623387233882338923390233912339223393233942339523396233972339823399234002340123402234032340423405234062340723408234092341023411234122341323414234152341623417234182341923420234212342223423234242342523426234272342823429234302343123432234332343423435234362343723438234392344023441234422344323444234452344623447234482344923450234512345223453234542345523456234572345823459234602346123462234632346423465234662346723468234692347023471234722347323474234752347623477234782347923480234812348223483234842348523486234872348823489234902349123492234932349423495234962349723498234992350023501235022350323504235052350623507235082350923510235112351223513235142351523516235172351823519235202352123522235232352423525235262352723528235292353023531235322353323534235352353623537235382353923540235412354223543235442354523546235472354823549235502355123552235532355423555235562355723558235592356023561235622356323564235652356623567235682356923570235712357223573235742357523576235772357823579235802358123582235832358423585235862358723588235892359023591235922359323594235952359623597235982359923600236012360223603236042360523606236072360823609236102361123612236132361423615236162361723618236192362023621236222362323624236252362623627236282362923630236312363223633236342363523636236372363823639236402364123642236432364423645236462364723648236492365023651236522365323654236552365623657236582365923660236612366223663236642366523666236672366823669236702367123672236732367423675236762367723678236792368023681236822368323684236852368623687236882368923690236912369223693236942369523696236972369823699237002370123702237032370423705237062370723708237092371023711237122371323714237152371623717237182371923720237212372223723237242372523726237272372823729237302373123732237332373423735237362373723738237392374023741237422374323744237452374623747237482374923750237512375223753237542375523756237572375823759237602376123762237632376423765237662376723768237692377023771237722377323774237752377623777237782377923780237812378223783237842378523786237872378823789237902379123792237932379423795237962379723798237992380023801238022380323804238052380623807238082380923810238112381223813238142381523816238172381823819238202382123822238232382423825238262382723828238292383023831238322383323834238352383623837238382383923840238412384223843238442384523846238472384823849238502385123852238532385423855238562385723858238592386023861238622386323864238652386623867238682386923870238712387223873238742387523876238772387823879238802388123882238832388423885238862388723888238892389023891238922389323894238952389623897238982389923900239012390223903239042390523906239072390823909239102391123912239132391423915239162391723918239192392023921239222392323924239252392623927239282392923930239312393223933239342393523936239372393823939239402394123942239432394423945239462394723948239492395023951239522395323954239552395623957239582395923960239612396223963239642396523966239672396823969239702397123972239732397423975239762397723978239792398023981239822398323984239852398623987239882398923990239912399223993239942399523996239972399823999240002400124002240032400424005240062400724008240092401024011240122401324014240152401624017240182401924020240212402224023240242402524026240272402824029240302403124032240332403424035240362403724038240392404024041240422404324044240452404624047240482404924050240512405224053240542405524056240572405824059240602406124062240632406424065240662406724068240692407024071240722407324074240752407624077240782407924080240812408224083240842408524086240872408824089240902409124092240932409424095240962409724098240992410024101241022410324104241052410624107241082410924110241112411224113241142411524116241172411824119241202412124122241232412424125241262412724128241292413024131241322413324134241352413624137241382413924140241412414224143241442414524146241472414824149241502415124152241532415424155241562415724158241592416024161241622416324164241652416624167241682416924170241712417224173241742417524176241772417824179241802418124182241832418424185241862418724188241892419024191241922419324194241952419624197241982419924200242012420224203242042420524206242072420824209242102421124212242132421424215242162421724218242192422024221242222422324224242252422624227242282422924230242312423224233242342423524236242372423824239242402424124242242432424424245242462424724248242492425024251242522425324254242552425624257242582425924260242612426224263242642426524266242672426824269242702427124272242732427424275242762427724278242792428024281242822428324284242852428624287242882428924290242912429224293242942429524296242972429824299243002430124302243032430424305243062430724308243092431024311243122431324314243152431624317243182431924320243212432224323243242432524326243272432824329243302433124332243332433424335243362433724338243392434024341243422434324344243452434624347243482434924350243512435224353243542435524356243572435824359243602436124362243632436424365243662436724368243692437024371243722437324374243752437624377243782437924380243812438224383243842438524386243872438824389243902439124392243932439424395243962439724398243992440024401244022440324404244052440624407244082440924410244112441224413244142441524416244172441824419244202442124422244232442424425244262442724428244292443024431244322443324434244352443624437244382443924440244412444224443244442444524446244472444824449244502445124452244532445424455244562445724458244592446024461244622446324464244652446624467244682446924470244712447224473244742447524476244772447824479244802448124482244832448424485244862448724488244892449024491244922449324494244952449624497244982449924500245012450224503245042450524506245072450824509245102451124512245132451424515245162451724518245192452024521245222452324524245252452624527245282452924530245312453224533245342453524536245372453824539245402454124542245432454424545245462454724548245492455024551245522455324554245552455624557245582455924560245612456224563245642456524566245672456824569245702457124572245732457424575245762457724578245792458024581245822458324584245852458624587245882458924590245912459224593245942459524596245972459824599246002460124602246032460424605246062460724608246092461024611246122461324614246152461624617246182461924620246212462224623246242462524626246272462824629246302463124632246332463424635246362463724638246392464024641246422464324644246452464624647246482464924650246512465224653246542465524656246572465824659246602466124662246632466424665246662466724668246692467024671246722467324674246752467624677246782467924680246812468224683246842468524686246872468824689246902469124692246932469424695246962469724698246992470024701247022470324704247052470624707247082470924710247112471224713247142471524716247172471824719247202472124722247232472424725247262472724728247292473024731247322473324734247352473624737247382473924740247412474224743247442474524746247472474824749247502475124752247532475424755247562475724758247592476024761247622476324764247652476624767247682476924770247712477224773247742477524776247772477824779247802478124782247832478424785247862478724788247892479024791247922479324794247952479624797247982479924800248012480224803248042480524806248072480824809248102481124812248132481424815248162481724818248192482024821248222482324824248252482624827248282482924830248312483224833248342483524836248372483824839248402484124842248432484424845248462484724848248492485024851248522485324854248552485624857248582485924860248612486224863248642486524866248672486824869248702487124872248732487424875248762487724878248792488024881248822488324884248852488624887248882488924890248912489224893248942489524896248972489824899249002490124902249032490424905249062490724908249092491024911249122491324914249152491624917249182491924920249212492224923249242492524926249272492824929249302493124932249332493424935249362493724938249392494024941249422494324944249452494624947249482494924950249512495224953249542495524956249572495824959249602496124962249632496424965249662496724968249692497024971249722497324974249752497624977249782497924980249812498224983249842498524986249872498824989249902499124992249932499424995249962499724998249992500025001250022500325004250052500625007250082500925010250112501225013250142501525016250172501825019250202502125022250232502425025250262502725028250292503025031250322503325034250352503625037250382503925040250412504225043250442504525046250472504825049250502505125052250532505425055250562505725058250592506025061250622506325064250652506625067250682506925070250712507225073250742507525076250772507825079250802508125082250832508425085250862508725088250892509025091250922509325094250952509625097250982509925100251012510225103251042510525106251072510825109251102511125112251132511425115251162511725118251192512025121251222512325124251252512625127251282512925130251312513225133251342513525136251372513825139251402514125142251432514425145251462514725148251492515025151251522515325154251552515625157251582515925160251612516225163251642516525166251672516825169251702517125172251732517425175251762517725178251792518025181251822518325184251852518625187251882518925190251912519225193251942519525196251972519825199252002520125202252032520425205252062520725208252092521025211252122521325214252152521625217252182521925220252212522225223252242522525226252272522825229252302523125232252332523425235252362523725238252392524025241252422524325244252452524625247252482524925250252512525225253252542525525256252572525825259252602526125262252632526425265252662526725268252692527025271252722527325274252752527625277252782527925280252812528225283252842528525286252872528825289252902529125292252932529425295252962529725298252992530025301253022530325304253052530625307253082530925310253112531225313253142531525316253172531825319253202532125322253232532425325253262532725328253292533025331253322533325334253352533625337253382533925340253412534225343253442534525346253472534825349253502535125352253532535425355253562535725358253592536025361253622536325364253652536625367253682536925370253712537225373253742537525376253772537825379253802538125382253832538425385253862538725388253892539025391253922539325394253952539625397253982539925400254012540225403254042540525406254072540825409254102541125412254132541425415254162541725418254192542025421254222542325424254252542625427254282542925430254312543225433254342543525436254372543825439254402544125442254432544425445254462544725448254492545025451254522545325454254552545625457254582545925460254612546225463254642546525466254672546825469254702547125472254732547425475254762547725478254792548025481254822548325484254852548625487254882548925490254912549225493254942549525496254972549825499255002550125502255032550425505255062550725508255092551025511255122551325514255152551625517255182551925520255212552225523255242552525526255272552825529255302553125532255332553425535255362553725538255392554025541255422554325544255452554625547255482554925550255512555225553255542555525556255572555825559255602556125562255632556425565255662556725568255692557025571255722557325574255752557625577255782557925580255812558225583255842558525586255872558825589255902559125592255932559425595255962559725598255992560025601256022560325604256052560625607256082560925610256112561225613256142561525616256172561825619256202562125622256232562425625256262562725628256292563025631256322563325634256352563625637256382563925640256412564225643256442564525646256472564825649256502565125652256532565425655256562565725658256592566025661256622566325664256652566625667256682566925670256712567225673256742567525676256772567825679256802568125682256832568425685256862568725688256892569025691256922569325694256952569625697256982569925700257012570225703257042570525706257072570825709257102571125712257132571425715257162571725718257192572025721257222572325724257252572625727257282572925730257312573225733257342573525736257372573825739257402574125742257432574425745257462574725748257492575025751257522575325754257552575625757257582575925760257612576225763257642576525766257672576825769257702577125772257732577425775257762577725778257792578025781257822578325784257852578625787257882578925790257912579225793257942579525796257972579825799258002580125802258032580425805258062580725808258092581025811258122581325814258152581625817258182581925820258212582225823258242582525826258272582825829258302583125832258332583425835258362583725838258392584025841258422584325844258452584625847258482584925850258512585225853258542585525856258572585825859258602586125862258632586425865258662586725868258692587025871258722587325874258752587625877258782587925880258812588225883258842588525886258872588825889258902589125892258932589425895258962589725898258992590025901259022590325904259052590625907259082590925910259112591225913259142591525916259172591825919259202592125922259232592425925259262592725928259292593025931259322593325934259352593625937259382593925940259412594225943259442594525946259472594825949259502595125952259532595425955259562595725958259592596025961259622596325964259652596625967259682596925970259712597225973259742597525976259772597825979259802598125982259832598425985259862598725988259892599025991259922599325994259952599625997259982599926000260012600226003260042600526006260072600826009260102601126012260132601426015260162601726018260192602026021260222602326024260252602626027260282602926030260312603226033260342603526036260372603826039260402604126042260432604426045260462604726048260492605026051260522605326054260552605626057260582605926060260612606226063260642606526066260672606826069260702607126072260732607426075260762607726078260792608026081260822608326084260852608626087260882608926090260912609226093260942609526096260972609826099261002610126102261032610426105261062610726108261092611026111261122611326114261152611626117261182611926120261212612226123261242612526126261272612826129261302613126132261332613426135261362613726138261392614026141261422614326144261452614626147261482614926150261512615226153261542615526156261572615826159261602616126162261632616426165261662616726168261692617026171261722617326174261752617626177261782617926180261812618226183261842618526186261872618826189261902619126192261932619426195261962619726198261992620026201262022620326204262052620626207262082620926210262112621226213262142621526216262172621826219262202622126222262232622426225262262622726228262292623026231262322623326234262352623626237262382623926240262412624226243262442624526246262472624826249262502625126252262532625426255262562625726258262592626026261262622626326264262652626626267262682626926270262712627226273262742627526276262772627826279262802628126282262832628426285262862628726288262892629026291262922629326294262952629626297262982629926300263012630226303263042630526306263072630826309263102631126312263132631426315263162631726318263192632026321263222632326324263252632626327263282632926330263312633226333263342633526336263372633826339263402634126342263432634426345263462634726348263492635026351263522635326354263552635626357263582635926360263612636226363263642636526366263672636826369263702637126372263732637426375263762637726378263792638026381263822638326384263852638626387263882638926390263912639226393263942639526396263972639826399264002640126402264032640426405264062640726408264092641026411264122641326414264152641626417264182641926420264212642226423264242642526426264272642826429264302643126432264332643426435264362643726438264392644026441264422644326444264452644626447264482644926450264512645226453264542645526456264572645826459264602646126462264632646426465264662646726468264692647026471264722647326474264752647626477264782647926480264812648226483264842648526486264872648826489264902649126492264932649426495264962649726498264992650026501265022650326504265052650626507265082650926510265112651226513265142651526516265172651826519265202652126522265232652426525265262652726528265292653026531265322653326534265352653626537265382653926540265412654226543265442654526546265472654826549265502655126552265532655426555265562655726558265592656026561265622656326564265652656626567265682656926570265712657226573265742657526576265772657826579265802658126582265832658426585265862658726588265892659026591265922659326594265952659626597265982659926600266012660226603266042660526606266072660826609266102661126612266132661426615266162661726618266192662026621266222662326624266252662626627266282662926630266312663226633266342663526636266372663826639266402664126642266432664426645266462664726648266492665026651266522665326654266552665626657266582665926660266612666226663266642666526666266672666826669266702667126672266732667426675266762667726678266792668026681266822668326684266852668626687266882668926690266912669226693266942669526696266972669826699267002670126702267032670426705267062670726708267092671026711267122671326714267152671626717267182671926720267212672226723267242672526726267272672826729267302673126732267332673426735267362673726738267392674026741
  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 "jlzw.hpp"
  27. #include "javahash.hpp"
  28. #include "javahash.tpp"
  29. #include "thorstep.ipp"
  30. #include "thorpipe.hpp"
  31. #include "thorfile.hpp"
  32. #include "eclhelper.hpp"
  33. #include "eclrtl_imp.hpp"
  34. #include "rtlfield_imp.hpp"
  35. #include "rtlds_imp.hpp"
  36. #include "rtlread_imp.hpp"
  37. #include "dafdesc.hpp"
  38. #include "dautils.hpp"
  39. namespace ccdserver_hqlhelper
  40. {
  41. #include "eclhelper_base.hpp"
  42. }
  43. #include "ccd.hpp"
  44. #include "ccdserver.hpp"
  45. #include "ccdcontext.hpp"
  46. #include "ccdactivities.hpp"
  47. #include "ccdquery.hpp"
  48. #include "ccdstate.hpp"
  49. #include "ccdqueue.ipp"
  50. #include "ccdsnmp.hpp"
  51. #include "ccddali.hpp"
  52. #include "jsmartsock.hpp"
  53. #include "dllserver.hpp"
  54. #include "workflow.hpp"
  55. #include "roxiemem.hpp"
  56. #include "roxierowbuff.hpp"
  57. #include "roxiehelper.hpp"
  58. #include "roxielmj.hpp"
  59. #include "roxierow.hpp"
  60. #include "thorplugin.hpp"
  61. #include "keybuild.hpp"
  62. #define MAX_HTTP_HEADERSIZE 8000
  63. #define MIN_PAYLOAD_SIZE 800
  64. #pragma warning(disable : 4355)
  65. #define DEFAULT_PARALLEL_LOOP_THREADS 1
  66. #define PROBE
  67. #ifdef _DEBUG
  68. //#define FAKE_EXCEPTIONS
  69. //#define TRACE_JOINGROUPS
  70. //#define TRACE_SPLIT
  71. //#define _CHECK_HEAPSORT
  72. //#undef PARALLEL_EXECUTE
  73. //#define TRACE_SEEK_REQUESTS
  74. #endif
  75. using roxiemem::OwnedRoxieRow;
  76. using roxiemem::OwnedRoxieString;
  77. using roxiemem::OwnedConstRoxieRow;
  78. using roxiemem::IRowManager;
  79. // 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...
  80. #if _MSC_VER==1200
  81. #define protected public
  82. #endif
  83. #define TRACE_STARTSTOP // This determines if it is available - it is enabled/disabled by a configuration option
  84. static const SmartStepExtra dummySmartStepExtra(SSEFreadAhead, NULL);
  85. inline void ReleaseRoxieRowSet(ConstPointerArray &data)
  86. {
  87. ForEachItemIn(idx, data)
  88. ReleaseRoxieRow(data.item(idx));
  89. data.kill();
  90. }
  91. //=================================================================================
  92. class RestartableThread : public CInterface
  93. {
  94. class MyThread : public Thread
  95. {
  96. Linked<RestartableThread> owner;
  97. public:
  98. MyThread(RestartableThread *_owner, const char *name) : Thread(name), owner(_owner)
  99. {
  100. }
  101. virtual int run()
  102. {
  103. owner->started.signal();
  104. return owner->run();
  105. }
  106. };
  107. friend class MyThread;
  108. Semaphore started;
  109. Owned<MyThread> thread;
  110. CriticalSection crit;
  111. StringAttr name;
  112. public:
  113. RestartableThread(const char *_name) : name(_name)
  114. {
  115. }
  116. virtual void start(const char *namePrefix)
  117. {
  118. StringBuffer s(namePrefix);
  119. s.append(name);
  120. {
  121. CriticalBlock b(crit);
  122. assertex(!thread);
  123. thread.setown(new MyThread(this, s));
  124. thread->start();
  125. }
  126. started.wait();
  127. }
  128. virtual void join()
  129. {
  130. {
  131. Owned<Thread> tthread;
  132. {
  133. CriticalBlock b(crit);
  134. tthread.setown(thread.getClear());
  135. }
  136. if (tthread)
  137. tthread->join();
  138. }
  139. }
  140. virtual int run() = 0;
  141. };
  142. //================================================================================
  143. // default implementation - can be overridden for efficiency...
  144. bool IRoxieInput::nextGroup(ConstPointerArray & group)
  145. {
  146. // MORE - this should be replaced with a version that reads to a builder
  147. const void * next;
  148. while ((next = nextInGroup()) != NULL)
  149. group.append(next);
  150. if (group.ordinality())
  151. return true;
  152. return false;
  153. }
  154. void IRoxieInput::readAll(RtlLinkedDatasetBuilder &builder)
  155. {
  156. loop
  157. {
  158. const void *nextrec = nextInGroup();
  159. if (!nextrec)
  160. {
  161. nextrec = nextInGroup();
  162. if (!nextrec)
  163. break;
  164. builder.appendEOG();
  165. }
  166. builder.appendOwn(nextrec);
  167. }
  168. }
  169. inline const void * nextUngrouped(IRoxieInput * input)
  170. {
  171. const void * ret = input->nextInGroup();
  172. if (!ret)
  173. ret = input->nextInGroup();
  174. return ret;
  175. };
  176. //=================================================================================
  177. //The following don't link their arguments because that creates a circular reference
  178. //But I wish there was a better way
  179. class IndirectSlaveContext : public CInterface, implements IRoxieSlaveContext
  180. {
  181. public:
  182. IndirectSlaveContext(IRoxieSlaveContext * _ctx = NULL) : ctx(_ctx) {}
  183. IMPLEMENT_IINTERFACE
  184. void set(IRoxieSlaveContext * _ctx) { ctx = _ctx; }
  185. virtual ICodeContext *queryCodeContext()
  186. {
  187. return ctx->queryCodeContext();
  188. }
  189. virtual void checkAbort()
  190. {
  191. ctx->checkAbort();
  192. }
  193. virtual void notifyAbort(IException *E)
  194. {
  195. ctx->notifyAbort(E);
  196. }
  197. virtual IActivityGraph * queryChildGraph(unsigned id)
  198. {
  199. return ctx->queryChildGraph(id);
  200. }
  201. virtual void noteChildGraph(unsigned id, IActivityGraph *childGraph)
  202. {
  203. ctx->noteChildGraph(id, childGraph) ;
  204. }
  205. virtual IRowManager &queryRowManager()
  206. {
  207. return ctx->queryRowManager();
  208. }
  209. virtual void noteStatistic(unsigned statCode, unsigned __int64 value, unsigned count) const
  210. {
  211. ctx->noteStatistic(statCode, value, count);
  212. }
  213. virtual void CTXLOG(const char *format, ...) const
  214. {
  215. va_list args;
  216. va_start(args, format);
  217. ctx->CTXLOGva(format, args);
  218. va_end(args);
  219. }
  220. virtual void CTXLOGva(const char *format, va_list args) const
  221. {
  222. ctx->CTXLOGva(format, args);
  223. }
  224. virtual void CTXLOGa(TracingCategory category, const char *prefix, const char *text) const
  225. {
  226. ctx->CTXLOGa(category, prefix, text);
  227. }
  228. virtual void logOperatorException(IException *E, const char *file, unsigned line, const char *format, ...) const
  229. {
  230. va_list args;
  231. va_start(args, format);
  232. ctx->logOperatorExceptionVA(E, file, line, format, args);
  233. va_end(args);
  234. }
  235. virtual void logOperatorExceptionVA(IException *E, const char *file, unsigned line, const char *format, va_list args) const
  236. {
  237. ctx->logOperatorExceptionVA(E, file, line, format, args);
  238. }
  239. virtual void CTXLOGae(IException *E, const char *file, unsigned line, const char *prefix, const char *format, ...) const
  240. {
  241. va_list args;
  242. va_start(args, format);
  243. ctx->CTXLOGaeva(E, file, line, prefix, format, args);
  244. va_end(args);
  245. }
  246. virtual void CTXLOGaeva(IException *E, const char *file, unsigned line, const char *prefix, const char *format, va_list args) const
  247. {
  248. ctx->CTXLOGaeva(E, file, line, prefix, format, args);
  249. }
  250. virtual void CTXLOGl(LogItem *log) const
  251. {
  252. ctx->CTXLOGl(log);
  253. }
  254. virtual StringBuffer &getLogPrefix(StringBuffer &ret) const
  255. {
  256. return ctx->getLogPrefix(ret);
  257. }
  258. virtual unsigned queryTraceLevel() const
  259. {
  260. return ctx->queryTraceLevel();
  261. }
  262. virtual bool isIntercepted() const
  263. {
  264. return ctx->isIntercepted();
  265. }
  266. virtual bool isBlind() const
  267. {
  268. return ctx->isBlind();
  269. }
  270. virtual unsigned parallelJoinPreload()
  271. {
  272. return ctx->parallelJoinPreload();
  273. }
  274. virtual unsigned concatPreload()
  275. {
  276. return ctx->concatPreload();
  277. }
  278. virtual unsigned fetchPreload()
  279. {
  280. return ctx->fetchPreload();
  281. }
  282. virtual unsigned fullKeyedJoinPreload()
  283. {
  284. return ctx->fullKeyedJoinPreload();
  285. }
  286. virtual unsigned keyedJoinPreload()
  287. {
  288. return ctx->keyedJoinPreload();
  289. }
  290. virtual unsigned prefetchProjectPreload()
  291. {
  292. return ctx->prefetchProjectPreload();
  293. }
  294. virtual void addSlavesReplyLen(unsigned len)
  295. {
  296. ctx->addSlavesReplyLen(len);
  297. }
  298. virtual const char *queryAuthToken()
  299. {
  300. return ctx->queryAuthToken();
  301. }
  302. virtual const IResolvedFile *resolveLFN(const char *filename, bool isOpt)
  303. {
  304. return ctx->resolveLFN(filename, isOpt);
  305. }
  306. virtual IRoxieWriteHandler *createLFN(const char *filename, bool overwrite, bool extend, const StringArray &clusters)
  307. {
  308. return ctx->createLFN(filename, overwrite, extend, clusters);
  309. }
  310. virtual void onFileCallback(const RoxiePacketHeader &header, const char *lfn, bool isOpt, bool isLocal)
  311. {
  312. ctx->onFileCallback(header, lfn, isOpt, isLocal);
  313. }
  314. virtual IActivityGraph *getLibraryGraph(const LibraryCallFactoryExtra &extra, IRoxieServerActivity *parentActivity)
  315. {
  316. return ctx->getLibraryGraph(extra, parentActivity);
  317. }
  318. virtual void noteProcessed(const IRoxieContextLogger &_activityContext, const IRoxieServerActivity *_activity, unsigned _idx, unsigned _processed, unsigned __int64 _totalCycles, unsigned __int64 _localCycles) const
  319. {
  320. ctx->noteProcessed(_activityContext, _activity, _idx, _processed, _totalCycles, _localCycles);
  321. }
  322. virtual IProbeManager *queryProbeManager() const
  323. {
  324. return ctx->queryProbeManager();
  325. }
  326. virtual IDebuggableContext *queryDebugContext() const
  327. {
  328. return ctx->queryDebugContext();
  329. }
  330. virtual bool queryTraceActivityTimes() const
  331. {
  332. return ctx->queryTraceActivityTimes();
  333. }
  334. virtual bool queryCheckingHeap() const
  335. {
  336. return ctx->queryCheckingHeap();
  337. }
  338. virtual bool queryTimeActivities() const
  339. {
  340. return ctx->queryTimeActivities();
  341. }
  342. virtual void printResults(IXmlWriter *output, const char *name, unsigned sequence)
  343. {
  344. ctx->printResults(output, name, sequence);
  345. }
  346. virtual void setWUState(WUState state)
  347. {
  348. ctx->setWUState(state);
  349. }
  350. virtual bool checkWuAborted()
  351. {
  352. return ctx->checkWuAborted();
  353. }
  354. virtual IWorkUnit *updateWorkUnit() const
  355. {
  356. return ctx->updateWorkUnit();
  357. }
  358. virtual IConstWorkUnit *queryWorkUnit() const
  359. {
  360. return ctx->queryWorkUnit();
  361. }
  362. virtual IRoxieServerContext *queryServerContext()
  363. {
  364. return ctx->queryServerContext();
  365. }
  366. virtual IWorkUnitRowReader *getWorkunitRowReader(const char *wuid, const char * name, unsigned sequence, IXmlToRowTransformer * xmlTransformer, IEngineRowAllocator *rowAllocator, bool isGrouped)
  367. {
  368. return ctx->getWorkunitRowReader(wuid, name, sequence, xmlTransformer, rowAllocator, isGrouped);
  369. }
  370. protected:
  371. IRoxieSlaveContext * ctx;
  372. };
  373. //=================================================================================
  374. #define RESULT_FLUSH_THRESHOLD 10000u
  375. #ifdef _DEBUG
  376. #define SOAP_SPLIT_THRESHOLD 100u
  377. #define SOAP_SPLIT_RESERVE 200u
  378. #else
  379. #define SOAP_SPLIT_THRESHOLD 64000u
  380. #define SOAP_SPLIT_RESERVE 65535u
  381. #endif
  382. //=================================================================================
  383. class CRoxieServerActivityFactoryBase : public CActivityFactory, implements IRoxieServerActivityFactory
  384. {
  385. protected:
  386. IntArray dependencies; // things I am dependent on
  387. IntArray dependencyIndexes; // things I am dependent on
  388. IntArray dependencyControlIds; // things I am dependent on
  389. StringArray dependencyEdgeIds; // How to describe them to the debugger
  390. unsigned dependentCount; // things dependent on me
  391. mutable CriticalSection statsCrit;
  392. mutable __int64 processed;
  393. mutable __int64 started;
  394. mutable __int64 totalCycles;
  395. mutable __int64 localCycles;
  396. public:
  397. IMPLEMENT_IINTERFACE;
  398. CRoxieServerActivityFactoryBase(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  399. : CActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  400. {
  401. processed = 0;
  402. started = 0;
  403. totalCycles = 0;
  404. localCycles = 0;
  405. dependentCount = 0;
  406. }
  407. ~CRoxieServerActivityFactoryBase()
  408. {
  409. }
  410. StringBuffer &toString(StringBuffer &ret) const
  411. {
  412. return ret.appendf("%p", this);
  413. }
  414. virtual void addDependency(unsigned _source, ThorActivityKind _kind, unsigned _sourceIdx, int controlId, const char *edgeId)
  415. {
  416. dependencies.append(_source);
  417. dependencyIndexes.append(_sourceIdx);
  418. dependencyControlIds.append(controlId);
  419. dependencyEdgeIds.append(edgeId);
  420. }
  421. virtual void noteDependent(unsigned target)
  422. {
  423. dependentCount++;
  424. }
  425. virtual IntArray &queryDependencies() { return dependencies; }
  426. virtual IntArray &queryDependencyIndexes() { return dependencyIndexes; }
  427. virtual IntArray &queryDependencyControlIds() { return dependencyControlIds; }
  428. virtual StringArray &queryDependencyEdgeIds() { return dependencyEdgeIds; }
  429. virtual unsigned queryId() const { return id; }
  430. virtual unsigned querySubgraphId() const { return subgraphId; }
  431. virtual ThorActivityKind getKind() const { return kind; }
  432. virtual IOutputMetaData * queryOutputMeta() const
  433. {
  434. return meta;
  435. }
  436. virtual bool isSink() const
  437. {
  438. return false;
  439. }
  440. virtual bool isFunction() const
  441. {
  442. return false;
  443. }
  444. virtual bool isGraphInvariant() const
  445. {
  446. return false;
  447. }
  448. virtual IHThorArg &getHelper() const
  449. {
  450. return *helperFactory();
  451. }
  452. virtual IRoxieServerActivity *createFunction(IHThorArg &arg, IProbeManager *_probeManager) const
  453. {
  454. arg.Release();
  455. throwUnexpected();
  456. }
  457. virtual void noteProcessed(unsigned idx, unsigned _processed, unsigned __int64 _totalCycles, unsigned __int64 _localCycles) const
  458. {
  459. if (_processed || _totalCycles || _localCycles)
  460. {
  461. CriticalBlock b(statsCrit);
  462. #ifdef _DEBUG
  463. assertex(_totalCycles >= _localCycles);
  464. #endif
  465. processed += _processed;
  466. totalCycles += _totalCycles;
  467. localCycles += _localCycles;
  468. }
  469. }
  470. virtual void noteStarted() const
  471. {
  472. CriticalBlock b(statsCrit);
  473. started ++;
  474. }
  475. virtual void noteStarted(unsigned idx) const
  476. {
  477. throwUnexpected(); // should be implemented/required by multiOutput cases only
  478. }
  479. virtual void getEdgeProgressInfo(unsigned output, IPropertyTree &edge) const
  480. {
  481. CriticalBlock b(statsCrit);
  482. if (output == 0)
  483. {
  484. putStatsValue(&edge, "count", "sum", processed);
  485. if (started)
  486. putStatsValue(&edge, "started", "sum", started);
  487. }
  488. else
  489. ERRLOG("unexpected call to getEdgeProcessInfo for output %d in activity %d", output, queryId());
  490. }
  491. virtual void getNodeProgressInfo(IPropertyTree &node) const
  492. {
  493. CActivityFactory::getNodeProgressInfo(node);
  494. CriticalBlock b(statsCrit);
  495. if (started)
  496. putStatsValue(&node, "_roxieStarted", "sum", started);
  497. if (totalCycles)
  498. putStatsValue(&node, "totalTime", "sum", (unsigned) (cycle_to_nanosec(totalCycles)/1000));
  499. if (localCycles)
  500. putStatsValue(&node, "localTime", "sum", (unsigned) (cycle_to_nanosec(localCycles)/1000));
  501. }
  502. virtual void resetNodeProgressInfo()
  503. {
  504. CActivityFactory::resetNodeProgressInfo();
  505. CriticalBlock b(statsCrit);
  506. started = 0;
  507. totalCycles = 0;
  508. localCycles = 0;
  509. }
  510. virtual void getActivityMetrics(StringBuffer &reply) const
  511. {
  512. CActivityFactory::getActivityMetrics(reply);
  513. CriticalBlock b(statsCrit);
  514. putStatsValue(reply, "_roxieStarted", "sum", started);
  515. putStatsValue(reply, "totalTime", "sum", (unsigned) (cycle_to_nanosec(totalCycles)/1000));
  516. putStatsValue(reply, "localTime", "sum", (unsigned) (cycle_to_nanosec(localCycles)/1000));
  517. }
  518. virtual unsigned __int64 queryLocalCycles() const
  519. {
  520. return localCycles;
  521. }
  522. virtual IQueryFactory &queryQueryFactory() const
  523. {
  524. return CActivityFactory::queryQueryFactory();
  525. }
  526. virtual ActivityArray *queryChildQuery(unsigned idx, unsigned &id)
  527. {
  528. return CActivityFactory::queryChildQuery(idx, id);
  529. }
  530. virtual void addChildQuery(unsigned id, ActivityArray *childQuery)
  531. {
  532. CActivityFactory::addChildQuery(id, childQuery);
  533. }
  534. virtual void createChildQueries(IArrayOf<IActivityGraph> &childGraphs, IRoxieServerActivity *parentActivity, IProbeManager *_probeManager, const IRoxieContextLogger &_logctx) const
  535. {
  536. ForEachItemIn(idx, childQueries)
  537. {
  538. childGraphs.append(*createActivityGraph(NULL, childQueryIndexes.item(idx), childQueries.item(idx), parentActivity, _probeManager, _logctx));
  539. }
  540. }
  541. virtual void onCreateChildQueries(IRoxieSlaveContext *ctx, IHThorArg *colocalArg, IArrayOf<IActivityGraph> &childGraphs) const
  542. {
  543. ForEachItemIn(idx, childGraphs)
  544. {
  545. ctx->noteChildGraph(childQueryIndexes.item(idx), &childGraphs.item(idx));
  546. childGraphs.item(idx).onCreate(ctx, colocalArg);
  547. }
  548. }
  549. IActivityGraph * createChildGraph(IRoxieSlaveContext * ctx, IHThorArg *colocalArg, unsigned childId, IRoxieServerActivity *parentActivity, IProbeManager * _probeManager, const IRoxieContextLogger &_logctx) const
  550. {
  551. unsigned match = childQueryIndexes.find(childId);
  552. assertex(match != NotFound);
  553. Owned<IActivityGraph> graph = createActivityGraph(NULL, childQueryIndexes.item(match), childQueries.item(match), parentActivity, _probeManager, _logctx);
  554. graph->onCreate(ctx, colocalArg);
  555. return graph.getClear();
  556. }
  557. virtual IRoxieServerSideCache *queryServerSideCache() const
  558. {
  559. return NULL; // Activities that wish to support server-side caching will need to do better....
  560. }
  561. virtual bool getEnableFieldTranslation() const
  562. {
  563. throwUnexpected(); // only implemented by index-related subclasses
  564. }
  565. virtual IDefRecordMeta *queryActivityMeta() const
  566. {
  567. throwUnexpected(); // only implemented by index-related subclasses
  568. }
  569. virtual void noteStatistic(unsigned statCode, unsigned __int64 value, unsigned count) const
  570. {
  571. mystats.noteStatistic(statCode, value, count);
  572. }
  573. virtual void getXrefInfo(IPropertyTree &reply, const IRoxieContextLogger &logctx) const
  574. {
  575. // Most activities have nothing to say...
  576. }
  577. };
  578. class CRoxieServerMultiInputInfo
  579. {
  580. private:
  581. UnsignedArray inputs;
  582. UnsignedArray inputIndexes;
  583. public:
  584. void set(unsigned idx, unsigned source, unsigned sourceidx)
  585. {
  586. if (idx==inputs.length())
  587. {
  588. inputs.append(source);
  589. inputIndexes.append(sourceidx);
  590. }
  591. else
  592. {
  593. while (!inputs.isItem(idx))
  594. {
  595. inputs.append(0);
  596. inputIndexes.append(0);
  597. }
  598. inputs.replace(source, idx);
  599. inputIndexes.replace(sourceidx, idx);
  600. }
  601. }
  602. unsigned get(unsigned idx, unsigned &sourceidx) const
  603. {
  604. if (inputs.isItem(idx))
  605. {
  606. sourceidx = inputIndexes.item(idx);
  607. return inputs.item(idx);
  608. }
  609. else
  610. return (unsigned) -1;
  611. }
  612. inline unsigned ordinality() const { return inputs.ordinality(); }
  613. };
  614. class CRoxieServerMultiInputFactory : public CRoxieServerActivityFactoryBase
  615. {
  616. private:
  617. CRoxieServerMultiInputInfo inputs;
  618. public:
  619. IMPLEMENT_IINTERFACE;
  620. CRoxieServerMultiInputFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  621. : CRoxieServerActivityFactoryBase(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  622. {
  623. }
  624. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  625. {
  626. inputs.set(idx, source, sourceidx);
  627. }
  628. virtual unsigned getInput(unsigned idx, unsigned &sourceidx) const
  629. {
  630. return inputs.get(idx, sourceidx);
  631. }
  632. virtual unsigned numInputs() const { return inputs.ordinality(); }
  633. };
  634. class CWrappedException : public CInterface, implements IException
  635. {
  636. Owned<IException> wrapped;
  637. ThorActivityKind kind;
  638. unsigned queryId;
  639. public:
  640. IMPLEMENT_IINTERFACE;
  641. CWrappedException(IException *_wrapped, ThorActivityKind _kind, unsigned _queryId)
  642. : wrapped(_wrapped), kind(_kind), queryId(_queryId)
  643. {
  644. }
  645. virtual int errorCode() const { return wrapped->errorCode(); }
  646. virtual StringBuffer & errorMessage(StringBuffer &msg) const { return wrapped->errorMessage(msg).appendf(" (in %s %d)", getActivityText(kind), queryId); }
  647. virtual MessageAudience errorAudience() const { return wrapped->errorAudience(); }
  648. };
  649. class CRoxieServerActivityFactory : public CRoxieServerActivityFactoryBase
  650. {
  651. protected:
  652. unsigned input;
  653. unsigned inputidx;
  654. public:
  655. IMPLEMENT_IINTERFACE;
  656. CRoxieServerActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  657. : CRoxieServerActivityFactoryBase(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  658. {
  659. input = (unsigned) -1;
  660. inputidx = 0;
  661. }
  662. inline void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  663. {
  664. if (idx != 0)
  665. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: id = %d : setInput() parameter out of bounds idx = %d at %s(%d)", id, idx, __FILE__, __LINE__);
  666. if (input != -1)
  667. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: id = %d : setInput() called twice for input = %d source = %d inputidx = %d sourceidx = %d at %s(%d)", id, input, source, inputidx, sourceidx, __FILE__, __LINE__);
  668. input = source;
  669. inputidx = sourceidx;
  670. }
  671. virtual unsigned getInput(unsigned idx, unsigned &sourceidx) const
  672. {
  673. if (!idx)
  674. {
  675. sourceidx = inputidx;
  676. return input;
  677. }
  678. return (unsigned) -1;
  679. }
  680. virtual unsigned numInputs() const { return (input == (unsigned)-1) ? 0 : 1; }
  681. };
  682. class CRoxieServerMultiOutputFactory : public CRoxieServerActivityFactory
  683. {
  684. protected:
  685. unsigned numOutputs;
  686. unsigned __int64 *processedArray;
  687. bool *startedArray;
  688. CRoxieServerMultiOutputFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  689. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  690. {
  691. numOutputs = 0;
  692. processedArray = NULL;
  693. startedArray = NULL;
  694. }
  695. ~CRoxieServerMultiOutputFactory()
  696. {
  697. delete [] processedArray;
  698. delete [] startedArray;
  699. }
  700. void setNumOutputs(unsigned num)
  701. {
  702. numOutputs = num;
  703. if (!num)
  704. num = 1; // Even sink activities like to track how many records they process
  705. processedArray = new unsigned __int64[num];
  706. startedArray = new bool[num];
  707. for (unsigned i = 0; i < num; i++)
  708. {
  709. processedArray[i] = 0;
  710. startedArray[i] = 0;
  711. }
  712. }
  713. virtual void getEdgeProgressInfo(unsigned idx, IPropertyTree &edge) const
  714. {
  715. assertex(numOutputs ? idx < numOutputs : idx==0);
  716. CriticalBlock b(statsCrit);
  717. putStatsValue(&edge, "count", "sum", processedArray[idx]);
  718. putStatsValue(&edge, "started", "sum", startedArray[idx]);
  719. }
  720. virtual void noteProcessed(unsigned idx, unsigned _processed, unsigned __int64 _totalCycles, unsigned __int64 _localCycles) const
  721. {
  722. assertex(numOutputs ? idx < numOutputs : idx==0);
  723. CriticalBlock b(statsCrit);
  724. processedArray[idx] += _processed;
  725. totalCycles += _totalCycles;
  726. localCycles += _localCycles;
  727. }
  728. virtual void noteStarted(unsigned idx) const
  729. {
  730. assertex(numOutputs ? idx < numOutputs : idx==0);
  731. CriticalBlock b(statsCrit);
  732. startedArray[idx] = true;
  733. }
  734. };
  735. class CRoxieServerInternalSinkFactory : public CRoxieServerActivityFactory
  736. {
  737. protected:
  738. bool isInternal;
  739. bool isRoot;
  740. unsigned usageCount;
  741. public:
  742. CRoxieServerInternalSinkFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
  743. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  744. {
  745. usageCount = _usageCount;
  746. isRoot = _isRoot;
  747. isInternal = false; // filled in by derived class constructor
  748. }
  749. virtual bool isSink() const
  750. {
  751. //only a sink if a root activity
  752. 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?
  753. }
  754. virtual void getEdgeProgressInfo(unsigned idx, IPropertyTree &edge) const
  755. {
  756. // 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
  757. // Just leave it blank is safest.
  758. }
  759. };
  760. typedef enum { STATEreset, STATEstarted, STATEstopped, STATEstarting } activityState;
  761. const char *queryStateText(activityState state)
  762. {
  763. switch (state)
  764. {
  765. case STATEreset: return "reset";
  766. case STATEstarted: return "started";
  767. case STATEstopped: return "stopped";
  768. case STATEstarting: return "starting";
  769. default: return "unknown";
  770. }
  771. }
  772. typedef ICopyArrayOf<IRoxieServerActivity> IRoxieServerActivityCopyArray;
  773. class CParallelActivityExecutor : public CAsyncFor
  774. {
  775. public:
  776. unsigned parentExtractSize;
  777. const byte * parentExtract;
  778. CParallelActivityExecutor(IRoxieServerActivityCopyArray & _activities, unsigned _parentExtractSize, const byte * _parentExtract) :
  779. activities(_activities), parentExtractSize(_parentExtractSize), parentExtract(_parentExtract) { }
  780. void Do(unsigned i)
  781. {
  782. activities.item(i).execute(parentExtractSize, parentExtract);
  783. }
  784. private:
  785. IRoxieServerActivityCopyArray & activities;
  786. };
  787. class CRoxieServerActivity : public CInterface, implements IRoxieServerActivity, implements IRoxieInput, implements IRoxieContextLogger
  788. {
  789. protected:
  790. IRoxieInput *input;
  791. IHThorArg &basehelper;
  792. IRoxieSlaveContext *ctx;
  793. const IRoxieServerActivityFactory *factory;
  794. IRoxieServerActivityCopyArray dependencies;
  795. IntArray dependencyIndexes;
  796. IntArray dependencyControlIds;
  797. IArrayOf<IActivityGraph> childGraphs;
  798. CachedOutputMetaData meta;
  799. IHThorArg *colocalParent;
  800. IEngineRowAllocator *rowAllocator;
  801. CriticalSection statecrit;
  802. mutable StatsCollector stats;
  803. unsigned processed;
  804. unsigned __int64 totalCycles;
  805. unsigned activityId;
  806. activityState state;
  807. bool createPending;
  808. bool debugging;
  809. bool timeActivities;
  810. public:
  811. IMPLEMENT_IINTERFACE;
  812. CRoxieServerActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  813. : factory(_factory),
  814. basehelper(_factory->getHelper()),
  815. activityId(_factory->queryId())
  816. {
  817. input = NULL;
  818. ctx = NULL;
  819. meta.set(basehelper.queryOutputMeta());
  820. processed = 0;
  821. totalCycles = 0;
  822. if (factory)
  823. factory->createChildQueries(childGraphs, this, _probeManager, *this);
  824. state=STATEreset;
  825. rowAllocator = NULL;
  826. debugging = _probeManager != NULL; // Don't want to collect timing stats from debug sessions
  827. colocalParent = NULL;
  828. createPending = true;
  829. timeActivities = defaultTimeActivities;
  830. }
  831. CRoxieServerActivity(IHThorArg & _helper) : factory(NULL), basehelper(_helper)
  832. {
  833. activityId = 0;
  834. input = NULL;
  835. ctx = NULL;
  836. meta.set(basehelper.queryOutputMeta());
  837. processed = 0;
  838. totalCycles = 0;
  839. state=STATEreset;
  840. rowAllocator = NULL;
  841. debugging = false;
  842. colocalParent = NULL;
  843. createPending = true;
  844. timeActivities = defaultTimeActivities;
  845. }
  846. inline ~CRoxieServerActivity()
  847. {
  848. CriticalBlock cb(statecrit);
  849. if (traceStartStop)
  850. {
  851. DBGLOG("%p destroy %d state=%s", this, activityId, queryStateText(state)); // Note- CTXLOG may not be safe
  852. if (watchActivityId && watchActivityId==activityId)
  853. {
  854. DBGLOG("WATCH: %p destroy %d state=%s", this, activityId, queryStateText(state)); // Note- CTXLOG may not be safe
  855. }
  856. }
  857. if (state!=STATEreset)
  858. {
  859. DBGLOG("STATE: Activity %d destroyed but not reset", activityId);
  860. state = STATEreset; // bit pointless but there you go...
  861. }
  862. basehelper.Release();
  863. ::Release(rowAllocator);
  864. }
  865. virtual const IRoxieContextLogger &queryLogCtx()const
  866. {
  867. return *this;
  868. }
  869. inline void createRowAllocator()
  870. {
  871. if (!rowAllocator)
  872. rowAllocator = ctx->queryCodeContext()->getRowAllocator(meta.queryOriginal(), activityId);
  873. }
  874. // MORE - most of this is copied from ccd.hpp - can't we refactor?
  875. virtual void CTXLOG(const char *format, ...) const
  876. {
  877. va_list args;
  878. va_start(args, format);
  879. CTXLOGva(format, args);
  880. va_end(args);
  881. }
  882. virtual void CTXLOGva(const char *format, va_list args) const
  883. {
  884. StringBuffer text, prefix;
  885. getLogPrefix(prefix);
  886. text.valist_appendf(format, args);
  887. CTXLOGa(LOG_TRACING, prefix.str(), text.str());
  888. }
  889. virtual void CTXLOGa(TracingCategory category, const char *prefix, const char *text) const
  890. {
  891. if (ctx)
  892. ctx->CTXLOGa(category, prefix, text);
  893. else
  894. DBGLOG("[%s] %s", prefix, text);
  895. }
  896. virtual void logOperatorException(IException *E, const char *file, unsigned line, const char *format, ...) const
  897. {
  898. va_list args;
  899. va_start(args, format);
  900. StringBuffer prefix;
  901. getLogPrefix(prefix);
  902. CTXLOGaeva(E, file, line, prefix.str(), format, args);
  903. va_end(args);
  904. }
  905. virtual void logOperatorExceptionVA(IException *E, const char *file, unsigned line, const char *format, va_list args) const
  906. {
  907. StringBuffer prefix;
  908. getLogPrefix(prefix);
  909. CTXLOGaeva(E, file, line, prefix.str(), format, args);
  910. }
  911. virtual void CTXLOGae(IException *E, const char *file, unsigned line, const char *prefix, const char *format, ...) const
  912. {
  913. va_list args;
  914. va_start(args, format);
  915. CTXLOGaeva(E, file, line, prefix, format, args);
  916. va_end(args);
  917. }
  918. virtual void CTXLOGaeva(IException *E, const char *file, unsigned line, const char *prefix, const char *format, va_list args) const
  919. {
  920. if (ctx)
  921. ctx->CTXLOGaeva(E, file, line, prefix, format, args);
  922. else
  923. {
  924. StringBuffer ss;
  925. ss.appendf("[%s] ERROR", prefix);
  926. if (E)
  927. ss.append(": ").append(E->errorCode());
  928. if (file)
  929. ss.appendf(": %s(%d) ", file, line);
  930. if (E)
  931. E->errorMessage(ss.append(": "));
  932. if (format)
  933. {
  934. ss.append(": ").valist_appendf(format, args);
  935. }
  936. LOG(MCoperatorProgress, unknownJob, "%s", ss.str());
  937. }
  938. }
  939. virtual void CTXLOGl(LogItem *log) const
  940. {
  941. if (ctx)
  942. ctx->CTXLOGl(log);
  943. else
  944. {
  945. assert(ctx);
  946. log->Release(); // Should never happen
  947. }
  948. }
  949. virtual void noteStatistic(unsigned statCode, unsigned __int64 value, unsigned count) const
  950. {
  951. if (factory)
  952. factory->noteStatistic(statCode, value, count);
  953. if (ctx)
  954. ctx->noteStatistic(statCode, value, count);
  955. stats.noteStatistic(statCode, value, count);
  956. }
  957. virtual StringBuffer &getLogPrefix(StringBuffer &ret) const
  958. {
  959. if (ctx)
  960. ctx->getLogPrefix(ret);
  961. return ret.append('@').append(activityId);
  962. }
  963. virtual bool isIntercepted() const
  964. {
  965. return ctx ? ctx->isIntercepted() : false;
  966. }
  967. virtual bool isBlind() const
  968. {
  969. return ctx ? ctx->isBlind() : blindLogging;
  970. }
  971. virtual unsigned queryTraceLevel() const
  972. {
  973. if (ctx)
  974. return ctx->queryTraceLevel();
  975. else
  976. return traceLevel;
  977. }
  978. virtual bool isPassThrough()
  979. {
  980. return false;
  981. }
  982. virtual const IResolvedFile *resolveLFN(const char *filename, bool isOpt)
  983. {
  984. return ctx->resolveLFN(filename, isOpt);
  985. }
  986. virtual const IResolvedFile *queryVarFileInfo() const
  987. {
  988. throwUnexpected(); // should be implemented in more derived class by anyone that has a remote adaptor
  989. return NULL;
  990. }
  991. virtual void serializeSkipInfo(MemoryBuffer &out, unsigned seekLen, const void *rawSeek, unsigned numFields, const void * seek, const SmartStepExtra &stepExtra) const
  992. {
  993. throwUnexpected(); // should be implemented in more derived class wherever needed
  994. }
  995. virtual IRoxieSlaveContext *queryContext()
  996. {
  997. return ctx;
  998. }
  999. virtual IRoxieServerActivity *queryActivity() { return this; }
  1000. virtual IIndexReadActivityInfo *queryIndexReadActivity() { return NULL; }
  1001. virtual bool needsAllocator() const { return false; }
  1002. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  1003. {
  1004. ctx = _ctx;
  1005. colocalParent = _colocalParent;
  1006. createPending = true;
  1007. if (needsAllocator())
  1008. createRowAllocator();
  1009. processed = 0;
  1010. totalCycles = 0;
  1011. if (factory)
  1012. factory->onCreateChildQueries(_ctx, &basehelper, childGraphs);
  1013. if (ctx)
  1014. timeActivities = ctx->queryTimeActivities();
  1015. }
  1016. virtual void serializeCreateStartContext(MemoryBuffer &out)
  1017. {
  1018. //This should only be called after onStart has been called on the helper
  1019. assertex(!createPending);
  1020. assertex(state==STATEstarted);
  1021. unsigned startlen = out.length();
  1022. basehelper.serializeCreateContext(out);
  1023. basehelper.serializeStartContext(out);
  1024. if (queryTraceLevel() > 10)
  1025. CTXLOG("serializeCreateStartContext for %d added %d bytes", activityId, out.length()-startlen);
  1026. }
  1027. virtual void serializeExtra(MemoryBuffer &out) {}
  1028. inline void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  1029. {
  1030. CriticalBlock cb(statecrit);
  1031. if (state != STATEreset && state != STATEstarting)
  1032. {
  1033. CTXLOG("STATE: Expected state to be reset, but was %s, in activity %d", queryStateText(state), activityId);
  1034. }
  1035. state=STATEstarted;
  1036. #ifdef TRACE_STARTSTOP
  1037. if (traceStartStop)
  1038. {
  1039. CTXLOG("start %p %d", this, activityId);
  1040. if (watchActivityId && watchActivityId==activityId)
  1041. {
  1042. CTXLOG("WATCH: start %p %d", this, activityId);
  1043. }
  1044. }
  1045. #endif
  1046. executeDependencies(parentExtractSize, parentExtract, 0);
  1047. if (input)
  1048. input->start(parentExtractSize, parentExtract, paused);
  1049. ensureCreated();
  1050. basehelper.onStart(parentExtract, NULL);
  1051. if (factory)
  1052. factory->noteStarted();
  1053. }
  1054. void executeDependencies(unsigned parentExtractSize, const byte *parentExtract, unsigned controlId)
  1055. {
  1056. //MORE: Create a filtered list and then use asyncfor
  1057. ForEachItemIn(idx, dependencies)
  1058. {
  1059. if (dependencyControlIds.item(idx) == controlId)
  1060. dependencies.item(idx).execute(parentExtractSize, parentExtract);
  1061. }
  1062. }
  1063. void stopDependencies(unsigned parentExtractSize, const byte *parentExtract, unsigned controlId)
  1064. {
  1065. ForEachItemIn(idx, dependencies)
  1066. {
  1067. if (dependencyControlIds.item(idx) == controlId)
  1068. dependencies.item(idx).stop(false);
  1069. }
  1070. }
  1071. virtual unsigned __int64 queryTotalCycles() const
  1072. {
  1073. return totalCycles;
  1074. }
  1075. virtual unsigned __int64 queryLocalCycles() const
  1076. {
  1077. __int64 ret = totalCycles;
  1078. if (input) ret -= input->queryTotalCycles();
  1079. if (ret < 0)
  1080. ret = 0;
  1081. return ret;
  1082. }
  1083. virtual IRoxieInput *queryInput(unsigned idx) const
  1084. {
  1085. if (idx==0)
  1086. return input;
  1087. else
  1088. return NULL;
  1089. }
  1090. void noteProcessed(unsigned _idx, unsigned _processed, unsigned __int64 _totalCycles, unsigned __int64 _localCycles) const
  1091. {
  1092. if (factory)
  1093. {
  1094. if (!debugging)
  1095. factory->noteProcessed(_idx, _processed, _totalCycles, _localCycles);
  1096. if (ctx)
  1097. ctx->noteProcessed(*this, this, _idx, _processed, _totalCycles, _localCycles);
  1098. }
  1099. }
  1100. inline void ensureCreated()
  1101. {
  1102. if (createPending)
  1103. {
  1104. createPending = false;
  1105. basehelper.onCreate(ctx->queryCodeContext(), colocalParent, NULL);
  1106. }
  1107. }
  1108. inline void stop(bool aborting)
  1109. {
  1110. // NOTE - don't be tempted to skip the stop for activities that are reset - splitters need to see the stops
  1111. if (state != STATEstopped)
  1112. {
  1113. CriticalBlock cb(statecrit);
  1114. if (state != STATEstopped)
  1115. {
  1116. #ifdef TRACE_STARTSTOP
  1117. if (traceStartStop)
  1118. {
  1119. CTXLOG("stop %p %d (state currently %s)", this, activityId, queryStateText(state));
  1120. if (watchActivityId && watchActivityId==activityId)
  1121. {
  1122. CTXLOG("WATCH: stop %p %d", this, activityId);
  1123. }
  1124. }
  1125. #endif
  1126. state=STATEstopped;
  1127. // NOTE - this is needed to ensure that dependencies which were not used are properly stopped
  1128. ForEachItemIn(idx, dependencies)
  1129. {
  1130. if (dependencyControlIds.item(idx) == 0)
  1131. dependencies.item(idx).stopSink(dependencyIndexes.item(idx));
  1132. }
  1133. if (input)
  1134. input->stop(aborting);
  1135. }
  1136. }
  1137. }
  1138. inline void reset()
  1139. {
  1140. if (state != STATEreset)
  1141. {
  1142. CriticalBlock cb(statecrit);
  1143. if (state != STATEreset)
  1144. {
  1145. if (state==STATEstarted || state==STATEstarting)
  1146. {
  1147. if (traceStartStop || traceLevel > 2)
  1148. CTXLOG("STATE: activity %d reset without stop", activityId);
  1149. stop(false);
  1150. }
  1151. if (ctx->queryTraceActivityTimes())
  1152. {
  1153. stats.dumpStats(*this);
  1154. StringBuffer prefix, text;
  1155. getLogPrefix(prefix);
  1156. text.appendf("records processed - %d", processed);
  1157. CTXLOGa(LOG_STATISTICS, prefix.str(), text.str());
  1158. text.clear().appendf("total time - %d us", (unsigned) (cycle_to_nanosec(totalCycles)/1000));
  1159. CTXLOGa(LOG_STATISTICS, prefix.str(), text.str());
  1160. text.clear().appendf("local time - %d us", (unsigned) (cycle_to_nanosec(queryLocalCycles())/1000));
  1161. CTXLOGa(LOG_STATISTICS, prefix.str(), text.str());
  1162. }
  1163. state = STATEreset;
  1164. #ifdef TRACE_STARTSTOP
  1165. if (traceStartStop)
  1166. {
  1167. CTXLOG("reset %p %d", this, activityId);
  1168. if (watchActivityId && watchActivityId==activityId)
  1169. {
  1170. CTXLOG("WATCH: reset %p %d", this, activityId);
  1171. }
  1172. }
  1173. #endif
  1174. ForEachItemIn(idx, dependencies)
  1175. dependencies.item(idx).reset();
  1176. noteProcessed(0, processed, totalCycles, queryLocalCycles());
  1177. if (input)
  1178. input->reset();
  1179. processed = 0;
  1180. totalCycles = 0;
  1181. }
  1182. }
  1183. }
  1184. virtual void addDependency(IRoxieServerActivity &source, unsigned sourceIdx, int controlId)
  1185. {
  1186. dependencies.append(source);
  1187. dependencyIndexes.append(sourceIdx);
  1188. dependencyControlIds.append(controlId);
  1189. }
  1190. virtual void resetEOF()
  1191. {
  1192. //would make more sense if the default implementation (and eof member) were in the base class
  1193. }
  1194. // Sink activities should override this....
  1195. virtual void execute(unsigned parentExtractSize, const byte * parentExtract)
  1196. {
  1197. throw MakeStringException(ROXIE_SINK, "Internal error: execute() requires a sink");
  1198. }
  1199. virtual void executeChild(size32_t & retSize, void * & ret, unsigned parentExtractSize, const byte * parentExtract)
  1200. {
  1201. throw MakeStringException(ROXIE_SINK, "Internal error: executeChild() requires a suitable sink");
  1202. }
  1203. virtual void stopSink(unsigned idx)
  1204. {
  1205. throw MakeStringException(ROXIE_SINK, "Internal error: stopSink() requires a suitable sink");
  1206. }
  1207. virtual __int64 evaluate()
  1208. {
  1209. throw MakeStringException(ROXIE_SINK, "Internal error: evaluate() requires a function");
  1210. }
  1211. virtual IRoxieInput * querySelectOutput(unsigned id)
  1212. {
  1213. return NULL;
  1214. }
  1215. virtual bool querySetStreamInput(unsigned id, IRoxieInput * _input)
  1216. {
  1217. return false;
  1218. }
  1219. virtual void setInput(unsigned idx, IRoxieInput *_in)
  1220. {
  1221. assertex(!idx);
  1222. input = _in;
  1223. }
  1224. virtual IRoxieInput *queryOutput(unsigned idx)
  1225. {
  1226. if (idx == (unsigned) -1)
  1227. idx = 0;
  1228. return idx ? NULL : this;
  1229. }
  1230. virtual IOutputMetaData *queryOutputMeta() const
  1231. {
  1232. return meta.queryOriginal();
  1233. }
  1234. virtual unsigned queryId() const
  1235. {
  1236. return activityId;
  1237. }
  1238. virtual unsigned querySubgraphId() const
  1239. {
  1240. return factory->querySubgraphId();
  1241. }
  1242. virtual void checkAbort()
  1243. {
  1244. ctx->checkAbort();
  1245. }
  1246. IException *makeWrappedException(IException *e)
  1247. {
  1248. StringBuffer msg;
  1249. ThorActivityKind activityKind = factory ? factory->getKind() : TAKnone;
  1250. CTXLOG("makeWrappedException - %s (in %s %d)", e->errorMessage(msg).str(), getActivityText(activityKind), activityId);
  1251. if (QUERYINTERFACE(e, CWrappedException) || QUERYINTERFACE(e, IUserException))
  1252. return e;
  1253. else
  1254. return new CWrappedException(e, activityKind, activityId);
  1255. }
  1256. virtual void gatherIterationUsage(IRoxieServerLoopResultProcessor & processor, unsigned parentExtractSize, const byte * parentExtract)
  1257. {
  1258. }
  1259. virtual void associateIterationOutputs(IRoxieServerLoopResultProcessor & processor, unsigned parentExtractSize, const byte * parentExtract, IProbeManager *probeManager, IArrayOf<IRoxieInput> &probes)
  1260. {
  1261. }
  1262. virtual void resetOutputsUsed()
  1263. {
  1264. }
  1265. virtual void noteOutputUsed()
  1266. {
  1267. }
  1268. virtual IRoxieServerSideCache *queryServerSideCache() const
  1269. {
  1270. return factory->queryServerSideCache();
  1271. }
  1272. virtual const IRoxieServerActivityFactory *queryFactory() const
  1273. {
  1274. return factory;
  1275. }
  1276. inline ThorActivityKind getKind() const
  1277. {
  1278. return factory->getKind();
  1279. }
  1280. inline bool isSink() const
  1281. {
  1282. return (factory != NULL) && factory->isSink();
  1283. }
  1284. };
  1285. //=====================================================================================================
  1286. class CRoxieServerLateStartActivity : public CRoxieServerActivity
  1287. {
  1288. protected:
  1289. IRoxieInput *input; // Don't use base class input field as we want to delay starts
  1290. bool prefiltered;
  1291. bool eof;
  1292. void lateStart(unsigned parentExtractSize, const byte *parentExtract, bool any)
  1293. {
  1294. prefiltered = !any;
  1295. eof = prefiltered;
  1296. if (!prefiltered)
  1297. input->start(parentExtractSize, parentExtract, false);
  1298. else
  1299. {
  1300. if (traceStartStop)
  1301. CTXLOG("lateStart activity stopping input early as prefiltered");
  1302. input->stop(false);
  1303. }
  1304. }
  1305. public:
  1306. CRoxieServerLateStartActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  1307. : CRoxieServerActivity(_factory, _probeManager)
  1308. {
  1309. input = NULL;
  1310. prefiltered = false;
  1311. eof = false;
  1312. }
  1313. virtual void stop(bool aborting)
  1314. {
  1315. if (!prefiltered)
  1316. {
  1317. input->stop(aborting);
  1318. }
  1319. else if (traceStartStop)
  1320. CTXLOG("lateStart activity NOT stopping input late as prefiltered");
  1321. CRoxieServerActivity::stop(aborting);
  1322. }
  1323. virtual unsigned __int64 queryLocalCycles() const
  1324. {
  1325. __int64 localCycles = totalCycles - input->queryTotalCycles();
  1326. if (localCycles < 0)
  1327. localCycles = 0;
  1328. return localCycles;
  1329. }
  1330. virtual IRoxieInput *queryInput(unsigned idx) const
  1331. {
  1332. if (idx==0)
  1333. return input;
  1334. else
  1335. return NULL;
  1336. }
  1337. virtual void reset()
  1338. {
  1339. CRoxieServerActivity::reset();
  1340. input->reset();
  1341. prefiltered = false;
  1342. }
  1343. virtual void setInput(unsigned idx, IRoxieInput *_in)
  1344. {
  1345. assertex(!idx);
  1346. input = _in;
  1347. }
  1348. };
  1349. //=====================================================================================================
  1350. atomic_t nextInstanceId;
  1351. extern unsigned getNextInstanceId()
  1352. {
  1353. return atomic_add_exchange(&nextInstanceId, 1)+1;
  1354. }
  1355. atomic_t nextRuid;
  1356. ruid_t getNextRuid()
  1357. {
  1358. ruid_t ret = atomic_add_exchange(&nextRuid, 1)+1;
  1359. while (ret < RUID_FIRST)
  1360. ret = atomic_add_exchange(&nextRuid, 1)+1; // ruids 0 and 1 are reserved for pings/unwanted discarder.
  1361. return ret;
  1362. }
  1363. void setStartRuid(unsigned restarts)
  1364. {
  1365. atomic_set(&nextRuid, restarts * 0x10000);
  1366. atomic_set(&nextInstanceId, restarts * 10000);
  1367. }
  1368. enum { LimitSkipErrorCode = 0, KeyedLimitSkipErrorCode = 1 };
  1369. class LimitSkipException : public CInterface, public IException
  1370. {
  1371. int code;
  1372. public:
  1373. LimitSkipException(int _code) { code = _code; }
  1374. IMPLEMENT_IINTERFACE;
  1375. virtual int errorCode() const { return code; }
  1376. virtual StringBuffer & errorMessage(StringBuffer &msg) const { return msg.append("LimitSkipException"); }
  1377. virtual MessageAudience errorAudience() const { return MSGAUD_internal; }
  1378. };
  1379. IException *makeLimitSkipException(bool isKeyed)
  1380. {
  1381. // We need to make sure what we throw is IException not something derived from it....
  1382. return new LimitSkipException(isKeyed ? KeyedLimitSkipErrorCode : LimitSkipErrorCode);
  1383. }
  1384. //=================================================================================
  1385. interface IRecordPullerCallback : extends IExceptionHandler
  1386. {
  1387. virtual void processRow(const void *row) = 0;
  1388. virtual void processEOG() = 0;
  1389. virtual void processGroup(const ConstPointerArray &rows) = 0;
  1390. virtual void processDone() = 0;
  1391. };
  1392. class RecordPullerThread : public RestartableThread
  1393. {
  1394. protected:
  1395. IRoxieInput *input;
  1396. IRecordPullerCallback *helper;
  1397. Semaphore started; // MORE: GH->RKC I'm pretty sure this can be deleted, since handled by RestartableThread
  1398. bool groupAtOnce, eof, eog;
  1399. CriticalSection crit;
  1400. public:
  1401. RecordPullerThread(bool _groupAtOnce)
  1402. : RestartableThread("RecordPullerThread"), groupAtOnce(_groupAtOnce)
  1403. {
  1404. input = NULL;
  1405. helper = NULL;
  1406. eof = eog = FALSE;
  1407. }
  1408. inline unsigned __int64 queryTotalCycles() const
  1409. {
  1410. return input->queryTotalCycles();
  1411. }
  1412. void setInput(IRecordPullerCallback *_helper, IRoxieInput *_input)
  1413. {
  1414. helper = _helper;
  1415. input = _input;
  1416. }
  1417. IRoxieInput *queryInput() const
  1418. {
  1419. return input;
  1420. }
  1421. void start(unsigned parentExtractSize, const byte *parentExtract, bool paused, unsigned preload, bool noThread, IRoxieSlaveContext *ctx)
  1422. {
  1423. eof = false;
  1424. eog = false;
  1425. input->start(parentExtractSize, parentExtract, paused);
  1426. try
  1427. {
  1428. if (preload && !paused)
  1429. {
  1430. if (traceLevel > 4)
  1431. DBGLOG("Preload fetching first %d records", preload);
  1432. if (groupAtOnce)
  1433. pullGroups(preload);
  1434. else
  1435. pullRecords(preload);
  1436. }
  1437. if (eof)
  1438. {
  1439. if (traceLevel > 4)
  1440. DBGLOG("No need to start puller after preload");
  1441. helper->processDone();
  1442. }
  1443. else
  1444. {
  1445. if (!noThread)
  1446. {
  1447. StringBuffer logPrefix("[");
  1448. if (ctx) ctx->getLogPrefix(logPrefix);
  1449. logPrefix.append("] ");
  1450. RestartableThread::start(logPrefix);
  1451. started.wait();
  1452. }
  1453. }
  1454. }
  1455. catch (IException *e)
  1456. {
  1457. helper->fireException(e);
  1458. }
  1459. catch (...)
  1460. {
  1461. helper->fireException(MakeStringException(ROXIE_INTERNAL_ERROR, "Unexpected exception caught in RecordPullerThread::start"));
  1462. }
  1463. }
  1464. void stop(bool aborting)
  1465. {
  1466. if (traceStartStop)
  1467. DBGLOG("RecordPullerThread::stop");
  1468. {
  1469. CriticalBlock c(crit); // stop is called on our consumer's thread. We need to take care calling stop for our input to make sure it is not in mid-nextInGroup etc etc.
  1470. input->stop(aborting);
  1471. }
  1472. RestartableThread::join();
  1473. }
  1474. void reset()
  1475. {
  1476. input->reset();
  1477. }
  1478. virtual int run()
  1479. {
  1480. started.signal();
  1481. try
  1482. {
  1483. if (groupAtOnce)
  1484. pullGroups((unsigned) -1);
  1485. else
  1486. pullRecords((unsigned) -1);
  1487. helper->processDone();
  1488. }
  1489. catch (IException *e)
  1490. {
  1491. helper->fireException(e);
  1492. }
  1493. catch (...)
  1494. {
  1495. helper->fireException(MakeStringException(ROXIE_INTERNAL_ERROR, "Unexpected exception caught in RecordPullerThread::run"));
  1496. }
  1497. return 0;
  1498. }
  1499. void done()
  1500. {
  1501. helper->processDone();
  1502. }
  1503. bool pullRecords(unsigned preload)
  1504. {
  1505. if (eof)
  1506. return false;
  1507. while (preload)
  1508. {
  1509. const void * row;
  1510. {
  1511. CriticalBlock c(crit); // See comments in stop for why this is needed
  1512. row = input->nextInGroup();
  1513. }
  1514. if (row)
  1515. {
  1516. eog = false;
  1517. helper->processRow(row);
  1518. }
  1519. else if (!eog)
  1520. {
  1521. helper->processEOG();
  1522. eog = true;
  1523. }
  1524. else
  1525. {
  1526. eof = true;
  1527. return false;
  1528. }
  1529. if (preload != (unsigned) -1)
  1530. preload--;
  1531. }
  1532. return true;
  1533. }
  1534. void pullGroups(unsigned preload)
  1535. {
  1536. ConstPointerArray thisGroup;
  1537. unsigned rowsDone = 0;
  1538. while (preload && !eof)
  1539. {
  1540. const void *row;
  1541. {
  1542. CriticalBlock c(crit);
  1543. row = input->nextInGroup();
  1544. }
  1545. if (row)
  1546. {
  1547. thisGroup.append(row);
  1548. rowsDone++;
  1549. }
  1550. else if (thisGroup.length())
  1551. {
  1552. helper->processGroup(thisGroup);
  1553. thisGroup.kill();
  1554. if (preload != (unsigned) -1)
  1555. {
  1556. if (preload > rowsDone)
  1557. preload -= rowsDone;
  1558. else
  1559. break;
  1560. }
  1561. rowsDone = 0;
  1562. }
  1563. else
  1564. {
  1565. eof = true;
  1566. break;
  1567. }
  1568. }
  1569. }
  1570. };
  1571. //=================================================================================
  1572. #define READAHEAD_SIZE 1000
  1573. // MORE - this code copied from ThreadedConcat code - may be able to common up some.
  1574. class CRoxieServerReadAheadInput : public CInterface, implements IRoxieInput, implements IRecordPullerCallback
  1575. {
  1576. QueueOf<const void, true> buffer;
  1577. InterruptableSemaphore ready;
  1578. InterruptableSemaphore space;
  1579. CriticalSection crit;
  1580. bool eof;
  1581. bool disabled;
  1582. RecordPullerThread puller;
  1583. unsigned preload;
  1584. unsigned __int64 totalCycles;
  1585. IRoxieSlaveContext *ctx;
  1586. bool timeActivities;
  1587. public:
  1588. IMPLEMENT_IINTERFACE;
  1589. CRoxieServerReadAheadInput(unsigned _preload) : puller(true), preload(_preload)
  1590. {
  1591. eof = false;
  1592. disabled = false;
  1593. totalCycles = 0;
  1594. ctx = NULL;
  1595. timeActivities = defaultTimeActivities;
  1596. }
  1597. void onCreate(IRoxieSlaveContext *_ctx)
  1598. {
  1599. ctx = _ctx;
  1600. disabled = (ctx->queryDebugContext() != NULL);
  1601. if (ctx)
  1602. timeActivities = ctx->queryTimeActivities();
  1603. }
  1604. virtual IRoxieServerActivity *queryActivity()
  1605. {
  1606. return puller.queryInput()->queryActivity();
  1607. }
  1608. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  1609. {
  1610. return puller.queryInput()->queryIndexReadActivity();
  1611. }
  1612. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  1613. {
  1614. eof = false;
  1615. totalCycles = 0;
  1616. if (disabled)
  1617. puller.queryInput()->start(parentExtractSize, parentExtract, paused);
  1618. else
  1619. {
  1620. space.reinit(READAHEAD_SIZE);
  1621. ready.reinit();
  1622. puller.start(parentExtractSize, parentExtract, paused, preload, false, ctx);
  1623. }
  1624. }
  1625. virtual void stop(bool aborting)
  1626. {
  1627. if (disabled)
  1628. puller.queryInput()->stop(aborting);
  1629. else
  1630. {
  1631. space.interrupt();
  1632. ready.interrupt();
  1633. puller.stop(aborting);
  1634. }
  1635. }
  1636. virtual void reset()
  1637. {
  1638. if (disabled)
  1639. puller.queryInput()->reset();
  1640. else
  1641. {
  1642. puller.reset();
  1643. ForEachItemIn(idx1, buffer)
  1644. ReleaseRoxieRow(buffer.item(idx1));
  1645. buffer.clear();
  1646. }
  1647. }
  1648. virtual void resetEOF()
  1649. {
  1650. throwUnexpected();
  1651. }
  1652. virtual IOutputMetaData * queryOutputMeta() const
  1653. {
  1654. return puller.queryInput()->queryOutputMeta();
  1655. }
  1656. virtual void checkAbort()
  1657. {
  1658. puller.queryInput()->checkAbort();
  1659. }
  1660. void setInput(unsigned idx, IRoxieInput *_in)
  1661. {
  1662. assertex(!idx);
  1663. puller.setInput(this, _in);
  1664. }
  1665. virtual unsigned __int64 queryTotalCycles() const
  1666. {
  1667. return totalCycles;
  1668. }
  1669. virtual unsigned __int64 queryLocalCycles() const
  1670. {
  1671. __int64 ret = totalCycles - puller.queryInput()->queryTotalCycles();
  1672. if (ret < 0) ret = 0;
  1673. return ret;
  1674. }
  1675. virtual IRoxieInput *queryInput(unsigned idx) const
  1676. {
  1677. return puller.queryInput()->queryInput(idx);
  1678. }
  1679. virtual const void * nextInGroup()
  1680. {
  1681. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  1682. if (disabled)
  1683. return puller.queryInput()->nextInGroup();
  1684. else
  1685. {
  1686. loop
  1687. {
  1688. {
  1689. CriticalBlock b(crit);
  1690. if (eof && !buffer.ordinality())
  1691. return NULL; // eof
  1692. }
  1693. ready.wait();
  1694. const void *ret;
  1695. {
  1696. CriticalBlock b(crit);
  1697. ret = buffer.dequeue();
  1698. }
  1699. space.signal();
  1700. return ret;
  1701. }
  1702. }
  1703. }
  1704. virtual unsigned queryId() const { throwUnexpected(); }
  1705. virtual bool fireException(IException *e)
  1706. {
  1707. // called from puller thread on failure
  1708. ready.interrupt(LINK(e));
  1709. space.interrupt(e);
  1710. return true;
  1711. }
  1712. virtual void processRow(const void *row)
  1713. {
  1714. {
  1715. CriticalBlock b(crit);
  1716. buffer.enqueue(row);
  1717. }
  1718. ready.signal();
  1719. space.wait();
  1720. }
  1721. virtual void processGroup(const ConstPointerArray &rows)
  1722. {
  1723. // NOTE - a bit bizarre in that it waits for the space AFTER using it.
  1724. // But the space semaphore is only there to stop infinite readahead. And otherwise it would deadlock
  1725. // if group was larger than max(space)
  1726. {
  1727. CriticalBlock b(crit);
  1728. ForEachItemIn(idx, rows)
  1729. buffer.enqueue(rows.item(idx));
  1730. buffer.enqueue(NULL);
  1731. }
  1732. for (unsigned i2 = 0; i2 <= rows.length(); i2++) // note - does 1 extra for the null
  1733. {
  1734. ready.signal();
  1735. space.wait();
  1736. }
  1737. }
  1738. virtual void processEOG()
  1739. {
  1740. // Used when output is not grouped - just ignore
  1741. }
  1742. virtual void processDone()
  1743. {
  1744. CriticalBlock b(crit);
  1745. eof = true;
  1746. ready.signal();
  1747. }
  1748. };
  1749. //=================================================================================
  1750. class CRoxieServerTwoInputActivity : public CRoxieServerActivity
  1751. {
  1752. protected:
  1753. IRoxieInput *input1;
  1754. Owned<CRoxieServerReadAheadInput> puller;
  1755. public:
  1756. CRoxieServerTwoInputActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  1757. : CRoxieServerActivity(_factory, _probeManager)
  1758. {
  1759. input1 = NULL;
  1760. }
  1761. ~CRoxieServerTwoInputActivity()
  1762. {
  1763. }
  1764. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  1765. {
  1766. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  1767. input1->start(parentExtractSize, parentExtract, paused);
  1768. }
  1769. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  1770. {
  1771. if (puller)
  1772. puller->onCreate(_ctx);
  1773. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  1774. }
  1775. virtual void stop(bool aborting)
  1776. {
  1777. input1->stop(aborting);
  1778. CRoxieServerActivity::stop(aborting);
  1779. }
  1780. virtual unsigned __int64 queryLocalCycles() const
  1781. {
  1782. __int64 ret;
  1783. __int64 inputCycles = input->queryTotalCycles();
  1784. __int64 input1Cycles = input1->queryTotalCycles();
  1785. if (puller)
  1786. ret = totalCycles - (inputCycles > input1Cycles ? inputCycles : input1Cycles);
  1787. else
  1788. ret = totalCycles - (inputCycles + input1Cycles);
  1789. if (ret < 0)
  1790. ret = 0;
  1791. return ret;
  1792. }
  1793. virtual IRoxieInput *queryInput(unsigned idx) const
  1794. {
  1795. switch (idx)
  1796. {
  1797. case 0:
  1798. return input;
  1799. case 1:
  1800. return input1;
  1801. default:
  1802. return NULL;
  1803. }
  1804. }
  1805. virtual void reset()
  1806. {
  1807. CRoxieServerActivity::reset();
  1808. if (input1)
  1809. input1->reset();
  1810. }
  1811. virtual void setInput(unsigned idx, IRoxieInput *_in)
  1812. {
  1813. switch(idx)
  1814. {
  1815. case 0:
  1816. input = _in;
  1817. break;
  1818. case 1:
  1819. input1 = _in;
  1820. break;
  1821. default:
  1822. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
  1823. }
  1824. }
  1825. };
  1826. //=================================================================================
  1827. class CRoxieServerMultiInputBaseActivity : public CRoxieServerActivity
  1828. {
  1829. protected:
  1830. unsigned numInputs;
  1831. IRoxieInput **inputArray;
  1832. public:
  1833. CRoxieServerMultiInputBaseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  1834. : CRoxieServerActivity(_factory, _probeManager), numInputs(_numInputs)
  1835. {
  1836. inputArray = new IRoxieInput*[numInputs];
  1837. for (unsigned i = 0; i < numInputs; i++)
  1838. inputArray[i] = NULL;
  1839. }
  1840. ~CRoxieServerMultiInputBaseActivity()
  1841. {
  1842. delete [] inputArray;
  1843. }
  1844. virtual unsigned __int64 queryLocalCycles() const
  1845. {
  1846. __int64 localCycles = totalCycles;
  1847. for (unsigned i = 0; i < numInputs; i++)
  1848. localCycles -= inputArray[i]->queryTotalCycles();
  1849. if (localCycles < 0)
  1850. localCycles = 0;
  1851. return localCycles;
  1852. }
  1853. virtual IRoxieInput *queryInput(unsigned idx) const
  1854. {
  1855. if (idx < numInputs)
  1856. return inputArray[idx];
  1857. else
  1858. return NULL;
  1859. }
  1860. virtual void reset()
  1861. {
  1862. for (unsigned i = 0; i < numInputs; i++)
  1863. inputArray[i]->reset();
  1864. CRoxieServerActivity::reset();
  1865. }
  1866. virtual void setInput(unsigned idx, IRoxieInput *_in)
  1867. {
  1868. inputArray[idx] = _in;
  1869. }
  1870. };
  1871. //=================================================================================
  1872. class CRoxieServerMultiInputActivity : public CRoxieServerMultiInputBaseActivity
  1873. {
  1874. public:
  1875. CRoxieServerMultiInputActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  1876. : CRoxieServerMultiInputBaseActivity(_factory, _probeManager, _numInputs)
  1877. {
  1878. }
  1879. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  1880. {
  1881. CRoxieServerMultiInputBaseActivity::start(parentExtractSize, parentExtract, paused);
  1882. for (unsigned i = 0; i < numInputs; i++)
  1883. {
  1884. inputArray[i]->start(parentExtractSize, parentExtract, paused);
  1885. }
  1886. }
  1887. virtual void stop(bool aborting)
  1888. {
  1889. for (unsigned i = 0; i < numInputs; i++)
  1890. {
  1891. inputArray[i]->stop(aborting);
  1892. }
  1893. CRoxieServerMultiInputBaseActivity::stop(aborting);
  1894. }
  1895. };
  1896. //=====================================================================================================
  1897. class CRoxieServerInternalSinkActivity : public CRoxieServerActivity
  1898. {
  1899. protected:
  1900. unsigned numOutputs;
  1901. bool executed;
  1902. bool *stopped;
  1903. CriticalSection ecrit;
  1904. Owned<IException> exception;
  1905. public:
  1906. CRoxieServerInternalSinkActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numOutputs)
  1907. : CRoxieServerActivity(_factory, _probeManager), numOutputs(_numOutputs)
  1908. {
  1909. executed = false;
  1910. stopped = new bool[numOutputs];
  1911. for (unsigned s = 0; s < numOutputs; s++)
  1912. stopped[s] = false;
  1913. }
  1914. ~CRoxieServerInternalSinkActivity()
  1915. {
  1916. delete [] stopped;
  1917. }
  1918. virtual void reset()
  1919. {
  1920. for (unsigned s = 0; s < numOutputs; s++)
  1921. stopped[s] = false;
  1922. executed = false;
  1923. exception.clear();
  1924. CRoxieServerActivity::reset();
  1925. }
  1926. virtual IRoxieInput *queryOutput(unsigned idx)
  1927. {
  1928. return NULL;
  1929. }
  1930. virtual void stopSink(unsigned outputIdx)
  1931. {
  1932. if (!stopped[outputIdx])
  1933. {
  1934. stopped[outputIdx] = true;
  1935. for (unsigned s = 0; s < numOutputs; s++)
  1936. if (!stopped[s])
  1937. return;
  1938. stop(false); // all outputs stopped - stop parent.
  1939. }
  1940. }
  1941. virtual const void *nextInGroup()
  1942. {
  1943. throwUnexpected(); // I am nobody's input
  1944. }
  1945. virtual void onExecute() = 0;
  1946. virtual void execute(unsigned parentExtractSize, const byte * parentExtract)
  1947. {
  1948. CriticalBlock b(ecrit);
  1949. if (exception)
  1950. throw exception.getLink();
  1951. if (!executed)
  1952. {
  1953. try
  1954. {
  1955. start(parentExtractSize, parentExtract, false);
  1956. {
  1957. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext()); // unfortunately this is not really best place for seeing in debugger.
  1958. onExecute();
  1959. }
  1960. stop(false);
  1961. executed = true;
  1962. }
  1963. catch (IException *E)
  1964. {
  1965. exception.set(E); // (or maybe makeWrappedException?)
  1966. stop(true);
  1967. throw;
  1968. }
  1969. catch (...)
  1970. {
  1971. exception.set(MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught at %s:%d", __FILE__, __LINE__));
  1972. stop(true);
  1973. throw;
  1974. }
  1975. }
  1976. }
  1977. };
  1978. //=================================================================================
  1979. class CRoxieServerQueryPacket : public CInterface, implements IRoxieServerQueryPacket
  1980. {
  1981. protected:
  1982. Owned<IMessageResult> result;
  1983. Owned<IRoxieQueryPacket> packet;
  1984. Linked<IRoxieServerQueryPacket> continuation;
  1985. unsigned hash;
  1986. unsigned seq;
  1987. unsigned lastDebugSequence;
  1988. Owned<IRoxieQueryPacket> lastDebugResponse;
  1989. ILRUChain *prev;
  1990. ILRUChain *next;
  1991. bool delayed;
  1992. public:
  1993. IMPLEMENT_IINTERFACE;
  1994. CRoxieServerQueryPacket(IRoxieQueryPacket *p) : packet(p)
  1995. {
  1996. hash = 0;
  1997. seq = 0;
  1998. prev = NULL;
  1999. next = NULL;
  2000. delayed = false;
  2001. lastDebugSequence = 0;
  2002. }
  2003. virtual IRoxieQueryPacket *queryPacket() const
  2004. {
  2005. return packet;
  2006. }
  2007. virtual bool isContinuation() const
  2008. {
  2009. return packet && (packet->queryHeader().continueSequence & ~CONTINUE_SEQUENCE_SKIPTO) != 0;
  2010. }
  2011. virtual bool isDelayed() const
  2012. {
  2013. return delayed;
  2014. }
  2015. virtual bool isEnd() const
  2016. {
  2017. return false;
  2018. }
  2019. virtual bool isLimit(unsigned __int64 &_rowLimit, unsigned __int64 &_keyedLimit, unsigned __int64 &_stopAfter) const
  2020. {
  2021. return false;
  2022. }
  2023. virtual bool hasResult() const
  2024. {
  2025. return result != NULL;
  2026. }
  2027. virtual bool hasContinuation() const
  2028. {
  2029. return continuation != NULL;
  2030. }
  2031. virtual void setDelayed(bool _delayed)
  2032. {
  2033. delayed = _delayed;
  2034. }
  2035. virtual void setPacket(IRoxieQueryPacket *_packet)
  2036. {
  2037. packet.setown(_packet);
  2038. }
  2039. virtual void setSequence(unsigned _seq)
  2040. {
  2041. assertex(!IsShared());
  2042. seq = _seq;
  2043. }
  2044. virtual unsigned getSequence() const
  2045. {
  2046. return seq;
  2047. }
  2048. IMessageResult *getResult()
  2049. {
  2050. return result.getLink();
  2051. }
  2052. IMessageResult *queryResult()
  2053. {
  2054. return result;
  2055. }
  2056. void setResult(IMessageResult *r)
  2057. {
  2058. result.setown(r);
  2059. }
  2060. IRoxieServerQueryPacket *queryContinuation()
  2061. {
  2062. return continuation;
  2063. }
  2064. void setContinuation(IRoxieServerQueryPacket *c)
  2065. {
  2066. continuation.setown(c);
  2067. }
  2068. virtual unsigned queryHash() const
  2069. {
  2070. return hash;
  2071. }
  2072. virtual void setHash(unsigned _hash)
  2073. {
  2074. hash = _hash;
  2075. }
  2076. virtual ILRUChain *queryPrev() const { return prev; }
  2077. virtual ILRUChain *queryNext() const { return next; }
  2078. virtual void setPrev(ILRUChain *p) { prev = p; }
  2079. virtual void setNext(ILRUChain *n) { next = n; }
  2080. virtual void unchain()
  2081. {
  2082. if (prev && next)
  2083. {
  2084. prev->setNext(next);
  2085. next->setPrev(prev);
  2086. }
  2087. next = NULL;
  2088. prev = NULL;
  2089. }
  2090. virtual IRoxieQueryPacket *getDebugResponse(unsigned sequence)
  2091. {
  2092. if (sequence == lastDebugSequence)
  2093. return lastDebugResponse.getLink();
  2094. else if (sequence > lastDebugSequence)
  2095. {
  2096. lastDebugResponse.clear();
  2097. return NULL;
  2098. }
  2099. else
  2100. throwUnexpected();
  2101. }
  2102. virtual void setDebugResponse(unsigned sequence, IRoxieQueryPacket *response)
  2103. {
  2104. lastDebugSequence = sequence;
  2105. lastDebugResponse.set(response);
  2106. }
  2107. };
  2108. class CRoxieServerQueryPacketEndMarker : public CRoxieServerQueryPacket
  2109. {
  2110. public:
  2111. CRoxieServerQueryPacketEndMarker() : CRoxieServerQueryPacket(NULL)
  2112. {
  2113. }
  2114. virtual bool isEnd() const
  2115. {
  2116. return true;
  2117. }
  2118. };
  2119. class CRoxieServerQueryPacketLimitMarker : public CRoxieServerQueryPacket
  2120. {
  2121. unsigned __int64 rowLimit;
  2122. unsigned __int64 keyedLimit;
  2123. unsigned __int64 stopAfter;
  2124. public:
  2125. CRoxieServerQueryPacketLimitMarker(unsigned __int64 _rowLimit, unsigned __int64 _keyedLimit, unsigned __int64 _stopAfter) : CRoxieServerQueryPacket(NULL)
  2126. {
  2127. rowLimit = _rowLimit;
  2128. keyedLimit = _keyedLimit;
  2129. stopAfter = _stopAfter;
  2130. }
  2131. virtual bool isLimit(unsigned __int64 &_rowLimit, unsigned __int64 &_keyedLimit, unsigned __int64 &_stopAfter) const
  2132. {
  2133. _rowLimit = rowLimit;
  2134. _keyedLimit = keyedLimit;
  2135. _stopAfter = stopAfter;
  2136. return true;
  2137. }
  2138. };
  2139. class CRoxieServerSideCache : implements IRoxieServerSideCache, implements ILRUChain
  2140. {
  2141. protected:
  2142. unsigned cacheTableSize;
  2143. unsigned cacheTableSpace;
  2144. IRoxieServerQueryPacket **cacheTable;
  2145. mutable ILRUChain *prev;
  2146. mutable ILRUChain *next;
  2147. mutable CriticalSection crit;
  2148. virtual ILRUChain *queryPrev() const { return prev; }
  2149. virtual ILRUChain *queryNext() const { return next; }
  2150. virtual void setPrev(ILRUChain *p) { prev = p; }
  2151. virtual void setNext(ILRUChain *n) { next = n; }
  2152. virtual void unchain()
  2153. {
  2154. prev->setNext(next);
  2155. next->setPrev(prev);
  2156. next = NULL;
  2157. prev = NULL;
  2158. }
  2159. void moveToHead(IRoxieServerQueryPacket *mru)
  2160. {
  2161. mru->unchain();
  2162. mru->setNext(next);
  2163. next->setPrev(mru);
  2164. mru->setPrev(this);
  2165. next = mru;
  2166. }
  2167. IRoxieServerQueryPacket *removeLRU()
  2168. {
  2169. if (next==this)
  2170. assertex(next != this);
  2171. IRoxieServerQueryPacket *goer = (IRoxieServerQueryPacket *) next;
  2172. goer->unchain(); // NOTE - this will modify the value of next
  2173. return goer;
  2174. }
  2175. void removeEntry(IRoxieServerQueryPacket *goer)
  2176. {
  2177. unsigned v = goer->queryHash() % cacheTableSize;
  2178. loop
  2179. {
  2180. IRoxieServerQueryPacket *found = cacheTable[v];
  2181. assertex(found);
  2182. if (found == goer)
  2183. {
  2184. cacheTable[v] = NULL;
  2185. unsigned vn = v;
  2186. loop
  2187. {
  2188. vn++;
  2189. if (vn==cacheTableSize) vn = 0;
  2190. IRoxieServerQueryPacket *found2 = cacheTable[vn];
  2191. if (!found2)
  2192. break;
  2193. unsigned vm = found2->queryHash() % cacheTableSize;
  2194. if (((vn+cacheTableSize-vm) % cacheTableSize)>=((vn+cacheTableSize-v) % cacheTableSize)) // diff(vn,vm)>=diff(vn,v)
  2195. {
  2196. cacheTable[v] = found2;
  2197. v = vn;
  2198. cacheTable[v] = NULL;
  2199. }
  2200. }
  2201. cacheTableSpace++;
  2202. break;
  2203. }
  2204. v++;
  2205. if (v==cacheTableSize)
  2206. v = 0;
  2207. }
  2208. goer->Release();
  2209. }
  2210. public:
  2211. CRoxieServerSideCache(unsigned _cacheSize)
  2212. {
  2213. cacheTableSize = (_cacheSize*4)/3;
  2214. cacheTable = new IRoxieServerQueryPacket *[cacheTableSize];
  2215. memset(cacheTable, 0, cacheTableSize * sizeof(IRoxieServerQueryPacket *));
  2216. cacheTableSpace = _cacheSize;
  2217. prev = this;
  2218. next = this;
  2219. }
  2220. ~CRoxieServerSideCache()
  2221. {
  2222. for (unsigned i = 0; i < cacheTableSize; i++)
  2223. {
  2224. ::Release(cacheTable[i]);
  2225. }
  2226. delete [] cacheTable;
  2227. }
  2228. virtual IRoxieServerQueryPacket *findCachedResult(const IRoxieContextLogger &logctx, IRoxieQueryPacket *p) const
  2229. {
  2230. unsigned hash = p->hash();
  2231. unsigned et = hash % cacheTableSize;
  2232. if (traceServerSideCache)
  2233. {
  2234. StringBuffer s;
  2235. logctx.CTXLOG("CRoxieServerSideCache::findCachedResult hash %x slot %d %s", hash, et, p->queryHeader().toString(s).str());
  2236. }
  2237. CriticalBlock b(crit);
  2238. loop
  2239. {
  2240. IRoxieServerQueryPacket *found = cacheTable[et];
  2241. if (!found)
  2242. return NULL;
  2243. if (found->queryHash() == hash && found->queryPacket()->cacheMatch(p))
  2244. {
  2245. const_cast<CRoxieServerSideCache *>(this)->moveToHead(found);
  2246. if (traceServerSideCache)
  2247. logctx.CTXLOG("CRoxieServerSideCache::findCachedResult cache hit");
  2248. logctx.noteStatistic(STATS_SERVERCACHEHIT, 1, 1);
  2249. return NULL;
  2250. // Because IMessageResult cannot be replayed, this echeme is flawed. I'm leaving the code here just as a stats gatherer to see how useful it would have been....
  2251. //IRoxieServerQueryPacket *ret = new CRoxieServerQueryPacket(p);
  2252. //ret->setResult(found->getResult());
  2253. //return ret;
  2254. }
  2255. et++;
  2256. if (et == cacheTableSize)
  2257. et = 0;
  2258. }
  2259. }
  2260. virtual void noteCachedResult(IRoxieServerQueryPacket *out, IMessageResult *in)
  2261. {
  2262. if (true) //!in->getLength()) // MORE - separate caches for hits and nohits
  2263. {
  2264. unsigned hash = out->queryPacket()->hash();
  2265. out->setHash(hash);
  2266. unsigned et = hash % cacheTableSize;
  2267. if (traceServerSideCache)
  2268. {
  2269. StringBuffer s;
  2270. DBGLOG("CRoxieServerSideCache::noteCachedResult hash %x slot %d %s", hash, et, out->queryPacket()->queryHeader().toString(s).str());
  2271. }
  2272. CriticalBlock b(crit);
  2273. loop
  2274. {
  2275. IRoxieServerQueryPacket *found = cacheTable[et];
  2276. if (!found)
  2277. {
  2278. if (cacheTableSpace)
  2279. {
  2280. out->setResult(LINK(in));
  2281. cacheTable[et] = LINK(out);
  2282. cacheTableSpace--;
  2283. moveToHead(out);
  2284. break;
  2285. }
  2286. else
  2287. {
  2288. IRoxieServerQueryPacket *goer = removeLRU();
  2289. removeEntry(goer);
  2290. et = hash % cacheTableSize;
  2291. continue;
  2292. }
  2293. }
  2294. else if (found->queryHash()==hash && found->queryPacket()->cacheMatch(out->queryPacket()))
  2295. {
  2296. moveToHead(found);
  2297. return; // already in the cache. Because we don't cache until we have result, this can happen where
  2298. // multiple copies of a slave query are in-flight at once.
  2299. }
  2300. et++;
  2301. if (et == cacheTableSize)
  2302. et = 0;
  2303. }
  2304. }
  2305. // MORE - do we need to worry about the attachment between the MessageUnpacker and the current row manager. May all fall out ok...
  2306. // Can I easily spot a null result? Do I want to cache null results separately? only?
  2307. }
  2308. // Note that this caching mechanism (unlike the old keyed-join specific one) does not common up cases where multiple
  2309. // identical queries are in-flight at the same time. But if we can make it persistant between queries that will
  2310. // more than make up for it
  2311. };
  2312. class CRowArrayMessageUnpackCursor : public CInterface, implements IMessageUnpackCursor
  2313. {
  2314. ConstPointerArray &data;
  2315. Linked<IMessageResult> result;
  2316. public:
  2317. IMPLEMENT_IINTERFACE;
  2318. CRowArrayMessageUnpackCursor(ConstPointerArray &_data, IMessageResult *_result)
  2319. : data(_data), result(_result)
  2320. {
  2321. }
  2322. virtual bool atEOF() const
  2323. {
  2324. return data.length()==0;
  2325. }
  2326. virtual bool isSerialized() const
  2327. {
  2328. return false;
  2329. }
  2330. virtual const void * getNext(int length)
  2331. {
  2332. if (!data.length())
  2333. return NULL;
  2334. const void *ret = data.item(0);
  2335. data.remove(0);
  2336. return ret;
  2337. }
  2338. };
  2339. // MORE - should possibly move more over to the lazy version used in indexread?
  2340. class CRowArrayMessageResult : public CInterface, implements IMessageResult
  2341. {
  2342. ConstPointerArray data;
  2343. IRowManager &rowManager;
  2344. bool variableSize;
  2345. public:
  2346. IMPLEMENT_IINTERFACE;
  2347. CRowArrayMessageResult(IRowManager &_rowManager, bool _variableSize) : rowManager(_rowManager), variableSize(_variableSize)
  2348. {
  2349. }
  2350. ~CRowArrayMessageResult()
  2351. {
  2352. ReleaseRoxieRowSet(data);
  2353. }
  2354. virtual IMessageUnpackCursor *getCursor(IRowManager *rowMgr) const
  2355. {
  2356. CRowArrayMessageResult *_this = (CRowArrayMessageResult *) this;
  2357. return new CRowArrayMessageUnpackCursor(_this->data, _this);
  2358. }
  2359. virtual const void *getMessageHeader(unsigned &length) const
  2360. {
  2361. throwUnexpected(); // should never get called - I don't have a header available
  2362. length = 0;
  2363. return NULL;
  2364. }
  2365. virtual const void *getMessageMetadata(unsigned &length) const
  2366. {
  2367. length = 0;
  2368. return NULL;
  2369. }
  2370. virtual void discard() const
  2371. {
  2372. throwUnexpected();
  2373. }
  2374. void append(const void *row)
  2375. {
  2376. data.append(row);
  2377. }
  2378. };
  2379. void throwRemoteException(IMessageUnpackCursor *extra)
  2380. {
  2381. RecordLengthType *rowlen = (RecordLengthType *) extra->getNext(sizeof(RecordLengthType));
  2382. if (rowlen)
  2383. {
  2384. char *xml = (char *) extra->getNext(*rowlen);
  2385. ReleaseRoxieRow(rowlen);
  2386. Owned<IPropertyTree> p = createPTreeFromXMLString(xml);
  2387. ReleaseRoxieRow(xml);
  2388. unsigned code = p->getPropInt("Code", 0);
  2389. const char *msg = p->queryProp("Message");
  2390. if (!msg)
  2391. msg = xml;
  2392. throw MakeStringException(code, "%s", msg);
  2393. }
  2394. throwUnexpected();
  2395. }
  2396. class CRemoteResultAdaptor :public CInterface, implements IRoxieInput, implements IExceptionHandler
  2397. {
  2398. friend class CRemoteResultMerger;
  2399. class CRemoteResultMerger
  2400. {
  2401. class HeapEntry : public CInterface
  2402. {
  2403. private:
  2404. CRemoteResultAdaptor &adaptor;
  2405. IMessageUnpackCursor *cursor;
  2406. public:
  2407. const void *current;
  2408. bool isLast;
  2409. bool lastIsComplete;
  2410. IRoxieServerQueryPacket *packet;
  2411. unsigned seq;
  2412. public:
  2413. inline const void *noteResult(IMessageUnpackCursor *_cursor, bool _lastIsComplete)
  2414. {
  2415. cursor = _cursor;
  2416. lastIsComplete = _lastIsComplete;
  2417. return next();
  2418. }
  2419. public:
  2420. HeapEntry(CRemoteResultAdaptor &_adaptor, IRoxieServerQueryPacket *_packet, unsigned _seq) : adaptor(_adaptor), packet(_packet), seq(_seq)
  2421. {
  2422. cursor = NULL;
  2423. current = NULL;
  2424. isLast = false;
  2425. lastIsComplete = true;
  2426. }
  2427. ~HeapEntry()
  2428. {
  2429. ::Release(packet);
  2430. ::Release(cursor);
  2431. ReleaseRoxieRow(current);
  2432. }
  2433. bool isCompleteMatch() const
  2434. {
  2435. if (!isLast || lastIsComplete)
  2436. return true;
  2437. else
  2438. return false;
  2439. }
  2440. const void *next()
  2441. {
  2442. if (cursor)
  2443. {
  2444. ReleaseClearRoxieRow(current);
  2445. current = adaptor.getRow(cursor);
  2446. isLast = cursor->atEOF();
  2447. if (!current)
  2448. {
  2449. cursor->Release();
  2450. cursor = NULL;
  2451. }
  2452. }
  2453. return current;
  2454. }
  2455. unsigned skipTo(IRangeCompare *compare, const void *seek, unsigned numFields, bool requireExactMatch)
  2456. {
  2457. // MORE - This loop should possibly be a binchop... though it's not absolutely clear that is true (depends on term frequencies)
  2458. unsigned skipped = 0;
  2459. loop
  2460. {
  2461. int c = compare->docompare(current, seek, numFields);
  2462. //If larger than the seek values, then we may be allowed to return an inexact match,
  2463. //if equal then it is required to be an exact match,
  2464. if (c > 0)
  2465. {
  2466. if (!requireExactMatch || isCompleteMatch())
  2467. break;
  2468. }
  2469. else if ((c == 0) && isCompleteMatch())
  2470. break;
  2471. skipped++;
  2472. if (!next())
  2473. break;
  2474. }
  2475. return skipped;
  2476. }
  2477. };
  2478. CRemoteResultAdaptor &adaptor;
  2479. CIArrayOf<HeapEntry> heapEntries;
  2480. UnsignedArray heap;
  2481. IRowManager *rowManager;
  2482. unsigned numPending;
  2483. unsigned numFields;
  2484. bool endSeen;
  2485. bool remakePending;
  2486. IRangeCompare *compare;
  2487. bool deferredContinuation;
  2488. inline int doCompare(unsigned l, unsigned r)
  2489. {
  2490. int ret = compare->docompare(heapEntries.item(l).current, heapEntries.item(r).current, numFields);
  2491. if (!ret) ret = heapEntries.item(l).seq - heapEntries.item(r).seq;
  2492. return ret;
  2493. }
  2494. void makeHeap()
  2495. {
  2496. /* Permute blocks to establish the heap property
  2497. For each element p, the children are p*2+1 and p*2+2 (provided these are in range)
  2498. The children of p must both be greater than or equal to p
  2499. The parent of a child c is given by p = (c-1)/2
  2500. */
  2501. unsigned i;
  2502. unsigned n = heap.length();
  2503. unsigned *s = heap.getArray();
  2504. for (i=1; i<n; i++)
  2505. {
  2506. unsigned r = s[i];
  2507. int c = i; /* child */
  2508. while (c > 0)
  2509. {
  2510. int p = (c-1)/2; /* parent */
  2511. if ( doCompare( s[c], s[p] ) >= 0 )
  2512. break;
  2513. s[c] = s[p];
  2514. s[p] = r;
  2515. c = p;
  2516. }
  2517. }
  2518. remakePending = false;
  2519. }
  2520. void remakeHeap()
  2521. {
  2522. /* The row associated with block[0] will have changed
  2523. This code restores the heap property
  2524. */
  2525. unsigned p = 0; /* parent */
  2526. unsigned n = heap.length();
  2527. unsigned *s = heap.getArray();
  2528. while (1)
  2529. {
  2530. unsigned c = p*2 + 1; /* child */
  2531. if ( c >= n )
  2532. break;
  2533. /* Select smaller child */
  2534. if ( c+1 < n && doCompare( s[c+1], s[c] ) < 0 ) c += 1;
  2535. /* If child is greater or equal than parent then we are done */
  2536. if ( doCompare( s[c], s[p] ) >= 0 )
  2537. break;
  2538. /* Swap parent and child */
  2539. unsigned r = s[c];
  2540. s[c] = s[p];
  2541. s[p] = r;
  2542. /* child becomes parent */
  2543. p = c;
  2544. }
  2545. remakePending = false;
  2546. }
  2547. void append(IRoxieServerQueryPacket *p, unsigned seq)
  2548. {
  2549. HeapEntry &h = *new HeapEntry(adaptor, LINK(p), seq);
  2550. IMessageResult *result = p->queryResult();
  2551. assertex(result);
  2552. if (h.noteResult(result->getCursor(rowManager), isCompleteMatchFlag(result)))
  2553. {
  2554. heapEntries.append(h);
  2555. heap.append(heap.ordinality());
  2556. }
  2557. else
  2558. h.Release();
  2559. }
  2560. void removeHeap(unsigned idx)
  2561. {
  2562. heapEntries.remove(idx);
  2563. ForEachItemIn(i, heap)
  2564. {
  2565. unsigned v = heap.item(i);
  2566. assertex(v != idx);
  2567. if (v > idx)
  2568. heap.replace(v-1, i);
  2569. }
  2570. }
  2571. bool isCompleteMatchFlag(IMessageResult *result)
  2572. {
  2573. unsigned metaLen;
  2574. const byte *metaInfo = (const byte *) result->getMessageMetadata(metaLen);
  2575. if (metaLen)
  2576. {
  2577. unsigned short continuationLen = *(unsigned short *) metaInfo;
  2578. if (continuationLen >= sizeof(bool))
  2579. {
  2580. metaInfo += sizeof(unsigned short);
  2581. return *(bool *) metaInfo;
  2582. }
  2583. }
  2584. return true; // if no continuation info, last row was complete.
  2585. }
  2586. public:
  2587. CRemoteResultMerger(CRemoteResultAdaptor &_adaptor) : adaptor(_adaptor)
  2588. {
  2589. init(NULL, NULL);
  2590. }
  2591. void init(ISteppingMeta *meta, IRowManager *_rowManager)
  2592. {
  2593. if (meta)
  2594. {
  2595. numFields = meta->getNumFields();
  2596. compare = meta->queryCompare();
  2597. }
  2598. else
  2599. {
  2600. numFields = 0;
  2601. compare = NULL;
  2602. }
  2603. rowManager = _rowManager;
  2604. numPending = 0;
  2605. endSeen = false;
  2606. remakePending = false;
  2607. deferredContinuation = false;
  2608. }
  2609. void reset()
  2610. {
  2611. heapEntries.kill();
  2612. heap.kill();
  2613. numPending = 0;
  2614. endSeen = false;
  2615. remakePending = false;
  2616. deferredContinuation = false;
  2617. }
  2618. inline bool noteEndSeen()
  2619. {
  2620. bool hadSeen = endSeen;
  2621. if (!endSeen)
  2622. makeHeap();
  2623. endSeen = true;
  2624. return !hadSeen;
  2625. }
  2626. void noteResult(IRoxieServerQueryPacket *p, unsigned seq)
  2627. {
  2628. if (!p->isContinuation())
  2629. append(p, seq);
  2630. else
  2631. {
  2632. ForEachItemIn(idx, heapEntries)
  2633. {
  2634. HeapEntry &h = heapEntries.item(idx);
  2635. if (h.packet == p)
  2636. {
  2637. IMessageResult *result = p->queryResult();
  2638. if (!h.noteResult(result->getCursor(rowManager), isCompleteMatchFlag(result)))
  2639. {
  2640. heap.zap(idx);
  2641. removeHeap(idx);
  2642. }
  2643. numPending--;
  2644. if (!numPending)
  2645. makeHeap();
  2646. return;
  2647. }
  2648. }
  2649. }
  2650. // If we get here it must be a continuation for one that I have not yet consumed... we don't need to do anything.
  2651. return;
  2652. }
  2653. unsigned skipRows(unsigned &idx, const void *seek, const void *rawSeek, unsigned numFields, unsigned seekLen, const SmartStepExtra & stepExtra)
  2654. {
  2655. HeapEntry &entry = heapEntries.item(idx);
  2656. unsigned skipped = entry.current ? entry.skipTo(compare, seek, numFields, !stepExtra.returnMismatches()) : 0;
  2657. if (!entry.current)
  2658. {
  2659. IRoxieServerQueryPacket *continuation = entry.packet->queryContinuation();
  2660. if (continuation)
  2661. {
  2662. continuation->Link();
  2663. entry.packet->Release();
  2664. entry.packet = continuation;
  2665. if (continuation->hasResult())
  2666. {
  2667. IMessageResult *result = continuation->queryResult();
  2668. bool lastIsCompleteMatch = isCompleteMatchFlag(result);
  2669. entry.noteResult(result->getCursor(rowManager), lastIsCompleteMatch);
  2670. }
  2671. else
  2672. {
  2673. if (continuation->isDelayed())
  2674. {
  2675. continuation->setDelayed(false);
  2676. MemoryBuffer serializedSkip;
  2677. adaptor.activity.serializeSkipInfo(serializedSkip, seekLen, rawSeek, numFields, seek, stepExtra);
  2678. continuation->setPacket(continuation->queryPacket()->insertSkipData(serializedSkip.length(), serializedSkip.toByteArray()));
  2679. ROQ->sendPacket(continuation->queryPacket(), adaptor.activity.queryLogCtx());
  2680. adaptor.sentsome.signal();
  2681. }
  2682. numPending++;
  2683. }
  2684. }
  2685. else
  2686. {
  2687. heap.zap(idx);
  2688. removeHeap(idx);
  2689. idx--;
  2690. }
  2691. }
  2692. return skipped;
  2693. }
  2694. const void * nextSteppedGE(const void * seek, const void *rawSeek, unsigned numFields, unsigned seeklen, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  2695. {
  2696. // We discard all rows < seekval from all entries in heap
  2697. // If this results in additional slave requests, we return NULL so that we can wait for them
  2698. // If not, we rebuild the heap (if any were skipped) and return the first row
  2699. deferredContinuation = false;
  2700. if (heap.length())
  2701. {
  2702. unsigned skipped = 0;
  2703. unsigned idx = 0;
  2704. while(heapEntries.isItem(idx))
  2705. {
  2706. skipped += skipRows(idx, seek, rawSeek, numFields, seeklen, stepExtra);
  2707. idx++;
  2708. }
  2709. if (numPending)
  2710. return NULL; // can't answer yet, need more results from slaves
  2711. else
  2712. {
  2713. if (skipped)
  2714. makeHeap();
  2715. return next(wasCompleteMatch, stepExtra);
  2716. }
  2717. }
  2718. else
  2719. return NULL;
  2720. }
  2721. bool doContinuation(HeapEntry &topEntry, bool canDefer)
  2722. {
  2723. IRoxieServerQueryPacket *continuation = topEntry.packet->queryContinuation();
  2724. if (continuation)
  2725. {
  2726. if (continuation->isDelayed() && canDefer)
  2727. {
  2728. if (adaptor.activity.queryLogCtx().queryTraceLevel() > 10)
  2729. adaptor.activity.queryLogCtx().CTXLOG("Deferring continuation");
  2730. deferredContinuation = true;
  2731. }
  2732. else
  2733. {
  2734. deferredContinuation = false;
  2735. continuation->Link();
  2736. topEntry.packet->Release();
  2737. topEntry.packet = continuation;
  2738. if (continuation->hasResult())
  2739. {
  2740. IMessageResult *result = continuation->queryResult();
  2741. bool lastIsCompleteMatch = isCompleteMatchFlag(result);
  2742. topEntry.noteResult(result->getCursor(rowManager), lastIsCompleteMatch);
  2743. }
  2744. else
  2745. {
  2746. if (continuation->isDelayed()) // has the continuation been requested yet?
  2747. {
  2748. continuation->Link();
  2749. topEntry.packet->Release();
  2750. topEntry.packet = continuation;
  2751. continuation->setDelayed(false);
  2752. if (adaptor.activity.queryLogCtx().queryTraceLevel() > 10)
  2753. adaptor.activity.queryLogCtx().CTXLOG("About to send continuation, from doContinuation");
  2754. ROQ->sendPacket(continuation->queryPacket(), adaptor.activity.queryLogCtx());
  2755. adaptor.sentsome.signal();
  2756. }
  2757. numPending++; // we are waiting for one that is already in flight
  2758. }
  2759. }
  2760. return true; // next not known yet
  2761. }
  2762. else
  2763. return false;
  2764. }
  2765. const void *next(bool & wasCompleteMatch, const SmartStepExtra & stepExtra)
  2766. {
  2767. OwnedConstRoxieRow ret;
  2768. if (heap.length())
  2769. {
  2770. if (deferredContinuation)
  2771. {
  2772. unsigned top = heap.item(0);
  2773. HeapEntry &topEntry = heapEntries.item(top);
  2774. doContinuation(topEntry, false);
  2775. return NULL;
  2776. }
  2777. if (remakePending)
  2778. remakeHeap();
  2779. unsigned top = heap.item(0);
  2780. HeapEntry &topEntry = heapEntries.item(top);
  2781. ret.set(topEntry.current);
  2782. wasCompleteMatch = topEntry.isCompleteMatch();
  2783. const void *next = topEntry.next();
  2784. if (!next)
  2785. {
  2786. if (!doContinuation(topEntry, stepExtra.returnMismatches()))
  2787. {
  2788. unsigned last = heap.pop();
  2789. if (heap.length())
  2790. heap.replace(last, 0);
  2791. removeHeap(top);
  2792. }
  2793. }
  2794. remakePending = true;
  2795. }
  2796. return ret.getClear();
  2797. }
  2798. bool ready()
  2799. {
  2800. return endSeen && numPending == 0;
  2801. }
  2802. };
  2803. IRoxieServerQueryPacket *createRoxieServerQueryPacket(IRoxieQueryPacket *p, bool &cached)
  2804. {
  2805. if (serverSideCache && !debugContext)
  2806. {
  2807. IRoxieServerQueryPacket *ret = serverSideCache->findCachedResult(activity.queryLogCtx(), p);
  2808. if (ret)
  2809. {
  2810. p->Release();
  2811. cached = true;
  2812. return ret;
  2813. }
  2814. }
  2815. cached = false;
  2816. return new CRoxieServerQueryPacket(p);
  2817. }
  2818. #ifdef _DEBUG
  2819. void dumpPending()
  2820. {
  2821. CriticalBlock b(pendingCrit);
  2822. ForEachItemIn(idx, pending)
  2823. {
  2824. IRoxieServerQueryPacket &p = pending.item(idx);
  2825. StringBuffer s;
  2826. unsigned __int64 dummy;
  2827. if (p.isEnd())
  2828. s.append("END");
  2829. else if (p.isLimit(dummy, dummy, dummy))
  2830. s.append("LIMIT");
  2831. else
  2832. {
  2833. IRoxieQueryPacket *i = p.queryPacket();
  2834. s.appendf("%s", p.hasResult() ? "COMPLETE " : "PENDING ");
  2835. if (i)
  2836. {
  2837. RoxiePacketHeader &header = i->queryHeader();
  2838. header.toString(s);
  2839. }
  2840. }
  2841. DBGLOG("Pending %d %s", idx, s.str());
  2842. }
  2843. }
  2844. #endif
  2845. void abortPending()
  2846. {
  2847. CriticalBlock b(pendingCrit);
  2848. ForEachItemIn(idx, pending)
  2849. {
  2850. IRoxieServerQueryPacket &p = pending.item(idx);
  2851. if (!p.hasResult())
  2852. {
  2853. IRoxieQueryPacket *i = p.queryPacket();
  2854. if (i)
  2855. {
  2856. RoxiePacketHeader &header = i->queryHeader();
  2857. ROQ->sendAbort(header, activity.queryLogCtx());
  2858. }
  2859. }
  2860. }
  2861. pending.kill();
  2862. }
  2863. void checkDelayed()
  2864. {
  2865. if (ctx->queryDebugContext() && ctx->queryDebugContext()->getExecuteSequentially())
  2866. {
  2867. bool allDelayed = true;
  2868. CriticalBlock b(pendingCrit);
  2869. unsigned sendIdx = (unsigned) -1;
  2870. ForEachItemIn(idx, pending)
  2871. {
  2872. IRoxieServerQueryPacket &p = pending.item(idx);
  2873. if (p.queryPacket())
  2874. {
  2875. if (p.isDelayed())
  2876. {
  2877. if (sendIdx == (unsigned) -1)
  2878. sendIdx = idx;
  2879. }
  2880. else if (!p.hasResult())
  2881. {
  2882. allDelayed = false;
  2883. break;
  2884. }
  2885. }
  2886. }
  2887. if (allDelayed && sendIdx != (unsigned) -1)
  2888. {
  2889. if (activity.queryLogCtx().queryTraceLevel() > 10)
  2890. activity.queryLogCtx().CTXLOG("About to send debug-deferred from next");
  2891. pending.item(sendIdx).setDelayed(false);
  2892. ROQ->sendPacket(pending.item(sendIdx).queryPacket(), activity.queryLogCtx());
  2893. sentsome.signal();
  2894. }
  2895. }
  2896. else if (deferredStart)
  2897. {
  2898. CriticalBlock b(pendingCrit);
  2899. ForEachItemIn(idx, pending)
  2900. {
  2901. IRoxieServerQueryPacket &p = pending.item(idx);
  2902. if (p.isDelayed())
  2903. {
  2904. if (activity.queryLogCtx().queryTraceLevel() > 10)
  2905. activity.queryLogCtx().CTXLOG("About to send deferred start from next");
  2906. p.setDelayed(false);
  2907. ROQ->sendPacket(p.queryPacket(), activity.queryLogCtx());
  2908. sentsome.signal();
  2909. }
  2910. }
  2911. deferredStart = false;
  2912. }
  2913. }
  2914. void retryPending()
  2915. {
  2916. CriticalBlock b(pendingCrit);
  2917. checkDelayed();
  2918. ForEachItemIn(idx, pending)
  2919. {
  2920. IRoxieServerQueryPacket &p = pending.item(idx);
  2921. if (!p.hasResult() && !p.isDelayed())
  2922. {
  2923. IRoxieQueryPacket *i = p.queryPacket();
  2924. if (i)
  2925. {
  2926. if (!i->queryHeader().retry())
  2927. {
  2928. StringBuffer s;
  2929. IException *E = MakeStringException(ROXIE_MULTICAST_ERROR, "Failed to get response from slave(s) for %s in activity %d", i->queryHeader().toString(s).str(), queryId());
  2930. activity.queryLogCtx().logOperatorException(E, __FILE__, __LINE__, "CRemoteResultAdaptor::retry");
  2931. throw E;
  2932. }
  2933. if (!localSlave)
  2934. {
  2935. ROQ->sendPacket(i, activity.queryLogCtx());
  2936. atomic_inc(&retriesSent);
  2937. }
  2938. }
  2939. }
  2940. }
  2941. }
  2942. class ChannelBuffer
  2943. {
  2944. protected:
  2945. unsigned bufferLeft;
  2946. MemoryBuffer buffer;
  2947. char *nextBuf;
  2948. unsigned overflowSequence;
  2949. unsigned channel; // == bonded channel
  2950. bool needsFlush;
  2951. InterruptableSemaphore flowController;
  2952. const CRemoteResultAdaptor &owner;
  2953. CriticalSection crit;
  2954. public:
  2955. ChannelBuffer(const CRemoteResultAdaptor &_owner, unsigned _channel) : owner(_owner), channel(_channel), flowController(perChannelFlowLimit)
  2956. {
  2957. overflowSequence = 0;
  2958. needsFlush = false;
  2959. bufferLeft = 0;
  2960. nextBuf = NULL;
  2961. }
  2962. void init(unsigned minSize)
  2963. {
  2964. assertex(!buffer.length());
  2965. if (minSize < MIN_PAYLOAD_SIZE)
  2966. minSize = MIN_PAYLOAD_SIZE;
  2967. unsigned headerSize = sizeof(RoxiePacketHeader)+owner.headerLength();
  2968. unsigned bufferSize = headerSize+minSize;
  2969. if (bufferSize < mtu_size)
  2970. bufferSize = mtu_size;
  2971. buffer.reserveTruncate(bufferSize);
  2972. bufferLeft = bufferSize - headerSize;
  2973. assertex(buffer.toByteArray());
  2974. nextBuf = (char *) buffer.toByteArray() + headerSize;
  2975. needsFlush = false;
  2976. }
  2977. inline IRoxieQueryPacket *flush()
  2978. {
  2979. CriticalBlock cb(crit);
  2980. Owned<IRoxieQueryPacket> ret;
  2981. if (needsFlush)
  2982. {
  2983. buffer.setLength(nextBuf - buffer.toByteArray());
  2984. RoxiePacketHeader *h = (RoxiePacketHeader *) buffer.toByteArray();
  2985. h->init(owner.remoteId, owner.ruid, channel, overflowSequence);
  2986. //patch logPrefix, cachedContext and parent extract into the place reserved in the message buffer
  2987. byte * tgt = (byte*)(h+1);
  2988. owner.copyHeader(tgt, channel);
  2989. ret.setown(createRoxiePacket(buffer));
  2990. if (overflowSequence == OVERFLOWSEQUENCE_MAX)
  2991. overflowSequence = 1; // don't wrap to 0 - that is a bit special
  2992. else
  2993. overflowSequence++;
  2994. needsFlush = false;
  2995. bufferLeft = 0;
  2996. if (owner.flowControlled)
  2997. {
  2998. CriticalUnblock cub(crit);
  2999. while (!flowController.wait(1000))
  3000. {
  3001. StringBuffer s;
  3002. owner.activity.queryLogCtx().CTXLOG("Channel %d blocked by flow control: %s", channel, h->toString(s).str());
  3003. }
  3004. }
  3005. }
  3006. return ret.getClear();
  3007. }
  3008. inline void signal()
  3009. {
  3010. if (owner.flowControlled)
  3011. flowController.signal();
  3012. }
  3013. inline void interrupt(IException *e)
  3014. {
  3015. flowController.interrupt(e);
  3016. }
  3017. inline void *getBuffer(unsigned size)
  3018. {
  3019. CriticalBlock cb(crit);
  3020. if (bufferLeft >= size)
  3021. {
  3022. needsFlush = true;
  3023. void * ret = nextBuf;
  3024. nextBuf += size;
  3025. bufferLeft -= size;
  3026. return ret;
  3027. }
  3028. else if (!needsFlush)
  3029. {
  3030. init(size);
  3031. return getBuffer(size);
  3032. }
  3033. else if (owner.mergeOrder)
  3034. {
  3035. return buffer.reserve(size); // whole query needs to go as single packet if we are to merge
  3036. }
  3037. else
  3038. return NULL; // will force it to flush and start a new packet
  3039. }
  3040. };
  3041. private:
  3042. friend class CRemoteResultMerger;
  3043. bool allread;
  3044. bool contextCached;
  3045. bool preserveOrder;
  3046. InterruptableSemaphore sentsome;
  3047. Owned <IMessageCollator> mc;
  3048. Owned<IMessageUnpackCursor> mu;
  3049. Owned<IMessageResult> mr;
  3050. ChannelBuffer **buffers;
  3051. IHThorArg &helper;
  3052. unsigned __int64 stopAfter;
  3053. unsigned resendSequence;
  3054. IHThorArg *colocalArg;
  3055. IArrayOf<IRoxieServerQueryPacket> pending;
  3056. CriticalSection pendingCrit;
  3057. IRoxieServerSideCache *serverSideCache;
  3058. unsigned sentSequence;
  3059. Owned<IOutputRowDeserializer> deserializer;
  3060. Owned<IEngineRowAllocator> rowAllocator;
  3061. CRemoteResultMerger merger;
  3062. // this is only used to avoid recreating a bufferStream for each row. A better solution may be needed
  3063. MemoryBuffer tempRowBuffer;
  3064. Owned<ISerialStream> bufferStream;
  3065. CThorStreamDeserializerSource rowSource;
  3066. protected:
  3067. IRowManager *rowManager;
  3068. IRoxieInput *owner;
  3069. unsigned __int64 rowLimit;
  3070. unsigned __int64 keyedLimit;
  3071. IRoxieServerErrorHandler *errorHandler;
  3072. CachedOutputMetaData meta;
  3073. public:
  3074. ISteppingMeta *mergeOrder;
  3075. IRoxieSlaveContext *ctx;
  3076. IDebuggableContext *debugContext;
  3077. IRoxieServerActivity &activity;
  3078. unsigned parentExtractSize;
  3079. const byte * parentExtract;
  3080. bool flowControlled;
  3081. bool deferredStart;
  3082. MemoryBuffer logInfo;
  3083. MemoryBuffer cachedContext;
  3084. const RemoteActivityId &remoteId;
  3085. ruid_t ruid;
  3086. mutable CriticalSection buffersCrit;
  3087. unsigned processed;
  3088. unsigned __int64 totalCycles;
  3089. bool timeActivities;
  3090. //private: //vc6 doesn't like this being private yet accessed by nested class...
  3091. const void *getRow(IMessageUnpackCursor *mu)
  3092. {
  3093. if (!mu->isSerialized() || (meta.isFixedSize() && !deserializer))
  3094. return mu->getNext(meta.getFixedSize());
  3095. else
  3096. {
  3097. RecordLengthType *rowlen = (RecordLengthType *) mu->getNext(sizeof(RecordLengthType));
  3098. if (rowlen)
  3099. {
  3100. RecordLengthType len = *rowlen;
  3101. ReleaseRoxieRow(rowlen);
  3102. const void *slaveRec = mu->getNext(len);
  3103. if (deserializer && mu->isSerialized())
  3104. {
  3105. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  3106. tempRowBuffer.setBuffer(len, const_cast<void *>(slaveRec), false);
  3107. size_t outsize = deserializer->deserialize(rowBuilder, rowSource);
  3108. ReleaseRoxieRow(slaveRec);
  3109. return rowBuilder.finalizeRowClear(outsize);
  3110. }
  3111. else
  3112. return slaveRec;
  3113. }
  3114. else
  3115. return NULL;
  3116. }
  3117. }
  3118. private:
  3119. ChannelBuffer *queryChannelBuffer(unsigned channel, bool force=false)
  3120. {
  3121. CriticalBlock cb(buffersCrit);
  3122. ChannelBuffer *b = buffers[channel];
  3123. if (!b && force)
  3124. {
  3125. if (!contextCached)
  3126. {
  3127. logInfo.clear();
  3128. unsigned char loggingFlags = LOGGING_FLAGSPRESENT | LOGGING_TRACELEVELSET;
  3129. unsigned char ctxTraceLevel = activity.queryLogCtx().queryTraceLevel() + 1; // Avoid passing a 0
  3130. if (activity.queryLogCtx().isIntercepted())
  3131. loggingFlags |= LOGGING_INTERCEPTED;
  3132. if (ctx->queryTraceActivityTimes())
  3133. loggingFlags |= LOGGING_TIMEACTIVITIES;
  3134. if (activity.queryLogCtx().isBlind())
  3135. loggingFlags |= LOGGING_BLIND;
  3136. if (ctx->queryCheckingHeap())
  3137. loggingFlags |= LOGGING_CHECKINGHEAP;
  3138. if (ctx->queryWorkUnit())
  3139. loggingFlags |= LOGGING_WUID;
  3140. if (debugContext)
  3141. {
  3142. loggingFlags |= LOGGING_DEBUGGERACTIVE;
  3143. logInfo.append(loggingFlags).append(ctxTraceLevel);
  3144. MemoryBuffer bpInfo;
  3145. debugContext->serialize(bpInfo);
  3146. bpInfo.append((__uint64)(memsize_t) &activity);
  3147. logInfo.append((unsigned short) bpInfo.length());
  3148. logInfo.append(bpInfo.length(), bpInfo.toByteArray());
  3149. }
  3150. else
  3151. logInfo.append(loggingFlags).append(ctxTraceLevel);
  3152. StringBuffer logPrefix;
  3153. activity.queryLogCtx().getLogPrefix(logPrefix);
  3154. logInfo.append(logPrefix);
  3155. activity.serializeCreateStartContext(cachedContext.clear());
  3156. activity.serializeExtra(cachedContext);
  3157. if (activity.queryVarFileInfo())
  3158. {
  3159. activity.queryVarFileInfo()->queryTimeStamp().serialize(cachedContext);
  3160. cachedContext.append(activity.queryVarFileInfo()->queryCheckSum());
  3161. }
  3162. contextCached = true;
  3163. }
  3164. b = buffers[channel] = new ChannelBuffer(*this, channel);
  3165. }
  3166. return b;
  3167. }
  3168. void processRow(const void *got)
  3169. {
  3170. processed++;
  3171. if (processed > rowLimit)
  3172. {
  3173. ReleaseRoxieRow(got);
  3174. errorHandler->onLimitExceeded(false); // NOTE - should throw exception
  3175. throwUnexpected();
  3176. }
  3177. else if (processed > keyedLimit)
  3178. {
  3179. ReleaseRoxieRow(got);
  3180. errorHandler->onLimitExceeded(true); // NOTE - should throw exception
  3181. throwUnexpected();
  3182. }
  3183. }
  3184. public:
  3185. IMPLEMENT_IINTERFACE;
  3186. CRemoteResultAdaptor(const RemoteActivityId &_remoteId, IOutputMetaData *_meta, IHThorArg &_helper, IRoxieServerActivity &_activity, bool _preserveOrder, bool _flowControlled)
  3187. : remoteId(_remoteId), meta(_meta), activity(_activity), helper(_helper), preserveOrder(_preserveOrder), flowControlled(_flowControlled), merger(*this)
  3188. {
  3189. rowLimit = (unsigned __int64) -1;
  3190. keyedLimit = (unsigned __int64) -1;
  3191. contextCached = false;
  3192. stopAfter = I64C(0x7FFFFFFFFFFFFFFF);
  3193. buffers = new ChannelBuffer*[numChannels+1];
  3194. memset(buffers, 0, (numChannels+1)*sizeof(ChannelBuffer *));
  3195. parentExtractSize = 0;
  3196. parentExtract = NULL;
  3197. owner = NULL;
  3198. mergeOrder = NULL;
  3199. deferredStart = false;
  3200. processed = 0;
  3201. totalCycles = 0;
  3202. sentSequence = 0;
  3203. resendSequence = 0;
  3204. serverSideCache = activity.queryServerSideCache();
  3205. bufferStream.setown(createMemoryBufferSerialStream(tempRowBuffer));
  3206. rowSource.setStream(bufferStream);
  3207. timeActivities = defaultTimeActivities;
  3208. }
  3209. ~CRemoteResultAdaptor()
  3210. {
  3211. if (mc)
  3212. {
  3213. ROQ->queryReceiveManager()->detachCollator(mc);
  3214. mc.clear();
  3215. }
  3216. for (unsigned channel = 0; channel <= numChannels; channel++)
  3217. {
  3218. delete(buffers[channel]);
  3219. }
  3220. delete [] buffers;
  3221. }
  3222. void setMeta(IOutputMetaData *newmeta)
  3223. {
  3224. meta.set(newmeta);
  3225. }
  3226. virtual IRoxieServerActivity *queryActivity()
  3227. {
  3228. return &activity;
  3229. }
  3230. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  3231. {
  3232. return NULL;
  3233. }
  3234. void setMergeInfo(ISteppingMeta *_mergeOrder)
  3235. {
  3236. mergeOrder = _mergeOrder;
  3237. deferredStart = true;
  3238. }
  3239. void send(IRoxieQueryPacket *p)
  3240. {
  3241. if (p)
  3242. {
  3243. Linked<IRoxieQueryPacket> saver(p); // avoids a race with abortPending, without keeping pendingCrit locked over the send which we might prefer not to
  3244. assertex(p->queryHeader().uid==ruid);
  3245. // MORE: Maybe we should base the fastlane flag on some other
  3246. // criteria !! (i.e A Roxie server prediction based on the
  3247. // activity type/activity behaviour/expected reply size .. etc).
  3248. //
  3249. // Currently (code below) based on high priority, seq=0, and none-child activity.
  3250. // But this could still cause too many reply packets on the fatlane
  3251. // (higher priority output Q), which may cause the activities on the
  3252. // low priority output Q to not get service on time.
  3253. if ((colocalArg == 0) && // not a child query activity??
  3254. (p->queryHeader().activityId & (ROXIE_SLA_PRIORITY | ROXIE_HIGH_PRIORITY)) &&
  3255. (p->queryHeader().overflowSequence == 0) &&
  3256. (p->queryHeader().continueSequence & ~CONTINUE_SEQUENCE_SKIPTO)==0)
  3257. p->queryHeader().retries |= ROXIE_FASTLANE;
  3258. if (p->queryHeader().channel)
  3259. {
  3260. bool cached = false;
  3261. IRoxieServerQueryPacket *rsqp = createRoxieServerQueryPacket(p, cached);
  3262. if (deferredStart)
  3263. rsqp->setDelayed(true);
  3264. rsqp->setSequence(sentSequence++);
  3265. {
  3266. CriticalBlock b(pendingCrit);
  3267. pending.append(*rsqp);
  3268. }
  3269. if (!deferredStart)
  3270. {
  3271. if (!cached)
  3272. ROQ->sendPacket(p, activity.queryLogCtx());
  3273. sentsome.signal();
  3274. }
  3275. }
  3276. else
  3277. {
  3278. // 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
  3279. // Need to add first, then send
  3280. unsigned i;
  3281. bool allCached = true;
  3282. for (i = 1; i <= numChannels; i++)
  3283. {
  3284. IRoxieQueryPacket *q = p->clonePacket(i);
  3285. bool thisChannelCached;
  3286. IRoxieServerQueryPacket *rsqp = createRoxieServerQueryPacket(q, thisChannelCached);
  3287. if (!thisChannelCached)
  3288. allCached = false;
  3289. rsqp->setSequence(sentSequence++);
  3290. if (deferredStart)
  3291. {
  3292. rsqp->setDelayed(true);
  3293. }
  3294. {
  3295. CriticalBlock b(pendingCrit);
  3296. pending.append(*rsqp);
  3297. }
  3298. if (!deferredStart)
  3299. sentsome.signal();
  3300. }
  3301. if (!allCached && !deferredStart)
  3302. ROQ->sendPacket(p, activity.queryLogCtx());
  3303. buffers[0]->signal(); // since replies won't come back on that channel...
  3304. p->Release();
  3305. }
  3306. }
  3307. }
  3308. void *getMem(unsigned partNo, unsigned fileNo, unsigned size)
  3309. {
  3310. unsigned channel = partNo ? getBondedChannel(partNo) : 0;
  3311. size += sizeof(PartNoType);
  3312. ChannelBuffer *b = queryChannelBuffer(channel, true);
  3313. char *buffer = (char *) b->getBuffer(size);
  3314. if (!buffer)
  3315. {
  3316. send(b->flush());
  3317. buffer = (char *) b->getBuffer(size);
  3318. }
  3319. PartNoType sp;
  3320. sp.partNo = partNo;
  3321. sp.fileNo = fileNo;
  3322. memcpy(buffer, &sp, sizeof(sp));
  3323. buffer += sizeof(sp);
  3324. return buffer;
  3325. }
  3326. void injectResult(IMessageResult *result)
  3327. {
  3328. IRoxieServerQueryPacket *f = new CRoxieServerQueryPacket(NULL);
  3329. f->setSequence(sentSequence++);
  3330. f->setResult(result);
  3331. CriticalBlock b(pendingCrit);
  3332. pending.append(*f);
  3333. sentsome.signal(); // MORE - arguably should only send if there is any point waking up the listener thread, to save context swicth
  3334. }
  3335. void flush()
  3336. {
  3337. for (unsigned channel = 0; channel <= numChannels; channel++)
  3338. {
  3339. ChannelBuffer *b = queryChannelBuffer(channel, false);
  3340. if (b)
  3341. send(b->flush());
  3342. }
  3343. }
  3344. void interruptBuffers(IException *e)
  3345. {
  3346. for (unsigned channel = 0; channel <= numChannels; channel++)
  3347. {
  3348. ChannelBuffer *b = queryChannelBuffer(channel, false);
  3349. if (b)
  3350. b->interrupt(LINK(e));
  3351. }
  3352. }
  3353. void senddone()
  3354. {
  3355. CriticalBlock b(pendingCrit);
  3356. pending.append(*new CRoxieServerQueryPacketEndMarker);
  3357. sentsome.signal();
  3358. }
  3359. bool fireException(IException *e)
  3360. {
  3361. {
  3362. CriticalBlock b(pendingCrit);
  3363. pending.append(*new CRoxieServerQueryPacketEndMarker);
  3364. }
  3365. interruptBuffers(e);
  3366. if (mc)
  3367. mc->interrupt(LINK(e));
  3368. sentsome.interrupt(e);
  3369. return true;
  3370. }
  3371. virtual void onCreate(IRoxieInput *_owner, IRoxieServerErrorHandler *_errorHandler, IRoxieSlaveContext *_ctx, IHThorArg *_colocalArg)
  3372. {
  3373. owner = _owner;
  3374. errorHandler = _errorHandler;
  3375. ctx = _ctx;
  3376. debugContext = ctx->queryDebugContext();
  3377. colocalArg = _colocalArg;
  3378. if (meta.needsSerializeDisk())
  3379. {
  3380. deserializer.setown(meta.createDiskDeserializer(_ctx->queryCodeContext(), activity.queryId()));
  3381. rowAllocator.setown(ctx->queryCodeContext()->getRowAllocator(meta.queryOriginal(), activity.queryId()));
  3382. }
  3383. if (ctx->queryDebugContext() && ctx->queryDebugContext()->getExecuteSequentially())
  3384. deferredStart = true;
  3385. if (ctx)
  3386. timeActivities = ctx->queryTimeActivities();
  3387. }
  3388. virtual unsigned queryId() const
  3389. {
  3390. return owner->queryId();
  3391. }
  3392. virtual void onStart(unsigned _parentExtractSize, const byte * _parentExtract)
  3393. {
  3394. #ifdef TRACE_STARTSTOP
  3395. if (traceStartStop)
  3396. activity.queryLogCtx().CTXLOG("RRAonstart");
  3397. #endif
  3398. sentsome.reinit();
  3399. ruid = getNextRuid();
  3400. rowManager = &ctx->queryRowManager();
  3401. if (mergeOrder)
  3402. merger.init(mergeOrder, rowManager);
  3403. if (mc)
  3404. {
  3405. ROQ->queryReceiveManager()->detachCollator(mc); // Should never happen - implies someone forgot to call onReset!
  3406. }
  3407. mc.setown(ROQ->queryReceiveManager()->createMessageCollator(rowManager, ruid));
  3408. allread = false;
  3409. mu.clear();
  3410. contextCached = false;
  3411. processed = 0;
  3412. totalCycles = 0;
  3413. resendSequence = 0;
  3414. sentSequence = 0;
  3415. for (unsigned channel = 0; channel <= numChannels; channel++)
  3416. {
  3417. delete(buffers[channel]);
  3418. buffers[channel] = NULL;
  3419. }
  3420. flush();
  3421. parentExtractSize = _parentExtractSize;
  3422. parentExtract = _parentExtract;
  3423. }
  3424. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  3425. {
  3426. #ifdef TRACE_STARTSTOP
  3427. if (traceStartStop)
  3428. activity.queryLogCtx().CTXLOG("RRAstart");
  3429. #endif
  3430. owner->start(parentExtractSize, parentExtract, paused);
  3431. totalCycles = 0;
  3432. }
  3433. void checkAbort()
  3434. {
  3435. owner->checkAbort();
  3436. }
  3437. void setLimits(unsigned __int64 _rowLimit, unsigned __int64 _keyedLimit, unsigned __int64 _stopAfter)
  3438. {
  3439. if (ctx->queryProbeManager())
  3440. {
  3441. if (_rowLimit != (unsigned __int64) -1) ctx->queryProbeManager()->setNodePropertyInt(&activity, "rowLimit", _rowLimit);
  3442. if (_keyedLimit != (unsigned __int64) -1) ctx->queryProbeManager()->setNodePropertyInt(&activity, "keyedLimit", _keyedLimit);
  3443. if (_stopAfter != I64C(0x7FFFFFFFFFFFFFFF)) ctx->queryProbeManager()->setNodePropertyInt(&activity, "choosenLimit", _stopAfter);
  3444. }
  3445. {
  3446. CriticalBlock b(pendingCrit);
  3447. if (pending.length())
  3448. {
  3449. #ifdef _DEBUG
  3450. dumpPending(); // MORE - only defined in debug build - could have put the ifdef inside the dumpPending method
  3451. #endif
  3452. assertex(pending.length()==0);
  3453. }
  3454. pending.append(*new CRoxieServerQueryPacketLimitMarker(_rowLimit, _keyedLimit, _stopAfter));
  3455. }
  3456. sentsome.signal();
  3457. rowLimit = _rowLimit;
  3458. keyedLimit = _keyedLimit;
  3459. stopAfter = _stopAfter;
  3460. }
  3461. virtual void stop(bool aborting)
  3462. {
  3463. #ifdef TRACE_STARTSTOP
  3464. if (traceStartStop)
  3465. activity.queryLogCtx().CTXLOG("RRAstop");
  3466. #endif
  3467. onStop(aborting);
  3468. owner->stop(aborting);
  3469. }
  3470. void onStop(bool aborting)
  3471. {
  3472. #ifdef TRACE_STARTSTOP
  3473. if (traceStartStop)
  3474. activity.queryLogCtx().CTXLOG("RRAonstop");
  3475. #endif
  3476. abortPending();
  3477. interruptBuffers(NULL);
  3478. sentsome.interrupt();
  3479. if (mc) // May not be set if start() chain threw exception
  3480. mc->interrupt();
  3481. }
  3482. virtual void reset()
  3483. {
  3484. #ifdef TRACE_STARTSTOP
  3485. if (traceStartStop)
  3486. activity.queryLogCtx().CTXLOG("RRAreset");
  3487. #endif
  3488. owner->reset();
  3489. onReset();
  3490. }
  3491. virtual void resetEOF()
  3492. {
  3493. throwUnexpected();
  3494. }
  3495. virtual void onReset()
  3496. {
  3497. #ifdef TRACE_STARTSTOP
  3498. if (traceStartStop)
  3499. activity.queryLogCtx().CTXLOG("RRAonreset");
  3500. #endif
  3501. if (mc)
  3502. ROQ->queryReceiveManager()->detachCollator(mc);
  3503. merger.reset();
  3504. pending.kill();
  3505. if (mc && ctx)
  3506. ctx->addSlavesReplyLen(mc->queryBytesReceived());
  3507. mc.clear(); // Or we won't free memory for graphs that get recreated
  3508. mu.clear(); //ditto
  3509. deferredStart = false;
  3510. // NOTE: do NOT clear mergeOrder - this is set at create time not per child query
  3511. }
  3512. virtual IOutputMetaData * queryOutputMeta() const
  3513. {
  3514. return helper.queryOutputMeta();
  3515. }
  3516. virtual unsigned __int64 queryTotalCycles() const
  3517. {
  3518. return totalCycles;
  3519. }
  3520. virtual unsigned __int64 queryLocalCycles() const
  3521. {
  3522. return owner->queryLocalCycles();
  3523. }
  3524. virtual IRoxieInput *queryInput(unsigned idx) const
  3525. {
  3526. return owner->queryInput(idx);
  3527. }
  3528. const void * nextSteppedGE(const void *seek, const void *rawSeek, unsigned numFields, unsigned seekLen, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  3529. {
  3530. if (activity.queryLogCtx().queryTraceLevel() > 20)
  3531. {
  3532. StringBuffer recstr;
  3533. unsigned i;
  3534. for (i = 0; i < seekLen; i++)
  3535. {
  3536. recstr.appendf("%02x ", ((unsigned char *) rawSeek)[i]);
  3537. }
  3538. activity.queryLogCtx().CTXLOG("CRemoteResultAdaptor::nextSteppedGE(rawSeek=%s numFields=%d, seeklen=%d, returnMismatches=%d)", recstr.str(), numFields, seekLen, stepExtra.returnMismatches());
  3539. }
  3540. assertex(mergeOrder);
  3541. if (deferredStart)
  3542. {
  3543. CriticalBlock b(pendingCrit);
  3544. ForEachItemIn(idx, pending)
  3545. {
  3546. IRoxieServerQueryPacket &p = pending.item(idx);
  3547. if (p.isDelayed())
  3548. {
  3549. p.setDelayed(false);
  3550. if (activity.queryLogCtx().queryTraceLevel() > 10)
  3551. activity.queryLogCtx().CTXLOG("About to send deferred start from nextSteppedGE, setting requireExact to %d", !stepExtra.returnMismatches());
  3552. MemoryBuffer serializedSkip;
  3553. activity.serializeSkipInfo(serializedSkip, seekLen, rawSeek, numFields, seek, stepExtra);
  3554. p.setPacket(p.queryPacket()->insertSkipData(serializedSkip.length(), serializedSkip.toByteArray()));
  3555. ROQ->sendPacket(p.queryPacket(), activity.queryLogCtx());
  3556. sentsome.signal();
  3557. }
  3558. }
  3559. deferredStart = false;
  3560. }
  3561. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  3562. if (processed==stopAfter)
  3563. return NULL;
  3564. if (allread)
  3565. return NULL;
  3566. loop
  3567. {
  3568. if (merger.ready())
  3569. {
  3570. const void *got = merger.nextSteppedGE(seek, rawSeek, numFields, seekLen, wasCompleteMatch, stepExtra);
  3571. if (got)
  3572. {
  3573. processRow(got);
  3574. return got;
  3575. }
  3576. }
  3577. if (!reload()) // MORE - should pass the seek info here...
  3578. return NULL;
  3579. }
  3580. }
  3581. virtual const void *nextInGroup()
  3582. {
  3583. // If we are merging then we need to do a heapsort on all
  3584. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  3585. if (activity.queryLogCtx().queryTraceLevel() > 10)
  3586. {
  3587. activity.queryLogCtx().CTXLOG("CRemoteResultAdaptor::nextInGroup()");
  3588. }
  3589. loop
  3590. {
  3591. checkDelayed();
  3592. if (processed==stopAfter)
  3593. return NULL;
  3594. if (allread)
  3595. return NULL;
  3596. // If we can still consume from the merger or the most recently retrieved mu, do so.
  3597. const void *got = NULL;
  3598. if (mergeOrder && merger.ready())
  3599. {
  3600. bool matched = true;
  3601. got = merger.next(matched, dummySmartStepExtra);
  3602. }
  3603. else if (mu)
  3604. got = getRow(mu);
  3605. if (got)
  3606. {
  3607. processRow(got);
  3608. return got;
  3609. }
  3610. if (!reload())
  3611. return NULL;
  3612. }
  3613. }
  3614. bool reload()
  3615. {
  3616. // Wait for something to be returned from a slave....
  3617. mu.clear();
  3618. sentsome.wait();
  3619. // must be at least an endMarker on the queue since sentsome was signalled
  3620. {
  3621. CriticalBlock b(pendingCrit);
  3622. IRoxieServerQueryPacket &top = pending.item(0);
  3623. if (top.isLimit(rowLimit, keyedLimit, stopAfter)) // This is really a start marker...
  3624. {
  3625. pending.remove(0);
  3626. return true;
  3627. }
  3628. else if (top.isEnd())
  3629. {
  3630. pending.remove(0);
  3631. allread = true;
  3632. if (activity.queryLogCtx().queryTraceLevel() > 5)
  3633. activity.queryLogCtx().CTXLOG("All read on ruid %x", ruid);
  3634. return false;
  3635. }
  3636. else if (mergeOrder)
  3637. {
  3638. unsigned idx = 0;
  3639. bool added = false;
  3640. while (pending.isItem(idx))
  3641. {
  3642. IRoxieServerQueryPacket &item = pending.item(idx);
  3643. if (item.isEnd())
  3644. {
  3645. if (merger.noteEndSeen())
  3646. {
  3647. sentsome.signal(); // Because we waited, yet didn't actually consume anything
  3648. added = true;
  3649. }
  3650. break;
  3651. }
  3652. else if (item.hasResult())
  3653. {
  3654. merger.noteResult(&item, item.getSequence());
  3655. pending.remove(idx);
  3656. added = true;
  3657. }
  3658. else if (item.isContinuation())
  3659. idx++;
  3660. else
  3661. break;
  3662. }
  3663. if (added)
  3664. return true;
  3665. }
  3666. else if (top.hasResult())
  3667. {
  3668. mr.setown(pending.item(0).getResult());
  3669. mu.setown(mr->getCursor(rowManager));
  3670. pending.remove(0);
  3671. return true;
  3672. }
  3673. }
  3674. getNextUnpacker();
  3675. return true;
  3676. }
  3677. void getNextUnpacker()
  3678. {
  3679. mu.clear();
  3680. unsigned ctxTraceLevel = activity.queryLogCtx().queryTraceLevel();
  3681. loop
  3682. {
  3683. checkDelayed();
  3684. unsigned timeout = remoteId.isSLAPriority() ? slaTimeout : (remoteId.isHighPriority() ? highTimeout : lowTimeout);
  3685. owner->checkAbort();
  3686. bool anyActivity;
  3687. if (ctxTraceLevel > 5)
  3688. activity.queryLogCtx().CTXLOG("Calling getNextUnpacker(%d)", timeout);
  3689. mr.setown(mc->getNextResult(timeout, anyActivity));
  3690. if (ctxTraceLevel > 6)
  3691. activity.queryLogCtx().CTXLOG("Called getNextUnpacker(%d), activity=%d", timeout, anyActivity);
  3692. owner->checkAbort();
  3693. if (mr)
  3694. {
  3695. unsigned roxieHeaderLen;
  3696. const RoxiePacketHeader &header = *(const RoxiePacketHeader *) mr->getMessageHeader(roxieHeaderLen);
  3697. #ifdef _DEBUG
  3698. assertex(roxieHeaderLen == sizeof(RoxiePacketHeader));
  3699. #endif
  3700. if (ctxTraceLevel > 5)
  3701. {
  3702. StringBuffer s;
  3703. activity.queryLogCtx().CTXLOG("getNextUnpacker got packet %s", header.toString(s).str());
  3704. }
  3705. CriticalBlock b(pendingCrit);
  3706. unsigned idx = 0;
  3707. IRoxieServerQueryPacket *original = NULL;
  3708. IRoxieQueryPacket *op;
  3709. while (pending.isItem(idx))
  3710. {
  3711. original = &pending.item(idx);
  3712. op = original->queryPacket();
  3713. if (op && header.matchPacket(op->queryHeader()))
  3714. break;
  3715. original = NULL;
  3716. idx++;
  3717. }
  3718. if (!original || original->hasResult())
  3719. {
  3720. switch (header.activityId)
  3721. {
  3722. case ROXIE_FILECALLBACK:
  3723. {
  3724. // tell slave to abort
  3725. //if (ctxTraceLevel > 5)
  3726. {
  3727. StringBuffer s;
  3728. activity.queryLogCtx().CTXLOG("Redundant callback on query %s", header.toString(s).str());
  3729. }
  3730. Owned<IMessageUnpackCursor> callbackData = mr->getCursor(rowManager);
  3731. OwnedConstRoxieRow len = callbackData->getNext(sizeof(RecordLengthType));
  3732. if (len)
  3733. {
  3734. RecordLengthType *rowlen = (RecordLengthType *) len.get();
  3735. OwnedConstRoxieRow row = callbackData->getNext(*rowlen);
  3736. const char *rowdata = (const char *) row.get();
  3737. // bool isOpt = * (bool *) rowdata;
  3738. // bool isLocal = * (bool *) (rowdata+1);
  3739. ROQ->sendAbortCallback(header, rowdata+2, activity.queryLogCtx());
  3740. }
  3741. else
  3742. throwUnexpected();
  3743. break;
  3744. }
  3745. // MORE - ROXIE_ALIVE perhaps should go here too
  3746. case ROXIE_TRACEINFO:
  3747. {
  3748. Owned<IMessageUnpackCursor> extra = mr->getCursor(rowManager);
  3749. loop
  3750. {
  3751. RecordLengthType *rowlen = (RecordLengthType *) extra->getNext(sizeof(RecordLengthType));
  3752. if (rowlen)
  3753. {
  3754. char *logInfo = (char *) extra->getNext(*rowlen);
  3755. MemoryBuffer buf;
  3756. buf.setBuffer(*rowlen, logInfo, false);
  3757. activity.queryLogCtx().CTXLOGl(new LogItem(buf));
  3758. ReleaseRoxieRow(rowlen);
  3759. ReleaseRoxieRow(logInfo);
  3760. }
  3761. else
  3762. break;
  3763. }
  3764. break;
  3765. }
  3766. default:
  3767. if (ctxTraceLevel > 3)
  3768. activity.queryLogCtx().CTXLOG("Discarding packet %p - original %p is NULL or has result already", mr.get(), original);
  3769. mr->discard();
  3770. break;
  3771. }
  3772. mr.clear();
  3773. }
  3774. else
  3775. {
  3776. atomic_inc(&resultsReceived);
  3777. switch (header.activityId)
  3778. {
  3779. case ROXIE_DEBUGCALLBACK:
  3780. {
  3781. Owned<IMessageUnpackCursor> callbackData = mr->getCursor(rowManager);
  3782. OwnedConstRoxieRow len = callbackData->getNext(sizeof(RecordLengthType));
  3783. if (len)
  3784. {
  3785. RecordLengthType *rowlen = (RecordLengthType *) len.get();
  3786. OwnedConstRoxieRow row = callbackData->getNext(*rowlen);
  3787. char *rowdata = (char *) row.get();
  3788. if (ctxTraceLevel > 5)
  3789. {
  3790. StringBuffer s;
  3791. activity.queryLogCtx().CTXLOG("Callback on query %s for debug", header.toString(s).str());
  3792. }
  3793. MemoryBuffer slaveInfo;
  3794. slaveInfo.setBuffer(*rowlen, rowdata, false);
  3795. unsigned debugSequence;
  3796. slaveInfo.read(debugSequence);
  3797. Owned<IRoxieQueryPacket> reply = original->getDebugResponse(debugSequence);
  3798. if (!reply)
  3799. reply.setown(activity.queryContext()->queryDebugContext()->onDebugCallback(header, *rowlen, rowdata));
  3800. if (reply)
  3801. {
  3802. original->setDebugResponse(debugSequence, reply);
  3803. ROQ->sendPacket(reply, activity.queryLogCtx());
  3804. }
  3805. }
  3806. else
  3807. throwUnexpected();
  3808. // MORE - somehow we need to make sure slave gets a reply even if I'm not waiting (in udp layer)
  3809. // Leave original message on pending queue in original location - this is not a reply to it.
  3810. break;
  3811. }
  3812. case ROXIE_FILECALLBACK:
  3813. {
  3814. // we need to send back to the slave a message containing the file info requested.
  3815. Owned<IMessageUnpackCursor> callbackData = mr->getCursor(rowManager);
  3816. OwnedConstRoxieRow len = callbackData->getNext(sizeof(RecordLengthType));
  3817. if (len)
  3818. {
  3819. RecordLengthType *rowlen = (RecordLengthType *) len.get();
  3820. OwnedConstRoxieRow row = callbackData->getNext(*rowlen);
  3821. const char *rowdata = (const char *) row.get();
  3822. bool isOpt = * (bool *) rowdata;
  3823. bool isLocal = * (bool *) (rowdata+1);
  3824. const char *lfn = rowdata+2;
  3825. if (ctxTraceLevel > 5)
  3826. {
  3827. StringBuffer s;
  3828. activity.queryLogCtx().CTXLOG("Callback on query %s file %s", header.toString(s).str(),(const char *) lfn);
  3829. }
  3830. activity.queryContext()->onFileCallback(header, lfn, isOpt, isLocal);
  3831. }
  3832. else
  3833. throwUnexpected();
  3834. // MORE - somehow we need to make sure slave gets a reply even if I'm not waiting (in udp layer)
  3835. // Leave original message on pending queue in original location - this is not a reply to it.
  3836. break;
  3837. }
  3838. case ROXIE_KEYEDLIMIT_EXCEEDED:
  3839. activity.queryLogCtx().CTXLOG("ROXIE_KEYEDLIMIT_EXCEEDED");
  3840. errorHandler->onLimitExceeded(true); // NOTE - should throw exception!
  3841. throwUnexpected();
  3842. case ROXIE_LIMIT_EXCEEDED:
  3843. activity.queryLogCtx().CTXLOG("ROXIE_LIMIT_EXCEEDED");
  3844. errorHandler->onLimitExceeded(false); // NOTE - should throw exception!
  3845. throwUnexpected();
  3846. case ROXIE_TRACEINFO:
  3847. {
  3848. Owned<IMessageUnpackCursor> extra = mr->getCursor(rowManager);
  3849. loop
  3850. {
  3851. RecordLengthType *rowlen = (RecordLengthType *) extra->getNext(sizeof(RecordLengthType));
  3852. if (rowlen)
  3853. {
  3854. char *logInfo = (char *) extra->getNext(*rowlen);
  3855. MemoryBuffer buf;
  3856. buf.setBuffer(*rowlen, logInfo, false);
  3857. activity.queryLogCtx().CTXLOGl(new LogItem(buf));
  3858. ReleaseRoxieRow(rowlen);
  3859. ReleaseRoxieRow(logInfo);
  3860. }
  3861. else
  3862. break;
  3863. }
  3864. break;
  3865. }
  3866. case ROXIE_EXCEPTION:
  3867. if (ctxTraceLevel > 1)
  3868. {
  3869. StringBuffer s;
  3870. activity.queryLogCtx().CTXLOG("Exception on query %s", header.toString(s).str());
  3871. }
  3872. op->queryHeader().noteException(header.retries);
  3873. if (op->queryHeader().allChannelsFailed())
  3874. {
  3875. activity.queryLogCtx().CTXLOG("Multiple exceptions on query - aborting");
  3876. Owned<IMessageUnpackCursor> exceptionData = mr->getCursor(rowManager);
  3877. throwRemoteException(exceptionData);
  3878. }
  3879. // Leave it on pending queue in original location
  3880. break;
  3881. case ROXIE_ALIVE:
  3882. if (ctxTraceLevel > 4)
  3883. {
  3884. StringBuffer s;
  3885. activity.queryLogCtx().CTXLOG("ROXIE_ALIVE: %s", header.toString(s).str());
  3886. }
  3887. op->queryHeader().noteAlive(header.retries & ROXIE_RETRIES_MASK);
  3888. // Leave it on pending queue in original location
  3889. break;
  3890. default:
  3891. if (header.retries & ROXIE_RETRIES_MASK)
  3892. atomic_inc(&retriesNeeded);
  3893. unsigned metaLen;
  3894. const void *metaData = mr->getMessageMetadata(metaLen);
  3895. if (metaLen)
  3896. {
  3897. // We got back first chunk but there is more.
  3898. // resend the packet, with the cursor info provided.
  3899. // MORE - if smart-stepping, we don't want to send the continuation immediately. Other cases it's not clear that we do.
  3900. if (ctxTraceLevel > 1)
  3901. {
  3902. StringBuffer s;
  3903. activity.queryLogCtx().CTXLOG("Additional data size %d on query %s mergeOrder %p", metaLen, header.toString(s).str(), mergeOrder);
  3904. }
  3905. if (*((unsigned short *) metaData) + sizeof(unsigned short) != metaLen)
  3906. {
  3907. StringBuffer s;
  3908. activity.queryLogCtx().CTXLOG("Additional data size %d on query %s mergeOrder %p", metaLen, header.toString(s).str(), mergeOrder);
  3909. activity.queryLogCtx().CTXLOG("Additional data is corrupt");
  3910. throwUnexpected();
  3911. }
  3912. MemoryBuffer nextQuery;
  3913. nextQuery.append(sizeof(RoxiePacketHeader), &header);
  3914. nextQuery.append(metaLen, metaData);
  3915. nextQuery.append(op->getTraceLength(), op->queryTraceInfo());
  3916. nextQuery.append(op->getContextLength(), op->queryContextData());
  3917. if (resendSequence == CONTINUESEQUENCE_MAX)
  3918. {
  3919. activity.queryLogCtx().CTXLOG("ERROR: Continuation sequence wrapped"); // shouldn't actually matter.... but suggests a very iffy query!
  3920. resendSequence = 1;
  3921. }
  3922. else
  3923. resendSequence++;
  3924. RoxiePacketHeader *newHeader = (RoxiePacketHeader *) nextQuery.toByteArray();
  3925. newHeader->continueSequence = resendSequence; // NOTE - we clear the skipTo flag since continuation of a skip is NOT a skip...
  3926. newHeader->retries &= ~ROXIE_RETRIES_MASK;
  3927. IRoxieQueryPacket *resend = createRoxiePacket(nextQuery);
  3928. CRoxieServerQueryPacket *fqp = new CRoxieServerQueryPacket(resend);
  3929. fqp->setSequence(original->getSequence());
  3930. pending.add(*fqp, idx+1); // note that pending takes ownership. sendPacket does not release.
  3931. original->setContinuation(LINK(fqp));
  3932. if (mergeOrder)
  3933. fqp->setDelayed(true);
  3934. else
  3935. {
  3936. ROQ->sendPacket(resend, activity.queryLogCtx());
  3937. sentsome.signal();
  3938. }
  3939. // Note that we don't attempt to cache results that have continuation records - too tricky !
  3940. }
  3941. else
  3942. {
  3943. if (serverSideCache)
  3944. serverSideCache->noteCachedResult(original, mr);
  3945. }
  3946. unsigned channel = header.channel;
  3947. {
  3948. ChannelBuffer *b = queryChannelBuffer(channel); // If not something is wrong, or we sent out on channel 0?
  3949. if (b)
  3950. b->signal();
  3951. }
  3952. original->setResult(mr.getClear());
  3953. sentsome.signal();
  3954. return;
  3955. }
  3956. }
  3957. }
  3958. else
  3959. {
  3960. if (!anyActivity)
  3961. {
  3962. activity.queryLogCtx().CTXLOG("Input has stalled - retry required?");
  3963. retryPending();
  3964. }
  3965. }
  3966. }
  3967. }
  3968. inline unsigned headerLength() const
  3969. {
  3970. return logInfo.length() + cachedContext.length() + sizeof(unsigned) + parentExtractSize;
  3971. }
  3972. void copyHeader(byte *tgt, unsigned channel) const
  3973. {
  3974. unsigned len = logInfo.length();
  3975. memcpy(tgt, logInfo.toByteArray(), len);
  3976. tgt += len;
  3977. *(unsigned *) tgt = parentExtractSize;
  3978. tgt += sizeof(unsigned);
  3979. memcpy(tgt, parentExtract, parentExtractSize);
  3980. tgt += parentExtractSize;
  3981. memcpy(tgt, cachedContext.toByteArray(), cachedContext.length());
  3982. tgt += cachedContext.length();
  3983. }
  3984. };
  3985. class CSkippableRemoteResultAdaptor : public CRemoteResultAdaptor
  3986. {
  3987. Owned <IException> exception;
  3988. bool skipping;
  3989. ConstPointerArray buff;
  3990. unsigned index;
  3991. bool pulled;
  3992. void pullInput()
  3993. {
  3994. try
  3995. {
  3996. if (exception)
  3997. throw exception.getClear();
  3998. unsigned __int64 count = 0;
  3999. loop
  4000. {
  4001. const void * next = CRemoteResultAdaptor::nextInGroup();
  4002. if (next == NULL)
  4003. {
  4004. next = CRemoteResultAdaptor::nextInGroup();
  4005. if(next == NULL)
  4006. break;
  4007. buff.append(NULL);
  4008. }
  4009. count++;
  4010. if (count > rowLimit)
  4011. {
  4012. ReleaseRoxieRow(next);
  4013. ReleaseRoxieRowSet(buff);
  4014. errorHandler->onLimitExceeded(false); // throws an exception - user or LimitSkipException
  4015. throwUnexpected();
  4016. }
  4017. else if (count > keyedLimit)
  4018. {
  4019. ReleaseRoxieRow(next);
  4020. ReleaseRoxieRowSet(buff);
  4021. errorHandler->onLimitExceeded(true); // throws an exception - user or LimitSkipException
  4022. throwUnexpected();
  4023. }
  4024. buff.append(next);
  4025. }
  4026. }
  4027. catch (IException *E)
  4028. {
  4029. if (QUERYINTERFACE(E, LimitSkipException))
  4030. {
  4031. Owned<IException> cleanup = E;
  4032. ReleaseRoxieRowSet(buff);
  4033. const void *onfail = errorHandler->createLimitFailRow(E->errorCode() == KeyedLimitSkipErrorCode);
  4034. if (onfail)
  4035. buff.append(onfail);
  4036. }
  4037. else
  4038. throw;
  4039. }
  4040. pulled = true;
  4041. }
  4042. public:
  4043. CSkippableRemoteResultAdaptor(const RemoteActivityId &_remoteId, IOutputMetaData *_meta, IHThorArg &_helper, IRoxieServerActivity &_activity, bool _preserveOrder, bool _flowControlled, bool _skipping) :
  4044. CRemoteResultAdaptor(_remoteId, _meta, _helper, _activity, _preserveOrder, _flowControlled)
  4045. {
  4046. skipping = _skipping;
  4047. index = 0;
  4048. pulled = false;
  4049. }
  4050. void setException(IException *E)
  4051. {
  4052. exception.setown(E);
  4053. }
  4054. virtual void onReset()
  4055. {
  4056. while (buff.isItem(index))
  4057. ReleaseRoxieRow(buff.item(index++));
  4058. buff.kill();
  4059. pulled = false;
  4060. exception.clear();
  4061. CRemoteResultAdaptor::onReset();
  4062. }
  4063. void onStart(unsigned _parentExtractSize, const byte * _parentExtract)
  4064. {
  4065. index = 0;
  4066. pulled = false;
  4067. CRemoteResultAdaptor::onStart(_parentExtractSize, _parentExtract);
  4068. }
  4069. virtual const void * nextSteppedGE(const void *seek, const void *rawSeek, unsigned numFields, unsigned seeklen, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  4070. {
  4071. // 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
  4072. if (exception)
  4073. throw exception.getClear();
  4074. return CRemoteResultAdaptor::nextSteppedGE(seek, rawSeek, numFields, seeklen, wasCompleteMatch, stepExtra);
  4075. }
  4076. virtual const void *nextInGroup()
  4077. {
  4078. if (skipping)
  4079. {
  4080. if(!pulled)
  4081. pullInput();
  4082. if(buff.isItem(index))
  4083. {
  4084. const void * next = buff.item(index++);
  4085. if(next)
  4086. processed++;
  4087. return next;
  4088. }
  4089. return NULL;
  4090. }
  4091. else
  4092. {
  4093. if (exception)
  4094. throw exception.getClear();
  4095. return CRemoteResultAdaptor::nextInGroup();
  4096. }
  4097. }
  4098. };
  4099. //=================================================================================
  4100. class CRoxieServerApplyActivity : public CRoxieServerInternalSinkActivity
  4101. {
  4102. IHThorApplyArg &helper;
  4103. public:
  4104. CRoxieServerApplyActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4105. : CRoxieServerInternalSinkActivity(_factory, _probeManager, 0), helper((IHThorApplyArg &) basehelper)
  4106. {
  4107. }
  4108. virtual void onExecute()
  4109. {
  4110. helper.start();
  4111. loop
  4112. {
  4113. const void * next = input->nextInGroup();
  4114. if (!next)
  4115. {
  4116. next = input->nextInGroup();
  4117. if (!next)
  4118. break;
  4119. }
  4120. helper.apply(next);
  4121. ReleaseRoxieRow(next);
  4122. }
  4123. helper.end();
  4124. }
  4125. };
  4126. class CRoxieServerApplyActivityFactory : public CRoxieServerActivityFactory
  4127. {
  4128. bool isRoot;
  4129. public:
  4130. CRoxieServerApplyActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  4131. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
  4132. {
  4133. }
  4134. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  4135. {
  4136. return new CRoxieServerApplyActivity(this, _probeManager);
  4137. }
  4138. virtual bool isSink() const
  4139. {
  4140. return isRoot;
  4141. }
  4142. };
  4143. IRoxieServerActivityFactory *createRoxieServerApplyActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  4144. {
  4145. return new CRoxieServerApplyActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
  4146. }
  4147. //=================================================================================
  4148. class CRoxieServerNullActivity : public CRoxieServerActivity
  4149. {
  4150. public:
  4151. CRoxieServerNullActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4152. : CRoxieServerActivity(_factory, _probeManager)
  4153. {
  4154. }
  4155. virtual const void *nextInGroup()
  4156. {
  4157. return NULL;
  4158. }
  4159. };
  4160. IRoxieServerActivity * createRoxieServerNullActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4161. {
  4162. return new CRoxieServerNullActivity(_factory, _probeManager);
  4163. }
  4164. class CRoxieServerNullActivityFactory : public CRoxieServerActivityFactory
  4165. {
  4166. public:
  4167. CRoxieServerNullActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4168. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  4169. {
  4170. }
  4171. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  4172. {
  4173. return new CRoxieServerNullActivity(this, _probeManager);
  4174. }
  4175. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  4176. {
  4177. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for null activity");
  4178. }
  4179. };
  4180. IRoxieServerActivityFactory *createRoxieServerNullActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4181. {
  4182. return new CRoxieServerNullActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  4183. }
  4184. //=================================================================================
  4185. class CRoxieServerPassThroughActivity : public CRoxieServerActivity
  4186. {
  4187. public:
  4188. CRoxieServerPassThroughActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4189. : CRoxieServerActivity(_factory, _probeManager)
  4190. {
  4191. }
  4192. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  4193. {
  4194. return input->gatherConjunctions(collector);
  4195. }
  4196. virtual void resetEOF()
  4197. {
  4198. input->resetEOF();
  4199. }
  4200. virtual const void *nextInGroup()
  4201. {
  4202. const void * next = input->nextInGroup();
  4203. if (next)
  4204. processed++;
  4205. return next;
  4206. }
  4207. virtual bool isPassThrough()
  4208. {
  4209. return true;
  4210. }
  4211. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  4212. {
  4213. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  4214. const void * next = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  4215. if (next)
  4216. processed++;
  4217. return next;
  4218. }
  4219. IInputSteppingMeta * querySteppingMeta()
  4220. {
  4221. return input->querySteppingMeta();
  4222. }
  4223. };
  4224. IRoxieServerActivity * createRoxieServerPassThroughActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4225. {
  4226. return new CRoxieServerPassThroughActivity(_factory, _probeManager);
  4227. }
  4228. //=================================================================================
  4229. class CRoxieServerChildBaseActivity : public CRoxieServerActivity
  4230. {
  4231. protected:
  4232. bool eof;
  4233. bool first;
  4234. public:
  4235. CRoxieServerChildBaseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4236. : CRoxieServerActivity(_factory, _probeManager)
  4237. {
  4238. eof = false;
  4239. first = true;
  4240. }
  4241. ~CRoxieServerChildBaseActivity()
  4242. {
  4243. }
  4244. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  4245. {
  4246. eof = false;
  4247. first = true;
  4248. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  4249. }
  4250. };
  4251. class CRoxieServerChildBaseActivityFactory : public CRoxieServerActivityFactory
  4252. {
  4253. public:
  4254. CRoxieServerChildBaseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4255. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  4256. {
  4257. }
  4258. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  4259. {
  4260. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for %s activity", getActivityText(kind));
  4261. }
  4262. };
  4263. //=================================================================================
  4264. class CRoxieServerChildIteratorActivity : public CRoxieServerChildBaseActivity
  4265. {
  4266. IHThorChildIteratorArg &helper;
  4267. public:
  4268. CRoxieServerChildIteratorActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4269. : CRoxieServerChildBaseActivity(_factory, _probeManager), helper((IHThorChildIteratorArg &) basehelper)
  4270. {
  4271. }
  4272. virtual bool needsAllocator() const { return true; }
  4273. virtual const void *nextInGroup()
  4274. {
  4275. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  4276. if (eof)
  4277. return NULL;
  4278. bool ok;
  4279. if (first)
  4280. {
  4281. ok = helper.first();
  4282. first = false;
  4283. }
  4284. else
  4285. ok = helper.next();
  4286. try
  4287. {
  4288. while (ok)
  4289. {
  4290. processed++;
  4291. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  4292. unsigned outSize = helper.transform(rowBuilder);
  4293. if (outSize)
  4294. return rowBuilder.finalizeRowClear(outSize);
  4295. ok = helper.next();
  4296. }
  4297. }
  4298. catch (IException *E)
  4299. {
  4300. throw makeWrappedException(E);
  4301. }
  4302. eof = true;
  4303. return NULL;
  4304. }
  4305. };
  4306. class CRoxieServerChildIteratorActivityFactory : public CRoxieServerChildBaseActivityFactory
  4307. {
  4308. public:
  4309. CRoxieServerChildIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4310. : CRoxieServerChildBaseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  4311. {
  4312. }
  4313. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  4314. {
  4315. return new CRoxieServerChildIteratorActivity(this, _probeManager);
  4316. }
  4317. };
  4318. IRoxieServerActivityFactory *createRoxieServerChildIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4319. {
  4320. return new CRoxieServerChildIteratorActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  4321. }
  4322. //=================================================================================
  4323. class CRoxieServerChildNormalizeActivity : public CRoxieServerChildBaseActivity
  4324. {
  4325. IHThorChildNormalizeArg &helper;
  4326. public:
  4327. CRoxieServerChildNormalizeActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4328. : CRoxieServerChildBaseActivity(_factory, _probeManager), helper((IHThorChildNormalizeArg &) basehelper)
  4329. {
  4330. }
  4331. virtual bool needsAllocator() const { return true; }
  4332. virtual const void *nextInGroup()
  4333. {
  4334. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  4335. if (eof)
  4336. return NULL;
  4337. bool ok;
  4338. if (first)
  4339. {
  4340. ok = helper.first();
  4341. first = false;
  4342. }
  4343. else
  4344. ok = helper.next();
  4345. if (ok)
  4346. {
  4347. try
  4348. {
  4349. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  4350. do {
  4351. unsigned outSize = helper.transform(rowBuilder);
  4352. if (outSize)
  4353. {
  4354. processed++;
  4355. return rowBuilder.finalizeRowClear(outSize);
  4356. }
  4357. ok = helper.next();
  4358. }
  4359. while (ok);
  4360. }
  4361. catch (IException *E)
  4362. {
  4363. throw makeWrappedException(E);
  4364. }
  4365. }
  4366. eof = true;
  4367. return NULL;
  4368. }
  4369. };
  4370. class CRoxieServerChildNormalizeActivityFactory : public CRoxieServerChildBaseActivityFactory
  4371. {
  4372. public:
  4373. CRoxieServerChildNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4374. : CRoxieServerChildBaseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  4375. {
  4376. }
  4377. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  4378. {
  4379. return new CRoxieServerChildNormalizeActivity(this, _probeManager);
  4380. }
  4381. };
  4382. IRoxieServerActivityFactory *createRoxieServerNewChildNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4383. {
  4384. return new CRoxieServerChildNormalizeActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  4385. }
  4386. //=================================================================================
  4387. class CRoxieServerChildAggregateActivity : public CRoxieServerChildBaseActivity
  4388. {
  4389. IHThorChildAggregateArg &helper;
  4390. public:
  4391. CRoxieServerChildAggregateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4392. : CRoxieServerChildBaseActivity(_factory, _probeManager), helper((IHThorChildAggregateArg &) basehelper)
  4393. {
  4394. }
  4395. virtual bool needsAllocator() const { return true; }
  4396. virtual const void *nextInGroup()
  4397. {
  4398. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  4399. if (eof)
  4400. return NULL;
  4401. eof = true;
  4402. processed++;
  4403. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  4404. helper.clearAggregate(rowBuilder);
  4405. helper.processRows(rowBuilder);
  4406. size32_t finalSize = meta.getRecordSize(rowBuilder.getSelf());
  4407. return rowBuilder.finalizeRowClear(finalSize);
  4408. }
  4409. };
  4410. class CRoxieServerChildAggregateActivityFactory : public CRoxieServerChildBaseActivityFactory
  4411. {
  4412. public:
  4413. CRoxieServerChildAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4414. : CRoxieServerChildBaseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  4415. {
  4416. }
  4417. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  4418. {
  4419. return new CRoxieServerChildAggregateActivity(this, _probeManager);
  4420. }
  4421. };
  4422. IRoxieServerActivityFactory *createRoxieServerNewChildAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4423. {
  4424. return new CRoxieServerChildAggregateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  4425. }
  4426. //=================================================================================
  4427. class CRoxieServerChildGroupAggregateActivity : public CRoxieServerChildBaseActivity, public IHThorGroupAggregateCallback
  4428. {
  4429. IHThorChildGroupAggregateArg &helper;
  4430. RowAggregator aggregated;
  4431. public:
  4432. IMPLEMENT_IINTERFACE
  4433. CRoxieServerChildGroupAggregateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4434. : CRoxieServerChildBaseActivity(_factory, _probeManager), helper((IHThorChildGroupAggregateArg &) basehelper),
  4435. aggregated(helper, helper)
  4436. {
  4437. }
  4438. void processRow(const void * next)
  4439. {
  4440. aggregated.addRow(next);
  4441. }
  4442. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  4443. {
  4444. CRoxieServerChildBaseActivity::start(parentExtractSize, parentExtract, paused);
  4445. aggregated.start(rowAllocator);
  4446. }
  4447. virtual void reset()
  4448. {
  4449. aggregated.reset();
  4450. CRoxieServerChildBaseActivity::reset();
  4451. }
  4452. virtual bool needsAllocator() const { return true; }
  4453. virtual const void *nextInGroup()
  4454. {
  4455. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  4456. if (eof)
  4457. return NULL;
  4458. if (first)
  4459. {
  4460. helper.processRows(this);
  4461. first = false;
  4462. }
  4463. Owned<AggregateRowBuilder> next = aggregated.nextResult();
  4464. if (next)
  4465. {
  4466. processed++;
  4467. return next->finalizeRowClear();
  4468. }
  4469. eof = true;
  4470. return NULL;
  4471. }
  4472. };
  4473. class CRoxieServerChildGroupAggregateActivityFactory : public CRoxieServerChildBaseActivityFactory
  4474. {
  4475. public:
  4476. CRoxieServerChildGroupAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4477. : CRoxieServerChildBaseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  4478. {
  4479. }
  4480. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  4481. {
  4482. return new CRoxieServerChildGroupAggregateActivity(this, _probeManager);
  4483. }
  4484. };
  4485. IRoxieServerActivityFactory *createRoxieServerNewChildGroupAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4486. {
  4487. return new CRoxieServerChildGroupAggregateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  4488. }
  4489. //=================================================================================
  4490. class CRoxieServerChildThroughNormalizeActivity : public CRoxieServerChildBaseActivity
  4491. {
  4492. IHThorChildThroughNormalizeArg &helper;
  4493. const void * lastInput;
  4494. unsigned numProcessedLastGroup;
  4495. bool ok;
  4496. public:
  4497. CRoxieServerChildThroughNormalizeActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4498. : CRoxieServerChildBaseActivity(_factory, _probeManager), helper((IHThorChildThroughNormalizeArg &) basehelper)
  4499. {
  4500. lastInput = NULL;
  4501. numProcessedLastGroup = 0;
  4502. ok = false;
  4503. }
  4504. virtual void stop(bool aborting)
  4505. {
  4506. CRoxieServerChildBaseActivity::stop(aborting);
  4507. ReleaseRoxieRow(lastInput);
  4508. lastInput = NULL;
  4509. }
  4510. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  4511. {
  4512. CRoxieServerChildBaseActivity::start(parentExtractSize, parentExtract, paused);
  4513. numProcessedLastGroup = processed;
  4514. ok = false;
  4515. }
  4516. virtual bool needsAllocator() const { return true; }
  4517. virtual const void *nextInGroup()
  4518. {
  4519. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  4520. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  4521. loop
  4522. {
  4523. if (ok)
  4524. ok = helper.next();
  4525. while (!ok)
  4526. {
  4527. ReleaseRoxieRow(lastInput);
  4528. lastInput = input->nextInGroup();
  4529. if (!lastInput)
  4530. {
  4531. if (numProcessedLastGroup != processed)
  4532. {
  4533. numProcessedLastGroup = processed;
  4534. return NULL;
  4535. }
  4536. lastInput = input->nextInGroup();
  4537. if (!lastInput)
  4538. return NULL;
  4539. }
  4540. ok = helper.first(lastInput);
  4541. }
  4542. try
  4543. {
  4544. do
  4545. {
  4546. unsigned outSize = helper.transform(rowBuilder);
  4547. if (outSize)
  4548. {
  4549. processed++;
  4550. return rowBuilder.finalizeRowClear(outSize);
  4551. }
  4552. ok = helper.next();
  4553. } while (ok);
  4554. }
  4555. catch (IException *E)
  4556. {
  4557. throw makeWrappedException(E);
  4558. }
  4559. }
  4560. }
  4561. };
  4562. class CRoxieServerChildThroughNormalizeActivityFactory : public CRoxieServerActivityFactory
  4563. {
  4564. public:
  4565. CRoxieServerChildThroughNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4566. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  4567. {
  4568. }
  4569. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  4570. {
  4571. return new CRoxieServerChildThroughNormalizeActivity(this, _probeManager);
  4572. }
  4573. };
  4574. IRoxieServerActivityFactory *createRoxieServerNewChildThroughNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4575. {
  4576. return new CRoxieServerChildThroughNormalizeActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  4577. }
  4578. //=================================================================================
  4579. class CRoxieServerDistributionActivity : public CRoxieServerInternalSinkActivity
  4580. {
  4581. IHThorDistributionArg &helper;
  4582. public:
  4583. CRoxieServerDistributionActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4584. : CRoxieServerInternalSinkActivity(_factory, _probeManager, 0), helper((IHThorDistributionArg &)basehelper)
  4585. {
  4586. }
  4587. virtual void onExecute()
  4588. {
  4589. MemoryAttr ma;
  4590. IDistributionTable * * accumulator = (IDistributionTable * *)ma.allocate(helper.queryInternalRecordSize()->getMinRecordSize());
  4591. helper.clearAggregate(accumulator);
  4592. OwnedConstRoxieRow nextrec(input->nextInGroup());
  4593. loop
  4594. {
  4595. if (!nextrec)
  4596. {
  4597. nextrec.setown(input->nextInGroup());
  4598. if (!nextrec)
  4599. break;
  4600. }
  4601. helper.process(accumulator, nextrec);
  4602. nextrec.setown(input->nextInGroup());
  4603. }
  4604. StringBuffer result;
  4605. result.append("<XML>");
  4606. helper.gatherResult(accumulator, result);
  4607. result.append("</XML>");
  4608. helper.sendResult(result.length(), result.str());
  4609. helper.destruct(accumulator);
  4610. }
  4611. };
  4612. class CRoxieServerDistributionActivityFactory : public CRoxieServerActivityFactory
  4613. {
  4614. bool isRoot;
  4615. public:
  4616. CRoxieServerDistributionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  4617. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
  4618. {
  4619. }
  4620. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  4621. {
  4622. return new CRoxieServerDistributionActivity(this, _probeManager);
  4623. }
  4624. virtual bool isSink() const
  4625. {
  4626. return isRoot;
  4627. }
  4628. };
  4629. IRoxieServerActivityFactory *createRoxieServerDistributionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  4630. {
  4631. return new CRoxieServerDistributionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
  4632. }
  4633. //=================================================================================
  4634. class CRoxieServerLinkedRawIteratorActivity : public CRoxieServerActivity
  4635. {
  4636. IHThorLinkedRawIteratorArg &helper;
  4637. public:
  4638. CRoxieServerLinkedRawIteratorActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4639. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorLinkedRawIteratorArg &) basehelper)
  4640. {
  4641. }
  4642. virtual const void *nextInGroup()
  4643. {
  4644. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  4645. const void *ret =helper.next();
  4646. if (ret)
  4647. {
  4648. LinkRoxieRow(ret);
  4649. processed++;
  4650. }
  4651. return ret;
  4652. }
  4653. };
  4654. class CRoxieServerLinkedRawIteratorActivityFactory : public CRoxieServerActivityFactory
  4655. {
  4656. public:
  4657. CRoxieServerLinkedRawIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4658. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  4659. {
  4660. }
  4661. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  4662. {
  4663. return new CRoxieServerLinkedRawIteratorActivity(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 %s activity", getActivityText(kind));
  4668. }
  4669. };
  4670. IRoxieServerActivityFactory *createRoxieServerLinkedRawIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4671. {
  4672. return new CRoxieServerLinkedRawIteratorActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  4673. }
  4674. //=================================================================================
  4675. class CRoxieServerDatasetResultActivity : public CRoxieServerActivity
  4676. {
  4677. public:
  4678. CRoxieServerDatasetResultActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4679. : CRoxieServerActivity(_factory, _probeManager)
  4680. {
  4681. }
  4682. virtual const void *nextInGroup()
  4683. {
  4684. throwUnexpected();
  4685. }
  4686. virtual void executeChild(size32_t & retSize, void * & ret, unsigned parentExtractSize, const byte * parentExtract)
  4687. {
  4688. try
  4689. {
  4690. start(parentExtractSize, parentExtract, false);
  4691. {
  4692. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  4693. MemoryBuffer result;
  4694. IRecordSize * inputMeta = input->queryOutputMeta();
  4695. loop
  4696. {
  4697. const void *nextrec = input->nextInGroup();
  4698. if (!nextrec)
  4699. {
  4700. nextrec = input->nextInGroup();
  4701. if (!nextrec)
  4702. break;
  4703. }
  4704. result.append(inputMeta->getRecordSize(nextrec), nextrec);
  4705. ReleaseRoxieRow(nextrec);
  4706. }
  4707. retSize = result.length();
  4708. ret = result.detach();
  4709. }
  4710. stop(false);
  4711. reset();
  4712. }
  4713. catch(IException *E)
  4714. {
  4715. ctx->notifyAbort(E);
  4716. stop(true);
  4717. reset();
  4718. throw;
  4719. }
  4720. catch(...)
  4721. {
  4722. Owned<IException> E = MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught at %s:%d", __FILE__, __LINE__);
  4723. ctx->notifyAbort(E);
  4724. stop(true);
  4725. reset();
  4726. throw;
  4727. }
  4728. }
  4729. };
  4730. class CRoxieServerDatasetResultActivityFactory : public CRoxieServerActivityFactory
  4731. {
  4732. bool isRoot;
  4733. public:
  4734. CRoxieServerDatasetResultActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  4735. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
  4736. {
  4737. }
  4738. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  4739. {
  4740. return new CRoxieServerDatasetResultActivity(this, _probeManager);
  4741. }
  4742. virtual bool isSink() const
  4743. {
  4744. return isRoot;
  4745. }
  4746. };
  4747. IRoxieServerActivityFactory *createRoxieServerDatasetResultActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  4748. {
  4749. return new CRoxieServerDatasetResultActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
  4750. }
  4751. //=================================================================================
  4752. class CRoxieServerInlineTableActivity : public CRoxieServerActivity
  4753. {
  4754. IHThorInlineTableArg &helper;
  4755. __uint64 curRow;
  4756. __uint64 numRows;
  4757. public:
  4758. CRoxieServerInlineTableActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4759. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorInlineTableArg &) basehelper)
  4760. {
  4761. curRow = 0;
  4762. numRows = 0;
  4763. }
  4764. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  4765. {
  4766. curRow = 0;
  4767. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  4768. numRows = helper.numRows();
  4769. }
  4770. virtual bool needsAllocator() const { return true; }
  4771. virtual const void *nextInGroup()
  4772. {
  4773. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  4774. // Filtering empty rows, returns the next valid row
  4775. while (curRow < numRows)
  4776. {
  4777. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  4778. unsigned outSize = helper.getRow(rowBuilder, curRow++);
  4779. if (outSize)
  4780. {
  4781. processed++;
  4782. return rowBuilder.finalizeRowClear(outSize);
  4783. }
  4784. }
  4785. return NULL;
  4786. }
  4787. virtual void setInput(unsigned idx, IRoxieInput *_in)
  4788. {
  4789. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  4790. }
  4791. };
  4792. class CRoxieServerInlineTableActivityFactory : public CRoxieServerActivityFactory
  4793. {
  4794. public:
  4795. CRoxieServerInlineTableActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4796. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  4797. {
  4798. }
  4799. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  4800. {
  4801. return new CRoxieServerInlineTableActivity(this, _probeManager);
  4802. }
  4803. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  4804. {
  4805. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for InlineTable activity");
  4806. }
  4807. };
  4808. IRoxieServerActivityFactory *createRoxieServerInlineTableActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4809. {
  4810. return new CRoxieServerInlineTableActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  4811. }
  4812. //=================================================================================
  4813. class CRoxieServerWorkUnitReadActivity : public CRoxieServerActivity
  4814. {
  4815. IHThorWorkunitReadArg &helper;
  4816. Owned<IWorkUnitRowReader> wuReader; // MORE - can we use IRoxieInput instead?
  4817. public:
  4818. CRoxieServerWorkUnitReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4819. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorWorkunitReadArg &)basehelper)
  4820. {
  4821. }
  4822. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  4823. {
  4824. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  4825. if (!ctx->queryServerContext())
  4826. {
  4827. throw MakeStringException(ROXIE_INTERNAL_ERROR, "Workunit read activity cannot be executed in slave context");
  4828. }
  4829. }
  4830. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  4831. {
  4832. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  4833. IXmlToRowTransformer * xmlTransformer = helper.queryXmlTransformer();
  4834. OwnedRoxieString fromWuid(helper.getWUID());
  4835. wuReader.setown(ctx->getWorkunitRowReader(fromWuid, helper.queryName(), helper.querySequence(), xmlTransformer, rowAllocator, meta.isGrouped()));
  4836. // MORE _ should that be in onCreate?
  4837. }
  4838. virtual void reset()
  4839. {
  4840. wuReader.clear();
  4841. CRoxieServerActivity::reset();
  4842. };
  4843. virtual bool needsAllocator() const { return true; }
  4844. virtual const void *nextInGroup()
  4845. {
  4846. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  4847. const void *ret = wuReader->nextInGroup();
  4848. if (ret)
  4849. processed++;
  4850. return ret;
  4851. }
  4852. virtual void setInput(unsigned idx, IRoxieInput *_in)
  4853. {
  4854. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  4855. }
  4856. };
  4857. class CRoxieServerWorkUnitReadActivityFactory : public CRoxieServerActivityFactory
  4858. {
  4859. public:
  4860. CRoxieServerWorkUnitReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4861. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  4862. {
  4863. }
  4864. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  4865. {
  4866. return new CRoxieServerWorkUnitReadActivity(this, _probeManager);
  4867. }
  4868. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  4869. {
  4870. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for WorkUnitRead activity");
  4871. }
  4872. };
  4873. IRoxieServerActivityFactory *createRoxieServerWorkUnitReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4874. {
  4875. return new CRoxieServerWorkUnitReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  4876. }
  4877. //=================================================================================
  4878. interface ILocalGraphEx : public IEclGraphResults
  4879. {
  4880. public:
  4881. virtual void setResult(unsigned id, IGraphResult * result) = 0;
  4882. virtual IRoxieInput * createResultIterator(unsigned id) = 0;
  4883. virtual void setGraphLoopResult(IGraphResult * result) = 0;
  4884. virtual IRoxieInput * createGraphLoopResultIterator(unsigned id) = 0;
  4885. };
  4886. class CSafeRoxieInput : public CInterface, implements IRoxieInput
  4887. {
  4888. public:
  4889. CSafeRoxieInput(IRoxieInput * _input) : input(_input) {}
  4890. IMPLEMENT_IINTERFACE
  4891. virtual IOutputMetaData * queryOutputMeta() const
  4892. {
  4893. return input->queryOutputMeta();
  4894. }
  4895. virtual unsigned queryId() const
  4896. {
  4897. return input->queryId();
  4898. }
  4899. virtual unsigned __int64 queryTotalCycles() const
  4900. {
  4901. return input->queryTotalCycles();
  4902. }
  4903. virtual unsigned __int64 queryLocalCycles() const
  4904. {
  4905. return input->queryLocalCycles();
  4906. }
  4907. virtual IRoxieInput *queryInput(unsigned idx) const
  4908. {
  4909. return input->queryInput(idx);
  4910. }
  4911. virtual IRoxieServerActivity *queryActivity()
  4912. {
  4913. return input->queryActivity();
  4914. }
  4915. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  4916. {
  4917. return input->queryIndexReadActivity();
  4918. }
  4919. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  4920. {
  4921. CriticalBlock procedure(cs);
  4922. input->start(parentExtractSize, parentExtract, paused);
  4923. }
  4924. virtual void stop(bool aborting)
  4925. {
  4926. CriticalBlock procedure(cs);
  4927. input->stop(aborting);
  4928. }
  4929. virtual void reset()
  4930. {
  4931. CriticalBlock procedure(cs);
  4932. input->reset();
  4933. }
  4934. virtual void resetEOF()
  4935. {
  4936. CriticalBlock procedure(cs);
  4937. input->resetEOF();
  4938. }
  4939. virtual void checkAbort()
  4940. {
  4941. CriticalBlock procedure(cs);
  4942. input->checkAbort();
  4943. }
  4944. virtual const void *nextInGroup()
  4945. {
  4946. CriticalBlock procedure(cs);
  4947. return input->nextInGroup();
  4948. }
  4949. virtual bool nextGroup(ConstPointerArray & group)
  4950. {
  4951. CriticalBlock procedure(cs);
  4952. return input->nextGroup(group);
  4953. }
  4954. private:
  4955. CriticalSection cs;
  4956. Linked<IRoxieInput> input;
  4957. };
  4958. //=================================================================================
  4959. class CPseudoRoxieInput : public CInterface, implements IRoxieInput
  4960. {
  4961. protected:
  4962. unsigned __int64 totalCycles;
  4963. public:
  4964. IMPLEMENT_IINTERFACE;
  4965. CPseudoRoxieInput()
  4966. {
  4967. totalCycles = 0;
  4968. }
  4969. virtual unsigned __int64 queryTotalCycles() const
  4970. {
  4971. return totalCycles;
  4972. }
  4973. virtual unsigned __int64 queryLocalCycles() const
  4974. {
  4975. return totalCycles;
  4976. }
  4977. virtual IRoxieInput *queryInput(unsigned idx) const
  4978. {
  4979. return NULL;
  4980. }
  4981. virtual IRoxieServerActivity *queryActivity()
  4982. {
  4983. throwUnexpected();
  4984. }
  4985. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  4986. {
  4987. throwUnexpected();
  4988. }
  4989. virtual IOutputMetaData * queryOutputMeta() const { throwUnexpected(); }
  4990. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused) { }
  4991. virtual void stop(bool aborting) { }
  4992. virtual void reset() { totalCycles = 0; }
  4993. virtual void checkAbort() { }
  4994. virtual unsigned queryId() const { throwUnexpected(); }
  4995. virtual void resetEOF() { }
  4996. };
  4997. class CIndirectRoxieInput : public CPseudoRoxieInput
  4998. {
  4999. public:
  5000. CIndirectRoxieInput(IRoxieInput * _input = NULL) : input(_input)
  5001. {
  5002. }
  5003. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5004. {
  5005. input->start(parentExtractSize, parentExtract, paused);
  5006. }
  5007. virtual void stop(bool aborting)
  5008. {
  5009. input->stop(aborting);
  5010. }
  5011. virtual void reset()
  5012. {
  5013. input->reset();
  5014. totalCycles = 0;
  5015. }
  5016. virtual void checkAbort()
  5017. {
  5018. input->checkAbort();
  5019. }
  5020. virtual const void * nextInGroup()
  5021. {
  5022. return input->nextInGroup();
  5023. }
  5024. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  5025. {
  5026. return input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  5027. }
  5028. virtual unsigned __int64 queryLocalCycles() const
  5029. {
  5030. __int64 ret = totalCycles - input->queryTotalCycles();
  5031. if (ret < 0)
  5032. ret = 0;
  5033. return ret;
  5034. }
  5035. virtual IRoxieInput *queryInput(unsigned idx) const
  5036. {
  5037. return input->queryInput(idx);
  5038. }
  5039. virtual unsigned queryId() const
  5040. {
  5041. return input->queryId();
  5042. }
  5043. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  5044. {
  5045. return input->gatherConjunctions(collector);
  5046. }
  5047. virtual void resetEOF()
  5048. {
  5049. input->resetEOF();
  5050. }
  5051. virtual unsigned numConcreteOutputs() const
  5052. {
  5053. return input->numConcreteOutputs();
  5054. }
  5055. virtual IRoxieInput * queryConcreteInput(unsigned idx)
  5056. {
  5057. return input->queryConcreteInput(idx);
  5058. }
  5059. virtual IOutputMetaData * queryOutputMeta() const
  5060. {
  5061. return input->queryOutputMeta();
  5062. }
  5063. virtual IRoxieServerActivity *queryActivity()
  5064. {
  5065. return input->queryActivity();
  5066. }
  5067. void setInput(IRoxieInput * _input)
  5068. {
  5069. input = _input;
  5070. }
  5071. protected:
  5072. IRoxieInput * input;
  5073. };
  5074. class CExtractMapperInput : public CIndirectRoxieInput
  5075. {
  5076. unsigned savedParentExtractSize;
  5077. const byte * savedParentExtract;
  5078. public:
  5079. CExtractMapperInput(IRoxieInput * _input = NULL) : CIndirectRoxieInput(_input)
  5080. {
  5081. savedParentExtractSize = 0;
  5082. savedParentExtract = NULL;
  5083. }
  5084. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5085. {
  5086. input->start(savedParentExtractSize, savedParentExtract, paused);
  5087. }
  5088. void setParentExtract(unsigned _savedParentExtractSize, const byte * _savedParentExtract)
  5089. {
  5090. savedParentExtractSize = _savedParentExtractSize;
  5091. savedParentExtract = _savedParentExtract;
  5092. }
  5093. };
  5094. class CGraphResult : public CInterface, implements IGraphResult
  5095. {
  5096. CriticalSection cs;
  5097. byte **rowset;
  5098. size32_t count;
  5099. bool complete;
  5100. void clear()
  5101. {
  5102. CriticalBlock func(cs);
  5103. rtlReleaseRowset(count, rowset);
  5104. rowset = NULL;
  5105. count = 0;
  5106. complete = false;
  5107. }
  5108. public:
  5109. IMPLEMENT_IINTERFACE
  5110. CGraphResult()
  5111. {
  5112. complete = false; // dummy result is not supposed to be used...
  5113. rowset = NULL;
  5114. count = 0;
  5115. }
  5116. CGraphResult(size32_t _count, byte **_rowset)
  5117. : count(_count), rowset(_rowset)
  5118. {
  5119. complete = true;
  5120. }
  5121. ~CGraphResult()
  5122. {
  5123. clear();
  5124. }
  5125. // interface IGraphResult
  5126. virtual IRoxieInput * createIterator()
  5127. {
  5128. if (!complete)
  5129. throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Internal Error: Reading uninitialised graph result");
  5130. return new CGraphResultIterator(this);
  5131. }
  5132. virtual void getLinkedResult(unsigned & countResult, byte * * & result)
  5133. {
  5134. if (!complete)
  5135. throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Internal Error: Reading uninitialised graph result");
  5136. result = rtlLinkRowset(rowset);
  5137. countResult = count;
  5138. }
  5139. virtual const void * getLinkedRowResult()
  5140. {
  5141. if (!complete)
  5142. throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Internal Error: Reading uninitialised graph result");
  5143. if (count != 1)
  5144. throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Internal Error: Expected a single row result");
  5145. const void * ret = rowset[0];
  5146. LinkRoxieRow(ret);
  5147. return ret;
  5148. }
  5149. //other
  5150. const void * getRow(unsigned i)
  5151. {
  5152. CriticalBlock func(cs);
  5153. if (i >= count)
  5154. return NULL;
  5155. const void * ret = rowset[i];
  5156. if (ret) LinkRoxieRow(ret);
  5157. return ret;
  5158. }
  5159. protected:
  5160. class CGraphResultIterator : public CPseudoRoxieInput
  5161. {
  5162. unsigned i;
  5163. Linked<CGraphResult> result;
  5164. public:
  5165. CGraphResultIterator(CGraphResult * _result) : result(_result) { i = 0; }
  5166. IMPLEMENT_IINTERFACE
  5167. public:
  5168. virtual const void * nextInGroup()
  5169. {
  5170. return result->getRow(i++);
  5171. }
  5172. };
  5173. };
  5174. //=================================================================================
  5175. class CRoxieServerLocalResultReadActivity : public CRoxieServerActivity
  5176. {
  5177. IHThorLocalResultReadArg &helper;
  5178. Owned<IRoxieInput> iter;
  5179. ILocalGraphEx * graph;
  5180. unsigned graphId;
  5181. unsigned sequence;
  5182. public:
  5183. CRoxieServerLocalResultReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _graphId)
  5184. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorLocalResultReadArg &)basehelper), graphId(_graphId)
  5185. {
  5186. graph = NULL;
  5187. sequence = 0;
  5188. }
  5189. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  5190. {
  5191. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  5192. graph = static_cast<ILocalGraphEx *>(_ctx->queryCodeContext()->resolveLocalQuery(graphId));
  5193. sequence = helper.querySequence();
  5194. }
  5195. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5196. {
  5197. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  5198. iter.setown(graph->createResultIterator(sequence));
  5199. }
  5200. virtual void reset()
  5201. {
  5202. iter.clear();
  5203. CRoxieServerActivity::reset();
  5204. };
  5205. virtual const void *nextInGroup()
  5206. {
  5207. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  5208. const void * next = iter->nextInGroup();
  5209. if (next)
  5210. {
  5211. processed++;
  5212. atomic_inc(&rowsIn);
  5213. }
  5214. return next;
  5215. }
  5216. virtual void setInput(unsigned idx, IRoxieInput *_in)
  5217. {
  5218. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  5219. }
  5220. };
  5221. class CRoxieServerLocalResultReadActivityFactory : public CRoxieServerActivityFactory
  5222. {
  5223. unsigned graphId;
  5224. public:
  5225. CRoxieServerLocalResultReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _graphId)
  5226. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), graphId(_graphId)
  5227. {
  5228. }
  5229. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  5230. {
  5231. return new CRoxieServerLocalResultReadActivity(this, _probeManager, graphId);
  5232. }
  5233. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  5234. {
  5235. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for LocalResultRead activity");
  5236. }
  5237. };
  5238. IRoxieServerActivityFactory *createRoxieServerLocalResultReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned graphId)
  5239. {
  5240. return new CRoxieServerLocalResultReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, graphId);
  5241. }
  5242. //=================================================================================
  5243. class CRoxieServerLocalResultStreamReadActivity : public CRoxieServerActivity
  5244. {
  5245. IHThorLocalResultReadArg &helper;
  5246. Owned<IRoxieInput> streamInput;
  5247. unsigned sequence;
  5248. public:
  5249. CRoxieServerLocalResultStreamReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  5250. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorLocalResultReadArg &)basehelper)
  5251. {
  5252. sequence = 0;
  5253. }
  5254. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  5255. {
  5256. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  5257. sequence = helper.querySequence();
  5258. }
  5259. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5260. {
  5261. assertex(streamInput != NULL);
  5262. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  5263. streamInput->start(parentExtractSize, parentExtract, paused);
  5264. }
  5265. virtual void stop(bool aborting)
  5266. {
  5267. CRoxieServerActivity::stop(aborting);
  5268. streamInput->stop(aborting);
  5269. }
  5270. virtual void reset()
  5271. {
  5272. streamInput->reset();
  5273. CRoxieServerActivity::reset();
  5274. };
  5275. virtual const void *nextInGroup()
  5276. {
  5277. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  5278. const void * next = streamInput->nextInGroup();
  5279. if (next)
  5280. {
  5281. processed++;
  5282. atomic_inc(&rowsIn);
  5283. }
  5284. return next;
  5285. }
  5286. virtual bool querySetStreamInput(unsigned id, IRoxieInput * _input)
  5287. {
  5288. if (id == sequence)
  5289. {
  5290. streamInput.set(_input);
  5291. return true;
  5292. }
  5293. return false;
  5294. }
  5295. virtual void setInput(unsigned idx, IRoxieInput *_in)
  5296. {
  5297. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  5298. }
  5299. };
  5300. class CRoxieServerLocalResultStreamReadActivityFactory : public CRoxieServerActivityFactory
  5301. {
  5302. public:
  5303. CRoxieServerLocalResultStreamReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  5304. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  5305. {
  5306. }
  5307. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  5308. {
  5309. return new CRoxieServerLocalResultStreamReadActivity(this, _probeManager);
  5310. }
  5311. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  5312. {
  5313. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for LocalResultRead activity");
  5314. }
  5315. };
  5316. IRoxieServerActivityFactory *createRoxieServerLocalResultStreamReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  5317. {
  5318. return new CRoxieServerLocalResultStreamReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  5319. }
  5320. //=====================================================================================================
  5321. class CRoxieServerLocalResultWriteActivity : public CRoxieServerInternalSinkActivity
  5322. {
  5323. IHThorLocalResultWriteArg &helper;
  5324. ILocalGraphEx * graph;
  5325. unsigned graphId;
  5326. public:
  5327. CRoxieServerLocalResultWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _graphId, unsigned _numOutputs)
  5328. : CRoxieServerInternalSinkActivity(_factory, _probeManager, _numOutputs), helper((IHThorLocalResultWriteArg &)basehelper), graphId(_graphId)
  5329. {
  5330. graph = NULL;
  5331. }
  5332. virtual bool needsAllocator() const { return true; }
  5333. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  5334. {
  5335. CRoxieServerInternalSinkActivity::onCreate(_ctx, _colocalParent);
  5336. graph = static_cast<ILocalGraphEx *>(_ctx->queryCodeContext()->resolveLocalQuery(graphId));
  5337. }
  5338. virtual void onExecute()
  5339. {
  5340. RtlLinkedDatasetBuilder builder(rowAllocator);
  5341. input->readAll(builder);
  5342. Owned<CGraphResult> result = new CGraphResult(builder.getcount(), builder.linkrows());
  5343. graph->setResult(helper.querySequence(), result);
  5344. }
  5345. virtual const void *nextInGroup()
  5346. {
  5347. return input->nextInGroup(); // I can act as a passthrough input
  5348. }
  5349. IRoxieInput * querySelectOutput(unsigned id)
  5350. {
  5351. if (id == helper.querySequence())
  5352. {
  5353. executed = true; // Ensure that we don't try to pull as a sink as well as via the passthrough
  5354. return LINK(this);
  5355. }
  5356. return NULL;
  5357. }
  5358. };
  5359. class CRoxieServerLocalResultWriteActivityFactory : public CRoxieServerInternalSinkFactory
  5360. {
  5361. unsigned graphId;
  5362. public:
  5363. CRoxieServerLocalResultWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, unsigned _graphId, bool _isRoot)
  5364. : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot), graphId(_graphId)
  5365. {
  5366. isInternal = true;
  5367. Owned<IHThorLocalResultWriteArg> helper = (IHThorLocalResultWriteArg *) helperFactory();
  5368. }
  5369. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  5370. {
  5371. return new CRoxieServerLocalResultWriteActivity(this, _probeManager, graphId, usageCount);
  5372. }
  5373. };
  5374. IRoxieServerActivityFactory *createRoxieServerLocalResultWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, unsigned _graphId, bool _isRoot)
  5375. {
  5376. return new CRoxieServerLocalResultWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _graphId, _isRoot);
  5377. }
  5378. //=====================================================================================================
  5379. class CRoxieServerDictionaryResultWriteActivity : public CRoxieServerInternalSinkActivity
  5380. {
  5381. IHThorDictionaryResultWriteArg &helper;
  5382. ILocalGraphEx * graph;
  5383. unsigned graphId;
  5384. public:
  5385. CRoxieServerDictionaryResultWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _usageCount, unsigned _graphId)
  5386. : CRoxieServerInternalSinkActivity(_factory, _probeManager, _usageCount), helper((IHThorDictionaryResultWriteArg &)basehelper), graphId(_graphId)
  5387. {
  5388. graph = NULL;
  5389. }
  5390. virtual bool needsAllocator() const { return true; }
  5391. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  5392. {
  5393. CRoxieServerInternalSinkActivity::onCreate(_ctx, _colocalParent);
  5394. graph = static_cast<ILocalGraphEx *>(_ctx->queryCodeContext()->resolveLocalQuery(graphId));
  5395. }
  5396. virtual void onExecute()
  5397. {
  5398. unsigned sequence = helper.querySequence();
  5399. RtlLinkedDictionaryBuilder builder(rowAllocator, helper.queryHashLookupInfo());
  5400. loop
  5401. {
  5402. const void *row = input->nextInGroup();
  5403. if (!row)
  5404. {
  5405. row = input->nextInGroup();
  5406. if (!row)
  5407. break;
  5408. }
  5409. builder.appendOwn(row);
  5410. processed++;
  5411. }
  5412. Owned<CGraphResult> result = new CGraphResult(builder.getcount(), builder.linkrows());
  5413. graph->setResult(helper.querySequence(), result);
  5414. }
  5415. virtual const void *nextInGroup()
  5416. {
  5417. return input->nextInGroup(); // I can act as a passthrough input
  5418. }
  5419. IRoxieInput * querySelectOutput(unsigned id)
  5420. {
  5421. if (id == helper.querySequence())
  5422. {
  5423. executed = true; // Ensure that we don't try to pull as a sink as well as via the passthrough
  5424. return LINK(this);
  5425. }
  5426. return NULL;
  5427. }
  5428. };
  5429. class CRoxieServerDictionaryResultWriteActivityFactory : public CRoxieServerInternalSinkFactory
  5430. {
  5431. unsigned graphId;
  5432. public:
  5433. CRoxieServerDictionaryResultWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, unsigned _graphId, bool _isRoot)
  5434. : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot), graphId(_graphId)
  5435. {
  5436. isInternal = true;
  5437. }
  5438. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  5439. {
  5440. return new CRoxieServerDictionaryResultWriteActivity(this, _probeManager, usageCount, graphId);
  5441. }
  5442. };
  5443. IRoxieServerActivityFactory *createRoxieServerDictionaryResultWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, unsigned _graphId, bool _isRoot)
  5444. {
  5445. return new CRoxieServerDictionaryResultWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _graphId, _isRoot);
  5446. }
  5447. //=================================================================================
  5448. class CRoxieServerGraphLoopResultReadActivity : public CRoxieServerActivity
  5449. {
  5450. protected:
  5451. IHThorGraphLoopResultReadArg &helper;
  5452. Owned<IRoxieInput> iter;
  5453. ILocalGraphEx * graph;
  5454. unsigned graphId;
  5455. unsigned sequence;
  5456. public:
  5457. CRoxieServerGraphLoopResultReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _graphId)
  5458. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorGraphLoopResultReadArg &)basehelper), graphId(_graphId)
  5459. {
  5460. graph = NULL;
  5461. sequence = 0;
  5462. }
  5463. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  5464. {
  5465. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  5466. graph = static_cast<ILocalGraphEx *>(_ctx->queryCodeContext()->resolveLocalQuery(graphId));
  5467. }
  5468. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5469. {
  5470. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  5471. if (iter)
  5472. iter->start(parentExtractSize, parentExtract, paused);
  5473. else
  5474. {
  5475. sequence = helper.querySequence();
  5476. if ((int)sequence >= 0)
  5477. {
  5478. try
  5479. {
  5480. iter.setown(graph->createGraphLoopResultIterator(sequence));
  5481. }
  5482. catch (IException * E)
  5483. {
  5484. throw makeWrappedException(E);
  5485. }
  5486. }
  5487. }
  5488. }
  5489. virtual void stop(bool aborting)
  5490. {
  5491. if (iter)
  5492. iter->stop(aborting);
  5493. CRoxieServerActivity::stop(aborting);
  5494. }
  5495. virtual void reset()
  5496. {
  5497. if (iter)
  5498. iter->reset();
  5499. iter.clear();
  5500. CRoxieServerActivity::reset();
  5501. };
  5502. virtual const void *nextInGroup()
  5503. {
  5504. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  5505. const void * next = iter ? iter->nextInGroup() : NULL;
  5506. if (next)
  5507. {
  5508. processed++;
  5509. atomic_inc(&rowsIn);
  5510. }
  5511. return next;
  5512. }
  5513. virtual void setInput(unsigned idx, IRoxieInput *_in)
  5514. {
  5515. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  5516. }
  5517. virtual void gatherIterationUsage(IRoxieServerLoopResultProcessor & processor, unsigned parentExtractSize, const byte * parentExtract)
  5518. {
  5519. ensureCreated();
  5520. basehelper.onStart(parentExtract, NULL);
  5521. processor.noteUseIteration(helper.querySequence());
  5522. }
  5523. virtual void associateIterationOutputs(IRoxieServerLoopResultProcessor & processor, unsigned parentExtractSize, const byte * parentExtract, IProbeManager *probeManager, IArrayOf<IRoxieInput> &probes)
  5524. {
  5525. //helper already initialised from the gratherIterationUsage() call.
  5526. iter.set(processor.connectIterationOutput(helper.querySequence(), probeManager, probes, this, 0));
  5527. }
  5528. virtual IInputSteppingMeta * querySteppingMeta()
  5529. {
  5530. assertex(iter);
  5531. return iter->querySteppingMeta();
  5532. }
  5533. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  5534. {
  5535. assertex(iter);
  5536. return iter->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  5537. }
  5538. };
  5539. //variety of CRoxieServerGraphLoopResultReadActivity created internally with a predefined sequence number
  5540. class CRoxieServerInternalGraphLoopResultReadActivity : public CRoxieServerGraphLoopResultReadActivity
  5541. {
  5542. public:
  5543. CRoxieServerInternalGraphLoopResultReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _graphId, unsigned _sequence)
  5544. : CRoxieServerGraphLoopResultReadActivity(_factory, _probeManager, _graphId)
  5545. {
  5546. sequence = _sequence;
  5547. }
  5548. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5549. {
  5550. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  5551. if ((int)sequence >= 0)
  5552. {
  5553. try
  5554. {
  5555. iter.setown(graph->createGraphLoopResultIterator(sequence));
  5556. }
  5557. catch (IException * E)
  5558. {
  5559. throw makeWrappedException(E);
  5560. }
  5561. }
  5562. }
  5563. };
  5564. class CRoxieServerGraphLoopResultReadActivityFactory : public CRoxieServerActivityFactory
  5565. {
  5566. unsigned graphId;
  5567. public:
  5568. CRoxieServerGraphLoopResultReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _graphId)
  5569. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), graphId(_graphId)
  5570. {
  5571. }
  5572. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  5573. {
  5574. return new CRoxieServerGraphLoopResultReadActivity(this, _probeManager, graphId);
  5575. }
  5576. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  5577. {
  5578. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for GraphLoopResultRead activity");
  5579. }
  5580. };
  5581. IRoxieServerActivityFactory *createRoxieServerGraphLoopResultReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned graphId)
  5582. {
  5583. return new CRoxieServerGraphLoopResultReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, graphId);
  5584. }
  5585. //=====================================================================================================
  5586. class CRoxieServerGraphLoopResultWriteActivity : public CRoxieServerInternalSinkActivity
  5587. {
  5588. IHThorGraphLoopResultWriteArg &helper;
  5589. ILocalGraphEx * graph;
  5590. unsigned graphId;
  5591. public:
  5592. CRoxieServerGraphLoopResultWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _graphId, unsigned _numOutputs)
  5593. : CRoxieServerInternalSinkActivity(_factory, _probeManager, _numOutputs), helper((IHThorGraphLoopResultWriteArg &)basehelper), graphId(_graphId)
  5594. {
  5595. graph = NULL;
  5596. }
  5597. virtual bool needsAllocator() const { return true; }
  5598. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  5599. {
  5600. CRoxieServerInternalSinkActivity::onCreate(_ctx, _colocalParent);
  5601. graph = static_cast<ILocalGraphEx *>(_ctx->queryCodeContext()->resolveLocalQuery(graphId));
  5602. }
  5603. virtual void onExecute()
  5604. {
  5605. RtlLinkedDatasetBuilder builder(rowAllocator);
  5606. input->readAll(builder);
  5607. Owned<CGraphResult> result = new CGraphResult(builder.getcount(), builder.linkrows());
  5608. graph->setGraphLoopResult(result);
  5609. }
  5610. virtual IRoxieInput *queryOutput(unsigned idx)
  5611. {
  5612. if (idx==0)
  5613. return this;
  5614. else
  5615. return NULL;
  5616. }
  5617. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  5618. {
  5619. return input->gatherConjunctions(collector);
  5620. }
  5621. virtual void resetEOF()
  5622. {
  5623. input->resetEOF();
  5624. }
  5625. virtual const void *nextInGroup()
  5626. {
  5627. const void * next = input->nextInGroup();
  5628. if (next)
  5629. processed++;
  5630. return next;
  5631. }
  5632. virtual bool isPassThrough()
  5633. {
  5634. return true;
  5635. }
  5636. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  5637. {
  5638. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  5639. const void * next = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  5640. if (next)
  5641. processed++;
  5642. return next;
  5643. }
  5644. IInputSteppingMeta * querySteppingMeta()
  5645. {
  5646. return input->querySteppingMeta();
  5647. }
  5648. virtual IOutputMetaData * queryOutputMeta() const
  5649. {
  5650. return input->queryOutputMeta();
  5651. }
  5652. };
  5653. class CRoxieServerGraphLoopResultWriteActivityFactory : public CRoxieServerInternalSinkFactory
  5654. {
  5655. unsigned graphId;
  5656. public:
  5657. CRoxieServerGraphLoopResultWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, unsigned _graphId)
  5658. : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, true), graphId(_graphId)
  5659. {
  5660. isInternal = true;
  5661. Owned<IHThorGraphLoopResultWriteArg> helper = (IHThorGraphLoopResultWriteArg *) helperFactory();
  5662. }
  5663. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  5664. {
  5665. return new CRoxieServerGraphLoopResultWriteActivity(this, _probeManager, graphId, usageCount);
  5666. }
  5667. };
  5668. IRoxieServerActivityFactory *createRoxieServerGraphLoopResultWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, unsigned _graphId)
  5669. {
  5670. return new CRoxieServerGraphLoopResultWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _graphId);
  5671. }
  5672. #if 0
  5673. //=====================================================================================================
  5674. CHThorLocalResultSpillActivity::CHThorLocalResultSpillActivity(IAgentContext &_agent, ActivityId const & _id, IHThorLocalResultSpillArg &_arg)
  5675. : CHThorSimpleActivityBase(_agent, _id, _arg), helper(_arg)
  5676. {
  5677. next = NULL;
  5678. }
  5679. void CHThorLocalResultSpillActivity::ready()
  5680. {
  5681. CHThorSimpleActivityBase::ready();
  5682. next = input->nextInGroup();
  5683. grouped = input->isGrouped();
  5684. rowdata.clear();
  5685. }
  5686. const void * CHThorLocalResultSpillActivity::nextInGroup()
  5687. {
  5688. const void * ret = next;
  5689. next = input->nextInGroup();
  5690. if (!ret && !next)
  5691. return NULL;
  5692. if (ret)
  5693. {
  5694. size32_t thisSize = outputMeta->getRecordSize(ret);
  5695. rowdata.append(thisSize, ret);
  5696. if (grouped)
  5697. rowdata.append(next == NULL);
  5698. }
  5699. return ret;
  5700. }
  5701. void CHThorLocalResultSpillActivity::done()
  5702. {
  5703. loop
  5704. {
  5705. const void * ret = nextInGroup();
  5706. if (!ret)
  5707. {
  5708. ret = nextInGroup();
  5709. if (!ret)
  5710. break;
  5711. }
  5712. ReleaseRoxieRow(ret);
  5713. }
  5714. agent.setLocalResult(helper.querySequence(), rowdata.length(), rowdata.toByteArray());
  5715. CHThorSimpleActivityBase::done();
  5716. }
  5717. #endif
  5718. //=================================================================================
  5719. class CRoxieServerDedupActivity : public CRoxieServerActivity
  5720. {
  5721. protected:
  5722. IHThorDedupArg &helper;
  5723. unsigned numKept;
  5724. unsigned numToKeep;
  5725. public:
  5726. CRoxieServerDedupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  5727. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorDedupArg &)basehelper)
  5728. {
  5729. numKept = 0;
  5730. numToKeep = 0;
  5731. }
  5732. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5733. {
  5734. numKept = 0;
  5735. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  5736. numToKeep = helper.numToKeep();
  5737. }
  5738. };
  5739. class CRoxieServerDedupKeepLeftActivity : public CRoxieServerDedupActivity
  5740. {
  5741. IRangeCompare * stepCompare;
  5742. const void *prev;
  5743. public:
  5744. CRoxieServerDedupKeepLeftActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  5745. : CRoxieServerDedupActivity(_factory, _probeManager)
  5746. {
  5747. prev = NULL;
  5748. stepCompare = NULL;
  5749. }
  5750. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5751. {
  5752. prev = NULL;
  5753. CRoxieServerDedupActivity::start(parentExtractSize, parentExtract, paused);
  5754. IInputSteppingMeta * stepMeta = input->querySteppingMeta();
  5755. stepCompare = NULL;
  5756. if (stepMeta)
  5757. stepCompare = stepMeta->queryCompare();
  5758. }
  5759. virtual void reset()
  5760. {
  5761. ReleaseClearRoxieRow(prev);
  5762. CRoxieServerDedupActivity::reset();
  5763. }
  5764. virtual const void * nextInGroup()
  5765. {
  5766. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  5767. const void * next;
  5768. loop
  5769. {
  5770. next = input->nextInGroup();
  5771. if (!prev || !next || !helper.matches(prev,next))
  5772. {
  5773. numKept = 0;
  5774. break;
  5775. }
  5776. if (numKept < numToKeep-1)
  5777. {
  5778. numKept++;
  5779. break;
  5780. }
  5781. ReleaseRoxieRow(next);
  5782. }
  5783. ReleaseRoxieRow(prev);
  5784. prev = next;
  5785. if (next)
  5786. {
  5787. LinkRoxieRow(next);
  5788. processed++;
  5789. }
  5790. return next;
  5791. }
  5792. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  5793. {
  5794. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  5795. const void * next;
  5796. loop
  5797. {
  5798. next = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  5799. //If the record was an in-exact match from the index then return it immediately
  5800. //and don't cause it to dedup following legal records.
  5801. if (!wasCompleteMatch)
  5802. {
  5803. assertex(stepExtra.returnMismatches());
  5804. return next;
  5805. }
  5806. if (!prev || !next || !helper.matches(prev,next))
  5807. {
  5808. numKept = 0;
  5809. break;
  5810. }
  5811. if (numKept < numToKeep-1)
  5812. {
  5813. numKept++;
  5814. break;
  5815. }
  5816. //Unusual - deduping by x,y stepped on x,y,z - still want any record back as soon as possible.
  5817. if (stepExtra.returnMismatches())
  5818. {
  5819. //If asked to return mismatches we are only interested in mismatches that will force the stepped
  5820. //condition to advance
  5821. if (stepCompare->docompare(next, seek, numFields) != 0)
  5822. {
  5823. wasCompleteMatch = false;
  5824. break;
  5825. }
  5826. }
  5827. ReleaseRoxieRow(next);
  5828. }
  5829. ReleaseRoxieRow(prev);
  5830. prev = next;
  5831. if (next)
  5832. {
  5833. LinkRoxieRow(next);
  5834. processed++;
  5835. }
  5836. return next;
  5837. }
  5838. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  5839. {
  5840. return input->gatherConjunctions(collector);
  5841. }
  5842. virtual void resetEOF()
  5843. {
  5844. input->resetEOF();
  5845. }
  5846. IInputSteppingMeta * querySteppingMeta()
  5847. {
  5848. return input->querySteppingMeta();
  5849. }
  5850. };
  5851. //=================================================================================
  5852. class CRoxieServerDedupKeepRightActivity : public CRoxieServerDedupActivity
  5853. {
  5854. const void *kept;
  5855. bool first;
  5856. public:
  5857. CRoxieServerDedupKeepRightActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  5858. : CRoxieServerDedupActivity(_factory, _probeManager)
  5859. {
  5860. kept = NULL;
  5861. first = true;
  5862. }
  5863. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5864. {
  5865. first = true;
  5866. kept = NULL;
  5867. CRoxieServerDedupActivity::start(parentExtractSize, parentExtract, paused);
  5868. }
  5869. virtual void reset()
  5870. {
  5871. ReleaseClearRoxieRow(kept);
  5872. CRoxieServerActivity::reset();
  5873. }
  5874. virtual const void * nextInGroup()
  5875. {
  5876. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  5877. if (first)
  5878. {
  5879. kept = input->nextInGroup();
  5880. first = false;
  5881. }
  5882. const void * next;
  5883. loop
  5884. {
  5885. next = input->nextInGroup();
  5886. if (!kept || !next || !helper.matches(kept,next))
  5887. {
  5888. numKept = 0;
  5889. break;
  5890. }
  5891. if (numKept < numToKeep-1)
  5892. {
  5893. numKept++;
  5894. break;
  5895. }
  5896. ReleaseRoxieRow(kept);
  5897. kept = next;
  5898. }
  5899. const void * ret = kept;
  5900. kept = next;
  5901. // CTXLOG("dedup returns %p", ret);
  5902. if (ret) processed++;
  5903. return ret;
  5904. }
  5905. };
  5906. class CRoxieServerDedupAllActivity : public CRoxieServerActivity
  5907. {
  5908. IHThorDedupArg &helper;
  5909. unsigned survivorIndex;
  5910. ConstPointerArray survivors;
  5911. bool keepLeft;
  5912. bool eof;
  5913. bool first;
  5914. ICompare *primaryCompare;
  5915. public:
  5916. CRoxieServerDedupAllActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _keepLeft)
  5917. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorDedupArg &)basehelper)
  5918. {
  5919. keepLeft = _keepLeft;
  5920. primaryCompare = helper.queryComparePrimary();
  5921. eof = false;
  5922. first = true;
  5923. survivorIndex = 0;
  5924. }
  5925. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5926. {
  5927. eof = false;
  5928. first = true;
  5929. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  5930. }
  5931. virtual void reset()
  5932. {
  5933. #ifdef _DEBUG
  5934. while (survivors.isItem(survivorIndex))
  5935. {
  5936. ReleaseRoxieRow(survivors.item(survivorIndex++));
  5937. }
  5938. #endif
  5939. survivors.kill();
  5940. eof = false;
  5941. first = true;
  5942. CRoxieServerActivity::reset();
  5943. }
  5944. void dedupRange(unsigned first, unsigned last, ConstPointerArray & group)
  5945. {
  5946. for (unsigned idxL = first; idxL < last; idxL++)
  5947. {
  5948. const void * left = group.item(idxL);
  5949. if (left)
  5950. {
  5951. for (unsigned idxR = first; idxR < last; idxR++)
  5952. {
  5953. const void * right = group.item(idxR);
  5954. if ((idxL != idxR) && right)
  5955. {
  5956. if (helper.matches(left, right))
  5957. {
  5958. if (keepLeft)
  5959. {
  5960. group.replace(NULL, idxR);
  5961. ReleaseRoxieRow(right);
  5962. }
  5963. else
  5964. {
  5965. group.replace(NULL, idxL);
  5966. ReleaseRoxieRow(left);
  5967. break;
  5968. }
  5969. }
  5970. }
  5971. }
  5972. }
  5973. }
  5974. }
  5975. void dedupRangeIndirect(unsigned first, unsigned last, void *** index)
  5976. {
  5977. for (unsigned idxL = first; idxL < last; idxL++)
  5978. {
  5979. void * left = *(index[idxL]);
  5980. if (left)
  5981. {
  5982. for (unsigned idxR = first; idxR < last; idxR++)
  5983. {
  5984. void * right = *(index[idxR]);
  5985. if ((idxL != idxR) && right)
  5986. {
  5987. if (helper.matches(left, right))
  5988. {
  5989. if (keepLeft)
  5990. {
  5991. *(index[idxR]) = NULL;
  5992. ReleaseRoxieRow(right);
  5993. }
  5994. else
  5995. {
  5996. *(index[idxL]) = NULL;
  5997. ReleaseRoxieRow(left);
  5998. break;
  5999. }
  6000. }
  6001. }
  6002. }
  6003. }
  6004. }
  6005. }
  6006. bool calcNextDedupAll()
  6007. {
  6008. survivors.kill();
  6009. survivorIndex = 0;
  6010. ConstPointerArray group;
  6011. if (eof || !input->nextGroup(group))
  6012. {
  6013. eof = true;
  6014. return false;
  6015. }
  6016. unsigned max = group.ordinality();
  6017. if (primaryCompare)
  6018. {
  6019. //hard, if not impossible, to hit this code once optimisations in place
  6020. MemoryAttr indexbuff(max*sizeof(void **));
  6021. void *** index = (void ***)indexbuff.bufferBase();
  6022. qsortvecstable(const_cast<void * *>(group.getArray()), max, *primaryCompare, index);
  6023. unsigned first = 0;
  6024. for (unsigned idx = 1; idx < max; idx++)
  6025. {
  6026. if (primaryCompare->docompare(*(index[first]), *(index[idx])) != 0)
  6027. {
  6028. dedupRangeIndirect(first, idx, index);
  6029. first = idx;
  6030. }
  6031. }
  6032. dedupRangeIndirect(first, max, index);
  6033. for(unsigned idx2=0; idx2<max; ++idx2)
  6034. {
  6035. void * cur = *(index[idx2]);
  6036. if(cur)
  6037. survivors.append(cur);
  6038. }
  6039. }
  6040. else
  6041. {
  6042. dedupRange(0, max, group);
  6043. for(unsigned idx=0; idx<max; ++idx)
  6044. {
  6045. const void * cur = group.item(idx);
  6046. if(cur)
  6047. survivors.append(cur);
  6048. }
  6049. }
  6050. return true;
  6051. }
  6052. virtual const void *nextInGroup()
  6053. {
  6054. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  6055. if (first)
  6056. {
  6057. calcNextDedupAll();
  6058. first = false;
  6059. }
  6060. while (survivors.isItem(survivorIndex))
  6061. {
  6062. const void *ret = survivors.item(survivorIndex++);
  6063. if (ret)
  6064. {
  6065. processed++;
  6066. return ret;
  6067. }
  6068. }
  6069. calcNextDedupAll();
  6070. return NULL;
  6071. }
  6072. };
  6073. class CRoxieServerDedupActivityFactory : public CRoxieServerActivityFactory
  6074. {
  6075. bool compareAll;
  6076. bool keepLeft;
  6077. public:
  6078. CRoxieServerDedupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  6079. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  6080. {
  6081. Owned<IHThorDedupArg> helper = (IHThorDedupArg *) helperFactory();
  6082. compareAll = helper->compareAll();
  6083. keepLeft = helper->keepLeft();
  6084. }
  6085. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  6086. {
  6087. if (compareAll)
  6088. return new CRoxieServerDedupAllActivity(this, _probeManager, keepLeft);
  6089. else if (keepLeft)
  6090. return new CRoxieServerDedupKeepLeftActivity(this, _probeManager);
  6091. else
  6092. return new CRoxieServerDedupKeepRightActivity(this, _probeManager);
  6093. }
  6094. };
  6095. IRoxieServerActivityFactory *createRoxieServerDedupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  6096. {
  6097. return new CRoxieServerDedupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  6098. }
  6099. //=================================================================================
  6100. class CRoxieServerHashDedupActivity : public CRoxieServerActivity
  6101. {
  6102. bool eof;
  6103. IHThorHashDedupArg &helper;
  6104. class HashDedupElement
  6105. {
  6106. public:
  6107. HashDedupElement(unsigned _hash, const void *_keyRow)
  6108. : hash(_hash), keyRow(_keyRow)
  6109. {
  6110. }
  6111. ~HashDedupElement()
  6112. {
  6113. ReleaseRoxieRow(keyRow);
  6114. }
  6115. inline unsigned queryHash() const
  6116. {
  6117. return hash;
  6118. }
  6119. inline const void *queryRow() const
  6120. {
  6121. return keyRow;
  6122. }
  6123. private:
  6124. unsigned hash;
  6125. const void *keyRow;
  6126. };
  6127. class HashDedupTable : public SuperHashTable
  6128. {
  6129. public:
  6130. HashDedupTable(IHThorHashDedupArg & _helper, unsigned _activityId)
  6131. : helper(_helper),
  6132. activityId(_activityId),
  6133. keySize(helper.queryKeySize())
  6134. {
  6135. }
  6136. virtual ~HashDedupTable() { releaseAll(); }
  6137. virtual unsigned getHashFromElement(const void *et) const
  6138. {
  6139. const HashDedupElement *element = reinterpret_cast<const HashDedupElement *>(et);
  6140. return element->queryHash();
  6141. }
  6142. virtual unsigned getHashFromFindParam(const void *fp) const { throwUnexpected(); }
  6143. virtual const void * getFindParam(const void *et) const { throwUnexpected(); }
  6144. virtual bool matchesElement(const void *et, const void *searchET) const { throwUnexpected(); }
  6145. virtual bool matchesFindParam(const void *et, const void *key, unsigned fphash) const
  6146. {
  6147. const HashDedupElement *element = reinterpret_cast<const HashDedupElement *>(et);
  6148. if (fphash != element->queryHash())
  6149. return false;
  6150. return (helper.queryKeyCompare()->docompare(element->queryRow(), key) == 0);
  6151. }
  6152. virtual void onAdd(void *et) {}
  6153. virtual void onRemove(void *et)
  6154. {
  6155. const HashDedupElement *element = reinterpret_cast<const HashDedupElement *>(et);
  6156. delete element;
  6157. }
  6158. void onCreate(IRoxieSlaveContext *ctx)
  6159. {
  6160. keyRowAllocator.setown(ctx->queryCodeContext()->getRowAllocator(keySize.queryOriginal(), activityId));
  6161. }
  6162. void reset()
  6163. {
  6164. kill();
  6165. }
  6166. bool insert(const void * row)
  6167. {
  6168. unsigned hash = helper.queryHash()->hash(row);
  6169. RtlDynamicRowBuilder keyRowBuilder(keyRowAllocator, true);
  6170. size32_t thisKeySize = helper.recordToKey(keyRowBuilder, row);
  6171. OwnedConstRoxieRow keyRow = keyRowBuilder.finalizeRowClear(thisKeySize);
  6172. if (find(hash, keyRow.get()))
  6173. return false;
  6174. addNew(new HashDedupElement(hash, keyRow.getClear()), hash);
  6175. return true;
  6176. }
  6177. private:
  6178. IHThorHashDedupArg & helper;
  6179. CachedOutputMetaData keySize;
  6180. Owned<IEngineRowAllocator> keyRowAllocator;
  6181. unsigned activityId;
  6182. } table;
  6183. public:
  6184. CRoxieServerHashDedupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  6185. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorHashDedupArg &)basehelper), table(helper, activityId)
  6186. {
  6187. eof = false;
  6188. }
  6189. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  6190. {
  6191. eof = false;
  6192. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  6193. }
  6194. virtual void onCreate(IRoxieSlaveContext *ctx, IHThorArg *_colocalParent)
  6195. {
  6196. CRoxieServerActivity::onCreate(ctx, colocalParent);
  6197. table.onCreate(ctx);
  6198. }
  6199. virtual void reset()
  6200. {
  6201. table.reset();
  6202. eof = false;
  6203. CRoxieServerActivity::reset();
  6204. }
  6205. virtual const void *nextInGroup()
  6206. {
  6207. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  6208. while(!eof)
  6209. {
  6210. const void * next = input->nextInGroup();
  6211. if(!next)
  6212. {
  6213. if (table.count() == 0)
  6214. eof = true;
  6215. table.reset();
  6216. return NULL;
  6217. }
  6218. if(table.insert(next))
  6219. return next;
  6220. else
  6221. ReleaseRoxieRow(next);
  6222. }
  6223. return NULL;
  6224. }
  6225. };
  6226. class CRoxieServerHashDedupActivityFactory : public CRoxieServerActivityFactory
  6227. {
  6228. public:
  6229. CRoxieServerHashDedupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  6230. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  6231. {
  6232. }
  6233. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  6234. {
  6235. return new CRoxieServerHashDedupActivity(this, _probeManager);
  6236. }
  6237. };
  6238. IRoxieServerActivityFactory *createRoxieServerHashDedupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  6239. {
  6240. return new CRoxieServerHashDedupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  6241. }
  6242. //=================================================================================
  6243. class CRoxieServerRollupActivity : public CRoxieServerActivity
  6244. {
  6245. IHThorRollupArg &helper;
  6246. OwnedConstRoxieRow left;
  6247. OwnedConstRoxieRow prev;
  6248. OwnedConstRoxieRow right;
  6249. bool readFirstRow;
  6250. public:
  6251. CRoxieServerRollupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  6252. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorRollupArg &)basehelper)
  6253. {
  6254. readFirstRow = false;
  6255. }
  6256. ~CRoxieServerRollupActivity()
  6257. {
  6258. }
  6259. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  6260. {
  6261. readFirstRow = false;
  6262. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  6263. }
  6264. virtual void reset()
  6265. {
  6266. left.clear();
  6267. prev.clear();
  6268. right.clear();
  6269. CRoxieServerActivity::reset();
  6270. }
  6271. virtual bool needsAllocator() const { return true; }
  6272. virtual const void * nextInGroup()
  6273. {
  6274. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  6275. if (!readFirstRow)
  6276. {
  6277. left.setown(input->nextInGroup());
  6278. prev.set(left);
  6279. readFirstRow = true;
  6280. }
  6281. loop
  6282. {
  6283. right.setown(input->nextInGroup());
  6284. if(!prev || !right || !helper.matches(prev,right))
  6285. {
  6286. const void * ret = left.getClear();
  6287. if(ret)
  6288. processed++;
  6289. left.setown(right.getClear());
  6290. prev.set(left);
  6291. return ret;
  6292. }
  6293. try
  6294. {
  6295. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  6296. unsigned outSize = helper.transform(rowBuilder, left, right);
  6297. if (outSize)
  6298. left.setown(rowBuilder.finalizeRowClear(outSize));
  6299. if (helper.getFlags() & RFrolledismatchleft)
  6300. prev.set(left);
  6301. else
  6302. prev.set(right);
  6303. }
  6304. catch(IException * E)
  6305. {
  6306. throw makeWrappedException(E);
  6307. }
  6308. }
  6309. }
  6310. };
  6311. class CRoxieServerRollupActivityFactory : public CRoxieServerActivityFactory
  6312. {
  6313. public:
  6314. CRoxieServerRollupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  6315. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  6316. {
  6317. }
  6318. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  6319. {
  6320. return new CRoxieServerRollupActivity(this, _probeManager);
  6321. }
  6322. };
  6323. IRoxieServerActivityFactory *createRoxieServerRollupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  6324. {
  6325. return new CRoxieServerRollupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  6326. }
  6327. //=================================================================================
  6328. class CRoxieServerNormalizeActivity : public CRoxieServerActivity
  6329. {
  6330. IHThorNormalizeArg &helper;
  6331. unsigned numThisRow;
  6332. unsigned curRow;
  6333. const void *buffer;
  6334. unsigned numProcessedLastGroup;
  6335. public:
  6336. CRoxieServerNormalizeActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  6337. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorNormalizeArg &)basehelper)
  6338. {
  6339. buffer = NULL;
  6340. numThisRow = 0;
  6341. curRow = 0;
  6342. numProcessedLastGroup = 0;
  6343. }
  6344. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  6345. {
  6346. numThisRow = 0;
  6347. curRow = 0;
  6348. numProcessedLastGroup = 0;
  6349. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  6350. }
  6351. virtual void reset()
  6352. {
  6353. ReleaseClearRoxieRow(buffer);
  6354. CRoxieServerActivity::reset();
  6355. }
  6356. virtual bool needsAllocator() const { return true; }
  6357. virtual const void * nextInGroup()
  6358. {
  6359. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  6360. loop
  6361. {
  6362. while (curRow == numThisRow)
  6363. {
  6364. if (buffer)
  6365. ReleaseClearRoxieRow(buffer);
  6366. buffer = input->nextInGroup();
  6367. if (!buffer && (processed == numProcessedLastGroup))
  6368. buffer = input->nextInGroup();
  6369. if (!buffer)
  6370. {
  6371. numProcessedLastGroup = processed;
  6372. return NULL;
  6373. }
  6374. curRow = 0;
  6375. numThisRow = helper.numExpandedRows(buffer);
  6376. }
  6377. try
  6378. {
  6379. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  6380. unsigned actualSize = helper.transform(rowBuilder, buffer, ++curRow);
  6381. if (actualSize != 0)
  6382. {
  6383. processed++;
  6384. return rowBuilder.finalizeRowClear(actualSize);
  6385. }
  6386. }
  6387. catch (IException *E)
  6388. {
  6389. throw makeWrappedException(E);
  6390. }
  6391. }
  6392. }
  6393. };
  6394. class CRoxieServerNormalizeActivityFactory : public CRoxieServerActivityFactory
  6395. {
  6396. public:
  6397. CRoxieServerNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  6398. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  6399. {
  6400. }
  6401. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  6402. {
  6403. return new CRoxieServerNormalizeActivity(this, _probeManager);
  6404. }
  6405. };
  6406. IRoxieServerActivityFactory *createRoxieServerNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  6407. {
  6408. return new CRoxieServerNormalizeActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  6409. }
  6410. //=================================================================================
  6411. class CRoxieServerNormalizeChildActivity : public CRoxieServerActivity
  6412. {
  6413. IHThorNormalizeChildArg &helper;
  6414. unsigned numThisRow;
  6415. unsigned curRow;
  6416. const void *buffer;
  6417. unsigned numProcessedLastGroup;
  6418. INormalizeChildIterator * cursor;
  6419. const void * curChildRow;
  6420. bool advanceInput()
  6421. {
  6422. loop
  6423. {
  6424. ReleaseClearRoxieRow(buffer);
  6425. buffer = input->nextInGroup();
  6426. if (!buffer && (processed == numProcessedLastGroup))
  6427. buffer = input->nextInGroup();
  6428. if (!buffer)
  6429. {
  6430. numProcessedLastGroup = processed;
  6431. return false;
  6432. }
  6433. curChildRow = cursor->first(buffer);
  6434. if (curChildRow)
  6435. {
  6436. curRow = 0;
  6437. return true;
  6438. }
  6439. }
  6440. }
  6441. public:
  6442. CRoxieServerNormalizeChildActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  6443. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorNormalizeChildArg &)basehelper)
  6444. {
  6445. buffer = NULL;
  6446. cursor = NULL;
  6447. numThisRow = 0;
  6448. curRow = 0;
  6449. numProcessedLastGroup = 0;
  6450. curChildRow = NULL;
  6451. }
  6452. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  6453. {
  6454. numThisRow = 0;
  6455. curRow = 0;
  6456. numProcessedLastGroup = 0;
  6457. curChildRow = NULL;
  6458. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  6459. cursor = helper.queryIterator();
  6460. }
  6461. virtual void stop(bool aborting)
  6462. {
  6463. CRoxieServerActivity::stop(aborting);
  6464. }
  6465. virtual void reset()
  6466. {
  6467. cursor = NULL;
  6468. ReleaseClearRoxieRow(buffer);
  6469. CRoxieServerActivity::reset();
  6470. }
  6471. virtual bool needsAllocator() const { return true; }
  6472. const void *nextInGroup()
  6473. {
  6474. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  6475. loop
  6476. {
  6477. if (!buffer)
  6478. {
  6479. if (!advanceInput())
  6480. return NULL;
  6481. }
  6482. try
  6483. {
  6484. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  6485. size32_t outSize = helper.transform(rowBuilder, buffer, curChildRow, ++curRow);
  6486. curChildRow = cursor->next();
  6487. if (!curChildRow)
  6488. ReleaseClearRoxieRow(buffer);
  6489. if (outSize != 0)
  6490. {
  6491. processed++;
  6492. return rowBuilder.finalizeRowClear(outSize);
  6493. }
  6494. }
  6495. catch (IException *E)
  6496. {
  6497. throw makeWrappedException(E);
  6498. }
  6499. }
  6500. }
  6501. };
  6502. class CRoxieServerNormalizeChildActivityFactory : public CRoxieServerActivityFactory
  6503. {
  6504. public:
  6505. CRoxieServerNormalizeChildActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  6506. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  6507. {
  6508. }
  6509. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  6510. {
  6511. return new CRoxieServerNormalizeChildActivity(this, _probeManager);
  6512. }
  6513. };
  6514. IRoxieServerActivityFactory *createRoxieServerNormalizeChildActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  6515. {
  6516. return new CRoxieServerNormalizeChildActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  6517. }
  6518. //=================================================================================
  6519. class CRoxieServerNormalizeLinkedChildActivity : public CRoxieServerActivity
  6520. {
  6521. IHThorNormalizeLinkedChildArg &helper;
  6522. OwnedConstRoxieRow curParent;
  6523. OwnedConstRoxieRow curChild;
  6524. unsigned numProcessedLastGroup;
  6525. bool advanceInput()
  6526. {
  6527. loop
  6528. {
  6529. curParent.setown(input->nextInGroup());
  6530. if (!curParent && (processed == numProcessedLastGroup))
  6531. curParent.setown(input->nextInGroup());
  6532. if (!curParent)
  6533. {
  6534. numProcessedLastGroup = processed;
  6535. return false;
  6536. }
  6537. curChild.set(helper.first(curParent));
  6538. if (curChild)
  6539. return true;
  6540. }
  6541. }
  6542. public:
  6543. CRoxieServerNormalizeLinkedChildActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  6544. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorNormalizeLinkedChildArg &)basehelper)
  6545. {
  6546. numProcessedLastGroup = 0;
  6547. }
  6548. ~CRoxieServerNormalizeLinkedChildActivity()
  6549. {
  6550. }
  6551. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  6552. {
  6553. numProcessedLastGroup = 0;
  6554. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  6555. }
  6556. virtual void reset()
  6557. {
  6558. curParent.clear();
  6559. curChild.clear();
  6560. CRoxieServerActivity::reset();
  6561. }
  6562. const void *nextInGroup()
  6563. {
  6564. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  6565. loop
  6566. {
  6567. if (!curParent)
  6568. {
  6569. if (!advanceInput())
  6570. return NULL;
  6571. }
  6572. try
  6573. {
  6574. const void *ret = curChild.getClear();
  6575. curChild.set(helper.next());
  6576. if (!curChild)
  6577. curParent.clear();
  6578. if (ret)
  6579. {
  6580. processed++;
  6581. return ret;
  6582. }
  6583. }
  6584. catch (IException *E)
  6585. {
  6586. throw makeWrappedException(E);
  6587. }
  6588. }
  6589. }
  6590. };
  6591. class CRoxieServerNormalizeLinkedChildActivityFactory : public CRoxieServerActivityFactory
  6592. {
  6593. public:
  6594. CRoxieServerNormalizeLinkedChildActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  6595. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  6596. {
  6597. }
  6598. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  6599. {
  6600. return new CRoxieServerNormalizeLinkedChildActivity(this, _probeManager);
  6601. }
  6602. };
  6603. IRoxieServerActivityFactory *createRoxieServerNormalizeLinkedChildActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  6604. {
  6605. return new CRoxieServerNormalizeLinkedChildActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  6606. }
  6607. //=================================================================================
  6608. interface ISortAlgorithm : extends IInterface
  6609. {
  6610. virtual void prepare(IRoxieInput *input) = 0;
  6611. virtual const void *next() = 0;
  6612. virtual void reset() = 0;
  6613. };
  6614. class CQuickSortAlgorithm : implements CInterfaceOf<ISortAlgorithm>
  6615. {
  6616. unsigned curIndex;
  6617. ConstPointerArray sorted;
  6618. ICompare *compare;
  6619. public:
  6620. CQuickSortAlgorithm(ICompare *_compare) : compare(_compare)
  6621. {
  6622. curIndex = 0;
  6623. }
  6624. virtual void prepare(IRoxieInput *input)
  6625. {
  6626. curIndex = 0;
  6627. if (input->nextGroup(sorted))
  6628. qsortvec(const_cast<void * *>(sorted.getArray()), sorted.ordinality(), *compare);
  6629. }
  6630. virtual const void *next()
  6631. {
  6632. if (sorted.isItem(curIndex))
  6633. return sorted.item(curIndex++);
  6634. return NULL;
  6635. }
  6636. virtual void reset()
  6637. {
  6638. while (sorted.isItem(curIndex))
  6639. ReleaseRoxieRow(sorted.item(curIndex++));
  6640. curIndex = 0;
  6641. sorted.kill();
  6642. }
  6643. };
  6644. class CSpillingQuickSortAlgorithm : implements CInterfaceOf<ISortAlgorithm>, implements roxiemem::IBufferedRowCallback
  6645. {
  6646. enum {
  6647. InitialSortElements = 0,
  6648. //The number of rows that can be added without entering a critical section, and therefore also the number
  6649. //of rows that might not get freed when memory gets tight.
  6650. CommitStep=32
  6651. };
  6652. roxiemem::DynamicRoxieOutputRowArray rowsToSort;
  6653. roxiemem::RoxieSimpleInputRowArray sorted;
  6654. ICompare *compare;
  6655. IRoxieSlaveContext * ctx;
  6656. Owned<IDiskMerger> diskMerger;
  6657. Owned<IRowStream> diskReader;
  6658. Owned<IOutputMetaData> rowMeta;
  6659. unsigned activityId;
  6660. public:
  6661. CSpillingQuickSortAlgorithm(ICompare *_compare, IRoxieSlaveContext * _ctx, IOutputMetaData * _rowMeta, unsigned _activityId)
  6662. : rowsToSort(&_ctx->queryRowManager(), InitialSortElements, CommitStep, _activityId), ctx(_ctx), compare(_compare), rowMeta(_rowMeta), activityId(_activityId)
  6663. {
  6664. ctx->queryRowManager().addRowBuffer(this);
  6665. }
  6666. ~CSpillingQuickSortAlgorithm()
  6667. {
  6668. ctx->queryRowManager().removeRowBuffer(this);
  6669. diskReader.clear();
  6670. }
  6671. virtual void prepare(IRoxieInput *input)
  6672. {
  6673. loop
  6674. {
  6675. const void * next = input->nextInGroup();
  6676. if (!next)
  6677. break;
  6678. if (!rowsToSort.append(next))
  6679. {
  6680. {
  6681. roxiemem::RoxieOutputRowArrayLock block(rowsToSort);
  6682. //We should have been called back to free any committed rows, but occasionally it may not (e.g., if
  6683. //the problem is global memory is exhausted) - in which case force a spill here (but add any pending
  6684. //rows first).
  6685. if (rowsToSort.numCommitted() != 0)
  6686. {
  6687. rowsToSort.flush();
  6688. spillRows();
  6689. }
  6690. //Ensure new rows are written to the head of the array. It needs to be a separate call because
  6691. //spillRows() cannot shift active row pointer since it can be called from any thread
  6692. rowsToSort.flush();
  6693. }
  6694. if (!rowsToSort.append(next))
  6695. {
  6696. ReleaseRoxieRow(next);
  6697. throw MakeStringException(ROXIEMM_MEMORY_LIMIT_EXCEEDED, "Insufficient memory to append sort row");
  6698. }
  6699. }
  6700. }
  6701. rowsToSort.flush();
  6702. roxiemem::RoxieOutputRowArrayLock block(rowsToSort);
  6703. if (diskMerger)
  6704. {
  6705. spillRows();
  6706. rowsToSort.kill();
  6707. diskReader.setown(diskMerger->merge(compare));
  6708. }
  6709. else
  6710. {
  6711. unsigned numRows = rowsToSort.numCommitted();
  6712. if (numRows)
  6713. {
  6714. const void * * rows = rowsToSort.getBlock(numRows);
  6715. //MORE: Should this be parallel? Should that be dependent on whether it is grouped? Should be a hint.
  6716. qsortvec(const_cast<void * *>(rows), numRows, *compare);
  6717. }
  6718. sorted.transferFrom(rowsToSort);
  6719. }
  6720. }
  6721. virtual const void *next()
  6722. {
  6723. if(diskReader)
  6724. return diskReader->nextRow();
  6725. return sorted.dequeue();
  6726. }
  6727. virtual void reset()
  6728. {
  6729. //MORE: This could transfer any row pointer from sorted back to rowsToSort. It would trade
  6730. //fewer heap allocations with not freeing up the memory from large group sorts.
  6731. rowsToSort.clearRows();
  6732. sorted.kill();
  6733. //Disk reader must be cleared before the merger - or the files may still be locked.
  6734. diskReader.clear();
  6735. diskMerger.clear();
  6736. }
  6737. //interface roxiemem::IBufferedRowCallback
  6738. virtual unsigned getSpillCost() const
  6739. {
  6740. //Spill global sorts before grouped sorts
  6741. if (rowMeta->isGrouped())
  6742. return 20;
  6743. return 10;
  6744. }
  6745. virtual bool freeBufferedRows(bool critical)
  6746. {
  6747. roxiemem::RoxieOutputRowArrayLock block(rowsToSort);
  6748. return spillRows();
  6749. }
  6750. protected:
  6751. bool spillRows()
  6752. {
  6753. unsigned numRows = rowsToSort.numCommitted();
  6754. if (numRows == 0)
  6755. return false;
  6756. const void * * rows = rowsToSort.getBlock(numRows);
  6757. qsortvec(const_cast<void * *>(rows), numRows, *compare);
  6758. Owned<IRowWriter> out = queryMerger()->createWriteBlock();
  6759. for (unsigned i= 0; i < numRows; i++)
  6760. {
  6761. out->putRow(rows[i]);
  6762. }
  6763. rowsToSort.noteSpilled(numRows);
  6764. return true;
  6765. }
  6766. IDiskMerger * queryMerger()
  6767. {
  6768. if (!diskMerger)
  6769. {
  6770. unsigned __int64 seq = (memsize_t)this ^ get_cycles_now();
  6771. StringBuffer spillBasename;
  6772. spillBasename.append(tempDirectory).append(PATHSEPCHAR).appendf("spill_sort_%"I64F"u", seq);
  6773. Owned<IRowLinkCounter> linker = new RoxieRowLinkCounter();
  6774. Owned<IRowInterfaces> rowInterfaces = createRowInterfaces(rowMeta, activityId, ctx->queryCodeContext());
  6775. diskMerger.setown(createDiskMerger(rowInterfaces, linker, spillBasename));
  6776. }
  6777. return diskMerger;
  6778. }
  6779. };
  6780. #define INSERTION_SORT_BLOCKSIZE 1024
  6781. class SortedBlock : public CInterface, implements IInterface
  6782. {
  6783. unsigned sequence;
  6784. const void **rows;
  6785. unsigned length;
  6786. unsigned pos;
  6787. SortedBlock(const SortedBlock &);
  6788. public:
  6789. IMPLEMENT_IINTERFACE;
  6790. SortedBlock(unsigned _sequence, IRowManager *rowManager, unsigned activityId) : sequence(_sequence)
  6791. {
  6792. rows = (const void **) rowManager->allocate(INSERTION_SORT_BLOCKSIZE * sizeof(void *), activityId);
  6793. length = 0;
  6794. pos = 0;
  6795. }
  6796. ~SortedBlock()
  6797. {
  6798. while (pos < length)
  6799. ReleaseRoxieRow(rows[pos++]);
  6800. ReleaseRoxieRow(rows);
  6801. }
  6802. int compareTo(SortedBlock *r, ICompare *compare)
  6803. {
  6804. int rc = compare->docompare(rows[pos], r->rows[r->pos]);
  6805. if (!rc)
  6806. rc = sequence - r->sequence;
  6807. return rc;
  6808. }
  6809. const void *next()
  6810. {
  6811. if (pos < length)
  6812. return rows[pos++];
  6813. else
  6814. return NULL;
  6815. }
  6816. inline bool eof()
  6817. {
  6818. return pos==length;
  6819. }
  6820. bool insert(const void *next, ICompare *_compare )
  6821. {
  6822. unsigned b = length;
  6823. if (b == INSERTION_SORT_BLOCKSIZE)
  6824. return false;
  6825. else if (b < 7)
  6826. {
  6827. while (b)
  6828. {
  6829. if (_compare->docompare(next, rows[b-1]) >= 0)
  6830. break;
  6831. b--;
  6832. }
  6833. if (b != length)
  6834. memmove(&rows[b+1], &rows[b], (length - b) * sizeof(void *));
  6835. rows[b] = next;
  6836. length++;
  6837. return true;
  6838. }
  6839. else
  6840. {
  6841. unsigned int a = 0;
  6842. while ((int)a<b)
  6843. {
  6844. int i = (a+b)/2;
  6845. int rc = _compare->docompare(next, rows[i]);
  6846. if (rc>=0)
  6847. a = i+1;
  6848. else
  6849. b = i;
  6850. }
  6851. if (a != length)
  6852. memmove(&rows[a+1], &rows[a], (length - a) * sizeof(void *));
  6853. rows[a] = next;
  6854. length++;
  6855. return true;
  6856. }
  6857. }
  6858. };
  6859. class CInsertionSortAlgorithm : implements CInterfaceOf<ISortAlgorithm>
  6860. {
  6861. SortedBlock *curBlock;
  6862. unsigned blockNo;
  6863. IArrayOf<SortedBlock> blocks;
  6864. unsigned activityId;
  6865. IRowManager *rowManager;
  6866. ICompare *compare;
  6867. void newBlock()
  6868. {
  6869. blocks.append(*curBlock);
  6870. curBlock = new SortedBlock(blockNo++, rowManager, activityId);
  6871. }
  6872. inline static int doCompare(SortedBlock &l, SortedBlock &r, ICompare *compare)
  6873. {
  6874. return l.compareTo(&r, compare);
  6875. }
  6876. void makeHeap()
  6877. {
  6878. /* Permute blocks to establish the heap property
  6879. For each element p, the children are p*2+1 and p*2+2 (provided these are in range)
  6880. The children of p must both be greater than or equal to p
  6881. The parent of a child c is given by p = (c-1)/2
  6882. */
  6883. unsigned i;
  6884. unsigned n = blocks.length();
  6885. SortedBlock **s = blocks.getArray();
  6886. for (i=1; i<n; i++)
  6887. {
  6888. SortedBlock * r = s[i];
  6889. int c = i; /* child */
  6890. while (c > 0)
  6891. {
  6892. int p = (c-1)/2; /* parent */
  6893. if ( doCompare( blocks.item(c), blocks.item(p), compare ) >= 0 )
  6894. break;
  6895. s[c] = s[p];
  6896. s[p] = r;
  6897. c = p;
  6898. }
  6899. }
  6900. }
  6901. void remakeHeap()
  6902. {
  6903. /* The row associated with block[0] will have changed
  6904. This code restores the heap property
  6905. */
  6906. unsigned p = 0; /* parent */
  6907. unsigned n = blocks.length();
  6908. SortedBlock **s = blocks.getArray();
  6909. while (1)
  6910. {
  6911. unsigned c = p*2 + 1; /* child */
  6912. if ( c >= n )
  6913. break;
  6914. /* Select smaller child */
  6915. if ( c+1 < n && doCompare( blocks.item(c+1), blocks.item(c), compare ) < 0 ) c += 1;
  6916. /* If child is greater or equal than parent then we are done */
  6917. if ( doCompare( blocks.item(c), blocks.item(p), compare ) >= 0 )
  6918. break;
  6919. /* Swap parent and child */
  6920. SortedBlock *r = s[c];
  6921. s[c] = s[p];
  6922. s[p] = r;
  6923. /* child becomes parent */
  6924. p = c;
  6925. }
  6926. }
  6927. public:
  6928. CInsertionSortAlgorithm(ICompare *_compare, IRowManager *_rowManager, unsigned _activityId)
  6929. : compare(_compare)
  6930. {
  6931. rowManager = _rowManager;
  6932. activityId = _activityId;
  6933. curBlock = NULL;
  6934. blockNo = 0;
  6935. }
  6936. virtual void reset()
  6937. {
  6938. blocks.kill();
  6939. delete curBlock;
  6940. curBlock = NULL;
  6941. blockNo = 0;
  6942. }
  6943. virtual void prepare(IRoxieInput *input)
  6944. {
  6945. blockNo = 0;
  6946. curBlock = new SortedBlock(blockNo++, rowManager, activityId);
  6947. loop
  6948. {
  6949. const void *next = input->nextInGroup();
  6950. if (!next)
  6951. break;
  6952. if (!curBlock->insert(next, compare))
  6953. {
  6954. newBlock();
  6955. curBlock->insert(next, compare);
  6956. }
  6957. }
  6958. if (blockNo > 1)
  6959. {
  6960. blocks.append(*curBlock);
  6961. curBlock = NULL;
  6962. makeHeap();
  6963. }
  6964. }
  6965. virtual const void * next()
  6966. {
  6967. const void *ret;
  6968. if (blockNo==1) // single block case..
  6969. {
  6970. ret = curBlock->next();
  6971. }
  6972. else if (blocks.length())
  6973. {
  6974. SortedBlock &top = blocks.item(0);
  6975. ret = top.next();
  6976. if (top.eof())
  6977. blocks.replace(blocks.popGet(), 0);
  6978. remakeHeap();
  6979. }
  6980. else
  6981. ret = NULL;
  6982. return ret;
  6983. }
  6984. };
  6985. class CHeapSortAlgorithm : implements CInterfaceOf<ISortAlgorithm>
  6986. {
  6987. unsigned curIndex;
  6988. ConstPointerArray sorted;
  6989. bool inputAlreadySorted;
  6990. IntArray sequences;
  6991. bool eof;
  6992. ICompare *compare;
  6993. #ifdef _CHECK_HEAPSORT
  6994. void checkHeap() const
  6995. {
  6996. unsigned n = sorted.ordinality();
  6997. if (n)
  6998. {
  6999. ICompare *_compare = compare;
  7000. void **s = sorted.getArray();
  7001. int *sq = sequences.getArray();
  7002. unsigned p;
  7003. #if 0
  7004. CTXLOG("------------------------%d entries-----------------", n);
  7005. for (p = 0; p < n; p++)
  7006. {
  7007. CTXLOG("HEAP %d: %d %.10s", p, sq[p], s[p] ? s[p] : "..");
  7008. }
  7009. #endif
  7010. for (p = 0; p < n; p++)
  7011. {
  7012. unsigned c = p*2+1;
  7013. if (c<n)
  7014. assertex(!s[c] || (docompare(p, c, _compare, s, sq) <= 0));
  7015. c++;
  7016. if (c<n)
  7017. assertex(!s[c] || (docompare(p, c, _compare, s, sq) <= 0));
  7018. }
  7019. }
  7020. }
  7021. #else
  7022. inline void checkHeap() const {}
  7023. #endif
  7024. const void *removeHeap()
  7025. {
  7026. unsigned n = sorted.ordinality();
  7027. if (n)
  7028. {
  7029. const void *ret = sorted.item(0);
  7030. if (n > 1 && ret)
  7031. {
  7032. ICompare *_compare = compare;
  7033. const void **s = sorted.getArray();
  7034. int *sq = sequences.getArray();
  7035. unsigned v = 0; // vacancy
  7036. loop
  7037. {
  7038. unsigned c = 2*v + 1;
  7039. if (c < n)
  7040. {
  7041. unsigned f = c; // favourite to fill it
  7042. c++;
  7043. if (c < n && s[c] && (!s[f] || (docompare(f, c, _compare, s, sq) > 0))) // is the smaller of the children
  7044. f = c;
  7045. sq[v] = sq[f];
  7046. if ((s[v] = s[f]) != NULL)
  7047. v = f;
  7048. else
  7049. break;
  7050. }
  7051. else
  7052. {
  7053. s[v] = NULL;
  7054. break;
  7055. }
  7056. }
  7057. }
  7058. checkHeap();
  7059. return ret;
  7060. }
  7061. else
  7062. return NULL;
  7063. }
  7064. static inline int docompare(unsigned l, unsigned r, ICompare *_compare, const void **s, int *sq)
  7065. {
  7066. int rc = _compare->docompare(s[l], s[r]);
  7067. if (!rc)
  7068. rc = sq[l] - sq[r];
  7069. return rc;
  7070. }
  7071. void insertHeap(const void *next)
  7072. {
  7073. // Upside-down heap sort
  7074. // Maintain a heap where every parent is lower than each of its children
  7075. // Root (at node 0) is lowest record seen, nodes 2n+1, 2n+2 are the children
  7076. // To insert a row, add it at end then keep swapping with parent as long as parent is greater
  7077. // To remove a row, take row 0, then recreate heap by replacing it with smaller of two children and so on down the tree
  7078. // Nice features:
  7079. // 1. Deterministic
  7080. // 2. Sort time can be overlapped with upstream/downstream processes - there is no delay between receiving last record from input and deliveriing first to output
  7081. // 3. Already sorted case can be spotted at zero cost while reading.
  7082. // 4. If you don't read all the results, you don't have to complete the sort
  7083. // BUT it is NOT stable, so we have to use a parallel array of sequence numbers
  7084. unsigned n = sorted.ordinality();
  7085. sorted.append(next);
  7086. sequences.append(n);
  7087. if (!n)
  7088. return;
  7089. ICompare *_compare = compare;
  7090. const void **s = sorted.getArray();
  7091. if (inputAlreadySorted)
  7092. {
  7093. if (_compare->docompare(next, s[n-1]) >= 0)
  7094. return;
  7095. else
  7096. {
  7097. // MORE - could delay creating sequences until now...
  7098. inputAlreadySorted = false;
  7099. }
  7100. }
  7101. int *sq = sequences.getArray();
  7102. unsigned q = n;
  7103. while (n)
  7104. {
  7105. unsigned parent = (n-1) / 2;
  7106. const void *p = s[parent];
  7107. if (_compare->docompare(p, next) <= 0)
  7108. break;
  7109. s[n] = p;
  7110. sq[n] = sq[parent];
  7111. s[parent] = next;
  7112. sq[parent] = q;
  7113. n = parent;
  7114. }
  7115. }
  7116. public:
  7117. CHeapSortAlgorithm(ICompare *_compare) : compare(_compare)
  7118. {
  7119. inputAlreadySorted = true;
  7120. curIndex = 0;
  7121. eof = false;
  7122. }
  7123. virtual void reset()
  7124. {
  7125. eof = false;
  7126. if (inputAlreadySorted)
  7127. {
  7128. while (sorted.isItem(curIndex))
  7129. ReleaseRoxieRow(sorted.item(curIndex++));
  7130. sorted.kill();
  7131. }
  7132. else
  7133. {
  7134. ReleaseRoxieRowSet(sorted);
  7135. }
  7136. inputAlreadySorted = true;
  7137. sequences.kill();
  7138. }
  7139. virtual void prepare(IRoxieInput *input)
  7140. {
  7141. inputAlreadySorted = true;
  7142. curIndex = 0;
  7143. eof = false;
  7144. assertex(sorted.ordinality()==0);
  7145. const void *next = input->nextInGroup();
  7146. if (!next)
  7147. {
  7148. eof = true;
  7149. return;
  7150. }
  7151. loop
  7152. {
  7153. insertHeap(next);
  7154. next = input->nextInGroup();
  7155. if (!next)
  7156. break;
  7157. }
  7158. checkHeap();
  7159. }
  7160. virtual const void * next()
  7161. {
  7162. if (inputAlreadySorted)
  7163. {
  7164. if (sorted.isItem(curIndex))
  7165. {
  7166. return sorted.item(curIndex++);
  7167. }
  7168. else
  7169. return NULL;
  7170. }
  7171. else
  7172. return removeHeap();
  7173. }
  7174. };
  7175. typedef enum {heapSort, insertionSort, quickSort, spillingQuickSort, unknownSort } RoxieSortAlgorithm;
  7176. class CRoxieServerSortActivity : public CRoxieServerActivity
  7177. {
  7178. protected:
  7179. IHThorSortArg &helper;
  7180. ICompare *compare;
  7181. Owned<ISortAlgorithm> sorter;
  7182. bool readInput;
  7183. RoxieSortAlgorithm sortAlgorithm;
  7184. unsigned sortFlags;
  7185. public:
  7186. CRoxieServerSortActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, RoxieSortAlgorithm _sortAlgorithm, unsigned _sortFlags)
  7187. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorSortArg &)basehelper), sortAlgorithm(_sortAlgorithm), sortFlags(_sortFlags)
  7188. {
  7189. compare = helper.queryCompare();
  7190. readInput = false;
  7191. }
  7192. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  7193. {
  7194. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  7195. switch (sortAlgorithm)
  7196. {
  7197. case heapSort:
  7198. sorter.setown(new CHeapSortAlgorithm(compare));
  7199. break;
  7200. case insertionSort:
  7201. sorter.setown(new CInsertionSortAlgorithm(compare, &ctx->queryRowManager(), activityId));
  7202. break;
  7203. case quickSort:
  7204. sorter.setown(new CQuickSortAlgorithm(compare));
  7205. break;
  7206. case spillingQuickSort:
  7207. sorter.setown(new CSpillingQuickSortAlgorithm(compare, ctx, meta, activityId));
  7208. break;
  7209. case unknownSort:
  7210. sorter.clear(); // create it later....
  7211. break;
  7212. default:
  7213. throwUnexpected();
  7214. break;
  7215. }
  7216. }
  7217. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  7218. {
  7219. assertex(!readInput);
  7220. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  7221. }
  7222. virtual void reset()
  7223. {
  7224. if (sorter)
  7225. sorter->reset();
  7226. readInput = false;
  7227. CRoxieServerActivity::reset();
  7228. }
  7229. virtual const void * nextInGroup()
  7230. {
  7231. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  7232. if (!readInput)
  7233. {
  7234. if (sortAlgorithm == unknownSort)
  7235. {
  7236. sorter.clear();
  7237. IHThorAlgorithm *sortMethod = static_cast<IHThorAlgorithm *>(helper.selectInterface(TAIalgorithm_1));
  7238. OwnedRoxieString useAlgorithm(sortMethod->getAlgorithm());
  7239. if (useAlgorithm)
  7240. {
  7241. if (stricmp(useAlgorithm, "quicksort")==0)
  7242. {
  7243. if (sortFlags & TAFstable)
  7244. throw MakeStringException(ROXIE_UNKNOWN_ALGORITHM, "Invalid stable sort algorithm %s requested", useAlgorithm.get());
  7245. sorter.setown(new CQuickSortAlgorithm(compare));
  7246. }
  7247. else if (stricmp(useAlgorithm, "heapsort")==0)
  7248. sorter.setown(new CHeapSortAlgorithm(compare));
  7249. else if (stricmp(useAlgorithm, "insertionsort")==0)
  7250. sorter.setown(new CInsertionSortAlgorithm(compare, &ctx->queryRowManager(), activityId));
  7251. else
  7252. {
  7253. WARNLOG(ROXIE_UNKNOWN_ALGORITHM, "Ignoring unsupported sort order algorithm '%s', using default", useAlgorithm.get());
  7254. if (sortFlags & TAFunstable)
  7255. sorter.setown(new CQuickSortAlgorithm(compare));
  7256. else
  7257. sorter.setown(new CHeapSortAlgorithm(compare));
  7258. }
  7259. }
  7260. else
  7261. sorter.setown(new CHeapSortAlgorithm(compare)); // shouldn't really happen but there was a vintage of codegen that did not set the flag when algorithm not specified...
  7262. }
  7263. sorter->prepare(input);
  7264. readInput = true;
  7265. }
  7266. const void *ret = sorter->next();
  7267. if (ret)
  7268. processed++;
  7269. else
  7270. {
  7271. sorter->reset();
  7272. readInput = false; // ready for next group
  7273. }
  7274. return ret;
  7275. }
  7276. };
  7277. class CRoxieServerSortActivityFactory : public CRoxieServerActivityFactory
  7278. {
  7279. RoxieSortAlgorithm sortAlgorithm;
  7280. unsigned sortFlags;
  7281. public:
  7282. CRoxieServerSortActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  7283. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  7284. {
  7285. sortAlgorithm = heapSort;
  7286. sortFlags = TAFstable;
  7287. Owned<IHThorSortArg> sortHelper = (IHThorSortArg *) helperFactory();
  7288. IHThorAlgorithm *sortMethod = static_cast<IHThorAlgorithm *>(sortHelper->selectInterface(TAIalgorithm_1));
  7289. if (sortMethod)
  7290. {
  7291. sortFlags = sortMethod->getAlgorithmFlags();
  7292. if (sortFlags & TAFunstable)
  7293. sortAlgorithm = quickSort;
  7294. if (!(sortFlags & TAFconstant))
  7295. sortAlgorithm = unknownSort;
  7296. else
  7297. {
  7298. OwnedRoxieString useAlgorithm(sortMethod->getAlgorithm());
  7299. if (useAlgorithm)
  7300. {
  7301. if (stricmp(useAlgorithm, "quicksort")==0)
  7302. {
  7303. if (sortFlags & TAFstable)
  7304. throw MakeStringException(ROXIE_UNKNOWN_ALGORITHM, "Invalid stable sort algorithm %s requested", useAlgorithm.get());
  7305. sortAlgorithm = quickSort;
  7306. }
  7307. else if (stricmp(useAlgorithm, "spillingquicksort")==0)
  7308. {
  7309. if (sortFlags & TAFstable)
  7310. throw MakeStringException(ROXIE_UNKNOWN_ALGORITHM, "Invalid stable sort algorithm %s requested", useAlgorithm.get());
  7311. sortAlgorithm = spillingQuickSort;
  7312. }
  7313. else if (stricmp(useAlgorithm, "heapsort")==0)
  7314. sortAlgorithm = heapSort; // NOTE - we do allow UNSTABLE('heapsort') in order to facilitate runtime selection
  7315. else if (stricmp(useAlgorithm, "insertionsort")==0)
  7316. sortAlgorithm = insertionSort;
  7317. else
  7318. {
  7319. WARNLOG(ROXIE_UNKNOWN_ALGORITHM, "Ignoring unsupported sort order algorithm '%s', using default", useAlgorithm.get());
  7320. if (sortFlags & TAFunstable)
  7321. sortAlgorithm = quickSort;
  7322. else
  7323. sortAlgorithm = heapSort;
  7324. }
  7325. }
  7326. }
  7327. }
  7328. }
  7329. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  7330. {
  7331. return new CRoxieServerSortActivity(this, _probeManager, sortAlgorithm, sortFlags);
  7332. }
  7333. };
  7334. IRoxieServerActivityFactory *createRoxieServerSortActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  7335. {
  7336. return new CRoxieServerSortActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  7337. }
  7338. //=====================================================================================================
  7339. class CRoxieServerSortedActivity : public CRoxieServerActivity
  7340. {
  7341. IHThorSortedArg &helper;
  7342. ICompare * compare;
  7343. const void *prev;
  7344. IRangeCompare * stepCompare;
  7345. public:
  7346. CRoxieServerSortedActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  7347. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorSortedArg &)basehelper)
  7348. {
  7349. prev = NULL;
  7350. compare = helper.queryCompare();
  7351. stepCompare = NULL;
  7352. }
  7353. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  7354. {
  7355. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  7356. IInputSteppingMeta * stepMeta = input->querySteppingMeta();
  7357. if (stepMeta)
  7358. stepCompare = stepMeta->queryCompare();
  7359. prev = NULL;
  7360. }
  7361. virtual void reset()
  7362. {
  7363. ReleaseClearRoxieRow(prev);
  7364. CRoxieServerActivity::reset();
  7365. }
  7366. virtual const void * nextInGroup()
  7367. {
  7368. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  7369. const void *ret = input->nextInGroup();
  7370. if (ret && prev && compare->docompare(prev, ret) > 0)
  7371. {
  7372. // MORE - better to give mismatching rows that indexes?
  7373. throw MakeStringException(ROXIE_NOT_SORTED, "SORTED(%u) detected incorrectly sorted rows (row %d, %d))", activityId, processed, processed+1);
  7374. }
  7375. ReleaseRoxieRow(prev);
  7376. prev = ret;
  7377. if (ret)
  7378. {
  7379. LinkRoxieRow(prev);
  7380. processed++;
  7381. }
  7382. return ret;
  7383. }
  7384. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  7385. {
  7386. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  7387. const void *ret = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  7388. if (ret && prev && compare->docompare(prev, ret) > 0)
  7389. {
  7390. // MORE - better to give mismatching rows that indexes?
  7391. throw MakeStringException(ROXIE_NOT_SORTED, "SORTED(%u) detected incorrectly sorted rows (row %d, %d))", activityId, processed, processed+1);
  7392. }
  7393. ReleaseRoxieRow(prev);
  7394. prev = ret;
  7395. if (ret)
  7396. {
  7397. LinkRoxieRow(prev);
  7398. processed++;
  7399. }
  7400. return ret;
  7401. }
  7402. IInputSteppingMeta * querySteppingMeta()
  7403. {
  7404. return input->querySteppingMeta();
  7405. }
  7406. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  7407. {
  7408. return input->gatherConjunctions(collector);
  7409. }
  7410. virtual void resetEOF()
  7411. {
  7412. input->resetEOF();
  7413. }
  7414. };
  7415. class CRoxieServerSortedActivityFactory : public CRoxieServerActivityFactory
  7416. {
  7417. public:
  7418. CRoxieServerSortedActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  7419. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  7420. {
  7421. }
  7422. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  7423. {
  7424. return new CRoxieServerSortedActivity(this, _probeManager);
  7425. }
  7426. };
  7427. IRoxieServerActivityFactory *createRoxieServerSortedActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  7428. {
  7429. return new CRoxieServerSortedActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  7430. }
  7431. //=====================================================================================================
  7432. class CRoxieServerThroughSpillActivity : public CRoxieServerActivity
  7433. {
  7434. /*
  7435. BE VERY CAREFUL - this code is tricky.
  7436. Note that starts and stops (and resets) can occur in strange orders
  7437. The FIRST start OR stop must initialize the activity but only the first START should call the upstream start.
  7438. The last stop should call the upstream stop.
  7439. The first reset should call the upstream reset.
  7440. 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
  7441. not yet had start or stop called - for this to happen init() is called on all outputs on the first start or stop.
  7442. Some outputs may be completely pruned away when used in a GRAPH - these outputs should not receive any start/stop/reset and should be
  7443. ignored in the minIndex calculation
  7444. */
  7445. public:
  7446. IHThorArg &helper;
  7447. unsigned activeOutputs;
  7448. unsigned numOutputs;
  7449. unsigned numOriginalOutputs;
  7450. QueueOf<const void, true> buffer;
  7451. CriticalSection crit;
  7452. CriticalSection crit2;
  7453. unsigned tailIdx;
  7454. unsigned headIdx;
  7455. Owned<IException> error;
  7456. class OutputAdaptor : public CInterface, implements IRoxieInput
  7457. {
  7458. bool eof, eofpending, stopped;
  7459. public:
  7460. CRoxieServerThroughSpillActivity *parent;
  7461. unsigned idx;
  7462. unsigned oid;
  7463. unsigned processed;
  7464. unsigned __int64 totalCycles;
  7465. public:
  7466. IMPLEMENT_IINTERFACE;
  7467. OutputAdaptor()
  7468. {
  7469. parent = NULL;
  7470. oid = 0;
  7471. idx = 0;
  7472. processed = 0;
  7473. totalCycles = 0;
  7474. eofpending = false;
  7475. eof = false;
  7476. stopped = false;
  7477. }
  7478. ~OutputAdaptor()
  7479. {
  7480. if (traceStartStop)
  7481. DBGLOG("%p ~OutputAdaptor %d", this, oid);
  7482. }
  7483. void init()
  7484. {
  7485. if (traceStartStop)
  7486. DBGLOG("%p init Input adaptor %d", this, oid);
  7487. idx = 0;
  7488. processed = 0;
  7489. totalCycles = 0;
  7490. eofpending = false;
  7491. eof = false;
  7492. stopped = false;
  7493. }
  7494. virtual unsigned queryId() const
  7495. {
  7496. return parent->queryId();
  7497. }
  7498. virtual IRoxieServerActivity *queryActivity()
  7499. {
  7500. return parent;
  7501. }
  7502. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  7503. {
  7504. return parent->queryIndexReadActivity();
  7505. }
  7506. virtual unsigned __int64 queryTotalCycles() const
  7507. {
  7508. return totalCycles;
  7509. }
  7510. virtual unsigned __int64 queryLocalCycles() const
  7511. {
  7512. return 0;
  7513. }
  7514. virtual IRoxieInput *queryInput(unsigned idx) const
  7515. {
  7516. return parent->queryInput(idx);
  7517. }
  7518. virtual const void * nextInGroup()
  7519. {
  7520. ActivityTimer t(totalCycles, parent->timeActivities, parent->ctx->queryDebugContext());
  7521. if (eof)
  7522. return NULL;
  7523. const void *ret = parent->readBuffered(idx, oid);
  7524. #ifdef TRACE_SPLIT
  7525. parent->CTXLOG("Adaptor %d got back %p for record %d", oid, ret, idx);
  7526. #endif
  7527. idx++;
  7528. if (ret)
  7529. {
  7530. processed++;
  7531. eofpending = false;
  7532. }
  7533. else if (eofpending)
  7534. eof = true;
  7535. else
  7536. eofpending = true;
  7537. return ret;
  7538. }
  7539. virtual IOutputMetaData * queryOutputMeta() const
  7540. {
  7541. return parent->queryOutputMeta();
  7542. }
  7543. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  7544. {
  7545. // NOTE: it is tempting to move the init() of all output adaptors here. However that is not a good idea,
  7546. // since adaptors that have not yet started or stopped (but are going to) still need to have been init()'ed
  7547. // for minIndex to give the correct answers
  7548. // therefore, we call init() on all adaptors on receipt of the first start() or stop()
  7549. if (traceStartStop)
  7550. parent->CTXLOG("%p start Input adaptor %d stopped = %d", this, oid, stopped);
  7551. parent->start(oid, parentExtractSize, parentExtract, paused);
  7552. }
  7553. virtual void stop(bool aborting)
  7554. {
  7555. if (traceStartStop)
  7556. parent->CTXLOG("%p stop Input adaptor %d stopped = %d", this, oid, stopped);
  7557. if (!stopped)
  7558. {
  7559. parent->stop(oid, idx, aborting); // NOTE - may call init()
  7560. stopped = true; // parent code relies on stop being called exactly once per adaptor, so make sure it is!
  7561. idx = (unsigned) -1; // causes minIndex not to save rows for me...
  7562. }
  7563. };
  7564. virtual void reset()
  7565. {
  7566. if (traceStartStop)
  7567. parent->CTXLOG("%p reset Input adaptor %d stopped = %d", this, oid, stopped);
  7568. parent->reset(oid);
  7569. parent->noteProcessed(oid, processed, 0, 0);
  7570. processed = 0;
  7571. idx = 0; // value should not be relevant really but this is the safest...
  7572. stopped = false;
  7573. };
  7574. virtual void resetEOF()
  7575. {
  7576. parent->resetEOF();
  7577. }
  7578. virtual void checkAbort()
  7579. {
  7580. parent->checkAbort();
  7581. }
  7582. } *adaptors;
  7583. bool *used;
  7584. unsigned nextFreeOutput()
  7585. {
  7586. unsigned i = numOutputs;
  7587. while (i)
  7588. {
  7589. i--;
  7590. if (!used[i])
  7591. return i;
  7592. }
  7593. throwUnexpected();
  7594. }
  7595. unsigned minIndex(unsigned exceptOid)
  7596. {
  7597. // MORE - yukky code (and slow). Could keep them heapsorted by idx or something
  7598. // this is trying to determine whethwe any of the adaptors will in the future read a given record
  7599. unsigned minIdx = (unsigned) -1;
  7600. for (unsigned i = 0; i < numOutputs; i++)
  7601. {
  7602. if (i != exceptOid && used[i] && adaptors[i].idx < minIdx)
  7603. minIdx = adaptors[i].idx;
  7604. }
  7605. return minIdx;
  7606. }
  7607. void initOutputs()
  7608. {
  7609. activeOutputs = numOutputs;
  7610. for (unsigned i = 0; i < numOriginalOutputs; i++)
  7611. if (used[i])
  7612. adaptors[i].init();
  7613. state = STATEstarting;
  7614. }
  7615. public:
  7616. CRoxieServerThroughSpillActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numOutputs)
  7617. : CRoxieServerActivity(_factory, _probeManager), helper(basehelper), numOutputs(_numOutputs)
  7618. {
  7619. numOriginalOutputs = numOutputs;
  7620. adaptors = new OutputAdaptor[numOutputs];
  7621. used = new bool[numOutputs];
  7622. for (unsigned i = 0; i < numOutputs; i++)
  7623. {
  7624. adaptors[i].parent = this;
  7625. adaptors[i].oid = i;
  7626. used[i] = false;
  7627. }
  7628. tailIdx = 0;
  7629. headIdx = 0;
  7630. activeOutputs = numOutputs;
  7631. }
  7632. ~CRoxieServerThroughSpillActivity()
  7633. {
  7634. delete [] adaptors;
  7635. delete [] used;
  7636. }
  7637. const void *readBuffered(unsigned idx, unsigned oid)
  7638. {
  7639. CriticalBlock b(crit);
  7640. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext()); // NOTE - time spent waiting for crit not included here. Is that right?
  7641. if (idx == headIdx) // test once without getting the crit2 sec
  7642. {
  7643. CriticalUnblock b1(crit);
  7644. CriticalBlock b2(crit2);
  7645. if (error)
  7646. {
  7647. throw error.getLink();
  7648. }
  7649. if (idx == headIdx) // test again now that we have it
  7650. {
  7651. try
  7652. {
  7653. const void *row = input->nextInGroup();
  7654. CriticalBlock b3(crit);
  7655. headIdx++;
  7656. if (activeOutputs==1)
  7657. {
  7658. #ifdef TRACE_SPLIT
  7659. CTXLOG("spill %d optimised return of %p", activityId, row);
  7660. #endif
  7661. return row; // optimization for the case where only one output still active.
  7662. }
  7663. buffer.enqueue(row);
  7664. }
  7665. catch (IException *E)
  7666. {
  7667. #ifdef TRACE_SPLIT
  7668. CTXLOG("spill %d caught exception", activityId);
  7669. #endif
  7670. error.set(E);
  7671. throw;
  7672. }
  7673. catch (...)
  7674. {
  7675. IException *E = MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught in CRoxieServerThroughSpillActivity::readBuffered");
  7676. error.set(E);
  7677. throw E;
  7678. }
  7679. }
  7680. }
  7681. idx -= tailIdx;
  7682. if (!idx)
  7683. {
  7684. unsigned min = minIndex(oid);
  7685. if (min > tailIdx)
  7686. {
  7687. tailIdx++;
  7688. const void *ret = buffer.dequeue(); // no need to link - last puller
  7689. #ifdef TRACE_SPLIT
  7690. CTXLOG("last puller return of %p", ret);
  7691. #endif
  7692. return ret;
  7693. }
  7694. }
  7695. const void *ret = buffer.item(idx);
  7696. if (ret) LinkRoxieRow(ret);
  7697. #ifdef TRACE_SPLIT
  7698. CTXLOG("standard return of %p", ret);
  7699. #endif
  7700. return ret;
  7701. }
  7702. virtual void start(unsigned oid, unsigned parentExtractSize, const byte *parentExtract, bool paused)
  7703. {
  7704. CriticalBlock b(crit);
  7705. if (error)
  7706. throw error.getLink();
  7707. if (factory)
  7708. factory->noteStarted(oid);
  7709. if (traceStartStop)
  7710. CTXLOG("SPLIT %p: start %d child %d activeOutputs %d numOutputs %d numOriginalOutputs %d state %s", this, activityId, oid, activeOutputs, numOutputs, numOriginalOutputs, queryStateText(state));
  7711. if (state != STATEstarted)
  7712. {
  7713. if (state != STATEstarting)
  7714. initOutputs();
  7715. tailIdx = 0;
  7716. headIdx = 0;
  7717. error.clear();
  7718. try
  7719. {
  7720. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  7721. }
  7722. catch (IException *E)
  7723. {
  7724. #ifdef TRACE_SPLIT
  7725. CTXLOG("spill %d caught exception in start", activityId);
  7726. #endif
  7727. error.set(E);
  7728. throw;
  7729. }
  7730. catch (...)
  7731. {
  7732. IException *E = MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught in CRoxieServerThroughSpillActivity::start");
  7733. error.set(E);
  7734. throw E;
  7735. }
  7736. }
  7737. }
  7738. void stop(unsigned oid, unsigned idx, bool aborting)
  7739. {
  7740. // Note that OutputAdaptor code ensures that stop is not called more than once per adaptor
  7741. CriticalBlock b(crit);
  7742. #ifdef TRACE_STARTSTOP
  7743. if (traceStartStop)
  7744. {
  7745. CTXLOG("SPLIT %p: stop %d child %d activeOutputs %d numOutputs %d numOriginalOutputs %d state %s", this, activityId, oid, activeOutputs, numOutputs, numOriginalOutputs, queryStateText(state));
  7746. if (watchActivityId && watchActivityId==activityId)
  7747. {
  7748. CTXLOG("WATCH: stop %d", activityId);
  7749. }
  7750. }
  7751. #endif
  7752. if (state != STATEstarting && state != STATEstarted)
  7753. initOutputs();
  7754. if (activeOutputs > 1)
  7755. {
  7756. if (tailIdx==idx)
  7757. {
  7758. // Discard all buffered rows that are there purely for this adaptor to read them
  7759. unsigned min = minIndex(oid);
  7760. if (min != (unsigned) -1)
  7761. // what does -1 signify?? No-one wants anything? In which case can't we kill all rows??
  7762. // Should never happen though if there are still some active.
  7763. // there may be a small window where adaptors are blocked on the semaphore...
  7764. {
  7765. #ifdef TRACE_SPLIT
  7766. CTXLOG("%p: Discarding buffered rows from %d to %d for oid %x (%d outputs active)", this, idx, min, oid, activeOutputs);
  7767. #endif
  7768. while (tailIdx < min)
  7769. {
  7770. ReleaseRoxieRow(buffer.dequeue());
  7771. tailIdx++;
  7772. }
  7773. }
  7774. }
  7775. activeOutputs--;
  7776. return;
  7777. }
  7778. #ifdef TRACE_SPLIT
  7779. CTXLOG("%p: All outputs done", this);
  7780. #endif
  7781. activeOutputs = numOutputs;
  7782. CRoxieServerActivity::stop(aborting);
  7783. };
  7784. void reset(unsigned oid)
  7785. {
  7786. if (traceStartStop)
  7787. CTXLOG("SPLIT %p: reset %d child %d activeOutputs %d numOutputs %d numOriginalOutputs %d state %s", this, activityId, oid, activeOutputs, numOutputs, numOriginalOutputs, queryStateText(state));
  7788. activeOutputs = numOutputs;
  7789. while (buffer.ordinality())
  7790. ReleaseRoxieRow(buffer.dequeue());
  7791. error.clear();
  7792. if (state != STATEreset) // make sure input is only reset once
  7793. CRoxieServerActivity::reset();
  7794. };
  7795. virtual unsigned __int64 queryLocalCycles() const
  7796. {
  7797. return 0;
  7798. }
  7799. virtual const void *nextInGroup()
  7800. {
  7801. throwUnexpected(); // Internal logic error - we are not anybody's input
  7802. }
  7803. virtual IOutputMetaData * queryOutputMeta() const
  7804. {
  7805. // if (outputMeta)
  7806. // return outputMeta;
  7807. // else
  7808. return input->queryOutputMeta(); // not always known (e.g. disk write - though Gavin _could_ fill it in)
  7809. }
  7810. virtual IRoxieInput *queryOutput(unsigned idx)
  7811. {
  7812. if (idx==(unsigned)-1)
  7813. idx = nextFreeOutput(); // MORE - what is this used for?
  7814. assertex(idx < numOriginalOutputs);
  7815. assertex(!used[idx]);
  7816. used[idx] = true;
  7817. return &adaptors[idx];
  7818. }
  7819. virtual void resetOutputsUsed()
  7820. {
  7821. numOutputs = 1;
  7822. activeOutputs = 1;
  7823. // MORE RKC->GH should we be clearing the used array here? anywhere?
  7824. }
  7825. virtual void noteOutputUsed()
  7826. {
  7827. assertex(numOutputs < numOriginalOutputs);
  7828. numOutputs++;
  7829. activeOutputs = numOutputs;
  7830. }
  7831. virtual bool isPassThrough()
  7832. {
  7833. return numOutputs==1;
  7834. }
  7835. };
  7836. class CRoxieServerThroughSpillActivityFactory : public CRoxieServerMultiOutputFactory
  7837. {
  7838. public:
  7839. CRoxieServerThroughSpillActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  7840. : CRoxieServerMultiOutputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  7841. {
  7842. Owned<IHThorSpillArg> helper = (IHThorSpillArg *) helperFactory();
  7843. setNumOutputs(helper->getTempUsageCount() + 1);
  7844. }
  7845. CRoxieServerThroughSpillActivityFactory(IQueryFactory &_queryFactory, HelperFactory *_helperFactory, unsigned _numOutputs)
  7846. : CRoxieServerMultiOutputFactory(0, 0, _queryFactory, _helperFactory, TAKsplit)
  7847. {
  7848. setNumOutputs(_numOutputs);
  7849. }
  7850. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  7851. {
  7852. return new CRoxieServerThroughSpillActivity(this, _probeManager, numOutputs);
  7853. }
  7854. };
  7855. IRoxieServerActivityFactory *createRoxieServerThroughSpillActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  7856. {
  7857. return new CRoxieServerThroughSpillActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  7858. }
  7859. IRoxieServerActivityFactory *createRoxieServerThroughSpillActivityFactory(IQueryFactory &_queryFactory, HelperFactory *_factory, unsigned _numOutputs)
  7860. {
  7861. return new CRoxieServerThroughSpillActivityFactory(_queryFactory, _factory, _numOutputs);
  7862. }
  7863. //----------------------------------------------------------------------------------------------
  7864. class CRoxieServerSplitActivityFactory : public CRoxieServerMultiOutputFactory
  7865. {
  7866. public:
  7867. CRoxieServerSplitActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  7868. : CRoxieServerMultiOutputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  7869. {
  7870. Owned<IHThorSplitArg> helper = (IHThorSplitArg *) helperFactory();
  7871. setNumOutputs(helper->numBranches());
  7872. }
  7873. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  7874. {
  7875. return new CRoxieServerThroughSpillActivity(this, _probeManager, numOutputs);
  7876. }
  7877. };
  7878. IRoxieServerActivityFactory *createRoxieServerSplitActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  7879. {
  7880. return new CRoxieServerSplitActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  7881. }
  7882. //=====================================================================================================
  7883. #define PIPE_BUFSIZE 0x8000
  7884. static IException *createPipeFailureException(const char *cmd, unsigned retcode, IPipeProcess *pipe)
  7885. {
  7886. StringBuffer msg;
  7887. if(pipe->hasError())
  7888. {
  7889. try
  7890. {
  7891. char error[512];
  7892. size32_t sz = pipe->readError(sizeof(error), error);
  7893. if(sz && sz!=(size32_t)-1)
  7894. msg.append(", stderr: '").append(sz, error).append("'");
  7895. }
  7896. catch (IException *e)
  7897. {
  7898. EXCLOG(e, "Error reading pipe stderr");
  7899. e->Release();
  7900. }
  7901. }
  7902. return MakeStringException(ROXIE_PIPE_ERROR, "Pipe process %s returned error %u%s", cmd, retcode, msg.str());
  7903. }
  7904. class CRoxieServerPipeReadActivity : public CRoxieServerActivity
  7905. {
  7906. IHThorPipeReadArg &helper;
  7907. Owned<IPipeProcess> pipe;
  7908. StringAttr pipeCommand;
  7909. Owned<IOutputRowDeserializer> rowDeserializer;
  7910. Owned<IReadRowStream> readTransformer;
  7911. bool groupSignalled;
  7912. public:
  7913. CRoxieServerPipeReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  7914. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorPipeReadArg &)basehelper)
  7915. {
  7916. groupSignalled = true;
  7917. }
  7918. virtual bool needsAllocator() const { return true; }
  7919. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  7920. {
  7921. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  7922. rowDeserializer.setown(rowAllocator->createDiskDeserializer(ctx->queryCodeContext()));
  7923. }
  7924. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  7925. {
  7926. groupSignalled = true; // i.e. don't start with a NULL row
  7927. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  7928. if (!readTransformer)
  7929. {
  7930. OwnedRoxieString xmlIteratorPath(helper.getXmlIteratorPath());
  7931. readTransformer.setown(createReadRowStream(rowAllocator, rowDeserializer, helper.queryXmlTransformer(), helper.queryCsvTransformer(), xmlIteratorPath, helper.getPipeFlags()));
  7932. }
  7933. OwnedRoxieString pipeProgram(helper.getPipeProgram());
  7934. openPipe(pipeProgram);
  7935. }
  7936. virtual void stop(bool aborting)
  7937. {
  7938. CRoxieServerActivity::stop(aborting);
  7939. pipe.clear();
  7940. readTransformer->setStream(NULL);
  7941. }
  7942. virtual const void *nextInGroup()
  7943. {
  7944. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  7945. while (!waitForPipe())
  7946. {
  7947. if (!pipe)
  7948. return NULL;
  7949. if (helper.getPipeFlags() & TPFgroupeachrow)
  7950. {
  7951. if (!groupSignalled)
  7952. {
  7953. groupSignalled = true;
  7954. return NULL;
  7955. }
  7956. }
  7957. }
  7958. const void *ret = readTransformer->next();
  7959. assertex(ret != NULL); // if ret can ever be NULL then we need to recode this logic
  7960. processed++;
  7961. groupSignalled = false;
  7962. return ret;
  7963. }
  7964. protected:
  7965. bool waitForPipe()
  7966. {
  7967. if (!pipe)
  7968. return false; // done
  7969. if (!readTransformer->eos())
  7970. return true;
  7971. verifyPipe();
  7972. return false;
  7973. }
  7974. void openPipe(char const * cmd)
  7975. {
  7976. pipeCommand.setown(cmd);
  7977. pipe.setown(createPipeProcess());
  7978. if(!pipe->run(NULL, cmd, ".", false, true, true, 0x10000))
  7979. throw MakeStringException(ROXIE_PIPE_ERROR, "Could not run pipe process %s", cmd);
  7980. Owned<ISimpleReadStream> pipeReader = pipe->getOutputStream();
  7981. readTransformer->setStream(pipeReader.get());
  7982. }
  7983. void verifyPipe()
  7984. {
  7985. if (pipe)
  7986. {
  7987. unsigned err = pipe->wait();
  7988. if(err && !(helper.getPipeFlags() & TPFnofail))
  7989. {
  7990. throw createPipeFailureException(pipeCommand.get(), err, pipe);
  7991. }
  7992. pipe.clear();
  7993. }
  7994. }
  7995. };
  7996. class CRoxieServerPipeThroughActivity : public CRoxieServerActivity, implements IRecordPullerCallback
  7997. {
  7998. IHThorPipeThroughArg &helper;
  7999. RecordPullerThread puller;
  8000. Owned<IPipeProcess> pipe;
  8001. StringAttr pipeCommand;
  8002. InterruptableSemaphore pipeVerified;
  8003. InterruptableSemaphore pipeOpened;
  8004. CachedOutputMetaData inputMeta;
  8005. Owned<IOutputRowSerializer> rowSerializer;
  8006. Owned<IOutputRowDeserializer> rowDeserializer;
  8007. Owned<IPipeWriteXformHelper> writeTransformer;
  8008. Owned<IReadRowStream> readTransformer;
  8009. bool firstRead;
  8010. bool recreate;
  8011. bool inputExhausted;
  8012. bool groupSignalled;
  8013. public:
  8014. CRoxieServerPipeThroughActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  8015. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorPipeThroughArg &)basehelper), puller(false)
  8016. {
  8017. recreate = helper.recreateEachRow();
  8018. groupSignalled = true;
  8019. firstRead = false;
  8020. inputExhausted = false;
  8021. }
  8022. virtual bool needsAllocator() const { return true; }
  8023. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  8024. {
  8025. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  8026. rowSerializer.setown(inputMeta.createDiskSerializer(ctx->queryCodeContext(), activityId));
  8027. rowDeserializer.setown(rowAllocator->createDiskDeserializer(ctx->queryCodeContext()));
  8028. writeTransformer.setown(createPipeWriteXformHelper(helper.getPipeFlags(), helper.queryXmlOutput(), helper.queryCsvOutput(), rowSerializer));
  8029. }
  8030. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  8031. {
  8032. firstRead = true;
  8033. inputExhausted = false;
  8034. groupSignalled = true; // i.e. don't start with a NULL row
  8035. pipeVerified.reinit();
  8036. pipeOpened.reinit();
  8037. writeTransformer->ready();
  8038. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  8039. if (!readTransformer)
  8040. {
  8041. OwnedRoxieString xmlIterator(helper.getXmlIteratorPath());
  8042. readTransformer.setown(createReadRowStream(rowAllocator, rowDeserializer, helper.queryXmlTransformer(), helper.queryCsvTransformer(), xmlIterator, helper.getPipeFlags()));
  8043. }
  8044. if(!recreate)
  8045. {
  8046. OwnedRoxieString pipeProgram(helper.getPipeProgram());
  8047. openPipe(pipeProgram);
  8048. }
  8049. puller.start(parentExtractSize, parentExtract, paused, 0, false, ctx); // Pipe does not support preload presently - locks up
  8050. }
  8051. virtual void setInput(unsigned idx, IRoxieInput *_in)
  8052. {
  8053. if (idx)
  8054. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
  8055. puller.setInput(this, _in);
  8056. inputMeta.set(_in->queryOutputMeta());
  8057. }
  8058. virtual void stop(bool aborting)
  8059. {
  8060. pipeVerified.interrupt(NULL);
  8061. pipeOpened.interrupt(NULL);
  8062. puller.stop(aborting);
  8063. CRoxieServerActivity::stop(aborting);
  8064. pipe.clear();
  8065. readTransformer->setStream(NULL);
  8066. }
  8067. virtual void reset()
  8068. {
  8069. puller.reset();
  8070. CRoxieServerActivity::reset();
  8071. }
  8072. virtual const void *nextInGroup()
  8073. {
  8074. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  8075. while (!waitForPipe())
  8076. {
  8077. if (!pipe)
  8078. return NULL;
  8079. if (helper.getPipeFlags() & TPFgroupeachrow)
  8080. {
  8081. if (!groupSignalled)
  8082. {
  8083. groupSignalled = true;
  8084. return NULL;
  8085. }
  8086. }
  8087. }
  8088. const void *ret = readTransformer->next();
  8089. assertex(ret != NULL); // if ret can ever be NULL then we need to recode this logic
  8090. processed++;
  8091. groupSignalled = false;
  8092. return ret;
  8093. }
  8094. virtual void processRow(const void *row)
  8095. {
  8096. // called from puller thread
  8097. if(recreate)
  8098. openPipe(helper.getNameFromRow(row));
  8099. writeTransformer->writeTranslatedText(row, pipe);
  8100. ReleaseRoxieRow(row);
  8101. if(recreate)
  8102. {
  8103. closePipe();
  8104. pipeVerified.wait();
  8105. }
  8106. }
  8107. virtual void processDone()
  8108. {
  8109. // called from puller thread
  8110. if(recreate)
  8111. {
  8112. inputExhausted = true;
  8113. pipeOpened.signal();
  8114. }
  8115. else
  8116. {
  8117. closePipe();
  8118. pipeVerified.wait();
  8119. }
  8120. }
  8121. virtual void processEOG()
  8122. {
  8123. }
  8124. void processGroup(const ConstPointerArray &)
  8125. {
  8126. throwUnexpected();
  8127. }
  8128. virtual bool fireException(IException *e)
  8129. {
  8130. pipeOpened.interrupt(LINK(e));
  8131. pipeVerified.interrupt(e);
  8132. return true;
  8133. }
  8134. private:
  8135. bool waitForPipe()
  8136. {
  8137. if (firstRead)
  8138. {
  8139. pipeOpened.wait();
  8140. firstRead = false;
  8141. }
  8142. if (!pipe)
  8143. return false; // done
  8144. if (!readTransformer->eos())
  8145. return true;
  8146. verifyPipe();
  8147. if (recreate && !inputExhausted)
  8148. pipeOpened.wait();
  8149. return false;
  8150. }
  8151. void openPipe(char const * cmd)
  8152. {
  8153. pipeCommand.setown(cmd);
  8154. pipe.setown(createPipeProcess());
  8155. if(!pipe->run(NULL, cmd, ".", true, true, true, 0x10000))
  8156. throw MakeStringException(ROXIE_PIPE_ERROR, "Could not run pipe process %s", cmd);
  8157. writeTransformer->writeHeader(pipe);
  8158. Owned<ISimpleReadStream> pipeReader = pipe->getOutputStream();
  8159. readTransformer->setStream(pipeReader.get());
  8160. pipeOpened.signal();
  8161. }
  8162. void closePipe()
  8163. {
  8164. writeTransformer->writeFooter(pipe);
  8165. pipe->closeInput();
  8166. }
  8167. void verifyPipe()
  8168. {
  8169. if (pipe)
  8170. {
  8171. unsigned err = pipe->wait();
  8172. if(err && !(helper.getPipeFlags() & TPFnofail))
  8173. {
  8174. throw createPipeFailureException(pipeCommand.get(), err, pipe);
  8175. }
  8176. pipe.clear();
  8177. pipeVerified.signal();
  8178. }
  8179. }
  8180. };
  8181. class CRoxieServerPipeWriteActivity : public CRoxieServerInternalSinkActivity
  8182. {
  8183. IHThorPipeWriteArg &helper;
  8184. Owned<IPipeProcess> pipe;
  8185. StringAttr pipeCommand;
  8186. CachedOutputMetaData inputMeta;
  8187. Owned<IOutputRowSerializer> rowSerializer;
  8188. Owned<IPipeWriteXformHelper> writeTransformer;
  8189. bool firstRead;
  8190. bool recreate;
  8191. bool inputExhausted;
  8192. public:
  8193. CRoxieServerPipeWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numOutputs)
  8194. : CRoxieServerInternalSinkActivity(_factory, _probeManager, _numOutputs), helper((IHThorPipeWriteArg &)basehelper)
  8195. {
  8196. recreate = helper.recreateEachRow();
  8197. firstRead = false;
  8198. inputExhausted = false;
  8199. }
  8200. virtual bool needsAllocator() const { return true; }
  8201. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  8202. {
  8203. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  8204. inputMeta.set(input->queryOutputMeta());
  8205. rowSerializer.setown(inputMeta.createDiskSerializer(ctx->queryCodeContext(), activityId));
  8206. writeTransformer.setown(createPipeWriteXformHelper(helper.getPipeFlags(), helper.queryXmlOutput(), helper.queryCsvOutput(), rowSerializer));
  8207. }
  8208. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  8209. {
  8210. firstRead = true;
  8211. inputExhausted = false;
  8212. writeTransformer->ready();
  8213. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  8214. if(!recreate)
  8215. {
  8216. OwnedRoxieString pipeProgram(helper.getPipeProgram());
  8217. openPipe(pipeProgram);
  8218. }
  8219. }
  8220. virtual void stop(bool aborting)
  8221. {
  8222. CRoxieServerActivity::stop(aborting);
  8223. pipe.clear();
  8224. }
  8225. virtual void onExecute()
  8226. {
  8227. loop
  8228. {
  8229. const void *row = input->nextInGroup();
  8230. if (!row)
  8231. {
  8232. row = input->nextInGroup();
  8233. if (!row)
  8234. break;
  8235. }
  8236. processed++;
  8237. if(recreate)
  8238. openPipe(helper.getNameFromRow(row));
  8239. writeTransformer->writeTranslatedText(row, pipe);
  8240. ReleaseRoxieRow(row);
  8241. if(recreate)
  8242. closePipe();
  8243. }
  8244. closePipe();
  8245. }
  8246. private:
  8247. void openPipe(char const * cmd)
  8248. {
  8249. pipeCommand.setown(cmd);
  8250. pipe.setown(createPipeProcess());
  8251. if(!pipe->run(NULL, cmd, ".", true, false, true, 0x10000))
  8252. throw MakeStringException(ROXIE_PIPE_ERROR, "Could not run pipe process %s", cmd);
  8253. writeTransformer->writeHeader(pipe);
  8254. }
  8255. void closePipe()
  8256. {
  8257. writeTransformer->writeFooter(pipe);
  8258. pipe->closeInput();
  8259. unsigned err = pipe->wait();
  8260. if(err && !(helper.getPipeFlags() & TPFnofail))
  8261. {
  8262. throw createPipeFailureException(pipeCommand.get(), err, pipe);
  8263. }
  8264. pipe.clear();
  8265. }
  8266. };
  8267. class CRoxieServerPipeReadActivityFactory : public CRoxieServerActivityFactory
  8268. {
  8269. public:
  8270. CRoxieServerPipeReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8271. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  8272. {
  8273. }
  8274. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  8275. {
  8276. return new CRoxieServerPipeReadActivity(this, _probeManager);
  8277. }
  8278. };
  8279. class CRoxieServerPipeThroughActivityFactory : public CRoxieServerActivityFactory
  8280. {
  8281. public:
  8282. CRoxieServerPipeThroughActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8283. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  8284. {
  8285. }
  8286. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  8287. {
  8288. return new CRoxieServerPipeThroughActivity(this, _probeManager);
  8289. }
  8290. };
  8291. class CRoxieServerPipeWriteActivityFactory : public CRoxieServerInternalSinkFactory
  8292. {
  8293. public:
  8294. CRoxieServerPipeWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
  8295. : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot)
  8296. {
  8297. }
  8298. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  8299. {
  8300. return new CRoxieServerPipeWriteActivity(this, _probeManager, usageCount);
  8301. }
  8302. };
  8303. IRoxieServerActivityFactory *createRoxieServerPipeReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8304. {
  8305. return new CRoxieServerPipeReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  8306. }
  8307. IRoxieServerActivityFactory *createRoxieServerPipeThroughActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8308. {
  8309. return new CRoxieServerPipeThroughActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  8310. }
  8311. IRoxieServerActivityFactory *createRoxieServerPipeWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
  8312. {
  8313. return new CRoxieServerPipeWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot);
  8314. }
  8315. //=====================================================================================================
  8316. class CRoxieServerStreamedIteratorActivity : public CRoxieServerActivity
  8317. {
  8318. IHThorStreamedIteratorArg &helper;
  8319. Owned<IRowStream> rows;
  8320. public:
  8321. CRoxieServerStreamedIteratorActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  8322. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorStreamedIteratorArg &)basehelper)
  8323. {
  8324. }
  8325. ~CRoxieServerStreamedIteratorActivity()
  8326. {
  8327. }
  8328. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  8329. {
  8330. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  8331. rows.setown(helper.createInput());
  8332. }
  8333. virtual void stop(bool aborting)
  8334. {
  8335. if (rows)
  8336. {
  8337. rows->stop();
  8338. rows.clear();
  8339. }
  8340. CRoxieServerActivity::stop(aborting);
  8341. }
  8342. virtual const void *nextInGroup()
  8343. {
  8344. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  8345. assertex(rows != NULL);
  8346. const void * next = rows->nextRow();
  8347. if (next)
  8348. processed++;
  8349. return next;
  8350. }
  8351. };
  8352. class CRoxieServerStreamedIteratorActivityFactory : public CRoxieServerActivityFactory
  8353. {
  8354. public:
  8355. CRoxieServerStreamedIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8356. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  8357. {
  8358. }
  8359. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  8360. {
  8361. return new CRoxieServerStreamedIteratorActivity(this, _probeManager);
  8362. }
  8363. };
  8364. IRoxieServerActivityFactory *createRoxieServerStreamedIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8365. {
  8366. return new CRoxieServerStreamedIteratorActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  8367. }
  8368. //=====================================================================================================
  8369. class CRoxieServerFilterActivity : public CRoxieServerLateStartActivity
  8370. {
  8371. IHThorFilterArg &helper;
  8372. bool anyThisGroup;
  8373. IRangeCompare * stepCompare;
  8374. public:
  8375. CRoxieServerFilterActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  8376. : CRoxieServerLateStartActivity(_factory, _probeManager), helper((IHThorFilterArg &)basehelper)
  8377. {
  8378. anyThisGroup = false;
  8379. stepCompare = NULL;
  8380. }
  8381. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  8382. {
  8383. anyThisGroup = false;
  8384. CRoxieServerLateStartActivity::start(parentExtractSize, parentExtract, paused);
  8385. lateStart(parentExtractSize, parentExtract, helper.canMatchAny());
  8386. stepCompare = NULL;
  8387. if (!eof)
  8388. {
  8389. IInputSteppingMeta * stepMeta = input->querySteppingMeta();
  8390. if (stepMeta)
  8391. stepCompare = stepMeta->queryCompare();
  8392. }
  8393. }
  8394. virtual const void * nextInGroup()
  8395. {
  8396. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  8397. if (eof)
  8398. return NULL;
  8399. loop
  8400. {
  8401. const void * ret = input->nextInGroup();
  8402. if (!ret)
  8403. {
  8404. //stop returning two NULLs in a row.
  8405. if (anyThisGroup)
  8406. {
  8407. anyThisGroup = false;
  8408. return NULL;
  8409. }
  8410. ret = input->nextInGroup();
  8411. if (!ret)
  8412. {
  8413. eof = true;
  8414. return NULL; // eof...
  8415. }
  8416. }
  8417. if (helper.isValid(ret))
  8418. {
  8419. anyThisGroup = true;
  8420. processed++;
  8421. return ret;
  8422. }
  8423. ReleaseRoxieRow(ret);
  8424. }
  8425. }
  8426. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  8427. {
  8428. //Could assert that this isn't grouped
  8429. // MORE - will need rethinking once we rethink the nextSteppedGE interface for global smart-stepping.
  8430. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  8431. if (eof)
  8432. return NULL;
  8433. loop
  8434. {
  8435. const void * ret = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  8436. if (!ret)
  8437. {
  8438. eof = true;
  8439. return NULL;
  8440. }
  8441. if (!wasCompleteMatch)
  8442. {
  8443. anyThisGroup = false; // RKC->GH - is this right??
  8444. return ret;
  8445. }
  8446. if (helper.isValid(ret))
  8447. {
  8448. anyThisGroup = true;
  8449. processed++;
  8450. return ret;
  8451. }
  8452. if (!stepExtra.returnMismatches())
  8453. {
  8454. ReleaseRoxieRow(ret);
  8455. return nextInGroup();
  8456. }
  8457. //If asked to return mismatches we are only interested in mismatches that will force the stepped
  8458. //condition to advance
  8459. if (stepCompare->docompare(ret, seek, numFields) != 0)
  8460. {
  8461. wasCompleteMatch = false;
  8462. anyThisGroup = false; // WHY?
  8463. return ret;
  8464. }
  8465. ReleaseRoxieRow(ret);
  8466. }
  8467. }
  8468. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  8469. {
  8470. return input->gatherConjunctions(collector);
  8471. }
  8472. virtual void resetEOF()
  8473. {
  8474. eof = prefiltered;
  8475. anyThisGroup = false;
  8476. input->resetEOF();
  8477. }
  8478. IInputSteppingMeta * querySteppingMeta()
  8479. {
  8480. return input->querySteppingMeta();
  8481. }
  8482. };
  8483. class CRoxieServerFilterActivityFactory : public CRoxieServerActivityFactory
  8484. {
  8485. public:
  8486. CRoxieServerFilterActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8487. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  8488. {
  8489. }
  8490. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  8491. {
  8492. return new CRoxieServerFilterActivity(this, _probeManager);
  8493. }
  8494. };
  8495. IRoxieServerActivityFactory *createRoxieServerFilterActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8496. {
  8497. return new CRoxieServerFilterActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  8498. }
  8499. //=====================================================================================================
  8500. class CRoxieServerFilterGroupActivity : public CRoxieServerLateStartActivity
  8501. {
  8502. IHThorFilterGroupArg &helper;
  8503. unsigned curIndex;
  8504. ConstPointerArray gathered;
  8505. IRangeCompare * stepCompare;
  8506. public:
  8507. CRoxieServerFilterGroupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  8508. : CRoxieServerLateStartActivity(_factory, _probeManager), helper((IHThorFilterGroupArg &)basehelper)
  8509. {
  8510. curIndex = 0;
  8511. stepCompare = NULL;
  8512. }
  8513. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  8514. {
  8515. CRoxieServerLateStartActivity::start(parentExtractSize, parentExtract, paused);
  8516. lateStart(parentExtractSize, parentExtract, helper.canMatchAny());//sets eof
  8517. assertex(eof == !helper.canMatchAny());
  8518. curIndex = 0;
  8519. stepCompare = NULL;
  8520. if (!eof)
  8521. {
  8522. IInputSteppingMeta * inputStepping = input->querySteppingMeta();
  8523. if (inputStepping)
  8524. stepCompare = inputStepping->queryCompare();
  8525. }
  8526. }
  8527. virtual void reset()
  8528. {
  8529. releaseGathered();
  8530. CRoxieServerLateStartActivity::reset();
  8531. }
  8532. inline void releaseGathered()
  8533. {
  8534. while (gathered.isItem(curIndex))
  8535. ReleaseRoxieRow(gathered.item(curIndex++));
  8536. gathered.kill();
  8537. }
  8538. virtual const void * nextInGroup()
  8539. {
  8540. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  8541. loop
  8542. {
  8543. if (eof)
  8544. return NULL;
  8545. if (gathered.ordinality())
  8546. {
  8547. if (gathered.isItem(curIndex))
  8548. {
  8549. const void * ret = gathered.item(curIndex++);
  8550. processed++;
  8551. return ret;
  8552. }
  8553. curIndex = 0;
  8554. gathered.kill();
  8555. return NULL;
  8556. }
  8557. const void * ret = input->nextInGroup();
  8558. while (ret)
  8559. {
  8560. gathered.append(ret);
  8561. ret = input->nextInGroup();
  8562. }
  8563. unsigned num = gathered.ordinality();
  8564. if (num != 0)
  8565. {
  8566. if (!helper.isValid(num, (const void * *)gathered.getArray()))
  8567. ReleaseRoxieRowSet(gathered); // read next group
  8568. }
  8569. else
  8570. eof = true;
  8571. }
  8572. }
  8573. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  8574. {
  8575. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  8576. if (eof)
  8577. return NULL;
  8578. if (gathered.ordinality())
  8579. {
  8580. while (gathered.isItem(curIndex))
  8581. {
  8582. const void * ret = gathered.item(curIndex++);
  8583. if (stepCompare->docompare(ret, seek, numFields) >= 0)
  8584. {
  8585. processed++;
  8586. return ret;
  8587. }
  8588. ReleaseRoxieRow(ret);
  8589. }
  8590. curIndex = 0;
  8591. gathered.kill();
  8592. //nextSteppedGE never returns an end of group marker.
  8593. }
  8594. //Not completely sure about this - it could lead the the start of a group being skipped,
  8595. //so the group filter could potentially work on a different group. If so, we'd need to check the
  8596. //next fields were a subset of the grouping fields - more an issue for the group activity.
  8597. //MORE: What do we do with wasCompleteMatch? something like the following????
  8598. #if 0
  8599. loop
  8600. {
  8601. const void * ret;
  8602. if (stepExtra.returnMismatches())
  8603. {
  8604. bool matchedCompletely = true;
  8605. ret = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  8606. if (!wasCompleteMatch)
  8607. return ret;
  8608. }
  8609. else
  8610. ret = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  8611. #endif
  8612. const void * ret = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  8613. while (ret)
  8614. {
  8615. gathered.append(ret);
  8616. ret = input->nextInGroup();
  8617. }
  8618. unsigned num = gathered.ordinality();
  8619. if (num != 0)
  8620. {
  8621. if (!helper.isValid(num, (const void * *)gathered.getArray()))
  8622. ReleaseRoxieRowSet(gathered); // read next group
  8623. }
  8624. else
  8625. eof = true;
  8626. return nextUngrouped(this);
  8627. }
  8628. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  8629. {
  8630. return input->gatherConjunctions(collector);
  8631. }
  8632. virtual void resetEOF()
  8633. {
  8634. eof = false;
  8635. releaseGathered();
  8636. input->resetEOF();
  8637. }
  8638. IInputSteppingMeta * querySteppingMeta()
  8639. {
  8640. return input->querySteppingMeta();
  8641. }
  8642. };
  8643. class CRoxieServerFilterGroupActivityFactory : public CRoxieServerActivityFactory
  8644. {
  8645. public:
  8646. CRoxieServerFilterGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8647. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  8648. {
  8649. }
  8650. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  8651. {
  8652. return new CRoxieServerFilterGroupActivity(this, _probeManager);
  8653. }
  8654. };
  8655. IRoxieServerActivityFactory *createRoxieServerFilterGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8656. {
  8657. return new CRoxieServerFilterGroupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  8658. }
  8659. //=================================================================================
  8660. class CRoxieServerSideEffectActivity : public CRoxieServerActivity
  8661. {
  8662. IHThorSideEffectArg &helper;
  8663. CriticalSection ecrit;
  8664. Owned<IException> exception;
  8665. bool executed;
  8666. public:
  8667. CRoxieServerSideEffectActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  8668. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorSideEffectArg &)basehelper)
  8669. {
  8670. executed = false;
  8671. }
  8672. virtual const void * nextInGroup()
  8673. {
  8674. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  8675. CriticalBlock b(ecrit);
  8676. if (exception)
  8677. throw(exception.getLink());
  8678. if (!executed)
  8679. {
  8680. try
  8681. {
  8682. executed = true;
  8683. helper.action();
  8684. }
  8685. catch(IException *E)
  8686. {
  8687. exception.set(E);
  8688. throw;
  8689. }
  8690. }
  8691. return NULL;
  8692. }
  8693. virtual void execute(unsigned parentExtractSize, const byte * parentExtract)
  8694. {
  8695. CriticalBlock b(ecrit);
  8696. if (exception)
  8697. throw(exception.getLink());
  8698. if (!executed)
  8699. {
  8700. try
  8701. {
  8702. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  8703. executed = true;
  8704. start(parentExtractSize, parentExtract, false);
  8705. helper.action();
  8706. stop(false);
  8707. }
  8708. catch(IException *E)
  8709. {
  8710. ctx->notifyAbort(E);
  8711. stop(true);
  8712. exception.set(E);
  8713. throw;
  8714. }
  8715. }
  8716. }
  8717. virtual void reset()
  8718. {
  8719. executed = false;
  8720. exception.clear();
  8721. CRoxieServerActivity::reset();
  8722. }
  8723. };
  8724. class CRoxieServerSideEffectActivityFactory : public CRoxieServerActivityFactory
  8725. {
  8726. bool isRoot;
  8727. public:
  8728. CRoxieServerSideEffectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  8729. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
  8730. {
  8731. }
  8732. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  8733. {
  8734. return new CRoxieServerSideEffectActivity(this, _probeManager);
  8735. }
  8736. virtual bool isSink() const
  8737. {
  8738. return isRoot && !meta.queryOriginal();
  8739. }
  8740. };
  8741. IRoxieServerActivityFactory *createRoxieServerSideEffectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  8742. {
  8743. return new CRoxieServerSideEffectActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
  8744. }
  8745. //=================================================================================
  8746. class CRoxieServerActionActivity : public CRoxieServerInternalSinkActivity
  8747. {
  8748. IHThorActionArg &helper;
  8749. public:
  8750. CRoxieServerActionActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numOutputs)
  8751. : CRoxieServerInternalSinkActivity(_factory, _probeManager, _numOutputs), helper((IHThorActionArg &)basehelper)
  8752. {
  8753. }
  8754. virtual void onExecute()
  8755. {
  8756. helper.action();
  8757. }
  8758. };
  8759. class CRoxieServerActionActivityFactory : public CRoxieServerInternalSinkFactory
  8760. {
  8761. public:
  8762. CRoxieServerActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
  8763. : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot)
  8764. {
  8765. }
  8766. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  8767. {
  8768. return new CRoxieServerActionActivity(this, _probeManager, usageCount);
  8769. }
  8770. };
  8771. IRoxieServerActivityFactory *createRoxieServerActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
  8772. {
  8773. return new CRoxieServerActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot);
  8774. }
  8775. //=================================================================================
  8776. class CRoxieServerSampleActivity : public CRoxieServerActivity
  8777. {
  8778. IHThorSampleArg &helper;
  8779. unsigned numSamples;
  8780. unsigned numToSkip;
  8781. unsigned whichSample;
  8782. bool anyThisGroup;
  8783. bool eof;
  8784. public:
  8785. CRoxieServerSampleActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  8786. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorSampleArg &)basehelper)
  8787. {
  8788. numSamples = 0;
  8789. numToSkip = 0;
  8790. whichSample = 0;
  8791. anyThisGroup = false;
  8792. eof = false;
  8793. }
  8794. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  8795. {
  8796. anyThisGroup = false;
  8797. eof = false;
  8798. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  8799. numSamples = helper.getProportion();
  8800. whichSample = helper.getSampleNumber();
  8801. numToSkip = (whichSample ? whichSample-1 : 0);
  8802. }
  8803. virtual const void * nextInGroup()
  8804. {
  8805. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  8806. if (eof)
  8807. return NULL;
  8808. loop
  8809. {
  8810. const void * ret = input->nextInGroup();
  8811. if (!ret)
  8812. {
  8813. //this does work with groups - may or may not be useful...
  8814. //reset the sample for each group.... probably best.
  8815. numToSkip = (whichSample ? whichSample-1 : 0);
  8816. if (anyThisGroup)
  8817. {
  8818. anyThisGroup = false;
  8819. return NULL;
  8820. }
  8821. ret = input->nextInGroup();
  8822. if (!ret)
  8823. {
  8824. eof = true;
  8825. return NULL; // eof...
  8826. }
  8827. }
  8828. if (numToSkip == 0)
  8829. {
  8830. anyThisGroup = true;
  8831. numToSkip = numSamples-1;
  8832. processed++;
  8833. return ret;
  8834. }
  8835. numToSkip--;
  8836. ReleaseRoxieRow(ret);
  8837. }
  8838. }
  8839. };
  8840. class CRoxieServerSampleActivityFactory : public CRoxieServerActivityFactory
  8841. {
  8842. public:
  8843. CRoxieServerSampleActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8844. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  8845. {
  8846. }
  8847. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  8848. {
  8849. return new CRoxieServerSampleActivity(this, _probeManager);
  8850. }
  8851. };
  8852. IRoxieServerActivityFactory *createRoxieServerSampleActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8853. {
  8854. return new CRoxieServerSampleActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  8855. }
  8856. //=================================================================================
  8857. class CRoxieServerChooseSetsActivity : public CRoxieServerActivity
  8858. {
  8859. IHThorChooseSetsArg &helper;
  8860. unsigned numSets;
  8861. unsigned * setCounts;
  8862. bool done;
  8863. public:
  8864. CRoxieServerChooseSetsActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  8865. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorChooseSetsArg &)basehelper)
  8866. {
  8867. setCounts = NULL;
  8868. numSets = 0;
  8869. done = false;
  8870. }
  8871. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  8872. {
  8873. done = false;
  8874. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  8875. numSets = helper.getNumSets();
  8876. setCounts = new unsigned[numSets];
  8877. memset(setCounts, 0, sizeof(unsigned)*numSets);
  8878. helper.setCounts(setCounts);
  8879. }
  8880. virtual void reset()
  8881. {
  8882. delete [] setCounts;
  8883. setCounts = NULL;
  8884. CRoxieServerActivity::reset();
  8885. }
  8886. virtual const void * nextInGroup()
  8887. {
  8888. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  8889. if (done)
  8890. return NULL;
  8891. loop
  8892. {
  8893. const void * ret = input->nextInGroup();
  8894. if (!ret)
  8895. {
  8896. ret = input->nextInGroup();
  8897. if (!ret)
  8898. {
  8899. done = true;
  8900. return NULL;
  8901. }
  8902. }
  8903. processed++;
  8904. switch (helper.getRecordAction(ret))
  8905. {
  8906. case 2:
  8907. done = true;
  8908. return ret;
  8909. case 1:
  8910. return ret;
  8911. }
  8912. ReleaseRoxieRow(ret);
  8913. }
  8914. }
  8915. };
  8916. class CRoxieServerChooseSetsActivityFactory : public CRoxieServerActivityFactory
  8917. {
  8918. public:
  8919. CRoxieServerChooseSetsActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8920. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  8921. {
  8922. }
  8923. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  8924. {
  8925. return new CRoxieServerChooseSetsActivity(this, _probeManager);
  8926. }
  8927. };
  8928. IRoxieServerActivityFactory *createRoxieServerChooseSetsActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8929. {
  8930. return new CRoxieServerChooseSetsActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  8931. }
  8932. //=================================================================================
  8933. class CRoxieServerChooseSetsExActivity : public CRoxieServerActivity
  8934. {
  8935. protected:
  8936. IHThorChooseSetsExArg &helper;
  8937. unsigned numSets;
  8938. unsigned curIndex;
  8939. unsigned * setCounts;
  8940. count_t * limits;
  8941. bool done;
  8942. ConstPointerArray gathered;
  8943. virtual bool includeRow(const void * row) = 0;
  8944. virtual void calculateSelection() = 0;
  8945. public:
  8946. CRoxieServerChooseSetsExActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  8947. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorChooseSetsExArg &)basehelper)
  8948. {
  8949. setCounts = NULL;
  8950. limits = NULL;
  8951. done = false;
  8952. curIndex = 0;
  8953. numSets = 0;
  8954. }
  8955. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  8956. {
  8957. done = false;
  8958. curIndex = 0;
  8959. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  8960. numSets = helper.getNumSets();
  8961. setCounts = new unsigned[numSets];
  8962. memset(setCounts, 0, sizeof(unsigned)*numSets);
  8963. limits = (count_t *)calloc(sizeof(count_t), numSets);
  8964. helper.getLimits(limits);
  8965. }
  8966. virtual void reset()
  8967. {
  8968. delete [] setCounts;
  8969. setCounts = NULL;
  8970. free(limits);
  8971. limits = NULL;
  8972. while (gathered.isItem(curIndex))
  8973. ReleaseRoxieRow(gathered.item(curIndex++));
  8974. gathered.kill();
  8975. CRoxieServerActivity::reset();
  8976. }
  8977. virtual const void * nextInGroup()
  8978. {
  8979. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  8980. if (gathered.ordinality() == 0)
  8981. {
  8982. curIndex = 0;
  8983. if (!input->nextGroup(gathered))
  8984. {
  8985. done = true;
  8986. return NULL;
  8987. }
  8988. ForEachItemIn(idx1, gathered)
  8989. {
  8990. unsigned category = helper.getCategory(gathered.item(idx1));
  8991. if (category)
  8992. setCounts[category-1]++;
  8993. }
  8994. calculateSelection();
  8995. }
  8996. while (gathered.isItem(curIndex))
  8997. {
  8998. const void * row = gathered.item(curIndex);
  8999. gathered.replace(NULL, curIndex);
  9000. curIndex++;
  9001. if (includeRow(row))
  9002. {
  9003. processed++;
  9004. return row;
  9005. }
  9006. ReleaseRoxieRow(row);
  9007. }
  9008. gathered.kill();
  9009. return NULL;
  9010. }
  9011. };
  9012. class CRoxieServerChooseSetsLastActivity : public CRoxieServerChooseSetsExActivity
  9013. {
  9014. unsigned * numToSkip;
  9015. public:
  9016. CRoxieServerChooseSetsLastActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager) : CRoxieServerChooseSetsExActivity(_factory, _probeManager)
  9017. {
  9018. numToSkip = NULL;
  9019. }
  9020. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9021. {
  9022. CRoxieServerChooseSetsExActivity::start(parentExtractSize, parentExtract, paused);
  9023. numToSkip = (unsigned *)calloc(sizeof(unsigned), numSets);
  9024. }
  9025. virtual void reset()
  9026. {
  9027. free(numToSkip);
  9028. numToSkip = NULL;
  9029. CRoxieServerChooseSetsExActivity::reset();
  9030. }
  9031. protected:
  9032. virtual void calculateSelection()
  9033. {
  9034. for (unsigned idx=0; idx < numSets; idx++)
  9035. {
  9036. if (setCounts[idx] < limits[idx])
  9037. numToSkip[idx] = 0;
  9038. else
  9039. numToSkip[idx] = (unsigned)(setCounts[idx] - limits[idx]);
  9040. }
  9041. }
  9042. virtual bool includeRow(const void * row)
  9043. {
  9044. unsigned category = helper.getCategory(row);
  9045. if (category)
  9046. {
  9047. if (numToSkip[category-1] == 0)
  9048. return true;
  9049. numToSkip[category-1]--;
  9050. }
  9051. return false;
  9052. }
  9053. };
  9054. class CRoxieServerChooseSetsEnthActivity : public CRoxieServerChooseSetsExActivity
  9055. {
  9056. count_t * counter;
  9057. public:
  9058. CRoxieServerChooseSetsEnthActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager) : CRoxieServerChooseSetsExActivity(_factory, _probeManager)
  9059. {
  9060. counter = NULL;
  9061. }
  9062. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9063. {
  9064. CRoxieServerChooseSetsExActivity::start(parentExtractSize, parentExtract, paused);
  9065. counter = (count_t *)calloc(sizeof(count_t), numSets);
  9066. }
  9067. virtual void reset()
  9068. {
  9069. free(counter);
  9070. counter = NULL;
  9071. CRoxieServerChooseSetsExActivity::reset();
  9072. }
  9073. protected:
  9074. virtual void calculateSelection()
  9075. {
  9076. }
  9077. virtual bool includeRow(const void * row)
  9078. {
  9079. unsigned category = helper.getCategory(row);
  9080. if (category)
  9081. {
  9082. assertex(category <= numSets);
  9083. counter[category-1] += limits[category-1];
  9084. if(counter[category-1] >= setCounts[category-1])
  9085. {
  9086. counter[category-1] -= setCounts[category-1];
  9087. return true;
  9088. }
  9089. }
  9090. return false;
  9091. }
  9092. };
  9093. class CRoxieServerChooseSetsEnthActivityFactory : public CRoxieServerActivityFactory
  9094. {
  9095. public:
  9096. CRoxieServerChooseSetsEnthActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  9097. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  9098. {
  9099. }
  9100. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  9101. {
  9102. return new CRoxieServerChooseSetsEnthActivity(this, _probeManager);
  9103. }
  9104. };
  9105. IRoxieServerActivityFactory *createRoxieServerChooseSetsEnthActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  9106. {
  9107. return new CRoxieServerChooseSetsEnthActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  9108. }
  9109. class CRoxieServerChooseSetsLastActivityFactory : public CRoxieServerActivityFactory
  9110. {
  9111. public:
  9112. CRoxieServerChooseSetsLastActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  9113. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  9114. {
  9115. }
  9116. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  9117. {
  9118. return new CRoxieServerChooseSetsLastActivity(this, _probeManager);
  9119. }
  9120. };
  9121. IRoxieServerActivityFactory *createRoxieServerChooseSetsLastActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  9122. {
  9123. return new CRoxieServerChooseSetsLastActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  9124. }
  9125. //=================================================================================
  9126. class CRoxieServerEnthActivity : public CRoxieServerActivity
  9127. {
  9128. IHThorEnthArg &helper;
  9129. unsigned __int64 numerator;
  9130. unsigned __int64 denominator;
  9131. unsigned __int64 counter;
  9132. bool eof;
  9133. public:
  9134. CRoxieServerEnthActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  9135. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorEnthArg &)basehelper)
  9136. {
  9137. eof = false;
  9138. numerator = denominator = counter = 0;
  9139. }
  9140. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9141. {
  9142. eof = false;
  9143. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  9144. numerator = helper.getProportionNumerator();
  9145. denominator = helper.getProportionDenominator();
  9146. if(denominator == 0) denominator = 1; //MORE: simplest way to avoid disaster in this case
  9147. counter = (helper.getSampleNumber()-1) * greatestCommonDivisor(numerator, denominator);
  9148. if (counter >= denominator)
  9149. counter %= denominator;
  9150. }
  9151. inline bool wanted()
  9152. {
  9153. counter += numerator;
  9154. if(counter >= denominator)
  9155. {
  9156. counter -= denominator;
  9157. return true;
  9158. }
  9159. return false;
  9160. }
  9161. virtual const void * nextInGroup()
  9162. {
  9163. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  9164. if (eof)
  9165. return NULL;
  9166. const void * ret;
  9167. loop
  9168. {
  9169. ret = input->nextInGroup();
  9170. if(!ret) //end of group
  9171. ret = input->nextInGroup();
  9172. if(!ret) //eof
  9173. {
  9174. eof = true;
  9175. return ret;
  9176. }
  9177. if (wanted())
  9178. return ret;
  9179. ReleaseRoxieRow(ret);
  9180. }
  9181. }
  9182. };
  9183. class CRoxieServerEnthActivityFactory : public CRoxieServerActivityFactory
  9184. {
  9185. public:
  9186. CRoxieServerEnthActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  9187. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  9188. {
  9189. }
  9190. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  9191. {
  9192. return new CRoxieServerEnthActivity(this, _probeManager);
  9193. }
  9194. };
  9195. IRoxieServerActivityFactory *createRoxieServerEnthActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  9196. {
  9197. return new CRoxieServerEnthActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  9198. }
  9199. //=================================================================================
  9200. class CRoxieServerAggregateActivity : public CRoxieServerActivity
  9201. {
  9202. IHThorAggregateArg &helper;
  9203. bool eof;
  9204. bool isInputGrouped;
  9205. bool abortEarly;
  9206. public:
  9207. CRoxieServerAggregateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  9208. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorAggregateArg &)basehelper)
  9209. {
  9210. eof = false;
  9211. isInputGrouped = false;
  9212. abortEarly = false;
  9213. }
  9214. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9215. {
  9216. eof = false;
  9217. isInputGrouped = input->queryOutputMeta()->isGrouped(); // could be done earlier, in setInput?
  9218. abortEarly = !isInputGrouped && (factory->getKind() == TAKexistsaggregate); // ditto
  9219. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  9220. }
  9221. virtual bool needsAllocator() const { return true; }
  9222. virtual const void * nextInGroup()
  9223. {
  9224. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  9225. if (eof)
  9226. return NULL;
  9227. const void * next = input->nextInGroup();
  9228. if (!next && isInputGrouped)
  9229. {
  9230. eof = true;
  9231. return NULL;
  9232. }
  9233. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  9234. size32_t finalSize = helper.clearAggregate(rowBuilder);
  9235. if (next)
  9236. {
  9237. finalSize = helper.processFirst(rowBuilder, next);
  9238. ReleaseRoxieRow(next);
  9239. if (!abortEarly)
  9240. {
  9241. loop
  9242. {
  9243. next = input->nextInGroup();
  9244. if (!next)
  9245. break;
  9246. finalSize = helper.processNext(rowBuilder, next);
  9247. ReleaseRoxieRow(next);
  9248. }
  9249. }
  9250. }
  9251. if (!isInputGrouped) // either read all, or aborted early
  9252. eof = true;
  9253. processed++;
  9254. return rowBuilder.finalizeRowClear(finalSize);
  9255. }
  9256. };
  9257. class CRoxieServerAggregateActivityFactory : public CRoxieServerActivityFactory
  9258. {
  9259. public:
  9260. CRoxieServerAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  9261. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  9262. {
  9263. }
  9264. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  9265. {
  9266. return new CRoxieServerAggregateActivity(this, _probeManager);
  9267. }
  9268. };
  9269. IRoxieServerActivityFactory *createRoxieServerAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  9270. {
  9271. return new CRoxieServerAggregateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  9272. }
  9273. //=================================================================================
  9274. typedef unsigned t_hashPrefix;
  9275. class CRoxieServerHashAggregateActivity : public CRoxieServerActivity
  9276. {
  9277. IHThorHashAggregateArg &helper;
  9278. RowAggregator aggregated;
  9279. bool eof;
  9280. bool gathered;
  9281. bool isGroupedAggregate;
  9282. public:
  9283. CRoxieServerHashAggregateActivity(const IRoxieServerActivityFactory *_factory, bool _isGroupedAggregate, IProbeManager *_probeManager)
  9284. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorHashAggregateArg &)basehelper),
  9285. isGroupedAggregate(_isGroupedAggregate),
  9286. aggregated(helper, helper)
  9287. {
  9288. eof = false;
  9289. gathered = false;
  9290. }
  9291. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9292. {
  9293. eof = false;
  9294. gathered = false;
  9295. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  9296. }
  9297. virtual void reset()
  9298. {
  9299. aggregated.reset();
  9300. CRoxieServerActivity::reset();
  9301. }
  9302. virtual bool needsAllocator() const { return true; }
  9303. virtual const void * nextInGroup()
  9304. {
  9305. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  9306. if (eof)
  9307. return NULL;
  9308. if (!gathered)
  9309. {
  9310. aggregated.start(rowAllocator);
  9311. bool eog = true;
  9312. loop
  9313. {
  9314. const void * next = input->nextInGroup();
  9315. if (!next)
  9316. {
  9317. if (isGroupedAggregate)
  9318. {
  9319. if (eog)
  9320. eof = true;
  9321. break;
  9322. }
  9323. next = input->nextInGroup();
  9324. if (!next)
  9325. break;
  9326. }
  9327. eog = false;
  9328. aggregated.addRow(next);
  9329. ReleaseRoxieRow(next);
  9330. }
  9331. gathered = true;
  9332. }
  9333. Owned<AggregateRowBuilder> next = aggregated.nextResult();
  9334. if (next)
  9335. {
  9336. processed++;
  9337. return next->finalizeRowClear();
  9338. }
  9339. if (!isGroupedAggregate)
  9340. eof = true;
  9341. aggregated.reset();
  9342. gathered = false;
  9343. return NULL;
  9344. }
  9345. };
  9346. class CRoxieServerHashAggregateActivityFactory : public CRoxieServerActivityFactory
  9347. {
  9348. public:
  9349. CRoxieServerHashAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  9350. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  9351. {
  9352. isGroupedAggregate = _graphNode.getPropBool("att[@name='grouped']/@value");
  9353. }
  9354. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  9355. {
  9356. return new CRoxieServerHashAggregateActivity(this, isGroupedAggregate, _probeManager);
  9357. }
  9358. protected:
  9359. bool isGroupedAggregate;
  9360. };
  9361. IRoxieServerActivityFactory *createRoxieServerHashAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  9362. {
  9363. return new CRoxieServerHashAggregateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  9364. }
  9365. //=================================================================================
  9366. class CRoxieServerDegroupActivity : public CRoxieServerActivity
  9367. {
  9368. IHThorDegroupArg &helper;
  9369. bool eof;
  9370. public:
  9371. CRoxieServerDegroupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  9372. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorDegroupArg &)basehelper)
  9373. {
  9374. eof = false;
  9375. }
  9376. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9377. {
  9378. eof = false;
  9379. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  9380. }
  9381. virtual const void * nextInGroup()
  9382. {
  9383. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  9384. if (eof)
  9385. return NULL;
  9386. const void * ret = input->nextInGroup();
  9387. if (!ret)
  9388. ret = input->nextInGroup();
  9389. if (ret)
  9390. processed++;
  9391. else
  9392. eof = true;
  9393. return ret;
  9394. }
  9395. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  9396. {
  9397. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  9398. if (eof)
  9399. return NULL;
  9400. const void * ret = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  9401. if (ret)
  9402. processed++;
  9403. else
  9404. eof = true;
  9405. return ret;
  9406. }
  9407. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  9408. {
  9409. return input->gatherConjunctions(collector);
  9410. }
  9411. virtual void resetEOF()
  9412. {
  9413. eof = false;
  9414. input->resetEOF();
  9415. }
  9416. IInputSteppingMeta * querySteppingMeta()
  9417. {
  9418. return input->querySteppingMeta();
  9419. }
  9420. };
  9421. class CRoxieServerDegroupActivityFactory : public CRoxieServerActivityFactory
  9422. {
  9423. public:
  9424. CRoxieServerDegroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  9425. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  9426. {
  9427. }
  9428. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  9429. {
  9430. return new CRoxieServerDegroupActivity(this, _probeManager);
  9431. }
  9432. };
  9433. IRoxieServerActivityFactory *createRoxieServerDegroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  9434. {
  9435. return new CRoxieServerDegroupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  9436. }
  9437. //=================================================================================
  9438. class CRoxieServerSpillReadActivity : public CRoxieServerActivity
  9439. {
  9440. IHThorDiskReadArg &helper;
  9441. bool needTransform;
  9442. bool eof;
  9443. bool anyThisGroup;
  9444. unsigned __int64 rowLimit;
  9445. unsigned __int64 choosenLimit;
  9446. public:
  9447. CRoxieServerSpillReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  9448. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorDiskReadArg &)basehelper)
  9449. {
  9450. needTransform = helper.needTransform();
  9451. rowLimit = (unsigned __int64) -1;
  9452. choosenLimit = 0;
  9453. eof = false;
  9454. anyThisGroup = false;
  9455. }
  9456. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9457. {
  9458. anyThisGroup = false;
  9459. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  9460. if (helper.canMatchAny())
  9461. eof = false;
  9462. else
  9463. eof = true;
  9464. choosenLimit = helper.getChooseNLimit();
  9465. rowLimit = helper.getRowLimit();
  9466. helper.setCallback(NULL); // members should not be called - change if they are
  9467. }
  9468. virtual bool needsAllocator() const { return true; }
  9469. virtual const void * nextInGroup()
  9470. {
  9471. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  9472. if (eof)
  9473. return NULL;
  9474. if (processed==choosenLimit)
  9475. {
  9476. eof = true;
  9477. return NULL;
  9478. }
  9479. if (needTransform)
  9480. {
  9481. loop
  9482. {
  9483. const void *in = input->nextInGroup();
  9484. if (!in)
  9485. {
  9486. if (anyThisGroup)
  9487. {
  9488. anyThisGroup = false;
  9489. return NULL;
  9490. }
  9491. in = input->nextInGroup();
  9492. if (!in)
  9493. {
  9494. eof = true;
  9495. return NULL; // eof...
  9496. }
  9497. }
  9498. unsigned outSize;
  9499. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  9500. try
  9501. {
  9502. outSize = helper.transform(rowBuilder, in);
  9503. ReleaseRoxieRow(in);
  9504. }
  9505. catch (IException *E)
  9506. {
  9507. throw makeWrappedException(E);
  9508. }
  9509. if (outSize)
  9510. {
  9511. anyThisGroup = true;
  9512. processed++;
  9513. if (processed==rowLimit)
  9514. {
  9515. if (traceLevel > 4)
  9516. DBGLOG("activityid = %d line = %d", activityId, __LINE__);
  9517. helper.onLimitExceeded();
  9518. }
  9519. return rowBuilder.finalizeRowClear(outSize);
  9520. }
  9521. }
  9522. }
  9523. else
  9524. {
  9525. const void *ret = input->nextInGroup();
  9526. if (ret)
  9527. {
  9528. processed++;
  9529. if (processed==rowLimit)
  9530. {
  9531. if (traceLevel > 4)
  9532. DBGLOG("activityid = %d line = %d", activityId, __LINE__);
  9533. ReleaseClearRoxieRow(ret);
  9534. helper.onLimitExceeded(); // should not return
  9535. throwUnexpected();
  9536. }
  9537. }
  9538. return ret;
  9539. }
  9540. }
  9541. };
  9542. class CRoxieServerSpillReadActivityFactory : public CRoxieServerActivityFactory
  9543. {
  9544. public:
  9545. CRoxieServerSpillReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  9546. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  9547. {
  9548. }
  9549. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  9550. {
  9551. return new CRoxieServerSpillReadActivity(this, _probeManager);
  9552. }
  9553. virtual void addDependency(unsigned source, ThorActivityKind sourceKind, unsigned sourceIdx, int controlId, const char *edgeId)
  9554. {
  9555. if (sourceKind==TAKspill || sourceKind==TAKdiskwrite) // Bit of a hack - codegen probably should differentiate
  9556. setInput(0, source, sourceIdx);
  9557. else
  9558. CRoxieServerActivityFactory::addDependency(source, kind, sourceIdx, controlId, edgeId);
  9559. }
  9560. };
  9561. IRoxieServerActivityFactory *createRoxieServerSpillReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  9562. {
  9563. return new CRoxieServerSpillReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  9564. }
  9565. //=================================================================================
  9566. class CRoxieServerSpillWriteActivity : public CRoxieServerActivity
  9567. {
  9568. public:
  9569. CRoxieServerSpillWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  9570. : CRoxieServerActivity(_factory, _probeManager)
  9571. {
  9572. }
  9573. ~CRoxieServerSpillWriteActivity()
  9574. {
  9575. }
  9576. virtual const void *nextInGroup()
  9577. {
  9578. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  9579. return input->nextInGroup();
  9580. }
  9581. };
  9582. //==================================================================================
  9583. class CRoxieServerDiskWriteActivity : public CRoxieServerInternalSinkActivity, implements IRoxiePublishCallback
  9584. {
  9585. protected:
  9586. Owned<IExtRowWriter> outSeq;
  9587. Owned<IOutputRowSerializer> rowSerializer;
  9588. Linked<IFileIOStream> diskout;
  9589. bool blockcompressed;
  9590. bool extend;
  9591. bool overwrite;
  9592. bool encrypted;
  9593. bool grouped;
  9594. IHThorDiskWriteArg &helper;
  9595. StringBuffer lfn; // logical filename
  9596. CachedOutputMetaData diskmeta;
  9597. Owned<IRoxieWriteHandler> writer;
  9598. bool tallycrc;
  9599. unsigned __int64 uncompressedBytesWritten;
  9600. CRC32 crc;
  9601. void updateWorkUnitResult(unsigned __int64 reccount)
  9602. {
  9603. assertex(writer);
  9604. // MORE - a lot of this is common with hthor
  9605. if(lfn.length()) //this is required as long as temp files don't get a name which can be stored in the WU and automatically deleted by the WU
  9606. {
  9607. WorkunitUpdate wu = ctx->updateWorkUnit();
  9608. if (wu)
  9609. {
  9610. unsigned flags = helper.getFlags();
  9611. WUFileKind fileKind;
  9612. if (TDXtemporary & flags)
  9613. fileKind = WUFileTemporary;
  9614. else if(TDXjobtemp & flags)
  9615. fileKind = WUFileJobOwned;
  9616. else if(TDWowned & flags)
  9617. fileKind = WUFileOwned;
  9618. else
  9619. fileKind = WUFileStandard;
  9620. StringArray clusters;
  9621. writer->getClusters(clusters);
  9622. wu->addFile(lfn.str(), &clusters, helper.getTempUsageCount(), fileKind, NULL);
  9623. if (!(flags & TDXtemporary) && helper.getSequence() >= 0)
  9624. {
  9625. Owned<IWUResult> result = wu->updateResultBySequence(helper.getSequence());
  9626. if (result)
  9627. {
  9628. result->setResultTotalRowCount(reccount);
  9629. result->setResultStatus(ResultStatusCalculated);
  9630. if (helper.getFlags() & TDWresult)
  9631. result->setResultFilename(lfn.str());
  9632. else
  9633. result->setResultLogicalName(lfn.str());
  9634. }
  9635. }
  9636. }
  9637. }
  9638. }
  9639. void resolve()
  9640. {
  9641. OwnedRoxieString rawLogicalName = helper.getFileName();
  9642. assertex(rawLogicalName);
  9643. assertex((helper.getFlags() & TDXtemporary) == 0);
  9644. StringArray clusters;
  9645. unsigned clusterIdx = 0;
  9646. while(true)
  9647. {
  9648. OwnedRoxieString cluster(helper.getCluster(clusterIdx));
  9649. if(!cluster)
  9650. break;
  9651. clusters.append(cluster);
  9652. clusterIdx++;
  9653. }
  9654. if (clusters.length())
  9655. {
  9656. if (extend)
  9657. throw MakeStringException(0, "Cannot combine EXTEND and CLUSTER flags on disk write of file %s", rawLogicalName.get());
  9658. }
  9659. else
  9660. {
  9661. if (roxieName.length())
  9662. clusters.append(roxieName.str());
  9663. else
  9664. clusters.append(".");
  9665. }
  9666. writer.setown(ctx->createLFN(rawLogicalName, overwrite, extend, clusters)); // MORE - if there's a workunit, use if for scope.
  9667. // MORE - need to check somewhere that single part if it's an existing file or an external one...
  9668. }
  9669. public:
  9670. CRoxieServerDiskWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  9671. : CRoxieServerInternalSinkActivity(_factory, _probeManager, 0), helper((IHThorDiskWriteArg &)basehelper)
  9672. {
  9673. extend = ((helper.getFlags() & TDWextend) != 0);
  9674. overwrite = ((helper.getFlags() & TDWoverwrite) != 0);
  9675. grouped = false; // don't think we need to support it...
  9676. diskmeta.set(helper.queryDiskRecordSize());
  9677. blockcompressed = (((helper.getFlags() & TDWnewcompress) != 0) || (((helper.getFlags() & TDXcompress) != 0) && (diskmeta.getFixedSize() >= MIN_ROWCOMPRESS_RECSIZE))); //always use new compression
  9678. encrypted = false; // set later
  9679. tallycrc = true;
  9680. uncompressedBytesWritten = 0;
  9681. }
  9682. ~CRoxieServerDiskWriteActivity()
  9683. {
  9684. }
  9685. virtual bool needsAllocator() const
  9686. {
  9687. return true;
  9688. }
  9689. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9690. {
  9691. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  9692. resolve();
  9693. Owned<IFileIO> io;
  9694. void *ekey;
  9695. size32_t ekeylen;
  9696. helper.getEncryptKey(ekeylen, ekey);
  9697. Owned<ICompressor> ecomp;
  9698. if (ekeylen!=0)
  9699. {
  9700. ecomp.setown(createAESCompressor256(ekeylen,ekey));
  9701. memset(ekey,0,ekeylen);
  9702. rtlFree(ekey);
  9703. encrypted = true;
  9704. blockcompressed = true;
  9705. }
  9706. if (blockcompressed)
  9707. io.setown(createCompressedFileWriter(writer->queryFile(), (diskmeta.isFixedSize() ? diskmeta.getFixedSize() : 0), extend, true, ecomp));
  9708. else
  9709. io.setown(writer->queryFile()->open(extend ? IFOwrite : IFOcreate));
  9710. if (!io)
  9711. throw MakeStringException(errno, "Failed to create%s file %s for writing", (encrypted ? " encrypted" : (blockcompressed ? " compressed" : "")), writer->queryFile()->queryFilename());
  9712. diskout.setown(createBufferedIOStream(io));
  9713. if (extend)
  9714. diskout->seek(0, IFSend);
  9715. tallycrc = !factory->queryQueryFactory().getDebugValueBool("skipFileFormatCrcCheck", false) && !(helper.getFlags() & TDRnocrccheck) && !blockcompressed;
  9716. Owned<IRowInterfaces> rowIf = createRowInterfaces(input->queryOutputMeta(), activityId, ctx->queryCodeContext());
  9717. rowSerializer.set(rowIf->queryRowSerializer());
  9718. unsigned rwFlags = rw_autoflush;
  9719. if(grouped)
  9720. rwFlags |= rw_grouped;
  9721. if(tallycrc)
  9722. rwFlags |= rw_crc;
  9723. if(!factory->queryQueryFactory().getDebugValueBool("skipFileFormatCrcCheck", false) && !(helper.getFlags() & TDRnocrccheck))
  9724. rwFlags |= rw_crc;
  9725. outSeq.setown(createRowWriter(diskout, rowIf, rwFlags));
  9726. }
  9727. virtual void stop(bool aborting)
  9728. {
  9729. if (aborting)
  9730. {
  9731. if (writer)
  9732. writer->finish(false, this);
  9733. }
  9734. else
  9735. {
  9736. if (outSeq)
  9737. outSeq->flush(&crc);
  9738. if (outSeq)
  9739. uncompressedBytesWritten = outSeq->getPosition();
  9740. if (writer)
  9741. {
  9742. updateWorkUnitResult(processed);
  9743. writer->finish(true, this);
  9744. }
  9745. }
  9746. writer.clear();
  9747. CRoxieServerActivity::stop(aborting);
  9748. }
  9749. virtual void reset()
  9750. {
  9751. CRoxieServerActivity::reset();
  9752. diskout.clear();
  9753. outSeq.clear();
  9754. writer.clear();
  9755. uncompressedBytesWritten = 0;
  9756. crc.reset();
  9757. }
  9758. virtual void onExecute()
  9759. {
  9760. loop
  9761. {
  9762. const void *nextrec = input->nextInGroup();
  9763. if (!nextrec)
  9764. {
  9765. nextrec = input->nextInGroup();
  9766. if (!nextrec)
  9767. break;
  9768. }
  9769. processed++;
  9770. outSeq->putRow(nextrec);
  9771. }
  9772. }
  9773. virtual void setFileProperties(IFileDescriptor *desc) const
  9774. {
  9775. IPropertyTree &partProps = desc->queryPart(0)->queryProperties(); //properties of the first file part.
  9776. IPropertyTree &fileProps = desc->queryProperties(); // properties of the logical file
  9777. if (blockcompressed)
  9778. {
  9779. // caller has already set @size from file size...
  9780. fileProps.setPropBool("@blockCompressed", true);
  9781. fileProps.setPropInt64("@compressedSize", partProps.getPropInt64("@size", 0));
  9782. partProps.setPropInt64("@compressedSize", partProps.getPropInt64("@size", 0));
  9783. fileProps.setPropInt64("@size", uncompressedBytesWritten);
  9784. partProps.setPropInt64("@size", uncompressedBytesWritten);
  9785. }
  9786. else if (tallycrc)
  9787. partProps.setPropInt64("@fileCrc", crc.get());
  9788. if (encrypted)
  9789. fileProps.setPropBool("@encrypted", true);
  9790. fileProps.setPropInt64("@recordCount", processed);
  9791. unsigned flags = helper.getFlags();
  9792. if (flags & TDWpersist)
  9793. fileProps.setPropBool("@persistent", true);
  9794. if (grouped)
  9795. fileProps.setPropBool("@grouped", true);
  9796. if (flags & (TDWowned|TDXjobtemp|TDXtemporary))
  9797. fileProps.setPropBool("@owned", true);
  9798. if (flags & TDWresult)
  9799. fileProps.setPropBool("@result", true);
  9800. IConstWorkUnit *workUnit = ctx->queryWorkUnit();
  9801. if (workUnit)
  9802. {
  9803. SCMStringBuffer owner, wuid, job;
  9804. fileProps.setProp("@owner", workUnit->getUser(owner).str());
  9805. fileProps.setProp("@workunit", workUnit->getWuid(wuid).str());
  9806. fileProps.setProp("@job", workUnit->getJobName(job).str());
  9807. }
  9808. if (flags & TDWexpires)
  9809. setExpiryTime(fileProps, helper.getExpiryDays());
  9810. if (flags & TDWupdate)
  9811. {
  9812. unsigned eclCRC;
  9813. unsigned __int64 totalCRC;
  9814. helper.getUpdateCRCs(eclCRC, totalCRC);
  9815. fileProps.setPropInt("@eclCRC", eclCRC);
  9816. fileProps.setPropInt64("@totalCRC", totalCRC);
  9817. }
  9818. fileProps.setPropInt("@formatCrc", helper.getFormatCrc());
  9819. IRecordSize * inputMeta = input->queryOutputMeta();
  9820. if ((inputMeta->isFixedSize()) && !isOutputTransformed())
  9821. fileProps.setPropInt("@recordSize", inputMeta->getFixedSize() + (grouped ? 1 : 0));
  9822. const char *recordECL = helper.queryRecordECL();
  9823. if (recordECL && *recordECL)
  9824. fileProps.setProp("ECL", recordECL);
  9825. fileProps.setProp("@kind", "flat"); // default, derivitives may override
  9826. }
  9827. virtual IUserDescriptor *queryUserDescriptor() const
  9828. {
  9829. IConstWorkUnit *workUnit = ctx->queryWorkUnit();
  9830. if (workUnit)
  9831. return workUnit->queryUserDescriptor();
  9832. else
  9833. return NULL;
  9834. }
  9835. virtual bool isOutputTransformed() const { return false; }
  9836. };
  9837. //=================================================================================
  9838. class CRoxieServerCsvWriteActivity : public CRoxieServerDiskWriteActivity
  9839. {
  9840. IHThorCsvWriteArg &csvHelper;
  9841. CSVOutputStream csvOutput;
  9842. public:
  9843. CRoxieServerCsvWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  9844. : CRoxieServerDiskWriteActivity(_factory, _probeManager), csvHelper(static_cast<IHThorCsvWriteArg &>(helper))
  9845. {
  9846. csvOutput.init(csvHelper.queryCsvParameters(), false);
  9847. }
  9848. virtual void onExecute()
  9849. {
  9850. OwnedRoxieString header(csvHelper.queryCsvParameters()->getHeader());
  9851. if (header)
  9852. {
  9853. csvOutput.beginLine();
  9854. csvOutput.writeHeaderLn(strlen(header), header);
  9855. diskout->write(csvOutput.length(), csvOutput.str());
  9856. }
  9857. loop
  9858. {
  9859. const void *nextrec = input->nextInGroup();
  9860. if (!nextrec)
  9861. {
  9862. nextrec = input->nextInGroup();
  9863. if (!nextrec)
  9864. break;
  9865. }
  9866. processed++;
  9867. csvOutput.beginLine();
  9868. csvHelper.writeRow((const byte *)nextrec, &csvOutput);
  9869. csvOutput.endLine();
  9870. diskout->write(csvOutput.length(), csvOutput.str());
  9871. ReleaseRoxieRow(nextrec);
  9872. }
  9873. OwnedRoxieString footer(csvHelper.queryCsvParameters()->getFooter());
  9874. if (footer)
  9875. {
  9876. csvOutput.beginLine();
  9877. csvOutput.writeHeaderLn(strlen(footer), footer);
  9878. diskout->write(csvOutput.length(), csvOutput.str());
  9879. }
  9880. }
  9881. virtual void setFileProperties(IFileDescriptor *desc) const
  9882. {
  9883. CRoxieServerDiskWriteActivity::setFileProperties(desc);
  9884. IPropertyTree &props = desc->queryProperties();
  9885. props.setProp("@format","utf8n");
  9886. ICsvParameters *csvParameters = csvHelper.queryCsvParameters();
  9887. StringBuffer separator;
  9888. OwnedRoxieString rs(csvParameters->getSeparator(0));
  9889. const char *s = rs;
  9890. while (s && *s)
  9891. {
  9892. if (',' == *s)
  9893. separator.append("\\,");
  9894. else
  9895. separator.append(*s);
  9896. ++s;
  9897. }
  9898. props.setProp("@csvSeparate", separator.str());
  9899. props.setProp("@csvQuote", rs.setown(csvParameters->getQuote(0)));
  9900. props.setProp("@csvTerminate", rs.setown(csvParameters->getTerminator(0)));
  9901. props.setProp("@csvEscape", rs.setown(csvParameters->getEscape(0)));
  9902. props.setProp("@kind", "csv");
  9903. }
  9904. virtual bool isOutputTransformed() const { return true; }
  9905. };
  9906. class CRoxieServerXmlWriteActivity : public CRoxieServerDiskWriteActivity
  9907. {
  9908. IHThorXmlWriteArg &xmlHelper;
  9909. StringAttr rowTag;
  9910. public:
  9911. CRoxieServerXmlWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  9912. : CRoxieServerDiskWriteActivity(_factory, _probeManager), xmlHelper(static_cast<IHThorXmlWriteArg &>(helper))
  9913. {
  9914. }
  9915. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9916. {
  9917. CRoxieServerDiskWriteActivity::start(parentExtractSize, parentExtract, paused);
  9918. OwnedRoxieString xmlpath(xmlHelper.getXmlIteratorPath());
  9919. if (!xmlpath)
  9920. rowTag.set("Row");
  9921. else
  9922. {
  9923. const char *path = xmlpath;
  9924. if (*path == '/') path++;
  9925. if (strchr(path, '/')) UNIMPLEMENTED; // more what do we do with /mydata/row
  9926. rowTag.set(path);
  9927. }
  9928. }
  9929. virtual void onExecute()
  9930. {
  9931. OwnedRoxieString suppliedHeader(xmlHelper.getHeader());
  9932. const char *header = suppliedHeader;
  9933. if (!header) header = "<Dataset>\n";
  9934. diskout->write(strlen(header), header);
  9935. CommonXmlWriter xmlOutput(xmlHelper.getXmlFlags());
  9936. loop
  9937. {
  9938. OwnedConstRoxieRow nextrec = input->nextInGroup();
  9939. if (!nextrec)
  9940. {
  9941. nextrec.setown(input->nextInGroup());
  9942. if (!nextrec)
  9943. break;
  9944. }
  9945. processed++;
  9946. xmlOutput.clear().outputBeginNested(rowTag, false);
  9947. xmlHelper.toXML((const byte *)nextrec.get(), xmlOutput);
  9948. xmlOutput.outputEndNested(rowTag);
  9949. diskout->write(xmlOutput.length(), xmlOutput.str());
  9950. }
  9951. OwnedRoxieString suppliedFooter(xmlHelper.getFooter());
  9952. const char * footer = suppliedFooter;
  9953. if (!footer) footer = "</Dataset>\n";
  9954. diskout->write(strlen(footer), footer);
  9955. }
  9956. virtual void reset()
  9957. {
  9958. CRoxieServerDiskWriteActivity::reset();
  9959. rowTag.clear();
  9960. }
  9961. virtual void setFileProperties(IFileDescriptor *desc) const
  9962. {
  9963. CRoxieServerDiskWriteActivity::setFileProperties(desc);
  9964. desc->queryProperties().setProp("@format","utf8n");
  9965. desc->queryProperties().setProp("@rowTag",rowTag.get());
  9966. desc->queryProperties().setProp("@kind", "xml");
  9967. }
  9968. virtual bool isOutputTransformed() const { return true; }
  9969. };
  9970. class CRoxieServerDiskWriteActivityFactory : public CRoxieServerMultiOutputFactory
  9971. {
  9972. bool isRoot;
  9973. bool isTemp;
  9974. public:
  9975. CRoxieServerDiskWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  9976. : CRoxieServerMultiOutputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
  9977. {
  9978. Owned<IHThorDiskWriteArg> helper = (IHThorDiskWriteArg *) helperFactory();
  9979. isTemp = (helper->getFlags() & TDXtemporary) != 0;
  9980. setNumOutputs(helper->getTempUsageCount());
  9981. if (_kind!=TAKdiskwrite)
  9982. assertex(numOutputs == 0);
  9983. }
  9984. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  9985. {
  9986. switch (numOutputs)
  9987. {
  9988. case 0:
  9989. switch (kind)
  9990. {
  9991. case TAKdiskwrite: return new CRoxieServerDiskWriteActivity(this, _probeManager);
  9992. case TAKcsvwrite: return new CRoxieServerCsvWriteActivity(this, _probeManager);
  9993. case TAKxmlwrite: return new CRoxieServerXmlWriteActivity(this, _probeManager);
  9994. };
  9995. throwUnexpected();
  9996. case 1:
  9997. return new CRoxieServerSpillWriteActivity(this, _probeManager);
  9998. default:
  9999. return new CRoxieServerThroughSpillActivity(this, _probeManager, numOutputs);
  10000. }
  10001. }
  10002. virtual bool isSink() const
  10003. {
  10004. return numOutputs == 0 && !isTemp; // MORE - check with Gavin if this is right if not a temp but reread in same job...
  10005. }
  10006. };
  10007. IRoxieServerActivityFactory *createRoxieServerDiskWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  10008. {
  10009. return new CRoxieServerDiskWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
  10010. }
  10011. //=================================================================================
  10012. class CRoxieServerIndexWriteActivity : public CRoxieServerInternalSinkActivity, implements IRoxiePublishCallback
  10013. {
  10014. IHThorIndexWriteArg &helper;
  10015. bool overwrite;
  10016. Owned<ClusterWriteHandler> clusterHandler;
  10017. Owned<IRoxieWriteHandler> writer;
  10018. unsigned __int64 reccount;
  10019. unsigned int fileCrc;
  10020. StringBuffer filename;
  10021. void updateWorkUnitResult()
  10022. {
  10023. if(filename.length()) //this is required as long as temp files don't get a name which can be stored in the WU and automatically deleted by the WU
  10024. {
  10025. WorkunitUpdate wu = ctx->updateWorkUnit();
  10026. if (wu)
  10027. {
  10028. if (!(helper.getFlags() & TDXtemporary) && helper.getSequence() >= 0)
  10029. {
  10030. Owned<IWUResult> result = wu->updateResultBySequence(helper.getSequence());
  10031. if (result)
  10032. {
  10033. result->setResultTotalRowCount(reccount);
  10034. result->setResultStatus(ResultStatusCalculated);
  10035. result->setResultLogicalName(filename.str());
  10036. }
  10037. }
  10038. if(clusterHandler)
  10039. clusterHandler->finish(writer->queryFile());
  10040. }
  10041. CTXLOG("Created roxie index file %s", filename.str());
  10042. }
  10043. }
  10044. virtual void resolve()
  10045. {
  10046. StringArray clusters;
  10047. unsigned clusterIdx = 0;
  10048. while(true)
  10049. {
  10050. OwnedRoxieString cluster(helper.getCluster(clusterIdx));
  10051. if(!cluster)
  10052. break;
  10053. clusters.append(cluster);
  10054. clusterIdx++;
  10055. }
  10056. if (roxieName.length())
  10057. clusters.append(roxieName.str());
  10058. else
  10059. clusters.append(".");
  10060. OwnedRoxieString fname(helper.getFileName());
  10061. writer.setown(ctx->createLFN(fname, overwrite, false, clusters)); // MORE - if there's a workunit, use if for scope.
  10062. filename.set(writer->queryFile()->queryFilename());
  10063. if (writer->queryFile()->exists())
  10064. {
  10065. if (overwrite)
  10066. {
  10067. CTXLOG("Removing existing %s from DFS",filename.str());
  10068. writer->queryFile()->remove();
  10069. }
  10070. else
  10071. throw MakeStringException(99, "Cannot write index file %s, file already exists (missing OVERWRITE attribute?)", filename.str());
  10072. }
  10073. }
  10074. void buildUserMetadata(Owned<IPropertyTree> & metadata)
  10075. {
  10076. size32_t nameLen;
  10077. char * nameBuff;
  10078. size32_t valueLen;
  10079. char * valueBuff;
  10080. unsigned idx = 0;
  10081. while(helper.getIndexMeta(nameLen, nameBuff, valueLen, valueBuff, idx++))
  10082. {
  10083. StringBuffer name(nameLen, nameBuff);
  10084. StringBuffer value(valueLen, valueBuff);
  10085. if(*nameBuff == '_' && strcmp(name, "_nodeSize") != 0)
  10086. {
  10087. OwnedRoxieString fname(helper.getFileName());
  10088. throw MakeStringException(0, "Invalid name %s in user metadata for index %s (names beginning with underscore are reserved)", name.str(), fname.get());
  10089. }
  10090. if(!validateXMLTag(name.str()))
  10091. {
  10092. OwnedRoxieString fname(helper.getFileName());
  10093. throw MakeStringException(0, "Invalid name %s in user metadata for index %s (not legal XML element name)", name.str(), fname.get());
  10094. }
  10095. if(!metadata)
  10096. metadata.setown(createPTree("metadata"));
  10097. metadata->setProp(name.str(), value.str());
  10098. }
  10099. }
  10100. void buildLayoutMetadata(Owned<IPropertyTree> & metadata)
  10101. {
  10102. if(!metadata)
  10103. metadata.setown(createPTree("metadata"));
  10104. metadata->setProp("_record_ECL", helper.queryRecordECL());
  10105. void * layoutMetaBuff;
  10106. size32_t layoutMetaSize;
  10107. if(helper.getIndexLayout(layoutMetaSize, layoutMetaBuff))
  10108. {
  10109. metadata->setPropBin("_record_layout", layoutMetaSize, layoutMetaBuff);
  10110. rtlFree(layoutMetaBuff);
  10111. }
  10112. }
  10113. public:
  10114. CRoxieServerIndexWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  10115. : CRoxieServerInternalSinkActivity(_factory, _probeManager, 0), helper(static_cast<IHThorIndexWriteArg &>(basehelper))
  10116. {
  10117. overwrite = ((helper.getFlags() & TIWoverwrite) != 0);
  10118. reccount = 0;
  10119. fileCrc = 0;
  10120. }
  10121. ~CRoxieServerIndexWriteActivity()
  10122. {
  10123. }
  10124. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  10125. {
  10126. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  10127. resolve();
  10128. }
  10129. virtual void onExecute()
  10130. {
  10131. bool isVariable = helper.queryDiskRecordSize()->isVariableSize();
  10132. size32_t maxDiskRecordSize;
  10133. if (isVariable)
  10134. maxDiskRecordSize = 0x8000;
  10135. else
  10136. {
  10137. maxDiskRecordSize = helper.queryDiskRecordSize()->getFixedSize();
  10138. if (maxDiskRecordSize > 0x8000)
  10139. throw MakeStringException(99, "Index minimum record length (%d) exceeds 32k internal limit", maxDiskRecordSize);
  10140. }
  10141. OwnedMalloc<char> rowBuffer(maxDiskRecordSize, true);
  10142. unsigned __int64 fileSize = 0;
  10143. fileCrc = -1;
  10144. OwnedRoxieString dsName(helper.getFileName());
  10145. if (dsName.get())
  10146. {
  10147. Owned<const IResolvedFile> dsFileInfo = resolveLFN(dsName, false);
  10148. if (dsFileInfo)
  10149. {
  10150. fileSize = dsFileInfo->getFileSize();
  10151. }
  10152. }
  10153. {
  10154. Owned<IFileIO> io;
  10155. try
  10156. {
  10157. io.setown(writer->queryFile()->open(IFOcreate));
  10158. }
  10159. catch(IException * e)
  10160. {
  10161. e->Release();
  10162. clearKeyStoreCache(false);
  10163. io.setown(writer->queryFile()->open(IFOcreate));
  10164. }
  10165. if(!io)
  10166. throw MakeStringException(errno, "Failed to create file %s for writing", filename.str());
  10167. Owned<IFileIOStream> out = createIOStream(io);
  10168. unsigned flags = COL_PREFIX | HTREE_FULLSORT_KEY;
  10169. if (helper.getFlags() & TIWrowcompress)
  10170. flags |= HTREE_COMPRESSED_KEY|HTREE_QUICK_COMPRESSED_KEY;
  10171. else if (!(helper.getFlags() & TIWnolzwcompress))
  10172. flags |= HTREE_COMPRESSED_KEY;
  10173. if (isVariable)
  10174. flags |= HTREE_VARSIZE;
  10175. Owned<IPropertyTree> metadata;
  10176. buildUserMetadata(metadata);
  10177. buildLayoutMetadata(metadata);
  10178. unsigned nodeSize = metadata ? metadata->getPropInt("_nodeSize", NODESIZE) : NODESIZE;
  10179. Owned<IKeyBuilder> builder = createKeyBuilder(out, flags, maxDiskRecordSize, fileSize, nodeSize, helper.getKeyedSize(), 0);
  10180. class BcWrapper : implements IBlobCreator
  10181. {
  10182. IKeyBuilder *builder;
  10183. public:
  10184. BcWrapper(IKeyBuilder *_builder) : builder(_builder) {}
  10185. virtual unsigned __int64 createBlob(size32_t size, const void * ptr)
  10186. {
  10187. return builder->createBlob(size, (const char *) ptr);
  10188. }
  10189. } bc(builder);
  10190. // Loop thru the results
  10191. loop
  10192. {
  10193. OwnedConstRoxieRow nextrec(input->nextInGroup());
  10194. if (!nextrec)
  10195. {
  10196. nextrec.setown(input->nextInGroup());
  10197. if (!nextrec)
  10198. break;
  10199. }
  10200. try
  10201. {
  10202. unsigned __int64 fpos;
  10203. RtlStaticRowBuilder rowBuilder(rowBuffer, maxDiskRecordSize);
  10204. size32_t thisSize = helper.transform(rowBuilder, nextrec, &bc, fpos);
  10205. builder->processKeyData(rowBuffer, fpos, thisSize);
  10206. }
  10207. catch(IException * e)
  10208. {
  10209. throw makeWrappedException(e);
  10210. }
  10211. reccount++;
  10212. }
  10213. if(metadata)
  10214. builder->finish(metadata,&fileCrc);
  10215. else
  10216. builder->finish(&fileCrc);
  10217. }
  10218. }
  10219. virtual void stop(bool aborting)
  10220. {
  10221. if (writer)
  10222. {
  10223. if (!aborting)
  10224. updateWorkUnitResult();
  10225. writer->finish(!aborting, this);
  10226. writer.clear();
  10227. }
  10228. CRoxieServerActivity::stop(aborting);
  10229. }
  10230. virtual void reset()
  10231. {
  10232. CRoxieServerActivity::reset();
  10233. writer.clear();
  10234. }
  10235. //interface IRoxiePublishCallback
  10236. virtual void setFileProperties(IFileDescriptor *desc) const
  10237. {
  10238. IPropertyTree &partProps = desc->queryPart(0)->queryProperties(); //properties of the first file part.
  10239. IPropertyTree &fileProps = desc->queryProperties(); // properties of the logical file
  10240. // Now publish to name services
  10241. StringBuffer dir,base;
  10242. offset_t indexFileSize = writer->queryFile()->size();
  10243. if(clusterHandler)
  10244. clusterHandler->splitPhysicalFilename(dir, base);
  10245. else
  10246. splitFilename(filename.str(), &dir, &dir, &base, &base);
  10247. desc->setDefaultDir(dir.str());
  10248. //properties of the first file part.
  10249. Owned<IPropertyTree> attrs;
  10250. if(clusterHandler)
  10251. attrs.setown(createPTree("Part")); // clusterHandler is going to set attributes
  10252. else
  10253. {
  10254. // add cluster
  10255. StringBuffer mygroupname;
  10256. desc->setNumParts(1);
  10257. desc->setPartMask(base.str());
  10258. attrs.set(&desc->queryPart(0)->queryProperties());
  10259. }
  10260. attrs->setPropInt64("@size", indexFileSize);
  10261. CDateTime createTime, modifiedTime, accessedTime;
  10262. writer->queryFile()->getTime(&createTime, &modifiedTime, &accessedTime);
  10263. // round file time down to nearest sec. Nanosec accurancy is not preserved elsewhere and can lead to mismatch later.
  10264. unsigned hour, min, sec, nanosec;
  10265. modifiedTime.getTime(hour, min, sec, nanosec);
  10266. modifiedTime.setTime(hour, min, sec, 0);
  10267. StringBuffer timestr;
  10268. modifiedTime.getString(timestr);
  10269. if(timestr.length())
  10270. attrs->setProp("@modified", timestr.str());
  10271. if(clusterHandler)
  10272. clusterHandler->setDescriptorParts(desc, base.str(), attrs);
  10273. // properties of the logical file
  10274. IPropertyTree & properties = desc->queryProperties();
  10275. properties.setProp("@kind", "key");
  10276. properties.setPropInt64("@size", indexFileSize);
  10277. properties.setPropInt64("@recordCount", reccount);
  10278. SCMStringBuffer info;
  10279. WorkunitUpdate workUnit = ctx->updateWorkUnit();
  10280. if (workUnit)
  10281. {
  10282. properties.setProp("@owner", workUnit->getUser(info).str());
  10283. info.clear();
  10284. properties.setProp("@workunit", workUnit->getWuid(info).str());
  10285. info.clear();
  10286. properties.setProp("@job", workUnit->getJobName(info).str());
  10287. }
  10288. char const * rececl = helper.queryRecordECL();
  10289. if(rececl && *rececl)
  10290. properties.setProp("ECL", rececl);
  10291. if (helper.getFlags() & TIWexpires)
  10292. setExpiryTime(properties, helper.getExpiryDays());
  10293. if (helper.getFlags() & TIWupdate)
  10294. {
  10295. unsigned eclCRC;
  10296. unsigned __int64 totalCRC;
  10297. helper.getUpdateCRCs(eclCRC, totalCRC);
  10298. properties.setPropInt("@eclCRC", eclCRC);
  10299. properties.setPropInt64("@totalCRC", totalCRC);
  10300. }
  10301. properties.setPropInt("@fileCrc", fileCrc);
  10302. properties.setPropInt("@formatCrc", helper.getFormatCrc());
  10303. void * layoutMetaBuff;
  10304. size32_t layoutMetaSize;
  10305. if(helper.getIndexLayout(layoutMetaSize, layoutMetaBuff))
  10306. {
  10307. properties.setPropBin("_record_layout", layoutMetaSize, layoutMetaBuff);
  10308. rtlFree(layoutMetaBuff);
  10309. }
  10310. }
  10311. IUserDescriptor *queryUserDescriptor() const
  10312. {
  10313. IConstWorkUnit *workUnit = ctx->queryWorkUnit();
  10314. if (workUnit)
  10315. return workUnit->queryUserDescriptor();
  10316. else
  10317. return NULL;
  10318. }
  10319. };
  10320. //=================================================================================
  10321. class CRoxieServerIndexWriteActivityFactory : public CRoxieServerMultiOutputFactory
  10322. {
  10323. public:
  10324. CRoxieServerIndexWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  10325. : CRoxieServerMultiOutputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  10326. {
  10327. setNumOutputs(0);
  10328. }
  10329. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  10330. {
  10331. return new CRoxieServerIndexWriteActivity(this, _probeManager);
  10332. }
  10333. virtual bool isSink() const
  10334. {
  10335. return true;
  10336. }
  10337. };
  10338. IRoxieServerActivityFactory *createRoxieServerIndexWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  10339. {
  10340. return new CRoxieServerIndexWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
  10341. }
  10342. //=================================================================================
  10343. static inline void getLimitType(unsigned flags, bool & limitFail, bool & limitOnFail)
  10344. {
  10345. if((flags & JFmatchAbortLimitSkips) != 0)
  10346. {
  10347. limitFail = false;
  10348. limitOnFail = false;
  10349. }
  10350. else
  10351. {
  10352. limitOnFail = ((flags & JFonfail) != 0);
  10353. limitFail = !limitOnFail;
  10354. }
  10355. }
  10356. class CRoxieServerJoinActivity : public CRoxieServerTwoInputActivity
  10357. {
  10358. enum { JSfill, JSfillleft, JSfillright, JScollate, JScompare, JSleftonly, JSrightonly } state;
  10359. IHThorJoinArg &helper;
  10360. ICompare * collate;
  10361. ICompare * collateupper;
  10362. ThorActivityKind activityKind;
  10363. bool leftOuterJoin;
  10364. bool rightOuterJoin;
  10365. bool exclude;
  10366. bool limitFail;
  10367. bool limitOnFail;
  10368. unsigned keepLimit;
  10369. unsigned joinLimit;
  10370. unsigned atmostLimit;
  10371. unsigned abortLimit;
  10372. unsigned atmostsTriggered;
  10373. bool betweenjoin;
  10374. OwnedRowArray right;
  10375. const void * left;
  10376. const void * pendingRight;
  10377. unsigned rightIndex;
  10378. unsigned joinCounter;
  10379. BoolArray matchedRight;
  10380. bool matchedLeft;
  10381. Owned<IException> failingLimit;
  10382. ConstPointerArray filteredRight;
  10383. Owned<IRHLimitedCompareHelper> limitedhelper;
  10384. OwnedConstRoxieRow defaultLeft;
  10385. OwnedConstRoxieRow defaultRight;
  10386. Owned<IEngineRowAllocator> defaultLeftAllocator;
  10387. Owned<IEngineRowAllocator> defaultRightAllocator;
  10388. bool cloneLeft;
  10389. void createDefaultLeft()
  10390. {
  10391. if (!defaultLeft)
  10392. {
  10393. if (!defaultLeftAllocator)
  10394. defaultLeftAllocator.setown(ctx->queryCodeContext()->getRowAllocator(input->queryOutputMeta(), activityId));
  10395. RtlDynamicRowBuilder rowBuilder(defaultLeftAllocator);
  10396. size32_t thisSize = helper.createDefaultLeft(rowBuilder);
  10397. defaultLeft.setown(rowBuilder.finalizeRowClear(thisSize));
  10398. }
  10399. }
  10400. void createDefaultRight()
  10401. {
  10402. if (!defaultRight)
  10403. {
  10404. if (!defaultRightAllocator)
  10405. defaultRightAllocator.setown(ctx->queryCodeContext()->getRowAllocator(input1->queryOutputMeta(), activityId));
  10406. RtlDynamicRowBuilder rowBuilder(defaultRightAllocator);
  10407. size32_t thisSize = helper.createDefaultRight(rowBuilder);
  10408. defaultRight.setown(rowBuilder.finalizeRowClear(thisSize));
  10409. }
  10410. }
  10411. public:
  10412. CRoxieServerJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  10413. : CRoxieServerTwoInputActivity(_factory, _probeManager), helper((IHThorJoinArg &)basehelper)
  10414. {
  10415. // MORE - some of this should be done in factory
  10416. unsigned joinFlags = helper.getJoinFlags();
  10417. leftOuterJoin = (joinFlags & JFleftouter) != 0;
  10418. rightOuterJoin = (joinFlags & JFrightouter) != 0;
  10419. exclude = (joinFlags & JFexclude) != 0;
  10420. cloneLeft = (joinFlags & JFtransformmatchesleft) != 0;
  10421. getLimitType(joinFlags, limitFail, limitOnFail);
  10422. if (joinFlags & JFslidingmatch)
  10423. {
  10424. betweenjoin = true;
  10425. collate = helper.queryCompareLeftRightLower();
  10426. collateupper = helper.queryCompareLeftRightUpper();
  10427. }
  10428. else
  10429. {
  10430. betweenjoin = false;
  10431. collate = collateupper = helper.queryCompareLeftRight();
  10432. }
  10433. rightIndex = 0;
  10434. joinCounter = 0;
  10435. state = JSfill;
  10436. matchedLeft = false;
  10437. joinLimit = 0;
  10438. keepLimit = 0; // wait until ctx available
  10439. atmostLimit = 0; // wait until ctx available
  10440. abortLimit = 0; // wait until ctx available
  10441. atmostsTriggered = 0;
  10442. assertex((joinFlags & (JFfirst | JFfirstleft | JFfirstright)) == 0);
  10443. left = NULL;
  10444. pendingRight = NULL;
  10445. activityKind = _factory->getKind();
  10446. }
  10447. virtual bool needsAllocator() const { return true; }
  10448. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  10449. {
  10450. left = NULL;
  10451. rightIndex = 0;
  10452. joinCounter = 0;
  10453. state = JSfill;
  10454. matchedLeft = false;
  10455. CRoxieServerTwoInputActivity::start(parentExtractSize, parentExtract, paused);
  10456. keepLimit = helper.getKeepLimit();
  10457. if (keepLimit == 0)
  10458. keepLimit = (unsigned)-1;
  10459. atmostsTriggered = 0;
  10460. atmostLimit = helper.getJoinLimit();
  10461. if(atmostLimit == 0)
  10462. atmostLimit = (unsigned)-1;
  10463. else
  10464. assertex(!rightOuterJoin && !betweenjoin);
  10465. abortLimit = helper.getMatchAbortLimit();
  10466. if (abortLimit == 0)
  10467. abortLimit = (unsigned)-1;
  10468. if (rightOuterJoin)
  10469. createDefaultLeft();
  10470. if ((leftOuterJoin && (activityKind==TAKjoin || activityKind==TAKjoinlight || activityKind==TAKdenormalizegroup)) || limitOnFail)
  10471. createDefaultRight();
  10472. if ((helper.getJoinFlags() & JFlimitedprefixjoin) && helper.getJoinLimit())
  10473. { //limited match join (s[1..n])
  10474. limitedhelper.setown(createRHLimitedCompareHelper());
  10475. limitedhelper->init( helper.getJoinLimit(), input1, collate, helper.queryPrefixCompare() );
  10476. }
  10477. }
  10478. virtual void reset()
  10479. {
  10480. if (atmostsTriggered)
  10481. noteStatistic(STATS_ATMOST, atmostsTriggered, 1);
  10482. right.clear();
  10483. ReleaseClearRoxieRow(left);
  10484. ReleaseClearRoxieRow(pendingRight);
  10485. defaultRight.clear();
  10486. defaultLeft.clear();
  10487. CRoxieServerTwoInputActivity::reset();
  10488. }
  10489. virtual void setInput(unsigned idx, IRoxieInput *_in)
  10490. {
  10491. switch(idx)
  10492. {
  10493. case 0:
  10494. if ((helper.getJoinFlags() & JFparallel) != 0)
  10495. {
  10496. puller.setown(new CRoxieServerReadAheadInput(0)); // MORE - cant ask context for parallelJoinPreload as context is not yet set up.
  10497. puller->setInput(0, _in);
  10498. _in = puller;
  10499. }
  10500. input = _in;
  10501. break;
  10502. case 1:
  10503. input1 = _in;
  10504. break;
  10505. default:
  10506. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
  10507. }
  10508. }
  10509. virtual IRoxieInput *queryOutput(unsigned idx)
  10510. {
  10511. if (idx==(unsigned)-1)
  10512. idx = 0;
  10513. return idx ? NULL : this;
  10514. }
  10515. void fillLeft()
  10516. {
  10517. matchedLeft = false;
  10518. left = input->nextInGroup();
  10519. if (!left)
  10520. left = input->nextInGroup();
  10521. if(betweenjoin && left && pendingRight && (collate->docompare(left, pendingRight) >= 0))
  10522. fillRight();
  10523. if (limitedhelper && 0==rightIndex)
  10524. {
  10525. rightIndex = 0;
  10526. joinCounter = 0;
  10527. right.clear();
  10528. matchedRight.kill();
  10529. if (left)
  10530. {
  10531. limitedhelper->getGroup(right,left);
  10532. ForEachItemIn(idx, right)
  10533. matchedRight.append(false);
  10534. }
  10535. }
  10536. }
  10537. void fillRight()
  10538. {
  10539. if (limitedhelper)
  10540. return;
  10541. failingLimit.clear();
  10542. if(betweenjoin && left)
  10543. {
  10544. aindex_t start = 0;
  10545. while(right.isItem(start) && (collateupper->docompare(left, right.item(start)) > 0))
  10546. start++;
  10547. if(start>0)
  10548. right.clearPart(0, start);
  10549. }
  10550. else
  10551. right.clear();
  10552. rightIndex = 0;
  10553. joinCounter = 0;
  10554. unsigned groupCount = 0;
  10555. const void * next;
  10556. while(true)
  10557. {
  10558. if(pendingRight)
  10559. {
  10560. next = pendingRight;
  10561. pendingRight = NULL;
  10562. }
  10563. else
  10564. {
  10565. next = input1->nextInGroup();
  10566. }
  10567. if(!rightOuterJoin && next && (!left || (collateupper->docompare(left, next) > 0))) // if right is less than left, and not right outer, can skip group
  10568. {
  10569. while(next)
  10570. {
  10571. ReleaseClearRoxieRow(next);
  10572. next = input1->nextInGroup();
  10573. }
  10574. continue;
  10575. }
  10576. while(next)
  10577. {
  10578. if(groupCount==abortLimit)
  10579. {
  10580. if(limitFail)
  10581. failLimit();
  10582. if (ctx->queryDebugContext())
  10583. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  10584. if(limitOnFail)
  10585. {
  10586. assertex(!failingLimit);
  10587. try
  10588. {
  10589. failLimit();
  10590. }
  10591. catch(IException * except)
  10592. {
  10593. failingLimit.setown(except);
  10594. }
  10595. assertex(failingLimit != NULL);
  10596. }
  10597. right.append(next);
  10598. do
  10599. {
  10600. next = input1->nextInGroup();
  10601. ReleaseRoxieRow(next);
  10602. } while(next);
  10603. break;
  10604. }
  10605. else if(groupCount==atmostLimit)
  10606. {
  10607. atmostsTriggered++;
  10608. right.clear();
  10609. groupCount = 0;
  10610. while(next)
  10611. {
  10612. ReleaseRoxieRow(next);
  10613. next = input1->nextInGroup();
  10614. }
  10615. }
  10616. else
  10617. {
  10618. right.append(next);
  10619. groupCount++;
  10620. }
  10621. next = input1->nextInGroup();
  10622. }
  10623. // 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
  10624. if(betweenjoin && left)
  10625. {
  10626. pendingRight = input1->nextInGroup();
  10627. if(!pendingRight || (collate->docompare(left, pendingRight) < 0))
  10628. break;
  10629. }
  10630. else
  10631. break;
  10632. }
  10633. matchedRight.kill();
  10634. ForEachItemIn(idx, right)
  10635. matchedRight.append(false);
  10636. }
  10637. const void * joinRecords(const void * curLeft, const void * curRight, unsigned counter)
  10638. {
  10639. if (cloneLeft)
  10640. {
  10641. LinkRoxieRow(curLeft);
  10642. return curLeft;
  10643. }
  10644. try
  10645. {
  10646. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  10647. size32_t thisSize = helper.transform(rowBuilder, curLeft, curRight, counter);
  10648. if (thisSize)
  10649. return rowBuilder.finalizeRowClear(thisSize);
  10650. else
  10651. return NULL;
  10652. }
  10653. catch (IException *E)
  10654. {
  10655. throw makeWrappedException(E);
  10656. }
  10657. }
  10658. const void * denormalizeRecords(const void * curLeft, ConstPointerArray & rows)
  10659. {
  10660. try
  10661. {
  10662. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  10663. unsigned numRows = rows.ordinality();
  10664. const void * right = numRows ? rows.item(0) : defaultRight.get();
  10665. size32_t thisSize = helper.transform(rowBuilder, curLeft, right, numRows, (const void * *)rows.getArray());
  10666. if (thisSize)
  10667. return rowBuilder.finalizeRowClear(thisSize);
  10668. else
  10669. return NULL;
  10670. }
  10671. catch (IException *E)
  10672. {
  10673. throw makeWrappedException(E);
  10674. }
  10675. }
  10676. const void * joinException(const void * curLeft, IException * except)
  10677. {
  10678. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  10679. size32_t thisSize = helper.onFailTransform(rowBuilder, curLeft, defaultRight, except);
  10680. return rowBuilder.finalizeRowClear(thisSize);
  10681. }
  10682. void failLimit()
  10683. {
  10684. helper.onMatchAbortLimitExceeded();
  10685. CommonXmlWriter xmlwrite(0);
  10686. if (input->queryOutputMeta() && input->queryOutputMeta()->hasXML())
  10687. {
  10688. input->queryOutputMeta()->toXML((byte *) left, xmlwrite);
  10689. }
  10690. throw MakeStringException(ROXIE_TOO_MANY_RESULTS, "More than %d match candidates in join %d for row %s", abortLimit, queryId(), xmlwrite.str());
  10691. }
  10692. virtual const void * nextInGroup()
  10693. {
  10694. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  10695. loop
  10696. {
  10697. switch (state)
  10698. {
  10699. case JSfill:
  10700. fillLeft();
  10701. state = JSfillright;
  10702. break;
  10703. case JSfillright:
  10704. fillRight();
  10705. state = JScollate;
  10706. break;
  10707. case JSfillleft:
  10708. fillLeft();
  10709. state = JScollate;
  10710. break;
  10711. case JScollate:
  10712. if (right.ordinality() == 0)
  10713. {
  10714. if (left == NULL)
  10715. return NULL;
  10716. state = JSleftonly;
  10717. }
  10718. else
  10719. {
  10720. if (!left)
  10721. state = JSrightonly;
  10722. else
  10723. {
  10724. int diff;
  10725. if(betweenjoin)
  10726. diff = ((collate->docompare(left, right.item(0)) < 0) ? -1 : ((collateupper->docompare(left, right.item(right.ordinality()-1)) > 0) ? +1 : 0));
  10727. else
  10728. diff = collate->docompare(left, right.item(0));
  10729. bool limitExceeded = right.ordinality()>abortLimit;
  10730. if (diff == 0)
  10731. {
  10732. if (limitExceeded)
  10733. {
  10734. const void * ret = NULL;
  10735. if(failingLimit)
  10736. ret = joinException(left, failingLimit);
  10737. ReleaseRoxieRow(left);
  10738. left = NULL;
  10739. state = JSfillleft;
  10740. ForEachItemIn(idx, right)
  10741. matchedRight.replace(true, idx);
  10742. if(ret)
  10743. {
  10744. processed++;
  10745. return ret;
  10746. }
  10747. }
  10748. else
  10749. {
  10750. state = JScompare;
  10751. joinLimit = keepLimit;
  10752. }
  10753. }
  10754. else if (diff < 0)
  10755. state = JSleftonly;
  10756. else if (limitExceeded)
  10757. {
  10758. // MORE - Roxie code seems to think there should be a destroyRowset(right) here....
  10759. state = JSfillright;
  10760. }
  10761. else
  10762. state = JSrightonly;
  10763. }
  10764. }
  10765. break;
  10766. case JSrightonly:
  10767. if (rightOuterJoin)
  10768. {
  10769. switch (activityKind)
  10770. {
  10771. case TAKjoin:
  10772. {
  10773. while (right.isItem(rightIndex))
  10774. {
  10775. if (!matchedRight.item(rightIndex))
  10776. {
  10777. const void * rhs = right.item(rightIndex++);
  10778. const void *ret = joinRecords(defaultLeft, rhs, 0);
  10779. if (ret)
  10780. {
  10781. processed++;
  10782. return ret;
  10783. }
  10784. }
  10785. else
  10786. rightIndex++;
  10787. }
  10788. break;
  10789. }
  10790. //Probably excessive to implement the following, but possibly useful
  10791. case TAKdenormalize:
  10792. {
  10793. OwnedConstRoxieRow newLeft;
  10794. newLeft.set(defaultLeft);
  10795. unsigned rowSize = 0;
  10796. unsigned leftCount = 0;
  10797. while (right.isItem(rightIndex))
  10798. {
  10799. if (!matchedRight.item(rightIndex))
  10800. {
  10801. const void * rhs = right.item(rightIndex);
  10802. try
  10803. {
  10804. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  10805. unsigned thisSize = helper.transform(rowBuilder, newLeft, rhs, ++leftCount);
  10806. if (thisSize)
  10807. {
  10808. rowSize = thisSize;
  10809. newLeft.setown(rowBuilder.finalizeRowClear(rowSize));
  10810. }
  10811. }
  10812. catch (IException *E)
  10813. {
  10814. throw makeWrappedException(E);
  10815. }
  10816. }
  10817. rightIndex++;
  10818. }
  10819. state = JSfillright;
  10820. if (rowSize)
  10821. {
  10822. processed++;
  10823. return newLeft.getClear();
  10824. }
  10825. break;
  10826. }
  10827. case TAKdenormalizegroup:
  10828. {
  10829. filteredRight.kill();
  10830. while (right.isItem(rightIndex))
  10831. {
  10832. if (!matchedRight.item(rightIndex))
  10833. filteredRight.append(right.item(rightIndex));
  10834. rightIndex++;
  10835. }
  10836. state = JSfillright;
  10837. if (filteredRight.ordinality())
  10838. {
  10839. const void * ret = denormalizeRecords(defaultLeft, filteredRight);
  10840. filteredRight.kill();
  10841. if (ret)
  10842. {
  10843. processed++;
  10844. return ret;
  10845. }
  10846. }
  10847. break;
  10848. }
  10849. }
  10850. }
  10851. state = JSfillright;
  10852. break;
  10853. case JSleftonly:
  10854. {
  10855. const void * ret = NULL;
  10856. if (!matchedLeft && leftOuterJoin)
  10857. {
  10858. switch (activityKind)
  10859. {
  10860. case TAKjoin:
  10861. ret = joinRecords(left, defaultRight, 0);
  10862. break;
  10863. case TAKdenormalize:
  10864. ret = left;
  10865. left = NULL;
  10866. break;
  10867. case TAKdenormalizegroup:
  10868. filteredRight.kill();
  10869. ret = denormalizeRecords(left, filteredRight);
  10870. break;
  10871. }
  10872. }
  10873. ReleaseRoxieRow(left);
  10874. left = NULL;
  10875. state = JSfillleft;
  10876. if (ret)
  10877. {
  10878. processed++;
  10879. return ret;
  10880. }
  10881. break;
  10882. }
  10883. case JScompare:
  10884. if (joinLimit != 0)
  10885. {
  10886. switch (activityKind)
  10887. {
  10888. case TAKjoin:
  10889. {
  10890. while (right.isItem(rightIndex))
  10891. {
  10892. const void * rhs = right.item(rightIndex++);
  10893. if (helper.match(left, rhs))
  10894. {
  10895. matchedRight.replace(true, rightIndex-1);
  10896. matchedLeft = true;
  10897. if (!exclude)
  10898. {
  10899. const void *ret = joinRecords(left, rhs, ++joinCounter);
  10900. if (ret)
  10901. {
  10902. processed++;
  10903. joinLimit--;
  10904. return ret;
  10905. }
  10906. }
  10907. }
  10908. }
  10909. break;
  10910. }
  10911. case TAKdenormalize:
  10912. {
  10913. OwnedConstRoxieRow newLeft;
  10914. newLeft.set(left);
  10915. unsigned rowSize = 0;
  10916. unsigned leftCount = 0;
  10917. while (right.isItem(rightIndex) && joinLimit)
  10918. {
  10919. try
  10920. {
  10921. const void * rhs = right.item(rightIndex++);
  10922. if (helper.match(left, rhs))
  10923. {
  10924. matchedRight.replace(true, rightIndex-1);
  10925. matchedLeft = true;
  10926. if (!exclude)
  10927. {
  10928. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  10929. unsigned thisSize = helper.transform(rowBuilder, newLeft, rhs, ++leftCount);
  10930. if (thisSize)
  10931. {
  10932. rowSize = thisSize;
  10933. newLeft.setown(rowBuilder.finalizeRowClear(rowSize));
  10934. joinLimit--;
  10935. }
  10936. }
  10937. }
  10938. }
  10939. catch (IException *E)
  10940. {
  10941. throw makeWrappedException(E);
  10942. }
  10943. }
  10944. state = JSleftonly;
  10945. rightIndex = 0;
  10946. if (rowSize)
  10947. {
  10948. processed++;
  10949. return newLeft.getClear();
  10950. }
  10951. break;
  10952. }
  10953. case TAKdenormalizegroup:
  10954. {
  10955. filteredRight.kill();
  10956. while (right.isItem(rightIndex))
  10957. {
  10958. const void * rhs = right.item(rightIndex++);
  10959. if (helper.match(left, rhs))
  10960. {
  10961. matchedRight.replace(true, rightIndex-1);
  10962. filteredRight.append(rhs);
  10963. matchedLeft = true;
  10964. if (filteredRight.ordinality()==joinLimit)
  10965. break;
  10966. }
  10967. }
  10968. state = JSleftonly;
  10969. rightIndex = 0;
  10970. if (!exclude && filteredRight.ordinality())
  10971. {
  10972. const void * ret = denormalizeRecords(left, filteredRight);
  10973. filteredRight.kill();
  10974. if (ret)
  10975. {
  10976. processed++;
  10977. return ret;
  10978. }
  10979. }
  10980. break;
  10981. }
  10982. }
  10983. }
  10984. state = JSleftonly;
  10985. rightIndex = 0;
  10986. joinCounter = 0;
  10987. break;
  10988. }
  10989. }
  10990. }
  10991. };
  10992. class CRoxieServerJoinActivityFactory : public CRoxieServerActivityFactory
  10993. {
  10994. unsigned input2;
  10995. unsigned input2idx;
  10996. public:
  10997. CRoxieServerJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  10998. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  10999. {
  11000. input2 = 0;
  11001. input2idx = 0;
  11002. }
  11003. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  11004. {
  11005. return new CRoxieServerJoinActivity(this, _probeManager);
  11006. }
  11007. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  11008. {
  11009. if (idx==1)
  11010. {
  11011. input2 = source;
  11012. input2idx = sourceidx;
  11013. }
  11014. else
  11015. CRoxieServerActivityFactory::setInput(idx, source, sourceidx);
  11016. }
  11017. virtual unsigned getInput(unsigned idx, unsigned &sourceidx) const
  11018. {
  11019. switch (idx)
  11020. {
  11021. case 1:
  11022. sourceidx = input2idx;
  11023. return input2;
  11024. case 0:
  11025. return CRoxieServerActivityFactory::getInput(idx, sourceidx);
  11026. default:
  11027. return (unsigned) -1;
  11028. }
  11029. }
  11030. virtual unsigned numInputs() const { return 2; }
  11031. };
  11032. IRoxieServerActivityFactory *createRoxieServerJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11033. {
  11034. return new CRoxieServerJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  11035. }
  11036. //=================================================================================
  11037. #define CONCAT_READAHEAD 1000
  11038. class CRoxieThreadedConcatReader : public CInterface, implements IRecordPullerCallback
  11039. {
  11040. public:
  11041. IMPLEMENT_IINTERFACE;
  11042. CRoxieThreadedConcatReader(InterruptableSemaphore &_ready, bool _grouped)
  11043. : puller(false), grouped(_grouped), atEog(true), ready(_ready), eof(false)
  11044. {
  11045. }
  11046. void start(unsigned parentExtractSize, const byte *parentExtract, bool paused, IRoxieSlaveContext *ctx)
  11047. {
  11048. space.reinit(CONCAT_READAHEAD);
  11049. puller.start(parentExtractSize, parentExtract, paused, ctx->concatPreload(), false, ctx);
  11050. }
  11051. void stop(bool aborting)
  11052. {
  11053. space.interrupt();
  11054. puller.stop(aborting);
  11055. }
  11056. IRoxieInput *queryInput() const
  11057. {
  11058. return puller.queryInput();
  11059. }
  11060. void reset()
  11061. {
  11062. puller.reset();
  11063. ForEachItemIn(idx, buffer)
  11064. ReleaseRoxieRow(buffer.item(idx));
  11065. buffer.clear();
  11066. eof = false;
  11067. atEog = true;
  11068. }
  11069. void setInput(IRoxieInput *_in)
  11070. {
  11071. puller.setInput(this, _in);
  11072. }
  11073. virtual void processRow(const void *row)
  11074. {
  11075. buffer.enqueue(row);
  11076. ready.signal();
  11077. space.wait();
  11078. }
  11079. virtual void processGroup(const ConstPointerArray &rows)
  11080. {
  11081. // We use record-by-record input mode of the puller thread even in grouped mode.
  11082. throwUnexpected();
  11083. }
  11084. virtual void processEOG()
  11085. {
  11086. if (grouped)
  11087. processRow(NULL);
  11088. }
  11089. virtual void processDone()
  11090. {
  11091. processRow(NULL);
  11092. }
  11093. virtual bool fireException(IException *e)
  11094. {
  11095. // called from puller thread on failure
  11096. ready.interrupt(LINK(e));
  11097. space.interrupt(e);
  11098. return true;
  11099. }
  11100. bool peek(const void * &row, bool &anyActive)
  11101. {
  11102. if (!eof)
  11103. {
  11104. if (buffer.ordinality())
  11105. {
  11106. space.signal();
  11107. row = buffer.dequeue();
  11108. if (row==NULL)
  11109. {
  11110. if (atEog)
  11111. {
  11112. eof = true;
  11113. return false;
  11114. }
  11115. else
  11116. atEog = true;
  11117. }
  11118. else if (grouped)
  11119. atEog = false;
  11120. return true;
  11121. }
  11122. anyActive = true;
  11123. }
  11124. return false;
  11125. }
  11126. protected:
  11127. RecordPullerThread puller;
  11128. InterruptableSemaphore space;
  11129. InterruptableSemaphore &ready;
  11130. SafeQueueOf<const void, true> buffer;
  11131. bool atEog;
  11132. bool eof;
  11133. bool grouped;
  11134. };
  11135. MAKEPointerArray(CRoxieThreadedConcatReader, ReaderArray);
  11136. class CRoxieServerThreadedConcatActivity : public CRoxieServerActivity
  11137. {
  11138. InterruptableSemaphore ready;
  11139. ReaderArray pullers;
  11140. unsigned numInputs;
  11141. unsigned nextPuller; // for round robin
  11142. unsigned readyPending;
  11143. bool eof;
  11144. bool inGroup;
  11145. bool grouped;
  11146. public:
  11147. CRoxieServerThreadedConcatActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _grouped, unsigned _numInputs)
  11148. : CRoxieServerActivity(_factory, _probeManager), grouped(_grouped)
  11149. {
  11150. numInputs = _numInputs;
  11151. eof = (numInputs==0);
  11152. inGroup = false;
  11153. nextPuller = 0;
  11154. readyPending = 0;
  11155. for (unsigned i = 0; i < numInputs; i++)
  11156. pullers.append(*new CRoxieThreadedConcatReader(ready, _grouped));
  11157. }
  11158. ~CRoxieServerThreadedConcatActivity()
  11159. {
  11160. ForEachItemIn(idx, pullers)
  11161. delete &pullers.item(idx);
  11162. }
  11163. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  11164. {
  11165. eof = (numInputs==0);
  11166. inGroup = false;
  11167. nextPuller = 0;
  11168. readyPending = 0;
  11169. ready.reinit();
  11170. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  11171. ForEachItemIn(idx, pullers)
  11172. {
  11173. pullers.item(idx).start(parentExtractSize, parentExtract, paused, ctx);
  11174. // NOTE - it is ok to start the thread running while parts of the subgraph are still being started, since everything
  11175. // in the part of the subgraph that the thread uses has been started.
  11176. // Note that splitters are supposed to cope with being used when only some outputs have been started.
  11177. }
  11178. }
  11179. virtual void stop(bool aborting)
  11180. {
  11181. ready.interrupt();
  11182. ForEachItemIn(idx, pullers)
  11183. pullers.item(idx).stop(aborting);
  11184. CRoxieServerActivity::stop(aborting);
  11185. }
  11186. virtual unsigned __int64 queryLocalCycles() const
  11187. {
  11188. return 0;
  11189. }
  11190. virtual IRoxieInput *queryInput(unsigned idx) const
  11191. {
  11192. if (pullers.isItem(idx))
  11193. return pullers.item(idx).queryInput();
  11194. else
  11195. return NULL;
  11196. }
  11197. virtual void reset()
  11198. {
  11199. CRoxieServerActivity::reset();
  11200. ForEachItemIn(idx, pullers)
  11201. pullers.item(idx).reset();
  11202. eof = false;
  11203. inGroup = false;
  11204. nextPuller = 0;
  11205. readyPending = 0;
  11206. }
  11207. virtual void setInput(unsigned idx, IRoxieInput *_in)
  11208. {
  11209. if (pullers.isItem(idx))
  11210. pullers.item(idx).setInput(_in);
  11211. else
  11212. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
  11213. }
  11214. virtual const void * nextInGroup()
  11215. {
  11216. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  11217. if (eof)
  11218. return NULL;
  11219. loop
  11220. {
  11221. if (readyPending && !inGroup)
  11222. {
  11223. if (readyPending > 1)
  11224. ready.signal(readyPending-1);
  11225. readyPending = 0;
  11226. }
  11227. else
  11228. ready.wait();
  11229. bool anyActive = false;
  11230. ForEachItemIn(unused_index, pullers)
  11231. {
  11232. // NOTE - we round robin not just because it's more efficient, but because it ensures the preservation of grouping information
  11233. const void *ret;
  11234. bool fetched = pullers.item(nextPuller).peek(ret, anyActive);
  11235. if (fetched)
  11236. {
  11237. inGroup = (ret != NULL);
  11238. return ret;
  11239. }
  11240. if (inGroup && grouped)
  11241. {
  11242. // Some other puller has data, but we can't consume it until the group we are reading is complete.
  11243. readyPending++;
  11244. anyActive = true;
  11245. break;
  11246. }
  11247. nextPuller++;
  11248. if (nextPuller==pullers.ordinality())
  11249. nextPuller = 0;
  11250. }
  11251. if (!anyActive)
  11252. break;
  11253. // A ready signal without anything being ready means someone reached end-of-file.
  11254. }
  11255. eof = true;
  11256. return NULL;
  11257. }
  11258. };
  11259. class CRoxieServerOrderedConcatActivity : public CRoxieServerActivity
  11260. {
  11261. IRoxieInput *curInput;
  11262. bool eogSeen;
  11263. bool anyThisGroup;
  11264. bool grouped;
  11265. unsigned numInputs;
  11266. unsigned inputIdx;
  11267. IRoxieInput **inputArray;
  11268. public:
  11269. CRoxieServerOrderedConcatActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _grouped, unsigned _numInputs)
  11270. : CRoxieServerActivity(_factory, _probeManager)
  11271. {
  11272. eogSeen = false;
  11273. anyThisGroup = false;
  11274. grouped = _grouped;
  11275. numInputs = _numInputs;
  11276. inputIdx = 0;
  11277. inputArray = new IRoxieInput*[numInputs];
  11278. for (unsigned i = 0; i < numInputs; i++)
  11279. inputArray[i] = NULL;
  11280. curInput = NULL;
  11281. }
  11282. ~CRoxieServerOrderedConcatActivity()
  11283. {
  11284. delete [] inputArray;
  11285. }
  11286. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  11287. {
  11288. inputIdx = 0;
  11289. curInput = inputArray[inputIdx];
  11290. eogSeen = false;
  11291. anyThisGroup = false;
  11292. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  11293. for (unsigned i = 0; i < numInputs; i++)
  11294. inputArray[i]->start(parentExtractSize, parentExtract, paused);
  11295. }
  11296. virtual void stop(bool aborting)
  11297. {
  11298. for (unsigned i = 0; i < numInputs; i++)
  11299. inputArray[i]->stop(aborting);
  11300. CRoxieServerActivity::stop(aborting);
  11301. }
  11302. virtual unsigned __int64 queryLocalCycles() const
  11303. {
  11304. return 0;
  11305. }
  11306. virtual IRoxieInput *queryInput(unsigned idx) const
  11307. {
  11308. if (idx < numInputs)
  11309. return inputArray[idx];
  11310. else
  11311. return NULL;
  11312. }
  11313. virtual void reset()
  11314. {
  11315. CRoxieServerActivity::reset();
  11316. for (unsigned i = 0; i < numInputs; i++)
  11317. inputArray[i]->reset();
  11318. }
  11319. virtual void setInput(unsigned idx, IRoxieInput *_in)
  11320. {
  11321. inputArray[idx] = _in;
  11322. }
  11323. virtual const void * nextInGroup()
  11324. {
  11325. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  11326. if (!curInput)
  11327. return NULL; // eof
  11328. const void * next = curInput->nextInGroup();
  11329. if (next)
  11330. {
  11331. anyThisGroup = true;
  11332. eogSeen = false;
  11333. processed++;
  11334. return next;
  11335. }
  11336. else if (!eogSeen)
  11337. {
  11338. eogSeen = true;
  11339. if (grouped)
  11340. {
  11341. if (anyThisGroup)
  11342. {
  11343. anyThisGroup = false;
  11344. return NULL;
  11345. }
  11346. else
  11347. return nextInGroup();
  11348. }
  11349. else
  11350. return nextInGroup();
  11351. }
  11352. else if (inputIdx < numInputs-1)
  11353. {
  11354. inputIdx++;
  11355. curInput = inputArray[inputIdx];
  11356. eogSeen = false;
  11357. return nextInGroup();
  11358. }
  11359. else
  11360. {
  11361. curInput = NULL;
  11362. return NULL;
  11363. }
  11364. }
  11365. };
  11366. class CRoxieServerConcatActivityFactory : public CRoxieServerMultiInputFactory
  11367. {
  11368. bool ordered;
  11369. bool grouped;
  11370. public:
  11371. CRoxieServerConcatActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11372. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  11373. {
  11374. Owned <IHThorFunnelArg> helper = (IHThorFunnelArg *) helperFactory();
  11375. ordered = helper->isOrdered();
  11376. grouped = helper->queryOutputMeta()->isGrouped();
  11377. }
  11378. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  11379. {
  11380. if (ordered || (_probeManager && _probeManager->queryDebugManager()))
  11381. return new CRoxieServerOrderedConcatActivity(this, _probeManager, grouped, numInputs());
  11382. else
  11383. return new CRoxieServerThreadedConcatActivity(this, _probeManager, grouped, numInputs());
  11384. }
  11385. };
  11386. IRoxieServerActivityFactory *createRoxieServerConcatActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11387. {
  11388. return new CRoxieServerConcatActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  11389. }
  11390. //=================================================================================
  11391. class CRoxieServerNonEmptyActivity : public CRoxieServerMultiInputBaseActivity
  11392. {
  11393. IRoxieInput * selectedInput;
  11394. unsigned savedParentExtractSize;
  11395. const byte * savedParentExtract;
  11396. bool foundInput;
  11397. public:
  11398. CRoxieServerNonEmptyActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  11399. : CRoxieServerMultiInputBaseActivity(_factory, _probeManager, _numInputs)
  11400. {
  11401. foundInput = false;
  11402. selectedInput = NULL;
  11403. savedParentExtractSize = 0;;
  11404. savedParentExtract = NULL;
  11405. }
  11406. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  11407. {
  11408. //Don't start the inputs yet so we can short-circuit...
  11409. CRoxieServerMultiInputBaseActivity::start(parentExtractSize, parentExtract, paused);
  11410. savedParentExtractSize = parentExtractSize;
  11411. savedParentExtract = parentExtract;
  11412. }
  11413. virtual void stop(bool aborting)
  11414. {
  11415. if (foundInput)
  11416. {
  11417. if (selectedInput)
  11418. selectedInput->stop(aborting);
  11419. }
  11420. else
  11421. {
  11422. for (unsigned i = 0; i < numInputs; i++)
  11423. inputArray[i]->stop(aborting);
  11424. }
  11425. CRoxieServerMultiInputBaseActivity::stop(aborting);
  11426. }
  11427. virtual void reset()
  11428. {
  11429. CRoxieServerMultiInputBaseActivity::reset();
  11430. foundInput = false;
  11431. selectedInput = NULL;
  11432. }
  11433. virtual unsigned __int64 queryLocalCycles() const
  11434. {
  11435. return 0; // Can't easily calcuate anything reliable but local processing is negligible
  11436. }
  11437. virtual const void * nextInGroup()
  11438. {
  11439. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  11440. if (!foundInput)
  11441. {
  11442. foundInput = true;
  11443. //If we get an exception in this loop then stop() will stop any started inputs
  11444. for (unsigned i=0; i < numInputs; i++)
  11445. {
  11446. selectedInput = inputArray[i];
  11447. selectedInput->start(savedParentExtractSize, savedParentExtract, false);
  11448. const void * next = selectedInput->nextInGroup();
  11449. if (next)
  11450. {
  11451. //Found a row so stop remaining
  11452. for (unsigned j=i+1; j < numInputs; j++)
  11453. inputArray[j]->stop(false);
  11454. processed++;
  11455. return next;
  11456. }
  11457. selectedInput->stop(false);
  11458. }
  11459. selectedInput = NULL;
  11460. return NULL;
  11461. }
  11462. if (!selectedInput)
  11463. return NULL;
  11464. const void * next = selectedInput->nextInGroup();
  11465. if (next)
  11466. processed++;
  11467. return next;
  11468. }
  11469. };
  11470. class CRoxieServerNonEmptyActivityFactory : public CRoxieServerMultiInputFactory
  11471. {
  11472. public:
  11473. CRoxieServerNonEmptyActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11474. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  11475. {
  11476. }
  11477. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  11478. {
  11479. return new CRoxieServerNonEmptyActivity(this, _probeManager, numInputs());
  11480. }
  11481. };
  11482. IRoxieServerActivityFactory *createRoxieServerNonEmptyActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11483. {
  11484. return new CRoxieServerNonEmptyActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  11485. }
  11486. //=================================================================================
  11487. class CRoxieServerMergeActivity : public CRoxieServerActivity
  11488. {
  11489. IHThorMergeArg &helper;
  11490. unsigned *mergeheap;
  11491. unsigned activeInputs;
  11492. unsigned numInputs;
  11493. IRoxieInput **inputArray;
  11494. const void **pending;
  11495. bool first;
  11496. ICompare *compare;
  11497. bool dedup;
  11498. void permute()
  11499. {
  11500. assertex(activeInputs == 0);
  11501. for(unsigned i = 0; i < numInputs; i++)
  11502. if(pullInput(i))
  11503. mergeheap[activeInputs++] = i;
  11504. // the tree structure: element p has children p*2+1 and p*2+2, or element c has parent (unsigned)(c-1)/2
  11505. // the heap property: no element should be smaller than its parent
  11506. // the dedup variant: if(dedup), the top of the heap should also not be equal to either child
  11507. // 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
  11508. if (activeInputs >= 2)
  11509. for(unsigned p = (activeInputs-2)/2; p > 0; --p)
  11510. siftDown(p);
  11511. if(dedup)
  11512. siftDownDedupTop();
  11513. else
  11514. siftDown(0);
  11515. }
  11516. void readNext()
  11517. {
  11518. if(!pullInput(mergeheap[0]))
  11519. if(!promote(0))
  11520. return;
  11521. // we have changed the element at the top of the heap, so need to sift it down to maintain the heap property
  11522. if(dedup)
  11523. siftDownDedupTop();
  11524. else
  11525. siftDown(0);
  11526. }
  11527. bool pullInput(unsigned i)
  11528. {
  11529. const void *next = inputArray[i]->nextInGroup();
  11530. if (!next)
  11531. next = inputArray[i]->nextInGroup();
  11532. pending[i] = next;
  11533. return (next != NULL);
  11534. }
  11535. bool promote(unsigned p)
  11536. {
  11537. activeInputs--;
  11538. if(activeInputs == p)
  11539. return false;
  11540. mergeheap[p] = mergeheap[activeInputs];
  11541. return true;
  11542. }
  11543. bool siftDown(unsigned p)
  11544. {
  11545. // assumimg that all descendents of p form a heap, sift p down to its correct position, and so include it in the heap
  11546. bool nochange = true;
  11547. while(1)
  11548. {
  11549. unsigned c = p*2 + 1;
  11550. if(c >= activeInputs)
  11551. return nochange;
  11552. if(c+1 < activeInputs)
  11553. {
  11554. int childcmp = BuffCompare(c+1, c);
  11555. if((childcmp < 0) || ((childcmp == 0) && (mergeheap[c+1] < mergeheap[c])))
  11556. ++c;
  11557. }
  11558. int cmp = BuffCompare(c, p);
  11559. if((cmp > 0) || ((cmp == 0) && (mergeheap[c] > mergeheap[p])))
  11560. return nochange;
  11561. nochange = false;
  11562. unsigned r = mergeheap[c];
  11563. mergeheap[c] = mergeheap[p];
  11564. mergeheap[p] = r;
  11565. p = c;
  11566. }
  11567. }
  11568. void siftDownDedupTop()
  11569. {
  11570. // same as siftDown(0), except that it also ensures that the top of the heap is not equal to either of its children
  11571. if(activeInputs < 2)
  11572. return;
  11573. unsigned c = 1;
  11574. int childcmp = 1;
  11575. if(activeInputs >= 3)
  11576. {
  11577. childcmp = BuffCompare(2, 1);
  11578. if(childcmp < 0)
  11579. c = 2;
  11580. }
  11581. int cmp = BuffCompare(c, 0);
  11582. if(cmp > 0)
  11583. return;
  11584. // the following loop ensures the correct property holds on the smaller branch, and that childcmp==0 iff the top matches the other branch
  11585. while(cmp <= 0)
  11586. {
  11587. if(cmp == 0)
  11588. {
  11589. if(mergeheap[c] < mergeheap[0])
  11590. {
  11591. unsigned r = mergeheap[c];
  11592. mergeheap[c] = mergeheap[0];
  11593. mergeheap[0] = r;
  11594. }
  11595. ReleaseClearRoxieRow(pending[mergeheap[c]]);
  11596. if(!pullInput(mergeheap[c]))
  11597. if(!promote(c))
  11598. break;
  11599. siftDown(c);
  11600. }
  11601. else
  11602. {
  11603. unsigned r = mergeheap[c];
  11604. mergeheap[c] = mergeheap[0];
  11605. mergeheap[0] = r;
  11606. if(siftDown(c))
  11607. break;
  11608. }
  11609. cmp = BuffCompare(c, 0);
  11610. }
  11611. // the following loop ensures the uniqueness property holds on the other branch too
  11612. c = 3-c;
  11613. if(activeInputs <= c)
  11614. return;
  11615. while(childcmp == 0)
  11616. {
  11617. if(mergeheap[c] < mergeheap[0])
  11618. {
  11619. unsigned r = mergeheap[c];
  11620. mergeheap[c] = mergeheap[0];
  11621. mergeheap[0] = r;
  11622. }
  11623. ReleaseClearRoxieRow(pending[mergeheap[c]]);
  11624. if(!pullInput(mergeheap[c]))
  11625. if(!promote(c))
  11626. break;
  11627. siftDown(c);
  11628. childcmp = BuffCompare(c, 0);
  11629. }
  11630. }
  11631. inline int BuffCompare(unsigned a, unsigned b)
  11632. {
  11633. return compare->docompare(pending[mergeheap[a]], pending[mergeheap[b]]);
  11634. }
  11635. public:
  11636. CRoxieServerMergeActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  11637. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorMergeArg &)basehelper), numInputs(_numInputs)
  11638. {
  11639. activeInputs = 0;
  11640. first = true;
  11641. mergeheap = new unsigned[numInputs];
  11642. inputArray = new IRoxieInput*[numInputs];
  11643. pending = new const void *[numInputs];
  11644. compare = helper.queryCompare();
  11645. dedup = helper.dedup();
  11646. for (unsigned i = 0; i < numInputs; i++)
  11647. {
  11648. inputArray[i] = NULL;
  11649. pending[i] = NULL;
  11650. }
  11651. }
  11652. ~CRoxieServerMergeActivity()
  11653. {
  11654. delete [] mergeheap;
  11655. delete [] inputArray;
  11656. delete [] pending;
  11657. }
  11658. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  11659. {
  11660. activeInputs = 0;
  11661. first = true;
  11662. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  11663. for (unsigned i = 0; i < numInputs; i++)
  11664. {
  11665. inputArray[i]->start(parentExtractSize, parentExtract, paused);
  11666. }
  11667. }
  11668. virtual void stop(bool aborting)
  11669. {
  11670. for (unsigned i = 0; i < numInputs; i++)
  11671. {
  11672. inputArray[i]->stop(aborting);
  11673. }
  11674. CRoxieServerActivity::stop(aborting);
  11675. }
  11676. virtual void reset()
  11677. {
  11678. for (unsigned i = 0; i < numInputs; i++)
  11679. {
  11680. ReleaseClearRoxieRow(pending[i]);
  11681. inputArray[i]->reset();
  11682. }
  11683. CRoxieServerActivity::reset();
  11684. }
  11685. virtual void setInput(unsigned idx, IRoxieInput *_in)
  11686. {
  11687. inputArray[idx] = _in;
  11688. }
  11689. virtual const void * nextInGroup()
  11690. {
  11691. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  11692. if (first)
  11693. {
  11694. permute();
  11695. first = false;
  11696. }
  11697. if (activeInputs)
  11698. {
  11699. const void *next = pending[mergeheap[0]];
  11700. readNext();
  11701. if (next)
  11702. processed++;
  11703. return next;
  11704. }
  11705. else
  11706. return NULL;
  11707. }
  11708. };
  11709. class CRoxieServerMergeActivityFactory : public CRoxieServerMultiInputFactory
  11710. {
  11711. public:
  11712. CRoxieServerMergeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11713. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  11714. {
  11715. }
  11716. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  11717. {
  11718. return new CRoxieServerMergeActivity(this, _probeManager, numInputs());
  11719. }
  11720. };
  11721. IRoxieServerActivityFactory *createRoxieServerMergeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11722. {
  11723. return new CRoxieServerMergeActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  11724. }
  11725. //=================================================================================
  11726. class CRoxieServerRegroupActivity : public CRoxieServerMultiInputActivity
  11727. {
  11728. IHThorRegroupArg &helper;
  11729. unsigned inputIndex;
  11730. bool eof;
  11731. unsigned __int64 numProcessedLastGroup;
  11732. public:
  11733. CRoxieServerRegroupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  11734. : CRoxieServerMultiInputActivity(_factory, _probeManager, _numInputs), helper((IHThorRegroupArg &)basehelper)
  11735. {
  11736. inputIndex = 0;
  11737. eof = false;
  11738. numProcessedLastGroup = 0;
  11739. }
  11740. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  11741. {
  11742. inputIndex = 0;
  11743. eof = false;
  11744. numProcessedLastGroup = processed;
  11745. CRoxieServerMultiInputActivity::start(parentExtractSize, parentExtract, paused);
  11746. }
  11747. const void * nextFromInputs()
  11748. {
  11749. unsigned initialInput = inputIndex;
  11750. while (inputIndex < numInputs)
  11751. {
  11752. const void * next = inputArray[inputIndex]->nextInGroup();
  11753. if (next)
  11754. {
  11755. if ((inputIndex != initialInput) && (inputIndex != initialInput+1))
  11756. {
  11757. ReleaseRoxieRow(next);
  11758. throw MakeStringException(ROXIE_MISMATCH_GROUP_ERROR, "Mismatched groups supplied to Regroup (%d)", factory->queryId());
  11759. }
  11760. return next;
  11761. }
  11762. inputIndex++;
  11763. }
  11764. if ((initialInput != 0) && (initialInput+1 != numInputs))
  11765. throw MakeStringException(ROXIE_MISMATCH_GROUP_ERROR, "Mismatched groups supplied to Regroup (%d)", factory->queryId());
  11766. inputIndex = 0;
  11767. return NULL;
  11768. }
  11769. virtual const void * nextInGroup()
  11770. {
  11771. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  11772. if (eof)
  11773. return NULL;
  11774. const void * ret = nextFromInputs();
  11775. if (ret)
  11776. {
  11777. processed++;
  11778. return ret;
  11779. }
  11780. if (numProcessedLastGroup != processed)
  11781. {
  11782. numProcessedLastGroup = processed;
  11783. return NULL;
  11784. }
  11785. eof = true;
  11786. return NULL;
  11787. }
  11788. #if 0
  11789. virtual void setInput(unsigned idx, IRoxieInput *_in)
  11790. {
  11791. //MORE: RKC: Do we want to do this i) always ii) conditionally iii) never
  11792. if (idx)
  11793. {
  11794. puller.setown(new CRoxieServerReadAheadInput(0)); // MORE - cant ask context for parallelJoinPreload as context is not yet set up.
  11795. puller->setInput(0, _in);
  11796. CRoxieServerMultiInputActivity::setInput(idx, puller);
  11797. }
  11798. else
  11799. CRoxieServerMultiInputActivity::setInput(idx, _in);
  11800. }
  11801. #endif
  11802. };
  11803. class CRoxieServerRegroupActivityFactory : public CRoxieServerMultiInputFactory
  11804. {
  11805. public:
  11806. CRoxieServerRegroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11807. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  11808. {
  11809. }
  11810. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  11811. {
  11812. return new CRoxieServerRegroupActivity(this, _probeManager, numInputs());
  11813. }
  11814. };
  11815. IRoxieServerActivityFactory *createRoxieServerRegroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11816. {
  11817. return new CRoxieServerRegroupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  11818. }
  11819. //=================================================================================
  11820. class CRoxieServerCombineActivity : public CRoxieServerMultiInputActivity
  11821. {
  11822. IHThorCombineArg &helper;
  11823. unsigned __int64 numProcessedLastGroup;
  11824. public:
  11825. CRoxieServerCombineActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  11826. : CRoxieServerMultiInputActivity(_factory, _probeManager, _numInputs), helper((IHThorCombineArg &)basehelper)
  11827. {
  11828. numProcessedLastGroup = 0;
  11829. }
  11830. ~CRoxieServerCombineActivity()
  11831. {
  11832. }
  11833. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  11834. {
  11835. numProcessedLastGroup = processed;
  11836. CRoxieServerMultiInputActivity::start(parentExtractSize, parentExtract, paused);
  11837. }
  11838. void nextInputs(ConstPointerArray & out)
  11839. {
  11840. for (unsigned i=0; i < numInputs; i++)
  11841. {
  11842. const void * next = inputArray[i]->nextInGroup();
  11843. if (next)
  11844. out.append(next);
  11845. }
  11846. }
  11847. virtual bool needsAllocator() const { return true; }
  11848. virtual const void * nextInGroup()
  11849. {
  11850. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  11851. loop
  11852. {
  11853. ConstPointerArray group;
  11854. nextInputs(group);
  11855. if ((group.ordinality() == 0) && (numProcessedLastGroup == processed))
  11856. nextInputs(group);
  11857. if (group.ordinality() == 0)
  11858. {
  11859. numProcessedLastGroup = processed;
  11860. return NULL;
  11861. }
  11862. else if (group.ordinality() != numInputs)
  11863. {
  11864. ReleaseRoxieRowSet(group);
  11865. throw MakeStringException(ROXIE_MISMATCH_GROUP_ERROR, "Mismatched group input for Combine Activity(%d)", factory->queryId());
  11866. }
  11867. try
  11868. {
  11869. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  11870. size32_t outSize = helper.transform(rowBuilder, group.ordinality(), group.getArray());
  11871. ReleaseRoxieRowSet(group);
  11872. if (outSize)
  11873. {
  11874. processed++;
  11875. return rowBuilder.finalizeRowClear(outSize);
  11876. }
  11877. }
  11878. catch (IException *E)
  11879. {
  11880. ReleaseRoxieRowSet(group);
  11881. throw makeWrappedException(E);
  11882. }
  11883. }
  11884. }
  11885. };
  11886. class CRoxieServerCombineActivityFactory : public CRoxieServerMultiInputFactory
  11887. {
  11888. public:
  11889. CRoxieServerCombineActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11890. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  11891. {
  11892. }
  11893. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  11894. {
  11895. return new CRoxieServerCombineActivity(this, _probeManager, numInputs());
  11896. }
  11897. };
  11898. IRoxieServerActivityFactory *createRoxieServerCombineActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11899. {
  11900. return new CRoxieServerCombineActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  11901. }
  11902. //=================================================================================
  11903. class CRoxieServerCombineGroupActivity : public CRoxieServerTwoInputActivity
  11904. {
  11905. IHThorCombineGroupArg &helper;
  11906. unsigned __int64 numProcessedLastGroup;
  11907. public:
  11908. CRoxieServerCombineGroupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  11909. : CRoxieServerTwoInputActivity(_factory, _probeManager), helper((IHThorCombineGroupArg &)basehelper)
  11910. {
  11911. numProcessedLastGroup = 0;
  11912. }
  11913. ~CRoxieServerCombineGroupActivity()
  11914. {
  11915. }
  11916. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  11917. {
  11918. numProcessedLastGroup = processed;
  11919. CRoxieServerTwoInputActivity::start(parentExtractSize, parentExtract, paused);
  11920. }
  11921. virtual void setInput(unsigned idx, IRoxieInput *_in)
  11922. {
  11923. switch(idx)
  11924. {
  11925. case 0:
  11926. #if 0
  11927. //MORE: RKC: Do we want to do this i) always ii) conditionally iii) never
  11928. puller.setown(new CRoxieServerReadAheadInput(0)); // MORE - cant ask context for parallelJoinPreload as context is not yet set up.
  11929. puller->setInput(0, _in);
  11930. _in = puller;
  11931. #endif
  11932. input = _in;
  11933. break;
  11934. case 1:
  11935. input1 = _in;
  11936. break;
  11937. default:
  11938. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
  11939. }
  11940. }
  11941. virtual IRoxieInput *queryOutput(unsigned idx)
  11942. {
  11943. if (idx==(unsigned)-1)
  11944. idx = 0;
  11945. return idx ? NULL : this;
  11946. }
  11947. virtual bool needsAllocator() const { return true; }
  11948. virtual const void * nextInGroup()
  11949. {
  11950. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  11951. loop
  11952. {
  11953. const void * left = input->nextInGroup();
  11954. if (!left && (numProcessedLastGroup == processed))
  11955. left = input->nextInGroup();
  11956. if (!left)
  11957. {
  11958. if (numProcessedLastGroup == processed)
  11959. {
  11960. const void * nextRight = input1->nextInGroup();
  11961. if (nextRight)
  11962. {
  11963. ReleaseRoxieRow(nextRight);
  11964. throw MakeStringException(ROXIE_MISSING_GROUP_ERROR, "Missing LEFT record for Combine Group (%d)", factory->queryId());
  11965. }
  11966. }
  11967. else
  11968. numProcessedLastGroup = processed;
  11969. return NULL;
  11970. }
  11971. ConstPointerArray group;
  11972. loop
  11973. {
  11974. const void * in = input1->nextInGroup();
  11975. if (!in)
  11976. break;
  11977. group.append(in);
  11978. }
  11979. if (group.ordinality() == 0)
  11980. {
  11981. ReleaseRoxieRow(left);
  11982. ReleaseRoxieRowSet(group);
  11983. throw MakeStringException(ROXIE_MISSING_GROUP_ERROR, "Missing RIGHT group for Combine Group (%d)", factory->queryId());
  11984. }
  11985. try
  11986. {
  11987. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  11988. size32_t outSize = helper.transform(rowBuilder, left, group.ordinality(), (const void * *)group.getArray());
  11989. ReleaseRoxieRow(left);
  11990. ReleaseRoxieRowSet(group);
  11991. if (outSize)
  11992. {
  11993. processed++;
  11994. return rowBuilder.finalizeRowClear(outSize);
  11995. }
  11996. }
  11997. catch (IException *E)
  11998. {
  11999. ReleaseRoxieRow(left);
  12000. ReleaseRoxieRowSet(group);
  12001. throw makeWrappedException(E);
  12002. }
  12003. }
  12004. }
  12005. };
  12006. class CRoxieServerCombineGroupActivityFactory : public CRoxieServerActivityFactory
  12007. {
  12008. unsigned input2;
  12009. unsigned input2idx;
  12010. public:
  12011. CRoxieServerCombineGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  12012. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  12013. {
  12014. input2 = 0;
  12015. input2idx = 0;
  12016. }
  12017. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  12018. {
  12019. return new CRoxieServerCombineGroupActivity(this, _probeManager);
  12020. }
  12021. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  12022. {
  12023. if (idx==1)
  12024. {
  12025. input2 = source;
  12026. input2idx = sourceidx;
  12027. }
  12028. else
  12029. CRoxieServerActivityFactory::setInput(idx, source, sourceidx);
  12030. }
  12031. virtual unsigned getInput(unsigned idx, unsigned &sourceidx) const
  12032. {
  12033. switch (idx)
  12034. {
  12035. case 1:
  12036. sourceidx = input2idx;
  12037. return input2;
  12038. case 0:
  12039. return CRoxieServerActivityFactory::getInput(idx, sourceidx);
  12040. default:
  12041. return (unsigned) -1;
  12042. }
  12043. }
  12044. virtual unsigned numInputs() const { return 2; }
  12045. };
  12046. IRoxieServerActivityFactory *createRoxieServerCombineGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  12047. {
  12048. return new CRoxieServerCombineGroupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  12049. }
  12050. //=================================================================================
  12051. class CRoxieServerRollupGroupActivity : public CRoxieServerActivity
  12052. {
  12053. IHThorRollupGroupArg &helper;
  12054. bool eof;
  12055. public:
  12056. CRoxieServerRollupGroupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  12057. : CRoxieServerActivity(_factory, _probeManager),
  12058. helper((IHThorRollupGroupArg &)basehelper)
  12059. {
  12060. eof = false;
  12061. }
  12062. ~CRoxieServerRollupGroupActivity()
  12063. {
  12064. }
  12065. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  12066. {
  12067. eof = false;
  12068. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  12069. }
  12070. virtual bool needsAllocator() const { return true; }
  12071. virtual const void * nextInGroup()
  12072. {
  12073. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  12074. if (eof)
  12075. return NULL;
  12076. loop
  12077. {
  12078. ConstPointerArray group;
  12079. loop
  12080. {
  12081. const void * in = input->nextInGroup();
  12082. if (!in)
  12083. break;
  12084. group.append(in);
  12085. }
  12086. if (group.ordinality() == 0)
  12087. {
  12088. eof = true;
  12089. return NULL;
  12090. }
  12091. try
  12092. {
  12093. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  12094. size32_t outSize = helper.transform(rowBuilder, group.ordinality(), (const void * *)group.getArray());
  12095. ReleaseRoxieRowSet(group);
  12096. if (outSize)
  12097. {
  12098. processed++;
  12099. return rowBuilder.finalizeRowClear(outSize);
  12100. }
  12101. }
  12102. catch (IException * E)
  12103. {
  12104. ReleaseRoxieRowSet(group);
  12105. throw makeWrappedException(E);
  12106. }
  12107. }
  12108. }
  12109. };
  12110. class CRoxieServerRollupGroupActivityFactory : public CRoxieServerActivityFactory
  12111. {
  12112. public:
  12113. CRoxieServerRollupGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  12114. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  12115. {
  12116. }
  12117. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  12118. {
  12119. return new CRoxieServerRollupGroupActivity(this, _probeManager);
  12120. }
  12121. };
  12122. IRoxieServerActivityFactory *createRoxieServerRollupGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  12123. {
  12124. return new CRoxieServerRollupGroupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  12125. }
  12126. //=================================================================================
  12127. class CRoxieServerFilterProjectActivity : public CRoxieServerLateStartActivity
  12128. {
  12129. IHThorFilterProjectArg &helper;
  12130. unsigned numProcessedLastGroup;
  12131. unsigned __int64 recordCount;
  12132. public:
  12133. CRoxieServerFilterProjectActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  12134. : CRoxieServerLateStartActivity(_factory, _probeManager), helper((IHThorFilterProjectArg &)basehelper)
  12135. {
  12136. numProcessedLastGroup = 0;
  12137. recordCount = 0;
  12138. }
  12139. ~CRoxieServerFilterProjectActivity()
  12140. {
  12141. }
  12142. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  12143. {
  12144. numProcessedLastGroup = 0;
  12145. recordCount = 0;
  12146. CRoxieServerLateStartActivity::start(parentExtractSize, parentExtract, paused);
  12147. lateStart(parentExtractSize, parentExtract, helper.canMatchAny()); //sets eof
  12148. }
  12149. virtual bool needsAllocator() const { return true; }
  12150. virtual const void * nextInGroup()
  12151. {
  12152. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  12153. if (eof)
  12154. return NULL;
  12155. loop
  12156. {
  12157. const void * in = input->nextInGroup();
  12158. if (!in)
  12159. {
  12160. recordCount = 0;
  12161. if (numProcessedLastGroup == processed)
  12162. in = input->nextInGroup();
  12163. if (!in)
  12164. {
  12165. numProcessedLastGroup = processed;
  12166. return NULL;
  12167. }
  12168. }
  12169. try
  12170. {
  12171. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  12172. size32_t outSize = helper.transform(rowBuilder, in, ++recordCount);
  12173. ReleaseRoxieRow(in);
  12174. if (outSize)
  12175. {
  12176. processed++;
  12177. return rowBuilder.finalizeRowClear(outSize);
  12178. }
  12179. }
  12180. catch (IException *E)
  12181. {
  12182. throw makeWrappedException(E);
  12183. }
  12184. }
  12185. }
  12186. };
  12187. class CRoxieServerFilterProjectActivityFactory : public CRoxieServerActivityFactory
  12188. {
  12189. public:
  12190. CRoxieServerFilterProjectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  12191. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  12192. {
  12193. }
  12194. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  12195. {
  12196. return new CRoxieServerFilterProjectActivity(this, _probeManager);
  12197. }
  12198. };
  12199. IRoxieServerActivityFactory *createRoxieServerFilterProjectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  12200. {
  12201. return new CRoxieServerFilterProjectActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  12202. }
  12203. //=================================================================================
  12204. class CRoxieServerProjectActivity : public CRoxieServerActivity
  12205. {
  12206. unsigned numProcessedLastGroup;
  12207. bool count;
  12208. unsigned __int64 recordCount;
  12209. public:
  12210. CRoxieServerProjectActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _count)
  12211. : CRoxieServerActivity(_factory, _probeManager),
  12212. count(_count)
  12213. {
  12214. numProcessedLastGroup = 0;
  12215. recordCount = 0;
  12216. }
  12217. ~CRoxieServerProjectActivity()
  12218. {
  12219. }
  12220. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  12221. {
  12222. numProcessedLastGroup = 0;
  12223. recordCount = 0;
  12224. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  12225. }
  12226. virtual bool needsAllocator() const { return true; }
  12227. virtual const void * nextInGroup()
  12228. {
  12229. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  12230. loop
  12231. {
  12232. OwnedConstRoxieRow in = input->nextInGroup();
  12233. if (!in)
  12234. {
  12235. recordCount = 0;
  12236. if (numProcessedLastGroup == processed)
  12237. in.setown(input->nextInGroup());
  12238. if (!in)
  12239. {
  12240. numProcessedLastGroup = processed;
  12241. return NULL;
  12242. }
  12243. }
  12244. try
  12245. {
  12246. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  12247. size32_t outSize;
  12248. if (count)
  12249. outSize = ((IHThorCountProjectArg &) basehelper).transform(rowBuilder, in, ++recordCount);
  12250. else
  12251. outSize = ((IHThorProjectArg &) basehelper).transform(rowBuilder, in);
  12252. if (outSize)
  12253. {
  12254. processed++;
  12255. return rowBuilder.finalizeRowClear(outSize);
  12256. }
  12257. }
  12258. catch (IException *E)
  12259. {
  12260. throw makeWrappedException(E);
  12261. }
  12262. }
  12263. }
  12264. };
  12265. class CRoxieServerProjectActivityFactory : public CRoxieServerActivityFactory
  12266. {
  12267. protected:
  12268. bool count;
  12269. public:
  12270. CRoxieServerProjectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  12271. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  12272. {
  12273. count = (_kind==TAKcountproject || _kind==TAKprefetchcountproject);
  12274. }
  12275. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  12276. {
  12277. return new CRoxieServerProjectActivity(this, _probeManager, count);
  12278. }
  12279. };
  12280. IRoxieServerActivityFactory *createRoxieServerProjectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  12281. {
  12282. return new CRoxieServerProjectActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  12283. }
  12284. //=================================================================================
  12285. class CRoxieServerPrefetchProjectActivity : public CRoxieServerActivity, implements IRecordPullerCallback
  12286. {
  12287. unsigned numProcessedLastGroup;
  12288. bool count;
  12289. bool eof;
  12290. bool allPulled;
  12291. bool isThreaded;
  12292. unsigned preload;
  12293. unsigned __int64 recordCount;
  12294. IHThorPrefetchProjectArg &helper;
  12295. RecordPullerThread puller;
  12296. InterruptableSemaphore ready;
  12297. InterruptableSemaphore space;
  12298. class PrefetchInfo : public CInterface
  12299. {
  12300. public:
  12301. inline PrefetchInfo(IHThorPrefetchProjectArg &helper, const void *_in, unsigned __int64 _recordCount)
  12302. {
  12303. if (helper.preTransform(extract, _in, _recordCount))
  12304. {
  12305. in.setown(_in);
  12306. recordCount = _recordCount;
  12307. }
  12308. else
  12309. ReleaseRoxieRow(_in);
  12310. }
  12311. OwnedConstRoxieRow in;
  12312. unsigned __int64 recordCount;
  12313. rtlRowBuilder extract;
  12314. };
  12315. QueueOf<PrefetchInfo, true> pulled;
  12316. CriticalSection pulledCrit;
  12317. public:
  12318. CRoxieServerPrefetchProjectActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _count)
  12319. : CRoxieServerActivity(_factory, _probeManager),
  12320. helper((IHThorPrefetchProjectArg &) basehelper),
  12321. puller(false),
  12322. count(_count)
  12323. {
  12324. numProcessedLastGroup = 0;
  12325. recordCount = 0;
  12326. eof = false;
  12327. allPulled = false;
  12328. isThreaded = (helper.getFlags() & PPFparallel) != 0;
  12329. preload = 0;
  12330. }
  12331. ~CRoxieServerPrefetchProjectActivity()
  12332. {
  12333. while (pulled.ordinality())
  12334. ::Release(pulled.dequeue());
  12335. }
  12336. virtual void setInput(unsigned idx, IRoxieInput *_in)
  12337. {
  12338. if (idx)
  12339. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
  12340. puller.setInput(this, _in);
  12341. }
  12342. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  12343. {
  12344. numProcessedLastGroup = 0;
  12345. recordCount = 0;
  12346. eof = false;
  12347. allPulled = false;
  12348. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  12349. preload = helper.getLookahead();
  12350. if (!preload)
  12351. preload = ctx->prefetchProjectPreload();
  12352. space.reinit(preload);
  12353. ready.reinit();
  12354. puller.start(parentExtractSize, parentExtract, paused, preload, !isThreaded, ctx);
  12355. }
  12356. virtual void stop(bool aborting)
  12357. {
  12358. space.interrupt();
  12359. ready.interrupt();
  12360. CRoxieServerActivity::stop(aborting);
  12361. puller.stop(aborting);
  12362. }
  12363. virtual void reset()
  12364. {
  12365. CRoxieServerActivity::reset();
  12366. puller.reset();
  12367. allPulled = false;
  12368. while (pulled.ordinality())
  12369. ::Release(pulled.dequeue());
  12370. }
  12371. virtual PrefetchInfo *readNextRecord()
  12372. {
  12373. if (!isThreaded)
  12374. {
  12375. if (!allPulled) // This looks like it's thread unsafe but we are inside the if(!isThreaded) so should be ok
  12376. puller.pullRecords(1);
  12377. }
  12378. else
  12379. ready.wait();
  12380. CriticalBlock b(pulledCrit);
  12381. PrefetchInfo *ret = pulled.ordinality() ? pulled.dequeue() : NULL;
  12382. space.signal();
  12383. return ret;
  12384. }
  12385. virtual bool needsAllocator() const { return true; }
  12386. virtual const void * nextInGroup()
  12387. {
  12388. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  12389. if (eof)
  12390. return NULL;
  12391. loop
  12392. {
  12393. Owned<PrefetchInfo> in = readNextRecord();
  12394. if (!in)
  12395. {
  12396. recordCount = 0;
  12397. if (numProcessedLastGroup == processed)
  12398. in.setown(readNextRecord());
  12399. if (!in)
  12400. {
  12401. numProcessedLastGroup = processed;
  12402. eof = true;
  12403. return NULL;
  12404. }
  12405. }
  12406. try
  12407. {
  12408. if (in->in)
  12409. {
  12410. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  12411. size32_t outSize;
  12412. IThorChildGraph *child = helper.queryChild();
  12413. Owned<IEclGraphResults> results;
  12414. if (child)
  12415. results.setown(child->evaluate(in->extract.size(), in->extract.getbytes()));
  12416. outSize = helper.transform(rowBuilder, in->in, results, in->recordCount);
  12417. if (outSize)
  12418. {
  12419. processed++;
  12420. return rowBuilder.finalizeRowClear(outSize);
  12421. }
  12422. }
  12423. }
  12424. catch (IException *E)
  12425. {
  12426. throw makeWrappedException(E);
  12427. }
  12428. }
  12429. }
  12430. // interface IExceptionHandler
  12431. virtual bool fireException(IException *e)
  12432. {
  12433. // called from puller thread on failure
  12434. ready.interrupt(LINK(e));
  12435. space.interrupt(e);
  12436. return true;
  12437. }
  12438. // interface IRecordPullerCallback
  12439. virtual void processRow(const void *row)
  12440. {
  12441. {
  12442. CriticalBlock b(pulledCrit);
  12443. pulled.enqueue(new PrefetchInfo(helper, row, ++recordCount));
  12444. }
  12445. if (isThreaded)
  12446. {
  12447. ready.signal();
  12448. space.wait();
  12449. }
  12450. }
  12451. virtual void processEOG()
  12452. {
  12453. {
  12454. CriticalBlock b(pulledCrit);
  12455. pulled.enqueue(NULL);
  12456. }
  12457. if (isThreaded)
  12458. {
  12459. ready.signal();
  12460. space.wait();
  12461. }
  12462. }
  12463. virtual void processGroup(const ConstPointerArray &rows)
  12464. {
  12465. throwUnexpected();
  12466. }
  12467. virtual void processDone()
  12468. {
  12469. CriticalBlock b(pulledCrit);
  12470. allPulled = true;
  12471. if (isThreaded)
  12472. ready.signal();
  12473. }
  12474. };
  12475. class CRoxieServerPrefetchProjectActivityFactory : public CRoxieServerProjectActivityFactory
  12476. {
  12477. public:
  12478. CRoxieServerPrefetchProjectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  12479. : CRoxieServerProjectActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  12480. {
  12481. }
  12482. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  12483. {
  12484. return new CRoxieServerPrefetchProjectActivity(this, _probeManager, count);
  12485. }
  12486. };
  12487. extern IRoxieServerActivityFactory *createRoxieServerPrefetchProjectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  12488. {
  12489. return new CRoxieServerPrefetchProjectActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  12490. }
  12491. //=================================================================================
  12492. class CPointerArrayRoxieInput : public CPseudoRoxieInput
  12493. {
  12494. public:
  12495. CPointerArrayRoxieInput()
  12496. {
  12497. rowset = NULL;
  12498. rowcount = 0;
  12499. curRow = 0;
  12500. }
  12501. void init(size32_t _rowcount, byte **_rowset)
  12502. {
  12503. rowset = _rowset;
  12504. rowcount = _rowcount;
  12505. curRow = 0;
  12506. }
  12507. virtual const void * nextInGroup()
  12508. {
  12509. if (curRow < rowcount)
  12510. {
  12511. const void * ret = rowset[curRow];
  12512. if (ret)
  12513. LinkRoxieRow(ret);
  12514. curRow++;
  12515. return ret;
  12516. }
  12517. return NULL;
  12518. }
  12519. protected:
  12520. byte **rowset;
  12521. size32_t rowcount;
  12522. size32_t curRow;
  12523. };
  12524. class CRoxieServerLoopActivity : public CRoxieServerActivity
  12525. {
  12526. protected:
  12527. IHThorLoopArg &helper;
  12528. ThorActivityKind activityKind;
  12529. unsigned maxIterations;
  12530. bool finishedLooping;
  12531. unsigned flags;
  12532. bool eof;
  12533. rtlRowBuilder loopExtractBuilder;
  12534. unsigned loopGraphId;
  12535. Linked<IOutputMetaData> counterMeta;
  12536. public:
  12537. CRoxieServerLoopActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _loopGraphId, IOutputMetaData * _counterMeta)
  12538. : CRoxieServerActivity(_factory, _probeManager),
  12539. helper((IHThorLoopArg &)basehelper), loopGraphId(_loopGraphId), counterMeta(_counterMeta)
  12540. {
  12541. eof = false;
  12542. finishedLooping = false;
  12543. activityKind = factory->getKind();
  12544. flags = helper.getFlags();
  12545. maxIterations = 0;
  12546. }
  12547. virtual bool needsAllocator() const { return true; }
  12548. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  12549. {
  12550. eof = false;
  12551. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  12552. int iterations = (int) helper.numIterations();
  12553. maxIterations = (iterations >= 0) ? iterations : 0;
  12554. finishedLooping = ((activityKind == TAKloopcount) && (maxIterations == 0));
  12555. if ((flags & IHThorLoopArg::LFnewloopagain) && !helper.loopFirstTime())
  12556. finishedLooping = true;
  12557. loopExtractBuilder.clear();
  12558. helper.createParentExtract(loopExtractBuilder); // could possibly delay this until execution actually happens
  12559. }
  12560. virtual void stop(bool aborting)
  12561. {
  12562. CRoxieServerActivity::stop(aborting);
  12563. loopExtractBuilder.clear();
  12564. }
  12565. void createCounterResult(IRoxieServerChildGraph * graph, unsigned counter)
  12566. {
  12567. if (flags & IHThorLoopArg::LFcounter)
  12568. {
  12569. void * counterRow = ctx->queryRowManager().allocate(sizeof(thor_loop_counter_t), activityId);
  12570. *((thor_loop_counter_t *)counterRow) = counter;
  12571. RtlLinkedDatasetBuilder builder(rowAllocator);
  12572. builder.appendOwn(counterRow);
  12573. Owned<CGraphResult> counterResult = new CGraphResult(builder.getcount(), builder.linkrows());
  12574. graph->setInputResult(2, counterResult);
  12575. }
  12576. }
  12577. };
  12578. //=================================================================================
  12579. class CRoxieServerSequentialLoopActivity : public CRoxieServerLoopActivity
  12580. {
  12581. Owned<IActivityGraph> loopQuery;
  12582. Owned<IRoxieServerChildGraph> loopGraph;
  12583. IRoxieInput * curInput;
  12584. RtlLinkedDatasetBuilder *loopInputBuilder;
  12585. CPointerArrayRoxieInput arrayInput;
  12586. Linked<IRoxieInput> resultInput;
  12587. unsigned loopCounter;
  12588. public:
  12589. CRoxieServerSequentialLoopActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _loopGraphId, IOutputMetaData * _counterMeta)
  12590. : CRoxieServerLoopActivity(_factory, _probeManager, _loopGraphId, _counterMeta)
  12591. {
  12592. curInput = NULL;
  12593. loopCounter = 0;
  12594. loopInputBuilder = NULL;
  12595. }
  12596. virtual bool needsAllocator() const { return true; }
  12597. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  12598. {
  12599. CRoxieServerLoopActivity::onCreate(_ctx, _colocalParent);
  12600. loopQuery.set(_ctx->queryChildGraph(loopGraphId));
  12601. }
  12602. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  12603. {
  12604. curInput = input;
  12605. loopCounter = 1;
  12606. CRoxieServerLoopActivity::start(parentExtractSize, parentExtract, paused);
  12607. //MORE: Not sure about this, should IRoxieServerChildGraph be combined with IActivityGraph?
  12608. loopGraph.set(loopQuery->queryLoopGraph());
  12609. loopInputBuilder = new RtlLinkedDatasetBuilder(rowAllocator);
  12610. }
  12611. virtual void stop(bool aborting)
  12612. {
  12613. delete loopInputBuilder;
  12614. loopInputBuilder = NULL;
  12615. CRoxieServerLoopActivity::stop(aborting);
  12616. }
  12617. virtual const void * nextInGroup()
  12618. {
  12619. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  12620. if (eof)
  12621. return NULL;
  12622. unsigned emptyIterations = 0;
  12623. loop
  12624. {
  12625. loop
  12626. {
  12627. const void * ret = curInput->nextInGroup();
  12628. if (!ret)
  12629. {
  12630. ret = curInput->nextInGroup(); // more cope with groups somehow....
  12631. if (!ret)
  12632. {
  12633. if (finishedLooping)
  12634. {
  12635. eof = true;
  12636. return NULL;
  12637. }
  12638. break;
  12639. }
  12640. }
  12641. if (finishedLooping ||
  12642. ((flags & IHThorLoopArg::LFfiltered) && !helper.sendToLoop(loopCounter, ret)))
  12643. {
  12644. processed++;
  12645. return ret;
  12646. }
  12647. loopInputBuilder->appendOwn(ret);
  12648. }
  12649. switch (activityKind)
  12650. {
  12651. case TAKloopdataset:
  12652. {
  12653. if (!(flags & IHThorLoopArg::LFnewloopagain))
  12654. {
  12655. if (!helper.loopAgain(loopCounter, loopInputBuilder->getcount(), (const void**) loopInputBuilder->queryrows()))
  12656. {
  12657. if (loopInputBuilder->getcount() == 0)
  12658. {
  12659. eof = true;
  12660. return NULL;
  12661. }
  12662. arrayInput.init(loopInputBuilder->getcount(), loopInputBuilder->linkrows());
  12663. // MORE - should builder be cleared here?
  12664. curInput = &arrayInput;
  12665. finishedLooping = true;
  12666. continue; // back to the input loop again
  12667. }
  12668. }
  12669. break;
  12670. }
  12671. case TAKlooprow:
  12672. if (!loopInputBuilder->getcount())
  12673. {
  12674. finishedLooping = true;
  12675. eof = true;
  12676. return NULL;
  12677. }
  12678. break;
  12679. }
  12680. if (loopInputBuilder->getcount())
  12681. emptyIterations = 0;
  12682. else
  12683. {
  12684. //note: any outputs which didn't go around the loop again, would return the record, reinitializing emptyIterations
  12685. emptyIterations++;
  12686. if (emptyIterations > maxEmptyLoopIterations)
  12687. throw MakeStringException(ROXIE_TOO_MANY_EMPTY_LOOP, "Executed LOOP with empty input and output %u times", emptyIterations);
  12688. if (emptyIterations % 32 == 0)
  12689. CTXLOG("Executing LOOP with empty input and output %u times", emptyIterations);
  12690. }
  12691. checkAbort();
  12692. try
  12693. {
  12694. Owned<IRoxieGraphResults> results = executeIteration(loopExtractBuilder.size(), loopExtractBuilder.getbytes(), loopCounter);
  12695. resultInput.setown(results->createIterator(0));
  12696. if (flags & IHThorLoopArg::LFnewloopagain)
  12697. {
  12698. Owned<IRoxieInput> againResult = results->createIterator(helper.loopAgainResult());
  12699. OwnedConstRoxieRow row = againResult->nextInGroup();
  12700. assertex(row);
  12701. //Result is a row which contains a single boolean field.
  12702. if (!((const bool *)row.get())[0])
  12703. finishedLooping = true;
  12704. }
  12705. }
  12706. catch (IException *E)
  12707. {
  12708. throw makeWrappedException(E);
  12709. }
  12710. curInput = resultInput.get();
  12711. loopCounter++;
  12712. if ((activityKind == TAKloopcount) && (loopCounter > maxIterations))
  12713. finishedLooping = true;
  12714. }
  12715. }
  12716. IRoxieGraphResults * executeIteration(unsigned parentExtractSize, const byte *parentExtract, unsigned counter)
  12717. {
  12718. try
  12719. {
  12720. loopGraph->beforeExecute();
  12721. Owned<IGraphResult> inputRowsResult = new CGraphResult(loopInputBuilder->getcount(), loopInputBuilder->linkrows());
  12722. loopInputBuilder->clear();
  12723. loopGraph->setInputResult(1, inputRowsResult);
  12724. createCounterResult(loopGraph, counter);
  12725. Owned<IRoxieGraphResults> ret = loopGraph->execute(parentExtractSize, parentExtract);
  12726. loopGraph->afterExecute();
  12727. return ret.getClear();
  12728. }
  12729. catch (...)
  12730. {
  12731. CTXLOG("Exception thrown in loop body - cleaning up");
  12732. loopGraph->afterExecute();
  12733. throw;
  12734. }
  12735. }
  12736. };
  12737. //=================================================================================
  12738. typedef SafeQueueOf<const void, true> SafeRowQueue;
  12739. class CRowQueuePseudoInput : public CPseudoRoxieInput
  12740. {
  12741. public:
  12742. CRowQueuePseudoInput(SafeRowQueue & _input) :
  12743. input(_input)
  12744. {
  12745. eof = false;
  12746. }
  12747. virtual const void * nextInGroup()
  12748. {
  12749. if (eof)
  12750. return NULL;
  12751. const void * ret = input.dequeue();
  12752. if (!ret)
  12753. eof = true;
  12754. return ret;
  12755. }
  12756. protected:
  12757. SafeRowQueue & input;
  12758. bool eof;
  12759. };
  12760. class CRoxieServerParallelLoopActivity;
  12761. class LoopFilterPseudoInput : public CIndirectRoxieInput
  12762. {
  12763. public:
  12764. LoopFilterPseudoInput(CRoxieServerParallelLoopActivity * _activity, IRoxieInput * _input, unsigned _counter) :
  12765. CIndirectRoxieInput(_input), activity(_activity), counter(_counter)
  12766. {
  12767. }
  12768. virtual const void * nextInGroup();
  12769. protected:
  12770. CRoxieServerParallelLoopActivity * activity;
  12771. unsigned counter;
  12772. };
  12773. class LoopExecutorThread : public RestartableThread
  12774. {
  12775. protected:
  12776. Owned<IRoxieInput> safeInput;
  12777. CRoxieServerParallelLoopActivity * activity;
  12778. bool eof;
  12779. CriticalSection crit;
  12780. unsigned flags;
  12781. SafeRowQueue tempResults[2];
  12782. unsigned savedParentExtractSize;
  12783. const byte * savedParentExtract;
  12784. IArrayOf<IActivityGraph> cachedGraphs;
  12785. IRoxieSlaveContext *ctx;
  12786. public:
  12787. LoopExecutorThread()
  12788. : RestartableThread("LoopExecutorThread")
  12789. {
  12790. activity = NULL;
  12791. eof = false;
  12792. flags = 0;
  12793. ctx = NULL;
  12794. savedParentExtract = NULL;
  12795. savedParentExtractSize = 0;
  12796. }
  12797. virtual IRoxieInput *queryInput(unsigned idx) const
  12798. {
  12799. return safeInput->queryInput(idx);
  12800. }
  12801. void setInput(CRoxieServerParallelLoopActivity * _activity, IRoxieInput *_input, unsigned _flags)
  12802. {
  12803. activity = _activity;
  12804. flags = _flags;
  12805. // stop is called on our consumer's thread. We need to take care calling stop for our input to make sure it is not in mid-nextInGroup etc etc.
  12806. safeInput.setown(new CSafeRoxieInput(_input));
  12807. }
  12808. IRoxieInput *queryInput() const
  12809. {
  12810. return safeInput;
  12811. }
  12812. void onCreate(IRoxieSlaveContext * _ctx);
  12813. void start(unsigned parentExtractSize, const byte *parentExtract, bool paused);
  12814. void stop(bool aborting);
  12815. void reset();
  12816. virtual int run();
  12817. protected:
  12818. void executeLoop();
  12819. void executeLoopInstance(unsigned counter, unsigned numIterations, IRoxieInput * input, SafeRowQueue * spillOutput);
  12820. IRoxieInput * createLoopIterationGraph(unsigned i, IRoxieInput * input, unsigned counter);
  12821. };
  12822. class CRoxieServerParallelLoopActivity : public CRoxieServerLoopActivity
  12823. {
  12824. friend class LoopFilterPseudoInput;
  12825. friend class LoopExecutorThread;
  12826. QueueOf<const void, true> ready;
  12827. CriticalSection helperCS;
  12828. CriticalSection cs;
  12829. size32_t sizeNumParallel;
  12830. rtlDataAttr listNumParallel;
  12831. unsigned defaultNumParallel;
  12832. LoopExecutorThread executor;
  12833. IProbeManager* probeManager;
  12834. CriticalSection canAccess;
  12835. CriticalSection scrit;
  12836. InterruptableSemaphore readySpace;
  12837. InterruptableSemaphore recordsReady;
  12838. protected:
  12839. bool includeInLoop(unsigned counter, const void * row)
  12840. {
  12841. CriticalBlock b(helperCS);
  12842. return helper.sendToLoop(counter, row);
  12843. }
  12844. public:
  12845. CRoxieServerParallelLoopActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _loopGraphId, IOutputMetaData * _counterMeta)
  12846. : CRoxieServerLoopActivity(_factory, _probeManager, _loopGraphId, _counterMeta),
  12847. readySpace(parallelLoopFlowLimit)
  12848. {
  12849. probeManager = _probeManager;
  12850. defaultNumParallel = 0;
  12851. sizeNumParallel = 0;
  12852. }
  12853. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  12854. {
  12855. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  12856. executor.onCreate(_ctx);
  12857. }
  12858. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  12859. {
  12860. CriticalBlock b(scrit); // can stop while still starting, if unlucky...
  12861. readySpace.reinit(parallelLoopFlowLimit);
  12862. recordsReady.reinit();
  12863. CRoxieServerLoopActivity::start(parentExtractSize, parentExtract, paused);
  12864. defaultNumParallel = helper.defaultParallelIterations();
  12865. if (!defaultNumParallel)
  12866. defaultNumParallel = DEFAULT_PARALLEL_LOOP_THREADS;
  12867. helper.numParallelIterations(sizeNumParallel, listNumParallel.refdata());
  12868. //MORE: If numIterations <= number of parallel iterations[1],
  12869. //then we don't need to create a separate thread to do the processing, and the results will also avoid
  12870. //being transferred via a queue
  12871. executor.start(parentExtractSize, parentExtract, paused);
  12872. }
  12873. virtual void setInput(unsigned idx, IRoxieInput *_in)
  12874. {
  12875. if (idx)
  12876. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
  12877. executor.setInput(this, _in, flags);
  12878. }
  12879. virtual void stop(bool aborting)
  12880. {
  12881. CriticalBlock b(scrit); // can stop while still starting, if unlucky...
  12882. readySpace.interrupt();
  12883. recordsReady.interrupt();
  12884. executor.join(); // MORE - may not be needed given stop/reset split
  12885. CRoxieServerLoopActivity::stop(aborting);
  12886. }
  12887. virtual void reset()
  12888. {
  12889. while (ready.ordinality())
  12890. ReleaseRoxieRow(ready.dequeue());
  12891. executor.reset();
  12892. CRoxieServerActivity::reset();
  12893. }
  12894. virtual const void * nextInGroup()
  12895. {
  12896. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  12897. loop
  12898. {
  12899. if (eof)
  12900. return NULL;
  12901. recordsReady.wait();
  12902. CriticalBlock procedure(canAccess);
  12903. if (ready.ordinality())
  12904. {
  12905. const void *result = ready.dequeue();
  12906. readySpace.signal();
  12907. if (result)
  12908. processed++;
  12909. return result;
  12910. }
  12911. else
  12912. eof = true;
  12913. }
  12914. }
  12915. unsigned getNumParallel(unsigned iter)
  12916. {
  12917. if (iter * sizeof(unsigned) >= sizeNumParallel)
  12918. return defaultNumParallel;
  12919. return ((unsigned *)listNumParallel.getdata())[iter];
  12920. }
  12921. inline void enqueueResult(const void * row)
  12922. {
  12923. try
  12924. {
  12925. while(!readySpace.wait(1000))
  12926. {
  12927. CTXLOG("Blocked waiting for space in loop %p activity id: %d output queue: %d records in queue", this, queryId(), ready.ordinality());
  12928. }
  12929. }
  12930. catch (...)
  12931. {
  12932. ReleaseRoxieRow(row);
  12933. throw;
  12934. }
  12935. CriticalBlock b2(canAccess);
  12936. ready.enqueue(row);
  12937. recordsReady.signal();
  12938. }
  12939. inline void finishResults()
  12940. {
  12941. recordsReady.signal();
  12942. }
  12943. virtual bool fireException(IException *e)
  12944. {
  12945. readySpace.interrupt(LINK(e));
  12946. recordsReady.interrupt(e);
  12947. return true;
  12948. }
  12949. IActivityGraph * createChildGraphInstance()
  12950. {
  12951. return factory->createChildGraph(ctx, &helper, loopGraphId, this, probeManager, *this);
  12952. }
  12953. IActivityGraph * queryChildGraph()
  12954. {
  12955. return ctx->queryChildGraph(loopGraphId);
  12956. }
  12957. };
  12958. //=================================================================================
  12959. const void * LoopFilterPseudoInput::nextInGroup()
  12960. {
  12961. loop
  12962. {
  12963. const void * next = input->nextInGroup();
  12964. if (!next || activity->includeInLoop(counter, next))
  12965. return next;
  12966. activity->enqueueResult(next);
  12967. }
  12968. }
  12969. void LoopExecutorThread::onCreate(IRoxieSlaveContext * _ctx)
  12970. {
  12971. //Initialise the cached graph list with the child instance that will always be created. Other iterations will be created on demand.
  12972. ctx = _ctx;
  12973. cachedGraphs.append(*LINK(activity->queryChildGraph()));
  12974. }
  12975. void LoopExecutorThread::start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  12976. {
  12977. savedParentExtractSize = parentExtractSize;
  12978. savedParentExtract = parentExtract;
  12979. eof = false;
  12980. StringBuffer logPrefix("[");
  12981. ctx->getLogPrefix(logPrefix).append("] ");
  12982. RestartableThread::start(logPrefix);
  12983. }
  12984. int LoopExecutorThread::run()
  12985. {
  12986. try
  12987. {
  12988. executeLoop();
  12989. }
  12990. catch (IException *e)
  12991. {
  12992. activity->fireException(e);
  12993. }
  12994. catch (...)
  12995. {
  12996. activity->fireException(MakeStringException(ROXIE_INTERNAL_ERROR, "Unexpected exception caught in LoopExecutorThread::run"));
  12997. }
  12998. return 0;
  12999. }
  13000. void LoopExecutorThread::stop(bool aborting)
  13001. {
  13002. safeInput->stop(aborting);
  13003. RestartableThread::join();
  13004. }
  13005. void LoopExecutorThread::reset()
  13006. {
  13007. safeInput->reset();
  13008. }
  13009. void LoopExecutorThread::executeLoop()
  13010. {
  13011. unsigned iterations = 0;
  13012. unsigned counter = 0;
  13013. unsigned outputIndex = 0;
  13014. //Note, activities don't link inputs, so need to be careful that special inputs remain linked while the activity is executing.
  13015. loop
  13016. {
  13017. if (activity->activityKind == TAKloopcount)
  13018. {
  13019. if (counter == activity->maxIterations)
  13020. break;
  13021. }
  13022. else
  13023. {
  13024. //This condition isn't quite right because it needs to be whether the filtered
  13025. //input is empty. May be ok if we include that in the semantics,
  13026. if (tempResults[1-outputIndex].ordinality() == 0)
  13027. break;
  13028. }
  13029. unsigned numParallel = activity->getNumParallel(iterations);
  13030. Linked<IRoxieInput> curInput;
  13031. if (iterations == 0)
  13032. curInput.set(safeInput);
  13033. else
  13034. {
  13035. SafeRowQueue & inputQueue = tempResults[1-outputIndex];
  13036. inputQueue.enqueue(NULL);
  13037. curInput.setown(new CRowQueuePseudoInput(inputQueue));
  13038. }
  13039. SafeRowQueue * curOutput = NULL;
  13040. if (counter+numParallel > activity->maxIterations)
  13041. numParallel = activity->maxIterations - counter;
  13042. else if (counter+numParallel < activity->maxIterations)
  13043. curOutput = &tempResults[outputIndex];
  13044. executeLoopInstance(counter, numParallel, curInput, curOutput);
  13045. outputIndex = 1-outputIndex;
  13046. counter += numParallel;
  13047. iterations++;
  13048. }
  13049. //Check for TAKlooprow, where end of loop couldn't be determined ahead of time
  13050. SafeRowQueue & inputQueue = tempResults[1-outputIndex];
  13051. while (inputQueue.ordinality())
  13052. {
  13053. const void * next = inputQueue.dequeue();
  13054. activity->enqueueResult(next);
  13055. }
  13056. activity->finishResults();
  13057. }
  13058. void LoopExecutorThread::executeLoopInstance(unsigned counter, unsigned numIterations, IRoxieInput * input, SafeRowQueue * spillOutput)
  13059. {
  13060. IArrayOf<IRoxieInput> savedInputs; // activities don't link their inputs, so this list keeps filters alive.
  13061. Linked<IRoxieInput> curInput = input;
  13062. unsigned i;
  13063. for (i= 0; i != numIterations; i++)
  13064. {
  13065. unsigned thisCounter = counter+i+1;
  13066. IRoxieInput * filtered = curInput;
  13067. if (flags & IHThorLoopArg::LFfiltered)
  13068. {
  13069. filtered = new LoopFilterPseudoInput(activity, curInput, thisCounter);
  13070. savedInputs.append(*filtered);
  13071. }
  13072. //graph is kept, so new curInput will be guaranteed to exist
  13073. curInput.setown(createLoopIterationGraph(i, filtered, thisCounter));
  13074. }
  13075. try
  13076. {
  13077. curInput->start(savedParentExtractSize, savedParentExtract, false);
  13078. if (spillOutput)
  13079. {
  13080. loop
  13081. {
  13082. const void * next = curInput->nextInGroup();
  13083. if (!next)
  13084. break;
  13085. spillOutput->enqueue(next);
  13086. }
  13087. }
  13088. else
  13089. {
  13090. loop
  13091. {
  13092. const void * next = curInput->nextInGroup();
  13093. if (!next)
  13094. break;
  13095. activity->enqueueResult(next);
  13096. }
  13097. }
  13098. }
  13099. catch (IException *E)
  13100. {
  13101. ctx->notifyAbort(E);
  13102. for (i= 0; i != numIterations; i++)
  13103. {
  13104. cachedGraphs.item(i).queryLoopGraph()->afterExecute();
  13105. }
  13106. curInput->stop(true);
  13107. curInput->reset();
  13108. throw;
  13109. }
  13110. for (i= 0; i != numIterations; i++)
  13111. {
  13112. cachedGraphs.item(i).queryLoopGraph()->afterExecute();
  13113. }
  13114. curInput->stop(false);
  13115. curInput->reset();
  13116. }
  13117. IRoxieInput * LoopExecutorThread::createLoopIterationGraph(unsigned i, IRoxieInput * input, unsigned counter)
  13118. {
  13119. if (!cachedGraphs.isItem(i))
  13120. cachedGraphs.append(*activity->createChildGraphInstance());
  13121. Linked<IRoxieServerChildGraph> loopGraph = cachedGraphs.item(i).queryLoopGraph();
  13122. loopGraph->beforeExecute();
  13123. if (!loopGraph->querySetInputResult(1, input))
  13124. throwUnexpected(); // a loop which doesn't use the value from the previous iteration. Should probably handle even if daft.
  13125. activity->createCounterResult(loopGraph, counter);
  13126. return loopGraph->selectOutput(0);
  13127. }
  13128. //=================================================================================
  13129. class CCounterRowMetaData : public CInterface, implements IOutputMetaData
  13130. {
  13131. public:
  13132. IMPLEMENT_IINTERFACE
  13133. virtual size32_t getRecordSize(const void *) { return sizeof(thor_loop_counter_t); }
  13134. virtual size32_t getMinRecordSize() const { return sizeof(thor_loop_counter_t); }
  13135. virtual size32_t getFixedSize() const { return sizeof(thor_loop_counter_t); }
  13136. virtual void toXML(const byte * self, IXmlWriter & out) { }
  13137. virtual unsigned getVersion() const { return OUTPUTMETADATA_VERSION; }
  13138. virtual unsigned getMetaFlags() { return 0; }
  13139. virtual void destruct(byte * self) {}
  13140. virtual IOutputRowSerializer * createDiskSerializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
  13141. virtual IOutputRowDeserializer * createDiskDeserializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
  13142. virtual ISourceRowPrefetcher * createDiskPrefetcher(ICodeContext * ctx, unsigned activityId) { return NULL; }
  13143. virtual IOutputMetaData * querySerializedDiskMeta() { return this; }
  13144. virtual IOutputRowSerializer * createInternalSerializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
  13145. virtual IOutputRowDeserializer * createInternalDeserializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
  13146. virtual void walkIndirectMembers(const byte * self, IIndirectMemberVisitor & visitor) {}
  13147. virtual IOutputMetaData * queryChildMeta(unsigned i) { return NULL; }
  13148. };
  13149. class CRoxieServerLoopActivityFactory : public CRoxieServerActivityFactory
  13150. {
  13151. unsigned loopGraphId;
  13152. unsigned flags;
  13153. Linked<IOutputMetaData> counterMeta;
  13154. public:
  13155. CRoxieServerLoopActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _loopGraphId)
  13156. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), loopGraphId(_loopGraphId)
  13157. {
  13158. Owned<IHThorLoopArg> helper = (IHThorLoopArg *) helperFactory();
  13159. flags = helper->getFlags();
  13160. counterMeta.setown(new CCounterRowMetaData);
  13161. }
  13162. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  13163. {
  13164. if (flags & IHThorLoopArg::LFparallel)
  13165. return new CRoxieServerParallelLoopActivity(this, _probeManager, loopGraphId, counterMeta);
  13166. else
  13167. return new CRoxieServerSequentialLoopActivity(this, _probeManager, loopGraphId, counterMeta);
  13168. }
  13169. };
  13170. IRoxieServerActivityFactory *createRoxieServerLoopActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _loopGraphId)
  13171. {
  13172. return new CRoxieServerLoopActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _loopGraphId);
  13173. }
  13174. //=================================================================================
  13175. class CRoxieServerGraphLoopActivity : public CRoxieServerActivity
  13176. {
  13177. protected:
  13178. IHThorGraphLoopArg &helper;
  13179. unsigned maxIterations;
  13180. unsigned flags;
  13181. rtlRowBuilder GraphExtractBuilder;
  13182. unsigned loopGraphId;
  13183. Linked<IOutputMetaData> counterMeta;
  13184. public:
  13185. CRoxieServerGraphLoopActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _GraphGraphId, IOutputMetaData * _counterMeta)
  13186. : CRoxieServerActivity(_factory, _probeManager),
  13187. helper((IHThorGraphLoopArg &)basehelper), loopGraphId(_GraphGraphId), counterMeta(_counterMeta)
  13188. {
  13189. flags = helper.getFlags();
  13190. maxIterations = 0;
  13191. }
  13192. virtual bool needsAllocator() const { return true; }
  13193. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  13194. {
  13195. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  13196. int iterations = (int) helper.numIterations();
  13197. maxIterations = (iterations >= 0) ? iterations : 0;
  13198. if (maxIterations > maxGraphLoopIterations)
  13199. throw MakeStringException(ROXIE_TOO_MANY_GRAPH_LOOP, "Attempt to execute graph %u times", maxIterations);
  13200. if (maxIterations != 0)
  13201. {
  13202. GraphExtractBuilder.clear();
  13203. helper.createParentExtract(GraphExtractBuilder);
  13204. }
  13205. }
  13206. virtual void stop(bool aborting)
  13207. {
  13208. CRoxieServerActivity::stop(aborting);
  13209. GraphExtractBuilder.clear();
  13210. }
  13211. void createCounterResult(IRoxieServerChildGraph * graph, unsigned counter)
  13212. {
  13213. if (flags & IHThorGraphLoopArg::GLFcounter)
  13214. {
  13215. void * counterRow = ctx->queryRowManager().allocate(sizeof(thor_loop_counter_t), activityId);
  13216. *((thor_loop_counter_t *)counterRow) = counter;
  13217. RtlLinkedDatasetBuilder builder(rowAllocator);
  13218. builder.appendOwn(counterRow);
  13219. Owned<CGraphResult> counterResult = new CGraphResult(builder.getcount(), builder.linkrows());
  13220. graph->setInputResult(0, counterResult);
  13221. }
  13222. }
  13223. };
  13224. //=================================================================================
  13225. class CRoxieServerSequentialGraphLoopActivity : public CRoxieServerGraphLoopActivity
  13226. {
  13227. Owned<IActivityGraph> GraphQuery;
  13228. Owned<IRoxieServerChildGraph> loopGraph;
  13229. Linked<IRoxieInput> resultInput;
  13230. bool evaluated;
  13231. public:
  13232. CRoxieServerSequentialGraphLoopActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _GraphGraphId, IOutputMetaData * _counterMeta)
  13233. : CRoxieServerGraphLoopActivity(_factory, _probeManager, _GraphGraphId, _counterMeta)
  13234. {
  13235. evaluated = false;
  13236. }
  13237. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  13238. {
  13239. CRoxieServerGraphLoopActivity::onCreate(_ctx, _colocalParent);
  13240. GraphQuery.set(_ctx->queryChildGraph(loopGraphId));
  13241. }
  13242. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  13243. {
  13244. CRoxieServerGraphLoopActivity::start(parentExtractSize, parentExtract, paused);
  13245. //MORE: Not sure about this, should IRoxieServerChildGraph be combined with IActivityGraph?
  13246. loopGraph.set(GraphQuery->queryLoopGraph());
  13247. evaluated = false;
  13248. }
  13249. virtual void stop(bool aborting)
  13250. {
  13251. if (loopGraph)
  13252. loopGraph->clearGraphLoopResults();
  13253. CRoxieServerGraphLoopActivity::stop(aborting);
  13254. }
  13255. virtual const void * nextInGroup()
  13256. {
  13257. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  13258. if (!evaluated)
  13259. {
  13260. executeEntireGraph();
  13261. evaluated = true;
  13262. }
  13263. const void * ret = resultInput->nextInGroup();
  13264. if (ret)
  13265. processed++;
  13266. return ret;
  13267. }
  13268. void executeIteration(unsigned parentExtractSize, const byte *parentExtract, unsigned counter)
  13269. {
  13270. try
  13271. {
  13272. loopGraph->beforeExecute();
  13273. createCounterResult(loopGraph, counter);
  13274. loopGraph->executeGraphLoop(parentExtractSize, parentExtract);
  13275. loopGraph->afterExecute();
  13276. }
  13277. catch (...)
  13278. {
  13279. CTXLOG("Exception thrown in graph body - cleaning up");
  13280. loopGraph->afterExecute();
  13281. throw;
  13282. }
  13283. }
  13284. void createInitialGraphInput()
  13285. {
  13286. loopGraph->clearGraphLoopResults();
  13287. RtlLinkedDatasetBuilder builder(rowAllocator);
  13288. input->readAll(builder);
  13289. Owned<CGraphResult> result = new CGraphResult(builder.getcount(), builder.linkrows());
  13290. loopGraph->setGraphLoopResult(0, result);
  13291. }
  13292. void executeEntireGraph()
  13293. {
  13294. createInitialGraphInput();
  13295. for (unsigned loopCounter=1; loopCounter <= maxIterations; loopCounter++)
  13296. {
  13297. executeIteration(GraphExtractBuilder.size(), GraphExtractBuilder.getbytes(), loopCounter);
  13298. }
  13299. resultInput.setown(loopGraph->getGraphLoopResult(maxIterations));
  13300. }
  13301. };
  13302. //=================================================================================
  13303. struct GraphOutputSplitterArg : public ccdserver_hqlhelper::CThorSplitArg
  13304. {
  13305. public:
  13306. virtual unsigned numBranches()
  13307. {
  13308. return 0;
  13309. }
  13310. virtual IOutputMetaData * queryOutputMeta()
  13311. {
  13312. return NULL;// get it from the parent..
  13313. }
  13314. };
  13315. extern "C" IHThorArg * createGraphOutputSplitter() { return new GraphOutputSplitterArg; }
  13316. class CGraphIterationInfo : public CInterface
  13317. {
  13318. private:
  13319. Owned<IRoxieServerActivityFactory> factory; // Note - before sourceAct, so destroyed last
  13320. unsigned sourceIdx;
  13321. Linked<IRoxieServerActivity> sourceAct;
  13322. Linked<IRoxieInput> sourceInput;
  13323. unsigned numUses;
  13324. unsigned iteration;
  13325. public:
  13326. CGraphIterationInfo(IRoxieServerActivity * _sourceAct, IRoxieInput *_input, unsigned _sourceIdx, unsigned _iteration)
  13327. : sourceAct(_sourceAct), sourceInput(_input), sourceIdx(_sourceIdx), iteration(_iteration)
  13328. {
  13329. numUses = 0;
  13330. }
  13331. inline void noteUsed()
  13332. {
  13333. numUses++;
  13334. }
  13335. void createSplitter(IRoxieSlaveContext *ctx, IProbeManager *probeManager)
  13336. {
  13337. if (numUses > 1)
  13338. {
  13339. factory.setown(createRoxieServerThroughSpillActivityFactory(sourceAct->queryFactory()->queryQueryFactory(), createGraphOutputSplitter, numUses));
  13340. IRoxieServerActivity *splitter = factory->createActivity(NULL);
  13341. splitter->onCreate(ctx, NULL);
  13342. IRoxieInput *input = sourceAct->queryOutput(sourceIdx);
  13343. if (probeManager)
  13344. {
  13345. IInputBase * inputBase = probeManager->createProbe(static_cast<IInputBase*>(input), sourceAct, splitter, sourceIdx, 0, iteration);
  13346. input = static_cast<IRoxieInput*>(inputBase);
  13347. // MORE - shouldn't this be added to probes?
  13348. }
  13349. sourceAct.setown(splitter);
  13350. sourceAct->setInput(0, input);
  13351. sourceIdx = 0;
  13352. sourceInput.clear();
  13353. }
  13354. }
  13355. IRoxieInput *connectOutput(IProbeManager *probeManager, IArrayOf<IRoxieInput> &probes, IRoxieServerActivity *targetAct, unsigned targetIdx)
  13356. {
  13357. // MORE - not really necessary to create splitters in separate pass, is it?
  13358. if (factory) // we created a splitter....
  13359. sourceInput.set(sourceAct->queryOutput(sourceIdx));
  13360. IRoxieInput *ret = sourceInput;
  13361. if (probeManager)
  13362. {
  13363. IInputBase *inputBase = probeManager->createProbe(ret, sourceAct, targetAct, sourceIdx, targetIdx, iteration);
  13364. ret = static_cast<IRoxieInput *>(inputBase);
  13365. probes.append(*LINK(ret));
  13366. }
  13367. if (factory) // we created a splitter....
  13368. sourceIdx++;
  13369. return ret;
  13370. }
  13371. };
  13372. class CRoxieServerParallelGraphLoopActivity : public CRoxieServerGraphLoopActivity, implements IRoxieServerLoopResultProcessor
  13373. {
  13374. Owned<IActivityGraph> childGraph;
  13375. IRoxieInput * resultInput;
  13376. CIArrayOf<CGraphIterationInfo> outputs;
  13377. IArrayOf<IRoxieServerChildGraph> iterationGraphs;
  13378. Owned<CExtractMapperInput> inputExtractMapper;
  13379. IProbeManager *probeManager;
  13380. unsigned createLoopCounter;
  13381. IArrayOf<IRoxieInput> probes;
  13382. public:
  13383. CRoxieServerParallelGraphLoopActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _GraphGraphId, IOutputMetaData * _counterMeta)
  13384. : CRoxieServerGraphLoopActivity(_factory, _probeManager, _GraphGraphId, _counterMeta), probeManager(_probeManager)
  13385. {
  13386. inputExtractMapper.setown(new CExtractMapperInput);
  13387. resultInput = NULL;
  13388. createLoopCounter = 0;
  13389. }
  13390. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  13391. {
  13392. CRoxieServerGraphLoopActivity::onCreate(_ctx, _colocalParent);
  13393. childGraph.set(_ctx->queryChildGraph(loopGraphId));
  13394. }
  13395. virtual void setInput(unsigned idx, IRoxieInput *_in)
  13396. {
  13397. //Input needs to be handled very carefully.....
  13398. //We don't want to call onStart on the input unless it is actually used, so don't use the base CRoxieServerActivity implementation.
  13399. //This activity's input needs to be started with (parentExtractSize, parentExtract), but the elements in the graph need to be started with the
  13400. //GraphExtractBuilder parent extract. So we need to wrap the input in a pseudo-input (inputExtractMapper) that passes through a different
  13401. //parentExtract. Something very similar will be needed for query library calls with streaming inputs when they are implemented.
  13402. assertex(idx == 0);
  13403. inputExtractMapper->setInput(_in);
  13404. }
  13405. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  13406. {
  13407. CRoxieServerGraphLoopActivity::start(parentExtractSize, parentExtract, paused); // initialises GraphExtractBuilder
  13408. inputExtractMapper->setParentExtract(parentExtractSize, parentExtract);
  13409. createExpandedGraph(GraphExtractBuilder.size(), GraphExtractBuilder.getbytes(), probeManager);
  13410. resultInput->start(GraphExtractBuilder.size(), GraphExtractBuilder.getbytes(), paused);
  13411. }
  13412. virtual void stop(bool aborting)
  13413. {
  13414. if (resultInput)
  13415. resultInput->stop(aborting);
  13416. CRoxieServerGraphLoopActivity::stop(aborting);
  13417. }
  13418. virtual void reset()
  13419. {
  13420. if (resultInput)
  13421. resultInput->reset();
  13422. resultInput = NULL;
  13423. iterationGraphs.kill();
  13424. outputs.kill();
  13425. if (probeManager)
  13426. {
  13427. probeManager->deleteGraph(NULL, (IArrayOf<IInputBase>*)&probes);
  13428. probes.kill();
  13429. }
  13430. CRoxieServerGraphLoopActivity::reset();
  13431. }
  13432. virtual const void * nextInGroup()
  13433. {
  13434. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  13435. const void * ret = resultInput->nextInGroup();
  13436. if (ret)
  13437. processed++;
  13438. return ret;
  13439. }
  13440. void createExpandedGraph(unsigned parentExtractSize, const byte *parentExtract, IProbeManager *probeManager)
  13441. {
  13442. //result(0) is the input to the graph.
  13443. resultInput = inputExtractMapper;
  13444. outputs.append(* new CGraphIterationInfo(resultInput->queryActivity(), resultInput, 0, 1));
  13445. for (createLoopCounter=1; createLoopCounter <= maxIterations; createLoopCounter++)
  13446. {
  13447. IRoxieServerChildGraph * graph = childGraph->createGraphLoopInstance(createLoopCounter, parentExtractSize, parentExtract, *this);
  13448. graph->beforeExecute();
  13449. iterationGraphs.append(*graph);
  13450. graph->gatherIterationUsage(*this);
  13451. CGraphIterationInfo *iteration = graph->selectGraphLoopOutput();
  13452. outputs.append(*iteration);
  13453. }
  13454. createLoopCounter = 0;
  13455. createSplitters(probeManager);
  13456. ForEachItemIn(i2, iterationGraphs)
  13457. iterationGraphs.item(i2).associateIterationOutputs(*this);
  13458. resultInput = outputs.tos().connectOutput(probeManager, probes, this, 0);
  13459. }
  13460. void createSplitters(IProbeManager *probeManager)
  13461. {
  13462. ForEachItemIn(i, outputs)
  13463. {
  13464. CGraphIterationInfo & next = outputs.item(i);
  13465. next.createSplitter(ctx, probeManager);
  13466. }
  13467. }
  13468. //IRoxieServerLoopResultProcessor
  13469. virtual void noteUseIteration(unsigned _whichIteration)
  13470. {
  13471. int whichIteration = (int) _whichIteration; // May go negative - API is unsigned for historical reasons
  13472. if (whichIteration >= 0)
  13473. {
  13474. if (!outputs.isItem(whichIteration))
  13475. throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Error reading graph result %d from iteration %d", whichIteration, createLoopCounter);
  13476. outputs.item(whichIteration).noteUsed();
  13477. }
  13478. }
  13479. virtual IRoxieInput * connectIterationOutput(unsigned whichIteration, IProbeManager *probeManager, IArrayOf<IRoxieInput> &probes, IRoxieServerActivity *targetAct, unsigned targetIdx)
  13480. {
  13481. if (outputs.isItem(whichIteration))
  13482. {
  13483. CGraphIterationInfo & next = outputs.item(whichIteration);
  13484. return next.connectOutput(probeManager, probes, targetAct, targetIdx);
  13485. }
  13486. return NULL;
  13487. }
  13488. };
  13489. //=================================================================================
  13490. class CRoxieServerGraphLoopActivityFactory : public CRoxieServerActivityFactory
  13491. {
  13492. unsigned loopGraphId;
  13493. unsigned flags;
  13494. Linked<IOutputMetaData> counterMeta;
  13495. public:
  13496. CRoxieServerGraphLoopActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _loopGraphId)
  13497. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), loopGraphId(_loopGraphId)
  13498. {
  13499. Owned<IHThorGraphLoopArg> helper = (IHThorGraphLoopArg *) helperFactory();
  13500. flags = helper->getFlags();
  13501. counterMeta.setown(new CCounterRowMetaData);
  13502. }
  13503. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  13504. {
  13505. if (kind == TAKparallelgraphloop)
  13506. return new CRoxieServerParallelGraphLoopActivity(this, _probeManager, loopGraphId, counterMeta);
  13507. else
  13508. return new CRoxieServerSequentialGraphLoopActivity(this, _probeManager, loopGraphId, counterMeta);
  13509. }
  13510. };
  13511. IRoxieServerActivityFactory *createRoxieServerGraphLoopActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _loopGraphId)
  13512. {
  13513. return new CRoxieServerGraphLoopActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _loopGraphId);
  13514. }
  13515. //=====================================================================================================
  13516. class CRoxieServerLibraryCallActivity : public CRoxieServerActivity
  13517. {
  13518. class OutputAdaptor : public CExtractMapperInput
  13519. {
  13520. bool stopped;
  13521. public:
  13522. CRoxieServerLibraryCallActivity *parent;
  13523. unsigned oid;
  13524. unsigned processed;
  13525. public:
  13526. IMPLEMENT_IINTERFACE;
  13527. OutputAdaptor() : CExtractMapperInput(NULL)
  13528. {
  13529. parent = NULL;
  13530. oid = 0;
  13531. init();
  13532. }
  13533. void init()
  13534. {
  13535. processed = 0;
  13536. stopped = false;
  13537. }
  13538. virtual unsigned queryId() const
  13539. {
  13540. return parent->queryId();
  13541. }
  13542. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  13543. {
  13544. parent->start(oid, parentExtractSize, parentExtract, paused);
  13545. CExtractMapperInput::start(parentExtractSize, parentExtract, paused);
  13546. }
  13547. virtual void stop(bool aborting)
  13548. {
  13549. if (!stopped)
  13550. {
  13551. stopped = true;
  13552. parent->stop(oid, aborting); // parent code relies on stop being called exactly once per adaptor, so make sure it is!
  13553. CExtractMapperInput::stop(aborting);
  13554. }
  13555. };
  13556. virtual void reset()
  13557. {
  13558. parent->reset(oid, processed);
  13559. CExtractMapperInput::reset();
  13560. init();
  13561. };
  13562. virtual void checkAbort()
  13563. {
  13564. parent->checkAbort();
  13565. }
  13566. };
  13567. IHThorLibraryCallArg &helper;
  13568. unsigned numInputs;
  13569. unsigned numOutputs;
  13570. unsigned numActiveOutputs;
  13571. bool started;
  13572. OutputAdaptor* outputAdaptors;
  13573. CExtractMapperInput * * inputAdaptors;
  13574. bool * inputUsed;
  13575. bool * outputUsed;
  13576. Owned<IException> error;
  13577. CriticalSection crit;
  13578. rtlRowBuilder libraryExtractBuilder;
  13579. Owned<IActivityGraph> libraryGraph;
  13580. const LibraryCallFactoryExtra & extra;
  13581. public:
  13582. CRoxieServerLibraryCallActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs, unsigned _numOutputs, const LibraryCallFactoryExtra & _extra)
  13583. : CRoxieServerActivity(_factory, _probeManager),
  13584. helper((IHThorLibraryCallArg &)basehelper), extra(_extra)
  13585. {
  13586. numInputs = _numInputs;
  13587. numOutputs = _numOutputs;
  13588. numActiveOutputs = numOutputs;
  13589. inputAdaptors = new CExtractMapperInput*[numInputs];
  13590. inputUsed = new bool[numInputs];
  13591. for (unsigned i1 = 0; i1 < numInputs; i1++)
  13592. {
  13593. inputAdaptors[i1] = new CExtractMapperInput;
  13594. inputUsed[i1] = false;
  13595. }
  13596. outputAdaptors = new OutputAdaptor[numOutputs];
  13597. outputUsed = new bool[numOutputs];
  13598. for (unsigned i2 = 0; i2 < numOutputs; i2++)
  13599. {
  13600. outputAdaptors[i2].parent = this;
  13601. outputAdaptors[i2].oid = i2;
  13602. outputUsed[i2] = false;
  13603. }
  13604. started = false;
  13605. }
  13606. ~CRoxieServerLibraryCallActivity()
  13607. {
  13608. for (unsigned i1 = 0; i1 < numInputs; i1++)
  13609. ::Release(inputAdaptors[i1]);
  13610. delete [] inputAdaptors;
  13611. delete [] inputUsed;
  13612. delete [] outputAdaptors;
  13613. delete [] outputUsed;
  13614. }
  13615. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  13616. {
  13617. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  13618. libraryGraph.setown(_ctx->getLibraryGraph(extra, this));
  13619. libraryGraph->onCreate(_ctx, _colocalParent);
  13620. //Now map the inputs and outputs to the adapters
  13621. IRoxieServerChildGraph * graph = libraryGraph->queryLoopGraph();
  13622. for (unsigned i1=0; i1<numInputs; i1++)
  13623. inputUsed[i1] = graph->querySetInputResult(i1, inputAdaptors[i1]);
  13624. for (unsigned i2=0; i2<numOutputs; i2++)
  13625. {
  13626. unsigned outputIndex = extra.outputs.item(i2);
  13627. Owned<IRoxieInput> output = graph->selectOutput(numInputs+outputIndex);
  13628. outputAdaptors[i2].setInput(output);
  13629. }
  13630. }
  13631. virtual void start(unsigned oid, unsigned parentExtractSize, const byte *parentExtract, bool paused)
  13632. {
  13633. CriticalBlock b(crit);
  13634. if (error)
  13635. throw error.getLink();
  13636. if (factory)
  13637. factory->noteStarted(oid);
  13638. if (!started)
  13639. {
  13640. // even though it is not complete, we don't want to run this again if it fails.
  13641. started = true;
  13642. //see notes on splitter above
  13643. try
  13644. {
  13645. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  13646. }
  13647. catch (IException *E)
  13648. {
  13649. #ifdef TRACE_SPLIT
  13650. CTXLOG("spill %d caught exception in start", activityId);
  13651. #endif
  13652. error.set(E);
  13653. throw;
  13654. }
  13655. catch (...)
  13656. {
  13657. IException *E = MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught in CRoxieServerLibraryCallActivity::start");
  13658. error.set(E);
  13659. throw E;
  13660. }
  13661. //recreate the parent extract, and use it to reinitialize the graphs...
  13662. libraryExtractBuilder.clear();
  13663. helper.createParentExtract(libraryExtractBuilder);
  13664. // 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
  13665. // some inputs before we see start on others.
  13666. for (unsigned i1 = 0; i1 < numInputs; i1++)
  13667. {
  13668. if (inputUsed[i1])
  13669. inputAdaptors[i1]->setParentExtract(parentExtractSize, parentExtract);
  13670. else
  13671. inputAdaptors[i1]->stop(false);
  13672. }
  13673. for (unsigned i2 = 0; i2 < numOutputs; i2++)
  13674. outputAdaptors[i2].setParentExtract(libraryExtractBuilder.size(), libraryExtractBuilder.getbytes());
  13675. //call stop on all the unused inputs.
  13676. IRoxieServerChildGraph * graph = libraryGraph->queryLoopGraph();
  13677. graph->beforeExecute();
  13678. ForEachItemIn(i3, extra.unusedOutputs)
  13679. {
  13680. Owned<IRoxieInput> output = graph->selectOutput(numInputs+extra.unusedOutputs.item(i3));
  13681. output->stop(false);
  13682. }
  13683. }
  13684. }
  13685. virtual void stop(unsigned oid, bool aborting)
  13686. {
  13687. CriticalBlock b(crit);
  13688. if (--numActiveOutputs == 0)
  13689. {
  13690. //call stop on all the unused inputs.
  13691. IRoxieServerChildGraph * graph = libraryGraph->queryLoopGraph();
  13692. graph->beforeExecute();
  13693. ForEachItemIn(i3, extra.unusedOutputs)
  13694. {
  13695. Owned<IRoxieInput> output = graph->selectOutput(numInputs+extra.unusedOutputs.item(i3));
  13696. output->stop(false);
  13697. }
  13698. CRoxieServerActivity::stop(aborting);
  13699. }
  13700. }
  13701. void reset(unsigned oid, unsigned _processed)
  13702. {
  13703. noteProcessed(oid, _processed, 0, 0);
  13704. started = false;
  13705. error.clear();
  13706. numActiveOutputs = numOutputs;
  13707. if (state != STATEreset) // make sure input is only reset once
  13708. {
  13709. CRoxieServerActivity::reset();
  13710. libraryGraph->reset();
  13711. //Call reset on all unused inputs/outputs from the graph - no one else will.
  13712. for (unsigned i1 = 0; i1 < numInputs; i1++)
  13713. {
  13714. if (!inputUsed[i1])
  13715. inputAdaptors[i1]->reset();
  13716. }
  13717. IRoxieServerChildGraph * graph = libraryGraph->queryLoopGraph();
  13718. ForEachItemIn(i3, extra.unusedOutputs)
  13719. {
  13720. Owned<IRoxieInput> output = graph->selectOutput(numInputs+extra.unusedOutputs.item(i3));
  13721. output->reset();
  13722. }
  13723. }
  13724. };
  13725. virtual void setInput(unsigned idx, IRoxieInput *_in)
  13726. {
  13727. inputAdaptors[idx]->setInput(_in);
  13728. }
  13729. public:
  13730. virtual const void *nextInGroup()
  13731. {
  13732. throwUnexpected(); // Internal logic error - we are not anybody's input
  13733. }
  13734. virtual IOutputMetaData * queryOutputMeta() const
  13735. {
  13736. throwUnexpected(); // should be called on outputs instead
  13737. }
  13738. virtual IRoxieInput *queryOutput(unsigned idx)
  13739. {
  13740. assertex(idx!=(unsigned)-1);
  13741. assertex(!outputUsed[idx]);
  13742. outputUsed[idx] = true;
  13743. return &outputAdaptors[idx];
  13744. }
  13745. };
  13746. void LibraryCallFactoryExtra::set(const LibraryCallFactoryExtra & _other)
  13747. {
  13748. ForEachItemIn(i1, _other.outputs)
  13749. outputs.append(_other.outputs.item(i1));
  13750. ForEachItemIn(i2, _other.unusedOutputs)
  13751. unusedOutputs.append(_other.unusedOutputs.item(i2));
  13752. maxOutputs = _other.maxOutputs;
  13753. graphid = _other.graphid;
  13754. libraryName.set(_other.libraryName);
  13755. interfaceHash = _other.interfaceHash;
  13756. embedded = _other.embedded;
  13757. }
  13758. void LibraryCallFactoryExtra::calcUnused()
  13759. {
  13760. for (unsigned i=0; i < maxOutputs; i++)
  13761. if (!outputs.contains(i))
  13762. unusedOutputs.append(i);
  13763. }
  13764. class CRoxieServerLibraryCallActivityFactory : public CRoxieServerMultiOutputFactory
  13765. {
  13766. private:
  13767. CRoxieServerMultiInputInfo inputs;
  13768. LibraryCallFactoryExtra extra;
  13769. public:
  13770. CRoxieServerLibraryCallActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, LibraryCallFactoryExtra & _extra)
  13771. : CRoxieServerMultiOutputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  13772. {
  13773. extra.set(_extra);
  13774. extra.calcUnused();
  13775. setNumOutputs(extra.outputs.ordinality());
  13776. }
  13777. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  13778. {
  13779. return new CRoxieServerLibraryCallActivity(this, _probeManager, numInputs(), numOutputs, extra);
  13780. }
  13781. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  13782. {
  13783. inputs.set(idx, source, sourceidx);
  13784. }
  13785. virtual unsigned getInput(unsigned idx, unsigned &sourceidx) const
  13786. {
  13787. return inputs.get(idx, sourceidx);
  13788. }
  13789. virtual unsigned numInputs() const { return inputs.ordinality(); }
  13790. virtual void getXrefInfo(IPropertyTree &reply, const IRoxieContextLogger &logctx) const
  13791. {
  13792. addXrefLibraryInfo(reply, extra.libraryName);
  13793. }
  13794. };
  13795. IRoxieServerActivityFactory *createRoxieServerLibraryCallActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, LibraryCallFactoryExtra & _extra)
  13796. {
  13797. return new CRoxieServerLibraryCallActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _extra);
  13798. }
  13799. //=====================================================================================================
  13800. class CRoxieServerNWayInputActivity : public CRoxieServerActivity
  13801. {
  13802. IHThorNWayInputArg & helper;
  13803. IRoxieInput ** inputs;
  13804. PointerArrayOf<IRoxieInput> selectedInputs;
  13805. unsigned numInputs;
  13806. public:
  13807. CRoxieServerNWayInputActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  13808. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorNWayInputArg &)basehelper), numInputs(_numInputs)
  13809. {
  13810. inputs = new IRoxieInput*[numInputs];
  13811. for (unsigned i = 0; i < numInputs; i++)
  13812. inputs[i] = NULL;
  13813. }
  13814. ~CRoxieServerNWayInputActivity()
  13815. {
  13816. delete [] inputs;
  13817. }
  13818. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  13819. {
  13820. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  13821. bool selectionIsAll;
  13822. size32_t selectionLen;
  13823. rtlDataAttr selection;
  13824. helper.getInputSelection(selectionIsAll, selectionLen, selection.refdata());
  13825. selectedInputs.kill();
  13826. if (selectionIsAll)
  13827. {
  13828. for (unsigned i=0; i < numInputs; i++)
  13829. selectedInputs.append(inputs[i]);
  13830. }
  13831. else
  13832. {
  13833. const size32_t * selections = (const size32_t *)selection.getdata();
  13834. unsigned max = selectionLen/sizeof(size32_t);
  13835. for (unsigned i = 0; i < max; i++)
  13836. {
  13837. unsigned nextIndex = selections[i];
  13838. //Check there are no duplicates..... Assumes there are a fairly small number of inputs, so n^2 search is ok.
  13839. for (unsigned j=i+1; j < max; j++)
  13840. {
  13841. if (nextIndex == selections[j])
  13842. throw MakeStringException(ROXIE_NWAY_INPUT_ERROR, "Selection list for nway input can not contain duplicates");
  13843. }
  13844. if (nextIndex > numInputs)
  13845. throw MakeStringException(ROXIE_NWAY_INPUT_ERROR, "Index %d in RANGE selection list is out of range", nextIndex);
  13846. selectedInputs.append(inputs[nextIndex-1]);
  13847. }
  13848. }
  13849. ForEachItemIn(i2, selectedInputs)
  13850. selectedInputs.item(i2)->start(parentExtractSize, parentExtract, paused);
  13851. }
  13852. virtual void stop(bool aborting)
  13853. {
  13854. ForEachItemIn(i2, selectedInputs)
  13855. selectedInputs.item(i2)->stop(aborting);
  13856. CRoxieServerActivity::stop(aborting);
  13857. }
  13858. virtual unsigned __int64 queryLocalCycles() const
  13859. {
  13860. __int64 localCycles = totalCycles;
  13861. ForEachItemIn(i, selectedInputs)
  13862. {
  13863. localCycles -= selectedInputs.item(i)->queryTotalCycles();
  13864. }
  13865. if (localCycles < 0)
  13866. localCycles = 0;
  13867. return localCycles;
  13868. }
  13869. virtual IRoxieInput *queryInput(unsigned idx) const
  13870. {
  13871. if (selectedInputs.isItem(idx))
  13872. return selectedInputs.item(idx);
  13873. else
  13874. return NULL;
  13875. }
  13876. virtual void reset()
  13877. {
  13878. ForEachItemIn(i, selectedInputs)
  13879. selectedInputs.item(i)->reset();
  13880. selectedInputs.kill();
  13881. CRoxieServerActivity::reset();
  13882. }
  13883. virtual void setInput(unsigned idx, IRoxieInput *_in)
  13884. {
  13885. assertex(idx < numInputs);
  13886. inputs[idx] = _in;
  13887. }
  13888. virtual const void * nextInGroup()
  13889. {
  13890. throwUnexpected();
  13891. }
  13892. virtual unsigned numConcreteOutputs() const
  13893. {
  13894. return selectedInputs.ordinality();
  13895. }
  13896. virtual IRoxieInput * queryConcreteInput(unsigned idx)
  13897. {
  13898. if (selectedInputs.isItem(idx))
  13899. return selectedInputs.item(idx);
  13900. return NULL;
  13901. }
  13902. };
  13903. class CRoxieServerNWayInputActivityFactory : public CRoxieServerMultiInputFactory
  13904. {
  13905. // bool ordered;
  13906. public:
  13907. CRoxieServerNWayInputActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  13908. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  13909. {
  13910. }
  13911. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  13912. {
  13913. return new CRoxieServerNWayInputActivity(this, _probeManager, numInputs());
  13914. }
  13915. };
  13916. IRoxieServerActivityFactory *createRoxieServerNWayInputActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  13917. {
  13918. return new CRoxieServerNWayInputActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  13919. }
  13920. //=====================================================================================================
  13921. class CRoxieServerNWayGraphLoopResultReadActivity : public CRoxieServerActivity
  13922. {
  13923. IHThorNWayGraphLoopResultReadArg & helper;
  13924. CIArrayOf<CRoxieServerActivity> resultReaders;
  13925. PointerArrayOf<IRoxieInput> inputs;
  13926. unsigned graphId;
  13927. bool grouped;
  13928. bool selectionIsAll;
  13929. size32_t selectionLen;
  13930. rtlDataAttr selection;
  13931. public:
  13932. CRoxieServerNWayGraphLoopResultReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _graphId)
  13933. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorNWayGraphLoopResultReadArg &)basehelper)
  13934. {
  13935. grouped = helper.isGrouped();
  13936. graphId = _graphId;
  13937. selectionIsAll = false;
  13938. selectionLen = 0;
  13939. }
  13940. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  13941. {
  13942. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  13943. if (inputs.ordinality() == 0)
  13944. {
  13945. initInputSelection();
  13946. unsigned max = selectionLen / sizeof(size32_t);
  13947. const size32_t * selections = (const size32_t *)selection.getdata();
  13948. IProbeManager * probeManager = NULL; // MORE!!
  13949. for (unsigned i = 0; i < max; i++)
  13950. {
  13951. CRoxieServerActivity * resultInput = new CRoxieServerInternalGraphLoopResultReadActivity(factory, probeManager, graphId, selections[i]);
  13952. resultReaders.append(*resultInput);
  13953. inputs.append(resultInput->queryOutput(0));
  13954. resultInput->onCreate(ctx, colocalParent);
  13955. resultInput->start(parentExtractSize, parentExtract, paused);
  13956. }
  13957. }
  13958. else
  13959. {
  13960. ForEachItemIn(i, inputs)
  13961. inputs.item(i)->start(parentExtractSize, parentExtract, paused);
  13962. }
  13963. }
  13964. virtual void stop(bool aborting)
  13965. {
  13966. ForEachItemIn(i, inputs)
  13967. inputs.item(i)->stop(aborting);
  13968. CRoxieServerActivity::stop(aborting);
  13969. }
  13970. virtual void reset()
  13971. {
  13972. ForEachItemIn(i, inputs)
  13973. inputs.item(i)->reset();
  13974. inputs.kill();
  13975. resultReaders.kill();
  13976. CRoxieServerActivity::reset();
  13977. }
  13978. virtual void setInput(unsigned idx, IRoxieInput *_in)
  13979. {
  13980. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for nway graph result read");
  13981. }
  13982. virtual const void * nextInGroup()
  13983. {
  13984. throwUnexpected();
  13985. }
  13986. virtual unsigned numConcreteOutputs() const
  13987. {
  13988. return inputs.ordinality();
  13989. }
  13990. virtual IRoxieInput * queryConcreteInput(unsigned idx)
  13991. {
  13992. if (inputs.isItem(idx))
  13993. return inputs.item(idx);
  13994. return NULL;
  13995. }
  13996. virtual void gatherIterationUsage(IRoxieServerLoopResultProcessor & processor, unsigned parentExtractSize, const byte * parentExtract)
  13997. {
  13998. ensureCreated();
  13999. basehelper.onStart(parentExtract, NULL);
  14000. initInputSelection();
  14001. unsigned max = selectionLen / sizeof(size32_t);
  14002. const size32_t * selections = (const size32_t *)selection.getdata();
  14003. for (unsigned i = 0; i < max; i++)
  14004. processor.noteUseIteration(selections[i]);
  14005. }
  14006. virtual void associateIterationOutputs(IRoxieServerLoopResultProcessor & processor, unsigned parentExtractSize, const byte * parentExtract, IProbeManager *probeManager, IArrayOf<IRoxieInput> &probes)
  14007. {
  14008. //selection etc. already initialised from the gratherIterationUsage() call.
  14009. unsigned max = selectionLen / sizeof(size32_t);
  14010. const size32_t * selections = (const size32_t *)selection.getdata();
  14011. for (unsigned i = 0; i < max; i++)
  14012. inputs.append(processor.connectIterationOutput(selections[i], probeManager, probes, this, i));
  14013. }
  14014. protected:
  14015. void initInputSelection()
  14016. {
  14017. helper.getInputSelection(selectionIsAll, selectionLen, selection.refdata());
  14018. if (selectionIsAll)
  14019. throw MakeStringException(ROXIE_NWAY_INPUT_ERROR, "ALL not yet supported for NWay graph inputs");
  14020. }
  14021. };
  14022. class CRoxieServerNWayGraphLoopResultReadActivityFactory : public CRoxieServerActivityFactory
  14023. {
  14024. unsigned graphId;
  14025. public:
  14026. CRoxieServerNWayGraphLoopResultReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _graphId)
  14027. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), graphId(_graphId)
  14028. {
  14029. }
  14030. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  14031. {
  14032. return new CRoxieServerNWayGraphLoopResultReadActivity(this, _probeManager, graphId);
  14033. }
  14034. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  14035. {
  14036. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for NWay GraphLoopResultRead activity");
  14037. }
  14038. };
  14039. IRoxieServerActivityFactory *createRoxieServerNWayGraphLoopResultReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned graphId)
  14040. {
  14041. return new CRoxieServerNWayGraphLoopResultReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, graphId);
  14042. }
  14043. //=================================================================================
  14044. class RoxieSteppedInput : public CInterface, implements ISteppedInput
  14045. {
  14046. public:
  14047. RoxieSteppedInput(IRoxieInput * _input) { input = _input; }
  14048. IMPLEMENT_IINTERFACE
  14049. protected:
  14050. virtual const void * nextInputRow()
  14051. {
  14052. #ifdef TRACE_SEEK_REQUESTS
  14053. IRoxieContextLogger * logger = input->queryActivity();
  14054. const void * ret = doNextInputRow();
  14055. {
  14056. CommonXmlWriter xmlwrite(XWFtrim|XWFopt|XWFnoindent);
  14057. if (!ret)
  14058. xmlwrite.outputBool(true,"eof");
  14059. else if (input->queryOutputMeta()->hasXML())
  14060. input->queryOutputMeta()->toXML((byte *) ret, xmlwrite);
  14061. logger->CTXLOG("next() returns (%s)", xmlwrite.str());
  14062. }
  14063. return ret;
  14064. #else
  14065. return doNextInputRow();
  14066. #endif
  14067. }
  14068. virtual const void * nextInputRowGE(const void * seek, unsigned numFields, bool & wasCompleteMatch, const SmartStepExtra & stepExtra)
  14069. {
  14070. #ifdef TRACE_SEEK_REQUESTS
  14071. IRoxieContextLogger * logger = input->queryActivity();
  14072. {
  14073. CommonXmlWriter xmlwrite(XWFtrim|XWFopt|XWFnoindent);
  14074. if (input->queryOutputMeta()->hasXML())
  14075. input->queryOutputMeta()->toXML((byte *) seek, xmlwrite);
  14076. logger->CTXLOG("nextInputRowGE(%d, %s%s%s, %s) seek(%s)",
  14077. numFields,
  14078. stepExtra.readAheadManyResults() ? "readahead " : "",
  14079. stepExtra.returnMismatches() ? "mismatch" : "exact",
  14080. stepExtra.onlyReturnFirstSeekMatch() ? " single-match" : "",
  14081. stepExtra.queryExtraSeeks() ? "multi-seek":"",
  14082. xmlwrite.str());
  14083. }
  14084. const void * ret = doNextInputRowGE(seek, numFields, wasCompleteMatch, stepExtra);
  14085. {
  14086. CommonXmlWriter xmlwrite(XWFtrim|XWFopt|XWFnoindent);
  14087. if (!ret)
  14088. xmlwrite.outputBool(true,"eof");
  14089. else if (input->queryOutputMeta()->hasXML())
  14090. input->queryOutputMeta()->toXML((byte *) ret, xmlwrite);
  14091. logger->CTXLOG("nextInputRowGE(%d, %s%s%s, %s) result(%s)",
  14092. numFields,
  14093. stepExtra.readAheadManyResults() ? "readahead " : "",
  14094. stepExtra.returnMismatches() ? "mismatch" : "exact",
  14095. stepExtra.onlyReturnFirstSeekMatch() ? " single-match" : "",
  14096. stepExtra.queryExtraSeeks() ? "multi-seek":"",
  14097. xmlwrite.str());
  14098. }
  14099. return ret;
  14100. #else
  14101. return doNextInputRowGE(seek, numFields, wasCompleteMatch, stepExtra);
  14102. #endif
  14103. }
  14104. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  14105. {
  14106. return input->gatherConjunctions(collector);
  14107. }
  14108. virtual void resetEOF()
  14109. {
  14110. input->resetEOF();
  14111. }
  14112. virtual IInputSteppingMeta * queryInputSteppingMeta()
  14113. {
  14114. return input->querySteppingMeta();
  14115. }
  14116. inline const void * doNextInputRow()
  14117. {
  14118. const void * ret = input->nextInGroup();
  14119. if (!ret)
  14120. ret = input->nextInGroup();
  14121. return ret;
  14122. }
  14123. inline const void * doNextInputRowGE(const void * seek, unsigned numFields, bool & wasCompleteMatch, const SmartStepExtra & stepExtra)
  14124. {
  14125. assertex(wasCompleteMatch);
  14126. return input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  14127. }
  14128. protected:
  14129. IRoxieInput * input;
  14130. };
  14131. //=================================================================================
  14132. class CRoxieServerNaryActivity : public CRoxieServerMultiInputActivity
  14133. {
  14134. public:
  14135. CRoxieServerNaryActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  14136. : CRoxieServerMultiInputActivity(_factory, _probeManager, _numInputs)
  14137. {
  14138. }
  14139. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14140. {
  14141. CRoxieServerMultiInputActivity::start(parentExtractSize, parentExtract, paused);
  14142. for (unsigned i=0; i < numInputs; i++)
  14143. {
  14144. IRoxieInput * cur = inputArray[i];
  14145. unsigned numRealInputs = cur->numConcreteOutputs();
  14146. for (unsigned j = 0; j < numRealInputs; j++)
  14147. {
  14148. IRoxieInput * curReal = cur->queryConcreteInput(j);
  14149. expandedInputs.append(curReal);
  14150. }
  14151. }
  14152. }
  14153. virtual void reset()
  14154. {
  14155. expandedInputs.kill();
  14156. CRoxieServerMultiInputActivity::reset();
  14157. }
  14158. protected:
  14159. PointerArrayOf<IRoxieInput> expandedInputs;
  14160. };
  14161. //=================================================================================
  14162. class CRoxieStreamMerger : public CStreamMerger
  14163. {
  14164. public:
  14165. CRoxieStreamMerger() : CStreamMerger(true)
  14166. {
  14167. inputArray = NULL;
  14168. }
  14169. void initInputs(unsigned _numInputs, IRoxieInput ** _inputArray)
  14170. {
  14171. CStreamMerger::initInputs(_numInputs);
  14172. inputArray = _inputArray;
  14173. }
  14174. virtual bool pullInput(unsigned i, const void * seek, unsigned numFields, const SmartStepExtra * stepExtra)
  14175. {
  14176. const void * next;
  14177. bool matches = true;
  14178. if (seek)
  14179. next = inputArray[i]->nextSteppedGE(seek, numFields, matches, *stepExtra);
  14180. else
  14181. next = nextUngrouped(inputArray[i]);
  14182. pending[i] = next;
  14183. pendingMatches[i] = matches;
  14184. return (next != NULL);
  14185. }
  14186. virtual void releaseRow(const void * row)
  14187. {
  14188. ReleaseRoxieRow(row);
  14189. }
  14190. protected:
  14191. IRoxieInput **inputArray;
  14192. };
  14193. class CRoxieServerNWayMergeActivity : public CRoxieServerNaryActivity
  14194. {
  14195. public:
  14196. CRoxieServerNWayMergeActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  14197. : CRoxieServerNaryActivity(_factory, _probeManager, _numInputs),
  14198. helper((IHThorNWayMergeArg &)basehelper)
  14199. {
  14200. initializedMeta = false;
  14201. }
  14202. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14203. {
  14204. CRoxieServerNaryActivity::start(parentExtractSize, parentExtract, paused);
  14205. merger.init(helper.queryCompare(), helper.dedup(), helper.querySteppingMeta()->queryCompare());
  14206. merger.initInputs(expandedInputs.length(), expandedInputs.getArray());
  14207. }
  14208. virtual void stop(bool aborting)
  14209. {
  14210. merger.done();
  14211. CRoxieServerNaryActivity::stop(aborting);
  14212. }
  14213. virtual void reset()
  14214. {
  14215. merger.cleanup();
  14216. CRoxieServerNaryActivity::reset();
  14217. initializedMeta = false;
  14218. }
  14219. virtual const void * nextInGroup()
  14220. {
  14221. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  14222. const void * next = merger.nextRow();
  14223. if (next)
  14224. processed++;
  14225. return next;
  14226. }
  14227. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool & wasCompleteMatch, const SmartStepExtra & stepExtra)
  14228. {
  14229. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  14230. const void * next = merger.nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);
  14231. if (next)
  14232. processed++;
  14233. return next;
  14234. }
  14235. virtual IInputSteppingMeta * querySteppingMeta()
  14236. {
  14237. if (expandedInputs.ordinality() == 0)
  14238. return NULL;
  14239. if (!initializedMeta)
  14240. {
  14241. meta.init(helper.querySteppingMeta(), false);
  14242. ForEachItemIn(i, expandedInputs)
  14243. {
  14244. if (meta.getNumFields() == 0)
  14245. break;
  14246. IInputSteppingMeta * inputMeta = expandedInputs.item(i)->querySteppingMeta();
  14247. meta.intersect(inputMeta);
  14248. }
  14249. initializedMeta = true;
  14250. }
  14251. if (meta.getNumFields() == 0)
  14252. return NULL;
  14253. return &meta;
  14254. }
  14255. protected:
  14256. IHThorNWayMergeArg &helper;
  14257. CRoxieStreamMerger merger;
  14258. CSteppingMeta meta;
  14259. bool initializedMeta;
  14260. };
  14261. class CRoxieServerNWayMergeActivityFactory : public CRoxieServerMultiInputFactory
  14262. {
  14263. public:
  14264. CRoxieServerNWayMergeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14265. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  14266. {
  14267. }
  14268. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  14269. {
  14270. return new CRoxieServerNWayMergeActivity(this, _probeManager, numInputs());
  14271. }
  14272. };
  14273. IRoxieServerActivityFactory *createRoxieServerNWayMergeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14274. {
  14275. return new CRoxieServerNWayMergeActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  14276. }
  14277. //=================================================================================
  14278. class CRoxieServerNWayMergeJoinActivity : public CRoxieServerNaryActivity
  14279. {
  14280. public:
  14281. CRoxieServerNWayMergeJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs, CMergeJoinProcessor & _processor)
  14282. : CRoxieServerNaryActivity(_factory, _probeManager, _numInputs),processor(_processor),
  14283. helper((IHThorNWayMergeJoinArg &)basehelper)
  14284. {
  14285. }
  14286. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14287. {
  14288. CRoxieServerNaryActivity::start(parentExtractSize, parentExtract, paused);
  14289. ForEachItemIn(i1, expandedInputs)
  14290. {
  14291. IRoxieInput * cur = expandedInputs.item(i1);
  14292. Owned<RoxieSteppedInput> stepInput = new RoxieSteppedInput(cur);
  14293. processor.addInput(stepInput);
  14294. }
  14295. ICodeContext * codectx = ctx->queryCodeContext();
  14296. Owned<IEngineRowAllocator> inputAllocator = codectx->getRowAllocator(helper.queryInputMeta(), activityId);
  14297. Owned<IEngineRowAllocator> outputAllocator = codectx->getRowAllocator(helper.queryOutputMeta(), activityId);
  14298. processor.beforeProcessing(inputAllocator, outputAllocator);
  14299. }
  14300. virtual void stop(bool aborting)
  14301. {
  14302. processor.afterProcessing();
  14303. CRoxieServerNaryActivity::stop(aborting);
  14304. }
  14305. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  14306. {
  14307. return processor.gatherConjunctions(collector);
  14308. }
  14309. virtual void resetEOF()
  14310. {
  14311. processor.queryResetEOF();
  14312. }
  14313. virtual const void * nextInGroup()
  14314. {
  14315. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  14316. const void * next = processor.nextInGroup();
  14317. if (next)
  14318. processed++;
  14319. return next;
  14320. }
  14321. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  14322. {
  14323. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  14324. const void * next = processor.nextGE(seek, numFields, wasCompleteMatch, stepExtra);
  14325. if (next)
  14326. processed++;
  14327. return next;
  14328. }
  14329. virtual IInputSteppingMeta * querySteppingMeta()
  14330. {
  14331. return processor.queryInputSteppingMeta();
  14332. }
  14333. protected:
  14334. IHThorNWayMergeJoinArg & helper;
  14335. CMergeJoinProcessor & processor;
  14336. };
  14337. class CRoxieServerAndMergeJoinActivity : public CRoxieServerNWayMergeJoinActivity
  14338. {
  14339. public:
  14340. CRoxieServerAndMergeJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  14341. : CRoxieServerNWayMergeJoinActivity(_factory, _probeManager, _numInputs, andProcessor), andProcessor(helper)
  14342. {
  14343. }
  14344. protected:
  14345. CAndMergeJoinProcessor andProcessor;
  14346. };
  14347. class CRoxieServerAndLeftMergeJoinActivity : public CRoxieServerNWayMergeJoinActivity
  14348. {
  14349. public:
  14350. CRoxieServerAndLeftMergeJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  14351. : CRoxieServerNWayMergeJoinActivity(_factory, _probeManager, _numInputs, andLeftProcessor), andLeftProcessor(helper)
  14352. {
  14353. }
  14354. protected:
  14355. CAndLeftMergeJoinProcessor andLeftProcessor;
  14356. };
  14357. class CRoxieServerMofNMergeJoinActivity : public CRoxieServerNWayMergeJoinActivity
  14358. {
  14359. public:
  14360. CRoxieServerMofNMergeJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  14361. : CRoxieServerNWayMergeJoinActivity(_factory, _probeManager, _numInputs, mofnProcessor), mofnProcessor(helper)
  14362. {
  14363. }
  14364. protected:
  14365. CMofNMergeJoinProcessor mofnProcessor;
  14366. };
  14367. class CRoxieServerProximityJoinActivity : public CRoxieServerNWayMergeJoinActivity
  14368. {
  14369. public:
  14370. CRoxieServerProximityJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  14371. : CRoxieServerNWayMergeJoinActivity(_factory, _probeManager, _numInputs, proximityProcessor), proximityProcessor(helper)
  14372. {
  14373. }
  14374. protected:
  14375. CProximityJoinProcessor proximityProcessor;
  14376. };
  14377. class CRoxieServerNWayMergeJoinActivityFactory : public CRoxieServerMultiInputFactory
  14378. {
  14379. unsigned flags;
  14380. public:
  14381. CRoxieServerNWayMergeJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14382. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  14383. {
  14384. Owned<IHThorNWayMergeJoinArg> helper = (IHThorNWayMergeJoinArg *) helperFactory();
  14385. flags = helper->getJoinFlags();
  14386. }
  14387. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  14388. {
  14389. if (flags & IHThorNWayMergeJoinArg::MJFhasrange)
  14390. return new CRoxieServerProximityJoinActivity(this, _probeManager, numInputs());
  14391. switch (flags & IHThorNWayMergeJoinArg::MJFkindmask)
  14392. {
  14393. case IHThorNWayMergeJoinArg::MJFinner:
  14394. return new CRoxieServerAndMergeJoinActivity(this, _probeManager, numInputs());
  14395. case IHThorNWayMergeJoinArg::MJFleftonly:
  14396. case IHThorNWayMergeJoinArg::MJFleftouter:
  14397. return new CRoxieServerAndLeftMergeJoinActivity(this, _probeManager, numInputs());
  14398. case IHThorNWayMergeJoinArg::MJFmofn:
  14399. return new CRoxieServerMofNMergeJoinActivity(this, _probeManager, numInputs());
  14400. default:
  14401. throwUnexpected();
  14402. }
  14403. }
  14404. };
  14405. IRoxieServerActivityFactory *createRoxieServerNWayMergeJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14406. {
  14407. return new CRoxieServerNWayMergeJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  14408. }
  14409. //=================================================================================
  14410. class CRoxieServerNWaySelectActivity : public CRoxieServerMultiInputActivity
  14411. {
  14412. IHThorNWaySelectArg &helper;
  14413. public:
  14414. CRoxieServerNWaySelectActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  14415. : CRoxieServerMultiInputActivity(_factory, _probeManager, _numInputs),
  14416. helper((IHThorNWaySelectArg &)basehelper)
  14417. {
  14418. selectedInput = NULL;
  14419. }
  14420. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14421. {
  14422. CRoxieServerMultiInputActivity::start(parentExtractSize, parentExtract, paused);
  14423. unsigned whichInput = helper.getInputIndex();
  14424. selectedInput = NULL;
  14425. if (whichInput--)
  14426. {
  14427. for (unsigned i=0; i < numInputs; i++)
  14428. {
  14429. IRoxieInput * cur = inputArray[i];
  14430. unsigned numRealInputs = cur->numConcreteOutputs();
  14431. if (whichInput < numRealInputs)
  14432. {
  14433. selectedInput = cur->queryConcreteInput(whichInput);
  14434. break;
  14435. }
  14436. whichInput -= numRealInputs;
  14437. }
  14438. }
  14439. }
  14440. virtual void reset()
  14441. {
  14442. selectedInput = NULL;
  14443. CRoxieServerMultiInputActivity::reset();
  14444. }
  14445. const void * nextInGroup()
  14446. {
  14447. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  14448. if (!selectedInput)
  14449. return NULL;
  14450. return selectedInput->nextInGroup();
  14451. }
  14452. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  14453. {
  14454. if (!selectedInput)
  14455. return false;
  14456. return selectedInput->gatherConjunctions(collector);
  14457. }
  14458. virtual void resetEOF()
  14459. {
  14460. if (selectedInput)
  14461. selectedInput->resetEOF();
  14462. }
  14463. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  14464. {
  14465. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  14466. if (!selectedInput)
  14467. return NULL;
  14468. return selectedInput->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  14469. }
  14470. IInputSteppingMeta * querySteppingMeta()
  14471. {
  14472. if (selectedInput)
  14473. return selectedInput->querySteppingMeta();
  14474. return NULL;
  14475. }
  14476. protected:
  14477. IRoxieInput * selectedInput;
  14478. };
  14479. class CRoxieServerNWaySelectActivityFactory : public CRoxieServerMultiInputFactory
  14480. {
  14481. public:
  14482. CRoxieServerNWaySelectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14483. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  14484. {
  14485. }
  14486. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  14487. {
  14488. return new CRoxieServerNWaySelectActivity(this, _probeManager, numInputs());
  14489. }
  14490. };
  14491. IRoxieServerActivityFactory *createRoxieServerNWaySelectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14492. {
  14493. return new CRoxieServerNWaySelectActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  14494. }
  14495. //=================================================================================
  14496. class CRoxieServerRemoteActivity : public CRoxieServerActivity, implements IRoxieServerErrorHandler
  14497. {
  14498. protected:
  14499. IHThorRemoteArg &helper;
  14500. CRemoteResultAdaptor remote;
  14501. public:
  14502. CRoxieServerRemoteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteID)
  14503. : CRoxieServerActivity(_factory, _probeManager),
  14504. helper((IHThorRemoteArg &)basehelper),
  14505. remote(_remoteID, meta.queryOriginal(), helper, *this, false, false) // MORE - if they need it stable we'll have to think!
  14506. {
  14507. }
  14508. virtual const IResolvedFile *queryVarFileInfo() const
  14509. {
  14510. return NULL;
  14511. }
  14512. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  14513. {
  14514. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  14515. remote.onCreate(this, this, _ctx, _colocalParent);
  14516. }
  14517. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14518. {
  14519. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  14520. remote.onStart(parentExtractSize, parentExtract);
  14521. remote.setLimits(helper.getRowLimit(), (unsigned __int64) -1, I64C(0x7FFFFFFFFFFFFFFF));
  14522. unsigned fileNo = 0; // MORE - superfiles require us to do this per file part... maybe (needs thought)
  14523. remote.getMem(0, fileNo, 0); // the cached context is all we need to send
  14524. remote.flush();
  14525. remote.senddone();
  14526. }
  14527. virtual void setInput(unsigned idx, IRoxieInput *_in)
  14528. {
  14529. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  14530. }
  14531. virtual IRoxieInput *queryOutput(unsigned idx)
  14532. {
  14533. if (idx==(unsigned)-1)
  14534. idx = 0;
  14535. return idx ? NULL: &remote;
  14536. }
  14537. virtual void reset()
  14538. {
  14539. processed = remote.processed;
  14540. remote.processed = 0;
  14541. CRoxieServerActivity::reset();
  14542. }
  14543. virtual void onLimitExceeded(bool isKeyed)
  14544. {
  14545. if (traceLevel > 4)
  14546. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  14547. helper.onLimitExceeded();
  14548. }
  14549. virtual const void *createLimitFailRow(bool isKeyed)
  14550. {
  14551. UNIMPLEMENTED; // MORE - is there an ONFAIL for a limit folded into a remote?
  14552. }
  14553. virtual const void *nextInGroup()
  14554. {
  14555. throwUnexpected(); // I am nobody's input
  14556. }
  14557. };
  14558. class CRoxieServerRemoteActivityFactory : public CRoxieServerActivityFactory
  14559. {
  14560. public:
  14561. RemoteActivityId remoteId;
  14562. bool isRoot;
  14563. CRoxieServerRemoteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, bool _isRoot)
  14564. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), remoteId(_remoteId), isRoot(_isRoot)
  14565. {
  14566. }
  14567. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  14568. {
  14569. return new CRoxieServerRemoteActivity(this, _probeManager, remoteId);
  14570. }
  14571. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  14572. {
  14573. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for %s activity", getActivityText(kind));
  14574. }
  14575. virtual bool isSink() const
  14576. {
  14577. //I don't think the action version of this is implemented - but this would be the code
  14578. return isRoot && !meta.queryOriginal();
  14579. }
  14580. };
  14581. IRoxieServerActivityFactory *createRoxieServerRemoteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, bool _isRoot)
  14582. {
  14583. return new CRoxieServerRemoteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _isRoot);
  14584. }
  14585. //=================================================================================
  14586. class CRoxieServerIterateActivity : public CRoxieServerActivity
  14587. {
  14588. IHThorIterateArg &helper;
  14589. OwnedConstRoxieRow defaultRecord;
  14590. OwnedConstRoxieRow left;
  14591. OwnedConstRoxieRow right;
  14592. unsigned counter;
  14593. public:
  14594. CRoxieServerIterateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  14595. : CRoxieServerActivity(_factory, _probeManager),
  14596. helper((IHThorIterateArg &)basehelper)
  14597. {
  14598. counter = 0;
  14599. }
  14600. virtual bool needsAllocator() const { return true; }
  14601. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14602. {
  14603. counter = 0;
  14604. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  14605. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  14606. size32_t thisSize = helper.createDefault(rowBuilder);
  14607. defaultRecord.setown(rowBuilder.finalizeRowClear(thisSize));
  14608. }
  14609. virtual void reset()
  14610. {
  14611. defaultRecord.clear();
  14612. right.clear();
  14613. left.clear();
  14614. CRoxieServerActivity::reset();
  14615. }
  14616. virtual const void * nextInGroup()
  14617. {
  14618. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  14619. loop
  14620. {
  14621. right.setown(input->nextInGroup());
  14622. if (!right)
  14623. {
  14624. bool skippedGroup = (left == NULL) && (counter > 0); //we have just skipped entire group, but shouldn't output a double null
  14625. left.clear();
  14626. counter = 0;
  14627. if (skippedGroup) continue;
  14628. return NULL;
  14629. }
  14630. try
  14631. {
  14632. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  14633. unsigned outSize = helper.transform(rowBuilder, left ? left : defaultRecord, right, ++counter);
  14634. if (outSize)
  14635. {
  14636. left.setown(rowBuilder.finalizeRowClear(outSize));
  14637. processed++;
  14638. return left.getLink();
  14639. }
  14640. }
  14641. catch (IException *E)
  14642. {
  14643. throw makeWrappedException(E);
  14644. }
  14645. }
  14646. }
  14647. };
  14648. class CRoxieServerIterateActivityFactory : public CRoxieServerActivityFactory
  14649. {
  14650. public:
  14651. CRoxieServerIterateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14652. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  14653. {
  14654. }
  14655. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  14656. {
  14657. return new CRoxieServerIterateActivity(this, _probeManager);
  14658. }
  14659. };
  14660. IRoxieServerActivityFactory *createRoxieServerIterateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14661. {
  14662. return new CRoxieServerIterateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  14663. }
  14664. //=================================================================================
  14665. class CRoxieServerProcessActivity : public CRoxieServerActivity
  14666. {
  14667. IHThorProcessArg &helper;
  14668. OwnedConstRoxieRow curRight;
  14669. OwnedConstRoxieRow initialRight;
  14670. unsigned counter;
  14671. Owned<IEngineRowAllocator> rightRowAllocator;
  14672. public:
  14673. CRoxieServerProcessActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  14674. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorProcessArg &)basehelper)
  14675. {
  14676. counter = 0;
  14677. }
  14678. virtual bool needsAllocator() const { return true; }
  14679. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  14680. {
  14681. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  14682. rightRowAllocator.setown(ctx->queryCodeContext()->getRowAllocator(QUERYINTERFACE(helper.queryRightRecordSize(), IOutputMetaData), activityId));
  14683. }
  14684. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14685. {
  14686. counter = 0;
  14687. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  14688. RtlDynamicRowBuilder rowBuilder(rightRowAllocator);
  14689. size32_t thisSize = helper.createInitialRight(rowBuilder);
  14690. initialRight.setown(rowBuilder.finalizeRowClear(thisSize));
  14691. curRight.set(initialRight);
  14692. }
  14693. virtual const void * nextInGroup()
  14694. {
  14695. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  14696. try
  14697. {
  14698. loop
  14699. {
  14700. const void * in = input->nextInGroup();
  14701. if (!in)
  14702. {
  14703. bool eog = (curRight != initialRight); // processed any records?
  14704. counter = 0;
  14705. curRight.set(initialRight);
  14706. if (eog)
  14707. return NULL;
  14708. in = input->nextInGroup();
  14709. if (!in)
  14710. return NULL;
  14711. }
  14712. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  14713. RtlDynamicRowBuilder rightRowBuilder(rightRowAllocator);
  14714. size32_t outSize = helper.transform(rowBuilder, rightRowBuilder, in, curRight, ++counter);
  14715. ReleaseRoxieRow(in);
  14716. if (outSize)
  14717. {
  14718. //MORE: This should be returned...
  14719. size32_t rightSize = rightRowAllocator->queryOutputMeta()->getRecordSize(rightRowBuilder.getSelf());
  14720. curRight.setown(rightRowBuilder.finalizeRowClear(rightSize));
  14721. processed++;
  14722. return rowBuilder.finalizeRowClear(outSize);
  14723. }
  14724. }
  14725. }
  14726. catch (IException *E)
  14727. {
  14728. throw makeWrappedException(E);
  14729. }
  14730. }
  14731. };
  14732. class CRoxieServerProcessActivityFactory : public CRoxieServerActivityFactory
  14733. {
  14734. public:
  14735. CRoxieServerProcessActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14736. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  14737. {
  14738. }
  14739. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  14740. {
  14741. return new CRoxieServerProcessActivity(this, _probeManager);
  14742. }
  14743. };
  14744. IRoxieServerActivityFactory *createRoxieServerProcessActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14745. {
  14746. return new CRoxieServerProcessActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  14747. }
  14748. //=================================================================================
  14749. class CRoxieServerGroupActivity : public CRoxieServerActivity
  14750. {
  14751. IHThorGroupArg &helper;
  14752. bool endPending;
  14753. bool eof;
  14754. bool first;
  14755. const void *next;
  14756. public:
  14757. CRoxieServerGroupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  14758. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorGroupArg &)basehelper)
  14759. {
  14760. next = NULL;
  14761. endPending = false;
  14762. eof = false;
  14763. first = true;
  14764. }
  14765. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14766. {
  14767. endPending = false;
  14768. eof = false;
  14769. first = true;
  14770. assertex(next == NULL);
  14771. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  14772. }
  14773. virtual void reset()
  14774. {
  14775. ReleaseClearRoxieRow(next);
  14776. CRoxieServerActivity::reset();
  14777. }
  14778. virtual const void * nextInGroup()
  14779. {
  14780. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  14781. if (first)
  14782. {
  14783. next = input->nextInGroup();
  14784. first = false;
  14785. }
  14786. if (eof || endPending)
  14787. {
  14788. endPending = false;
  14789. return NULL;
  14790. }
  14791. const void * prev = next;
  14792. next = input->nextInGroup();
  14793. if (!next)
  14794. next = input->nextInGroup();
  14795. if (next)
  14796. {
  14797. assertex(prev);
  14798. if (!helper.isSameGroup(prev, next))
  14799. endPending = true;
  14800. }
  14801. else
  14802. eof = true;
  14803. if (prev)
  14804. processed++;
  14805. return prev;
  14806. }
  14807. };
  14808. class CRoxieServerGroupActivityFactory : public CRoxieServerActivityFactory
  14809. {
  14810. public:
  14811. CRoxieServerGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14812. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  14813. {
  14814. }
  14815. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  14816. {
  14817. return new CRoxieServerGroupActivity(this, _probeManager);
  14818. }
  14819. };
  14820. IRoxieServerActivityFactory *createRoxieServerGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14821. {
  14822. return new CRoxieServerGroupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  14823. }
  14824. //=================================================================================
  14825. class CRoxieServerFirstNActivity : public CRoxieServerLateStartActivity
  14826. {
  14827. unsigned __int64 limit;
  14828. unsigned __int64 skip;
  14829. unsigned doneThisGroup;
  14830. IHThorFirstNArg &helper;
  14831. public:
  14832. CRoxieServerFirstNActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  14833. : CRoxieServerLateStartActivity(_factory, _probeManager), helper((IHThorFirstNArg &)basehelper)
  14834. {
  14835. doneThisGroup = 0;
  14836. limit = 0;
  14837. skip = 0;
  14838. }
  14839. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14840. {
  14841. doneThisGroup = 0;
  14842. CRoxieServerLateStartActivity::start(parentExtractSize, parentExtract, paused);
  14843. limit = helper.getLimit();
  14844. skip = helper.numToSkip();
  14845. lateStart(parentExtractSize, parentExtract, limit > 0);
  14846. if (limit + skip >= limit)
  14847. limit += skip;
  14848. }
  14849. const void * nextInGroup()
  14850. {
  14851. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  14852. if (eof)
  14853. return NULL;
  14854. const void *ret;
  14855. loop
  14856. {
  14857. ret = input->nextInGroup();
  14858. if (!ret)
  14859. {
  14860. if (meta.isGrouped())
  14861. {
  14862. if (doneThisGroup > skip)
  14863. {
  14864. doneThisGroup = 0;
  14865. return NULL;
  14866. }
  14867. doneThisGroup = 0;
  14868. }
  14869. ret = input->nextInGroup();
  14870. if (!ret)
  14871. {
  14872. eof = true;
  14873. return NULL;
  14874. }
  14875. }
  14876. doneThisGroup++;
  14877. if (doneThisGroup > skip)
  14878. break;
  14879. ReleaseRoxieRow(ret);
  14880. }
  14881. if (doneThisGroup <= limit)
  14882. {
  14883. processed++;
  14884. return ret;
  14885. }
  14886. ReleaseRoxieRow(ret);
  14887. if (meta.isGrouped())
  14888. {
  14889. while ((ret = input->nextInGroup()) != NULL)
  14890. ReleaseRoxieRow(ret);
  14891. doneThisGroup = 0;
  14892. }
  14893. else
  14894. eof = true;
  14895. return NULL;
  14896. }
  14897. };
  14898. class CRoxieServerFirstNActivityFactory : public CRoxieServerActivityFactory
  14899. {
  14900. public:
  14901. CRoxieServerFirstNActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14902. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  14903. {
  14904. }
  14905. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  14906. {
  14907. return new CRoxieServerFirstNActivity(this, _probeManager);
  14908. }
  14909. };
  14910. IRoxieServerActivityFactory *createRoxieServerFirstNActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14911. {
  14912. return new CRoxieServerFirstNActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  14913. }
  14914. //=================================================================================
  14915. class CRoxieServerSelectNActivity : public CRoxieServerActivity
  14916. {
  14917. bool done;
  14918. IHThorSelectNArg &helper;
  14919. public:
  14920. CRoxieServerSelectNActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  14921. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorSelectNArg &)basehelper)
  14922. {
  14923. done = false;
  14924. }
  14925. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14926. {
  14927. done = false;
  14928. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  14929. }
  14930. const void *defaultRow()
  14931. {
  14932. if (!rowAllocator)
  14933. createRowAllocator(); // We delay as often not needed...
  14934. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  14935. size32_t thisSize = helper.createDefault(rowBuilder);
  14936. return rowBuilder.finalizeRowClear(thisSize);
  14937. }
  14938. virtual const void * nextInGroup()
  14939. {
  14940. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  14941. if (done)
  14942. return NULL;
  14943. done = true;
  14944. processed++; // always going to return a row!
  14945. unsigned __int64 index = helper.getRowToSelect();
  14946. while (--index)
  14947. {
  14948. const void * next = input->nextInGroup();
  14949. if (!next)
  14950. next = input->nextInGroup();
  14951. if (!next)
  14952. return defaultRow();
  14953. ReleaseRoxieRow(next);
  14954. }
  14955. const void * next = input->nextInGroup();
  14956. if (!next)
  14957. next = input->nextInGroup();
  14958. if (!next)
  14959. next = defaultRow();
  14960. return next;
  14961. }
  14962. };
  14963. class CRoxieServerSelectNActivityFactory : public CRoxieServerActivityFactory
  14964. {
  14965. public:
  14966. CRoxieServerSelectNActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14967. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  14968. {
  14969. }
  14970. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  14971. {
  14972. return new CRoxieServerSelectNActivity(this, _probeManager);
  14973. }
  14974. };
  14975. IRoxieServerActivityFactory *createRoxieServerSelectNActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14976. {
  14977. return new CRoxieServerSelectNActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  14978. }
  14979. //=================================================================================
  14980. class CRoxieServerSelfJoinActivity : public CRoxieServerActivity
  14981. {
  14982. IHThorJoinArg &helper;
  14983. ICompare *collate;
  14984. OwnedRowArray group;
  14985. bool matchedLeft;
  14986. BoolArray matchedRight;
  14987. bool eof;
  14988. bool first;
  14989. unsigned leftIndex;
  14990. unsigned rightIndex;
  14991. unsigned rightOuterIndex;
  14992. unsigned joinLimit;
  14993. unsigned atmostLimit;
  14994. unsigned atmostsTriggered;
  14995. unsigned abortLimit;
  14996. unsigned keepLimit;
  14997. unsigned joinCounter;
  14998. bool leftOuterJoin;
  14999. bool rightOuterJoin;
  15000. bool exclude;
  15001. bool limitFail;
  15002. bool limitOnFail;
  15003. bool cloneLeft;
  15004. OwnedConstRoxieRow defaultLeft;
  15005. OwnedConstRoxieRow defaultRight;
  15006. OwnedConstRoxieRow lhs;
  15007. Owned<IException> failingLimit;
  15008. bool failingOuterAtmost;
  15009. Owned<IEngineRowAllocator> defaultAllocator;
  15010. Owned<IRHLimitedCompareHelper> limitedhelper;
  15011. Owned<CRHDualCache> dualcache;
  15012. IInputBase *dualCacheInput;
  15013. bool fillGroup()
  15014. {
  15015. group.clear();
  15016. matchedLeft = false;
  15017. matchedRight.kill();
  15018. failingOuterAtmost = false;
  15019. const void * next;
  15020. unsigned groupCount = 0;
  15021. while((next = input->nextInGroup()) != NULL)
  15022. {
  15023. if(groupCount==abortLimit)
  15024. {
  15025. if(limitFail)
  15026. failLimit(next);
  15027. if (ctx->queryDebugContext())
  15028. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  15029. if(limitOnFail)
  15030. {
  15031. assertex(!failingLimit);
  15032. try
  15033. {
  15034. failLimit(next);
  15035. }
  15036. catch(IException * except)
  15037. {
  15038. failingLimit.setown(except);
  15039. }
  15040. assertex(failingLimit != NULL);
  15041. group.append(next);
  15042. groupCount++;
  15043. break;
  15044. }
  15045. group.clear();
  15046. groupCount = 0;
  15047. while(next)
  15048. {
  15049. ReleaseRoxieRow(next);
  15050. next = input->nextInGroup();
  15051. }
  15052. }
  15053. else if(groupCount==atmostLimit)
  15054. {
  15055. atmostsTriggered++;
  15056. if(leftOuterJoin)
  15057. {
  15058. group.append(next);
  15059. groupCount++;
  15060. failingOuterAtmost = true;
  15061. break;
  15062. }
  15063. else
  15064. {
  15065. group.clear();
  15066. groupCount = 0;
  15067. while (next)
  15068. {
  15069. ReleaseRoxieRow(next);
  15070. next = input->nextInGroup();
  15071. }
  15072. }
  15073. }
  15074. else
  15075. {
  15076. group.append(next);
  15077. groupCount++;
  15078. }
  15079. }
  15080. if(group.ordinality()==0)
  15081. {
  15082. eof = true;
  15083. return false;
  15084. }
  15085. leftIndex = 0;
  15086. rightIndex = 0;
  15087. rightOuterIndex = 0;
  15088. joinCounter = 0;
  15089. joinLimit = keepLimit;
  15090. ForEachItemIn(idx, group)
  15091. matchedRight.append(false);
  15092. return true;
  15093. }
  15094. void failLimit(const void * next)
  15095. {
  15096. helper.onMatchAbortLimitExceeded();
  15097. CommonXmlWriter xmlwrite(XWFtrim|XWFopt );
  15098. if (!ctx->isBlind() && input->queryOutputMeta() && input->queryOutputMeta()->hasXML())
  15099. {
  15100. input->queryOutputMeta()->toXML((byte *) next, xmlwrite);
  15101. }
  15102. throw MakeStringException(ROXIE_TOO_MANY_RESULTS, "More than %d match candidates in self-join %d for row %s", abortLimit, queryId(), xmlwrite.str());
  15103. }
  15104. virtual bool needsAllocator() const { return true; }
  15105. const void *joinRecords(const void * curLeft, const void * curRight, unsigned counter, IException * except)
  15106. {
  15107. try
  15108. {
  15109. if (cloneLeft && !except)
  15110. {
  15111. LinkRoxieRow(curLeft);
  15112. return curLeft;
  15113. }
  15114. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  15115. size32_t outsize = except ? helper.onFailTransform(rowBuilder, curLeft, curRight, except) : helper.transform(rowBuilder, curLeft, curRight, counter);
  15116. if (outsize)
  15117. return rowBuilder.finalizeRowClear(outsize);
  15118. else
  15119. return NULL;
  15120. }
  15121. catch (IException *E)
  15122. {
  15123. throw makeWrappedException(E);
  15124. }
  15125. }
  15126. void createDefaultLeft()
  15127. {
  15128. if (!defaultLeft)
  15129. {
  15130. if (!defaultAllocator)
  15131. defaultAllocator.setown(ctx->queryCodeContext()->getRowAllocator(input->queryOutputMeta(), activityId));
  15132. RtlDynamicRowBuilder rowBuilder(defaultAllocator);
  15133. size32_t thisSize = helper.createDefaultLeft(rowBuilder);
  15134. defaultLeft.setown(rowBuilder.finalizeRowClear(thisSize));
  15135. }
  15136. }
  15137. void createDefaultRight()
  15138. {
  15139. if (!defaultRight)
  15140. {
  15141. if (!defaultAllocator)
  15142. defaultAllocator.setown(ctx->queryCodeContext()->getRowAllocator(input->queryOutputMeta(), activityId));
  15143. RtlDynamicRowBuilder rowBuilder(defaultAllocator);
  15144. size32_t thisSize = helper.createDefaultRight(rowBuilder);
  15145. defaultRight.setown(rowBuilder.finalizeRowClear(thisSize));
  15146. }
  15147. }
  15148. public:
  15149. CRoxieServerSelfJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  15150. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorJoinArg &)basehelper)
  15151. {
  15152. collate = helper.queryCompareLeftRight();
  15153. eof = false;
  15154. first = true;
  15155. keepLimit = 0;
  15156. atmostLimit = 0;
  15157. atmostsTriggered = 0;
  15158. unsigned joinFlags = helper.getJoinFlags();
  15159. leftOuterJoin = (joinFlags & JFleftouter) != 0;
  15160. rightOuterJoin = (joinFlags & JFrightouter) != 0;
  15161. cloneLeft = (joinFlags & JFtransformmatchesleft) != 0;
  15162. exclude = (joinFlags & JFexclude) != 0;
  15163. abortLimit = 0;
  15164. joinLimit = 0;
  15165. assertex((joinFlags & (JFfirst | JFfirstleft | JFfirstright)) == 0); // no longer supported
  15166. getLimitType(joinFlags, limitFail, limitOnFail);
  15167. if((joinFlags & JFslidingmatch) != 0)
  15168. throw MakeStringException(ROXIE_UNIMPLEMENTED_ERROR, "Internal Error: Sliding self join not supported");
  15169. failingOuterAtmost = false;
  15170. matchedLeft = false;
  15171. leftIndex = 0;
  15172. rightIndex = 0;
  15173. rightOuterIndex = 0;
  15174. joinCounter = 0;
  15175. dualCacheInput = NULL;
  15176. }
  15177. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  15178. {
  15179. eof = false;
  15180. first = true;
  15181. failingLimit.clear();
  15182. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  15183. keepLimit = helper.getKeepLimit();
  15184. if(keepLimit == 0)
  15185. keepLimit = (unsigned)-1;
  15186. atmostsTriggered = 0;
  15187. atmostLimit = helper.getJoinLimit();
  15188. if(atmostLimit == 0)
  15189. atmostLimit = (unsigned)-1;
  15190. else
  15191. assertex(!rightOuterJoin);
  15192. abortLimit = helper.getMatchAbortLimit();
  15193. if (abortLimit == 0)
  15194. abortLimit = (unsigned)-1;
  15195. if (rightOuterJoin)
  15196. createDefaultLeft();
  15197. if (leftOuterJoin || limitOnFail)
  15198. createDefaultRight();
  15199. if ((helper.getJoinFlags() & JFlimitedprefixjoin) && helper.getJoinLimit())
  15200. { //limited match join (s[1..n])
  15201. dualcache.setown(new CRHDualCache());
  15202. dualcache->init(CRoxieServerActivity::input);
  15203. dualCacheInput = dualcache->queryOut1();
  15204. failingOuterAtmost = false;
  15205. matchedLeft = false;
  15206. leftIndex = 0;
  15207. rightOuterIndex = 0;
  15208. joinCounter = 0;
  15209. limitedhelper.setown(createRHLimitedCompareHelper());
  15210. limitedhelper->init( helper.getJoinLimit(), dualcache->queryOut2(), collate, helper.queryPrefixCompare() );
  15211. }
  15212. }
  15213. virtual void reset()
  15214. {
  15215. if (atmostsTriggered)
  15216. noteStatistic(STATS_ATMOST, atmostsTriggered, 1);
  15217. group.clear();
  15218. CRoxieServerActivity::reset();
  15219. defaultLeft.clear();
  15220. defaultRight.clear();
  15221. }
  15222. virtual const void * nextInGroup()
  15223. {
  15224. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  15225. if (limitedhelper)
  15226. {
  15227. while(!eof) //limited match join
  15228. {
  15229. if (!group.isItem(rightIndex))
  15230. {
  15231. lhs.setown(dualCacheInput->nextInGroup());
  15232. if (lhs)
  15233. {
  15234. rightIndex = 0;
  15235. joinCounter = 0;
  15236. group.clear();
  15237. limitedhelper->getGroup(group,lhs);
  15238. }
  15239. else
  15240. {
  15241. eof = true;
  15242. }
  15243. }
  15244. if (group.isItem(rightIndex))
  15245. {
  15246. const void * rhs = group.item(rightIndex++);
  15247. if(helper.match(lhs, rhs))
  15248. {
  15249. const void * ret = joinRecords(lhs, rhs, ++joinCounter, NULL);
  15250. return ret;
  15251. }
  15252. }
  15253. }
  15254. return NULL;
  15255. }
  15256. else
  15257. {
  15258. if (first)
  15259. {
  15260. first = false;
  15261. fillGroup();
  15262. }
  15263. while(!eof)
  15264. {
  15265. if(failingOuterAtmost)
  15266. while(group.isItem(leftIndex))
  15267. {
  15268. const void * ret = joinRecords(group.item(leftIndex++), defaultRight, 0, NULL);
  15269. if(ret)
  15270. {
  15271. processed++;
  15272. return ret;
  15273. }
  15274. }
  15275. if((joinLimit == 0) || !group.isItem(rightIndex))
  15276. {
  15277. if(leftOuterJoin && !matchedLeft && !failingLimit)
  15278. {
  15279. const void * ret = joinRecords(group.item(leftIndex), defaultRight, 0, NULL);
  15280. if(ret)
  15281. {
  15282. matchedLeft = true;
  15283. processed++;
  15284. return ret;
  15285. }
  15286. }
  15287. leftIndex++;
  15288. matchedLeft = false;
  15289. rightIndex = 0;
  15290. joinCounter = 0;
  15291. joinLimit = keepLimit;
  15292. }
  15293. if(!group.isItem(leftIndex))
  15294. {
  15295. if(failingLimit || failingOuterAtmost)
  15296. {
  15297. const void * lhs;
  15298. while((lhs = input->nextInGroup()) != NULL) // dualCache never active here
  15299. {
  15300. const void * ret = joinRecords(lhs, defaultRight, 0, failingLimit);
  15301. ReleaseRoxieRow(lhs);
  15302. if(ret)
  15303. {
  15304. processed++;
  15305. return ret;
  15306. }
  15307. }
  15308. failingLimit.clear();
  15309. }
  15310. if(rightOuterJoin && !failingLimit)
  15311. while(group.isItem(rightOuterIndex))
  15312. if(!matchedRight.item(rightOuterIndex++))
  15313. {
  15314. const void * ret = joinRecords(defaultLeft, group.item(rightOuterIndex-1), 0, NULL);
  15315. if(ret)
  15316. {
  15317. processed++;
  15318. return ret;
  15319. }
  15320. }
  15321. if(!fillGroup())
  15322. return NULL;
  15323. continue;
  15324. }
  15325. const void * lhs = group.item(leftIndex);
  15326. if(failingLimit)
  15327. {
  15328. leftIndex++;
  15329. const void * ret = joinRecords(lhs, defaultRight, 0, failingLimit);
  15330. if(ret)
  15331. {
  15332. processed++;
  15333. return ret;
  15334. }
  15335. }
  15336. else
  15337. {
  15338. const void * rhs = group.item(rightIndex++);
  15339. if(helper.match(lhs, rhs))
  15340. {
  15341. matchedLeft = true;
  15342. matchedRight.replace(true, rightIndex-1);
  15343. if(!exclude)
  15344. {
  15345. const void * ret = joinRecords(lhs, rhs, ++joinCounter, NULL);
  15346. if(ret)
  15347. {
  15348. processed++;
  15349. joinLimit--;
  15350. return ret;
  15351. }
  15352. }
  15353. }
  15354. }
  15355. }
  15356. return NULL;
  15357. }
  15358. }
  15359. };
  15360. class CRoxieServerSelfJoinActivityFactory : public CRoxieServerActivityFactory
  15361. {
  15362. public:
  15363. CRoxieServerSelfJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  15364. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  15365. {
  15366. }
  15367. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  15368. {
  15369. return new CRoxieServerSelfJoinActivity(this, _probeManager);
  15370. }
  15371. };
  15372. IRoxieServerActivityFactory *createRoxieServerSelfJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  15373. {
  15374. return new CRoxieServerSelfJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  15375. }
  15376. //=====================================================================================================
  15377. class CRoxieServerLookupJoinActivity : public CRoxieServerTwoInputActivity
  15378. {
  15379. private:
  15380. class LookupTable : public CInterface
  15381. {
  15382. public:
  15383. LookupTable(IHThorHashJoinArg &helper)
  15384. : leftRightCompare(helper.queryCompareLeftRight()), rightCompare(helper.queryCompareRight()),
  15385. leftHash(helper.queryHashLeft()), rightHash(helper.queryHashRight())
  15386. {
  15387. size = 0;
  15388. }
  15389. virtual const void *find(const void * left) const = 0;
  15390. virtual const void *findNext(const void * left) const = 0;
  15391. protected:
  15392. ICompare * leftRightCompare;
  15393. ICompare * rightCompare;
  15394. IHash * leftHash;
  15395. IHash * rightHash;
  15396. unsigned size;
  15397. };
  15398. class DedupLookupTable : public LookupTable
  15399. {
  15400. public:
  15401. DedupLookupTable(ConstPointerArray &rightRows, IHThorHashJoinArg &helper)
  15402. : LookupTable(helper)
  15403. {
  15404. size = (4*rightRows.length())/3 + 1;
  15405. table = (const void * *)calloc(size, sizeof(void *)); // This should probably be allocated from roxiemem (and size rounded up to actual available size)
  15406. ForEachItemIn(idx, rightRows)
  15407. add(rightRows.item(idx));
  15408. }
  15409. ~DedupLookupTable()
  15410. {
  15411. unsigned i;
  15412. for(i=0; i<size; i++)
  15413. ReleaseRoxieRow(table[i]);
  15414. free(table);
  15415. }
  15416. virtual const void *find(const void * left) const
  15417. {
  15418. unsigned index = leftHash->hash(left) % size;
  15419. unsigned start = index;
  15420. while (table[index])
  15421. {
  15422. if(leftRightCompare->docompare(left, table[index]) == 0)
  15423. return table[index];
  15424. index++;
  15425. if (index==size)
  15426. index = 0;
  15427. if (index==start)
  15428. throw MakeStringException(ROXIE_JOIN_ERROR, "Internal error in lookup join activity (hash table full on lookup)");
  15429. }
  15430. return NULL;
  15431. }
  15432. virtual const void *findNext(const void * left) const
  15433. {
  15434. return NULL;
  15435. }
  15436. protected:
  15437. void add(const void * right)
  15438. {
  15439. unsigned index = rightHash->hash(right) % size;
  15440. unsigned start = index;
  15441. while (table[index])
  15442. {
  15443. if (rightCompare->docompare(table[index], right) == 0)
  15444. {
  15445. ReleaseRoxieRow(right);
  15446. return;
  15447. }
  15448. index++;
  15449. if (index==size)
  15450. index = 0;
  15451. if (index==start)
  15452. throw MakeStringException(ROXIE_JOIN_ERROR, "Internal error in lookup join activity (hash table full on add)");
  15453. }
  15454. table[index] = right;
  15455. }
  15456. const void * * table;
  15457. };
  15458. class FewLookupTable : public LookupTable
  15459. {
  15460. public:
  15461. FewLookupTable(ConstPointerArray &rightRows, IHThorHashJoinArg &helper)
  15462. : LookupTable(helper)
  15463. {
  15464. size = (4*rightRows.length())/3 + 1;
  15465. table = (const void * *)calloc(size, sizeof(void *)); // This should probably be allocated from roxiemem
  15466. findex = fstart = BadIndex;
  15467. ForEachItemIn(idx, rightRows)
  15468. add(rightRows.item(idx));
  15469. }
  15470. ~FewLookupTable()
  15471. {
  15472. unsigned i;
  15473. for(i=0; i<size; i++)
  15474. ReleaseRoxieRow(table[i]);
  15475. free(table);
  15476. }
  15477. virtual const void *find(const void * left) const
  15478. {
  15479. fstart = leftHash->hash(left) % size;
  15480. findex = fstart;
  15481. return doFind(left);
  15482. }
  15483. virtual const void *findNext(const void * left) const
  15484. {
  15485. if (findex == BadIndex)
  15486. return NULL;
  15487. advance();
  15488. return doFind(left);
  15489. }
  15490. protected:
  15491. void add(const void * right)
  15492. {
  15493. unsigned start = rightHash->hash(right) % size;
  15494. unsigned index = start;
  15495. while (table[index])
  15496. {
  15497. index++;
  15498. if (index==size)
  15499. index = 0;
  15500. if (index==start)
  15501. throwUnexpected(); //table is full, should never happen
  15502. }
  15503. table[index] = right;
  15504. }
  15505. void advance() const
  15506. {
  15507. findex++;
  15508. if(findex==size)
  15509. findex = 0;
  15510. if(findex==fstart)
  15511. throw MakeStringException(ROXIE_JOIN_ERROR, "Internal error in lookup join activity (hash table full on lookup)");
  15512. }
  15513. const void *doFind(const void * left) const
  15514. {
  15515. while(table[findex])
  15516. {
  15517. if (leftRightCompare->docompare(left, table[findex]) == 0)
  15518. return table[findex];
  15519. advance();
  15520. }
  15521. findex = BadIndex;
  15522. return NULL;
  15523. }
  15524. const void * * table;
  15525. unsigned mutable fstart;
  15526. unsigned mutable findex;
  15527. static unsigned const BadIndex;
  15528. };
  15529. class ManyLookupTable : public LookupTable
  15530. {
  15531. public:
  15532. ManyLookupTable(ConstPointerArray &rightRows, IHThorHashJoinArg &helper)
  15533. : LookupTable(helper)
  15534. {
  15535. rightRows.swapWith(rowtable);
  15536. UInt64Array groups;
  15537. unsigned numRows = rowtable.length();
  15538. if (numRows)
  15539. {
  15540. unsigned groupStart = 0;
  15541. const void *groupStartRow = rowtable.item(0);
  15542. for (unsigned i=1; i < numRows; i++)
  15543. {
  15544. const void *thisRow = rowtable.item(i);
  15545. if (rightCompare->docompare(groupStartRow, thisRow))
  15546. {
  15547. groups.append(makeint64(groupStart, i-groupStart));
  15548. groupStart = i;
  15549. groupStartRow = thisRow;
  15550. }
  15551. }
  15552. groups.append(makeint64(groupStart, numRows-groupStart));
  15553. }
  15554. size = (4*groups.length())/3 + 1;
  15555. table = (__uint64 *) calloc(size, sizeof(__uint64)); // This should probably be allocated from roxiemem
  15556. ForEachItemIn(idx, groups)
  15557. {
  15558. unsigned __int64 group = groups.item(idx);
  15559. unsigned groupstart = high(group);
  15560. const void *row = rowtable.item(groupstart);
  15561. add(row, group);
  15562. }
  15563. }
  15564. ~ManyLookupTable()
  15565. {
  15566. ForEachItemIn(idx, rowtable)
  15567. {
  15568. ReleaseRoxieRow(rowtable.item(idx));
  15569. }
  15570. free(table);
  15571. }
  15572. void add(const void *row, unsigned __int64 group)
  15573. {
  15574. unsigned start = rightHash->hash(row) % size;
  15575. unsigned index = start;
  15576. while (table[index])
  15577. {
  15578. index++;
  15579. if (index==size)
  15580. index = 0;
  15581. if (index==start)
  15582. throwUnexpected(); //table is full, should never happen
  15583. }
  15584. table[index] = group;
  15585. }
  15586. virtual const void *find(const void * left) const
  15587. {
  15588. unsigned index = leftHash->hash(left) % size;
  15589. unsigned start = index;
  15590. while (table[index])
  15591. {
  15592. __uint64 group = table[index];
  15593. currentMatch = high(group);
  15594. const void *right = rowtable.item(currentMatch);
  15595. if (leftRightCompare->docompare(left, right) == 0)
  15596. {
  15597. currentMatch++;
  15598. matchCount = low(group) - 1;
  15599. return right;
  15600. }
  15601. index++;
  15602. if (index==size)
  15603. index = 0;
  15604. if (index==start)
  15605. throw MakeStringException(ROXIE_JOIN_ERROR, "Internal error in lookup join activity (hash table full on lookup)");
  15606. }
  15607. matchCount = 0;
  15608. return NULL;
  15609. }
  15610. virtual const void *findNext(const void * left) const
  15611. {
  15612. if (!matchCount)
  15613. return NULL;
  15614. matchCount--;
  15615. return rowtable.item(currentMatch++);
  15616. }
  15617. protected:
  15618. __uint64 *table;
  15619. ConstPointerArray rowtable;
  15620. mutable unsigned currentMatch;
  15621. mutable unsigned matchCount;
  15622. };
  15623. IHThorHashJoinArg &helper;
  15624. bool leftOuterJoin;
  15625. bool exclude;
  15626. bool eog;
  15627. bool many;
  15628. bool dedupRHS;
  15629. bool useFewTable;
  15630. bool matchedGroup;
  15631. const void *left;
  15632. OwnedConstRoxieRow defaultRight;
  15633. Owned<LookupTable> table;
  15634. unsigned keepLimit;
  15635. unsigned atmostLimit;
  15636. unsigned atmostsTriggered;
  15637. unsigned limitLimit;
  15638. unsigned joinCounter;
  15639. bool limitFail;
  15640. bool limitOnFail;
  15641. bool hasGroupLimit;
  15642. bool isSmartJoin;
  15643. unsigned keepCount;
  15644. bool gotMatch;
  15645. bool cloneLeft;
  15646. ConstPointerArray rightGroup;
  15647. aindex_t rightGroupIndex;
  15648. Owned<IException> failingLimit;
  15649. ConstPointerArray filteredRight;
  15650. ThorActivityKind activityKind;
  15651. Owned<IEngineRowAllocator> defaultRightAllocator;
  15652. void createDefaultRight()
  15653. {
  15654. if (!defaultRight)
  15655. {
  15656. if (!defaultRightAllocator)
  15657. defaultRightAllocator.setown(ctx->queryCodeContext()->getRowAllocator(input1->queryOutputMeta(), activityId));
  15658. RtlDynamicRowBuilder rowBuilder(defaultRightAllocator);
  15659. size32_t thisSize = helper.createDefaultRight(rowBuilder);
  15660. defaultRight.setown(rowBuilder.finalizeRowClear(thisSize));
  15661. }
  15662. }
  15663. public:
  15664. CRoxieServerLookupJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _useFewTable)
  15665. : CRoxieServerTwoInputActivity(_factory, _probeManager), helper((IHThorHashJoinArg &)basehelper), useFewTable(_useFewTable)
  15666. {
  15667. unsigned joinFlags = helper.getJoinFlags();
  15668. leftOuterJoin = (joinFlags & JFleftouter) != 0;
  15669. assertex((joinFlags & JFrightouter) == 0);
  15670. exclude = (joinFlags & JFexclude) != 0;
  15671. many = (joinFlags & JFmanylookup) != 0;
  15672. cloneLeft = (joinFlags & JFtransformmatchesleft) != 0;
  15673. dedupRHS = (joinFlags & (JFmanylookup | JFmatchrequired | JFtransformMaySkip)) == 0; // optimisation: can implicitly dedup RHS unless is many lookup, or match required, or transform may skip
  15674. left = NULL;
  15675. activityKind = factory->getKind();
  15676. eog = false;
  15677. matchedGroup = false;
  15678. gotMatch = false;
  15679. keepLimit = 0;
  15680. keepCount = 0;
  15681. joinCounter = 0;
  15682. atmostLimit = 0;
  15683. atmostsTriggered = 0;
  15684. limitLimit = 0;
  15685. rightGroupIndex = 0;
  15686. hasGroupLimit = false;
  15687. isSmartJoin = (joinFlags & JFsmart) != 0;
  15688. getLimitType(joinFlags, limitFail, limitOnFail);
  15689. }
  15690. void loadRight()
  15691. {
  15692. ConstPointerArray rightset;
  15693. try
  15694. {
  15695. const void * next;
  15696. while(true)
  15697. {
  15698. next = input1->nextInGroup();
  15699. if(!next)
  15700. next = input1->nextInGroup();
  15701. if(!next)
  15702. break;
  15703. rightset.append(next);
  15704. }
  15705. if (!dedupRHS)
  15706. {
  15707. if (useFewTable)
  15708. {
  15709. table.setown(new FewLookupTable(rightset, helper)); // NOTE - takes ownership of rightset
  15710. }
  15711. else
  15712. {
  15713. if (!helper.isRightAlreadySorted())
  15714. {
  15715. if (helper.getJoinFlags() & JFunstable)
  15716. {
  15717. qsortvec(const_cast<void * *>(rightset.getArray()), rightset.ordinality(), *helper.queryCompareRight());
  15718. }
  15719. else
  15720. {
  15721. unsigned rightord = rightset.ordinality();
  15722. MemoryAttr tempAttr(rightord*sizeof(void **)); // Temp storage for stable sort. This should probably be allocated from roxiemem
  15723. void **temp = (void **) tempAttr.bufferBase();
  15724. void **_rows = const_cast<void * *>(rightset.getArray());
  15725. memcpy(temp, _rows, rightord*sizeof(void **));
  15726. qsortvecstable(temp, rightord, *helper.queryCompareRight(), (void ***)_rows);
  15727. for (unsigned i = 0; i < rightord; i++)
  15728. {
  15729. *_rows = **((void ***)_rows);
  15730. _rows++;
  15731. }
  15732. }
  15733. }
  15734. table.setown(new ManyLookupTable(rightset, helper)); // NOTE - takes ownership of rightset
  15735. }
  15736. }
  15737. else
  15738. {
  15739. table.setown(new DedupLookupTable(rightset, helper)); // NOTE - takes ownership of rightset
  15740. }
  15741. }
  15742. catch (...)
  15743. {
  15744. ForEachItemIn(idx, rightset)
  15745. ReleaseRoxieRow(rightset.item(idx));
  15746. throw;
  15747. }
  15748. };
  15749. virtual void reset()
  15750. {
  15751. if (atmostsTriggered)
  15752. noteStatistic(STATS_ATMOST, atmostsTriggered, 1);
  15753. CRoxieServerTwoInputActivity::reset();
  15754. ReleaseClearRoxieRow(left);
  15755. defaultRight.clear();
  15756. table.clear();
  15757. }
  15758. virtual bool needsAllocator() const { return true; }
  15759. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  15760. {
  15761. eog = false;
  15762. matchedGroup = false;
  15763. left = NULL;
  15764. CRoxieServerTwoInputActivity::start(parentExtractSize, parentExtract, paused);
  15765. keepLimit = helper.getKeepLimit();
  15766. if(keepLimit==0) keepLimit = static_cast<unsigned>(-1);
  15767. atmostsTriggered = 0;
  15768. atmostLimit = helper.getJoinLimit();
  15769. limitLimit = helper.getMatchAbortLimit();
  15770. hasGroupLimit = ((atmostLimit > 0) || (limitLimit > 0));
  15771. if(atmostLimit==0) atmostLimit = static_cast<unsigned>(-1);
  15772. if(limitLimit==0) limitLimit = static_cast<unsigned>(-1);
  15773. getLimitType(helper.getJoinFlags(), limitFail, limitOnFail);
  15774. switch (activityKind)
  15775. {
  15776. case TAKlookupjoin:
  15777. case TAKlookupdenormalizegroup:
  15778. case TAKsmartjoin:
  15779. case TAKsmartdenormalizegroup:
  15780. if (leftOuterJoin)
  15781. createDefaultRight();
  15782. break;
  15783. }
  15784. if (limitOnFail)
  15785. createDefaultRight();
  15786. }
  15787. virtual void setInput(unsigned idx, IRoxieInput *_in)
  15788. {
  15789. if (idx==1)
  15790. input1 = _in;
  15791. else
  15792. {
  15793. if ((helper.getJoinFlags() & JFparallel) != 0)
  15794. {
  15795. puller.setown(new CRoxieServerReadAheadInput(0)); // MORE - cant ask context for parallelJoinPreload as context is not yet set up.
  15796. puller->setInput(0, _in);
  15797. _in = puller;
  15798. }
  15799. CRoxieServerActivity::setInput(idx, _in);
  15800. }
  15801. }
  15802. virtual const void * nextInGroup()
  15803. {
  15804. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  15805. if(!table)
  15806. loadRight();
  15807. switch (activityKind)
  15808. {
  15809. case TAKlookupjoin:
  15810. case TAKsmartjoin:
  15811. return nextInGroupJoin();
  15812. case TAKlookupdenormalize:
  15813. case TAKlookupdenormalizegroup:
  15814. case TAKsmartdenormalize:
  15815. case TAKsmartdenormalizegroup:
  15816. return nextInGroupDenormalize();
  15817. }
  15818. throwUnexpected();
  15819. }
  15820. private:
  15821. const void * nextInGroupJoin()
  15822. {
  15823. if(!table)
  15824. loadRight();
  15825. while(true)
  15826. {
  15827. const void * right = NULL;
  15828. if(!left)
  15829. {
  15830. left = input->nextInGroup();
  15831. keepCount = keepLimit;
  15832. joinCounter = 0;
  15833. if(!left)
  15834. {
  15835. if (isSmartJoin)
  15836. left = input->nextInGroup();
  15837. if (!left)
  15838. {
  15839. if(matchedGroup || eog)
  15840. {
  15841. matchedGroup = false;
  15842. eog = true;
  15843. return NULL;
  15844. }
  15845. eog = true;
  15846. continue;
  15847. }
  15848. }
  15849. eog = false;
  15850. gotMatch = false;
  15851. right = getRightFirst();
  15852. }
  15853. else
  15854. right = getRightNext();
  15855. const void * ret = NULL;
  15856. if(failingLimit)
  15857. {
  15858. ret = joinException(left, failingLimit);
  15859. }
  15860. else
  15861. {
  15862. while(right)
  15863. {
  15864. if(helper.match(left, right))
  15865. {
  15866. gotMatch = true;
  15867. if(exclude)
  15868. break;
  15869. ret = joinRecords(left, right, ++joinCounter);
  15870. if(ret)
  15871. break;
  15872. }
  15873. right = getRightNext();
  15874. ret = NULL;
  15875. }
  15876. if(leftOuterJoin && !gotMatch)
  15877. {
  15878. ret = joinRecords(left, defaultRight, 0);
  15879. gotMatch = true;
  15880. }
  15881. }
  15882. if(ret)
  15883. {
  15884. matchedGroup = true;
  15885. processed++;
  15886. if(!many || (--keepCount == 0) || failingLimit)
  15887. {
  15888. ReleaseClearRoxieRow(left);
  15889. failingLimit.clear();
  15890. }
  15891. return ret;
  15892. }
  15893. ReleaseClearRoxieRow(left);
  15894. }
  15895. }
  15896. const void * nextInGroupDenormalize()
  15897. {
  15898. while(true)
  15899. {
  15900. left = input->nextInGroup();
  15901. if(!left)
  15902. {
  15903. if (!matchedGroup || isSmartJoin)
  15904. left = input->nextInGroup();
  15905. if (!left)
  15906. {
  15907. matchedGroup = false;
  15908. return NULL;
  15909. }
  15910. }
  15911. gotMatch = false;
  15912. const void * right = getRightFirst();
  15913. const void * ret = NULL;
  15914. if (failingLimit)
  15915. ret = joinException(left, failingLimit);
  15916. else if (activityKind == TAKlookupdenormalize || activityKind == TAKsmartdenormalize)
  15917. {
  15918. OwnedConstRoxieRow newLeft;
  15919. newLeft.set(left);
  15920. unsigned rowSize = 0;
  15921. unsigned leftCount = 0;
  15922. keepCount = keepLimit;
  15923. while (right)
  15924. {
  15925. try
  15926. {
  15927. if (helper.match(left, right))
  15928. {
  15929. gotMatch = true;
  15930. if (exclude)
  15931. break;
  15932. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  15933. unsigned thisSize = helper.transform(rowBuilder, newLeft, right, ++leftCount);
  15934. if (thisSize)
  15935. {
  15936. rowSize = thisSize;
  15937. newLeft.setown(rowBuilder.finalizeRowClear(rowSize));
  15938. }
  15939. if(!many || (--keepCount == 0))
  15940. break;
  15941. }
  15942. right = getRightNext();
  15943. }
  15944. catch (IException *E)
  15945. {
  15946. throw makeWrappedException(E);
  15947. }
  15948. }
  15949. if (rowSize)
  15950. ret = newLeft.getClear();
  15951. else if (leftOuterJoin && !gotMatch)
  15952. {
  15953. ret = left;
  15954. left = NULL;
  15955. }
  15956. }
  15957. else
  15958. {
  15959. filteredRight.kill();
  15960. keepCount = keepLimit;
  15961. while (right)
  15962. {
  15963. if (helper.match(left, right))
  15964. {
  15965. gotMatch = true;
  15966. if(exclude)
  15967. break;
  15968. filteredRight.append(right);
  15969. if(!many || (--keepCount == 0))
  15970. break;
  15971. }
  15972. right = getRightNext();
  15973. }
  15974. if((filteredRight.ordinality() > 0) || (leftOuterJoin && !gotMatch))
  15975. ret = denormalizeRecords(left, filteredRight);
  15976. filteredRight.kill();
  15977. }
  15978. ReleaseRoxieRow(left);
  15979. left = NULL;
  15980. failingLimit.clear();
  15981. if(ret)
  15982. {
  15983. matchedGroup = true;
  15984. processed++;
  15985. return ret;
  15986. }
  15987. }
  15988. }
  15989. const void * joinRecords(const void * left, const void * right, unsigned counter)
  15990. {
  15991. if (cloneLeft)
  15992. {
  15993. LinkRoxieRow(left);
  15994. return left;
  15995. }
  15996. try
  15997. {
  15998. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  15999. unsigned outSize = helper.transform(rowBuilder, left, right, counter);
  16000. if (outSize)
  16001. return rowBuilder.finalizeRowClear(outSize);
  16002. else
  16003. return NULL;
  16004. }
  16005. catch (IException *E)
  16006. {
  16007. throw makeWrappedException(E);
  16008. }
  16009. }
  16010. const void * joinException(const void * left, IException * except)
  16011. {
  16012. try
  16013. {
  16014. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  16015. unsigned outSize = helper.onFailTransform(rowBuilder, left, defaultRight, except);
  16016. if (outSize)
  16017. return rowBuilder.finalizeRowClear(outSize);
  16018. else
  16019. return NULL;
  16020. }
  16021. catch (IException *E)
  16022. {
  16023. throw makeWrappedException(E);
  16024. }
  16025. }
  16026. const void * denormalizeRecords(const void * left, ConstPointerArray & rows)
  16027. {
  16028. try
  16029. {
  16030. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  16031. unsigned numRows = rows.ordinality();
  16032. const void * right = numRows ? rows.item(0) : defaultRight.get();
  16033. unsigned outSize = helper.transform(rowBuilder, left, right, numRows, (const void * *)rows.getArray());
  16034. if (outSize)
  16035. return rowBuilder.finalizeRowClear(outSize);
  16036. else
  16037. return NULL;
  16038. }
  16039. catch (IException *E)
  16040. {
  16041. throw makeWrappedException(E);
  16042. }
  16043. }
  16044. const void * getRightFirst() { if(hasGroupLimit) return fillRightGroup(); else return table->find(left); }
  16045. const void * getRightNext() { if(hasGroupLimit) return readRightGroup(); else return table->findNext(left); }
  16046. const void * readRightGroup() { if(rightGroup.isItem(rightGroupIndex)) return rightGroup.item(rightGroupIndex++); else return NULL; }
  16047. const void *fillRightGroup()
  16048. {
  16049. rightGroup.kill();
  16050. for(const void * right = table->find(left); right; right = table->findNext(left))
  16051. {
  16052. rightGroup.append(right);
  16053. if(rightGroup.ordinality() > limitLimit)
  16054. {
  16055. if(limitFail)
  16056. failLimit();
  16057. gotMatch = true;
  16058. if (ctx->queryDebugContext())
  16059. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  16060. if(limitOnFail)
  16061. {
  16062. assertex(!failingLimit);
  16063. try
  16064. {
  16065. failLimit();
  16066. }
  16067. catch(IException * e)
  16068. {
  16069. failingLimit.setown(e);
  16070. }
  16071. assertex(failingLimit != NULL);
  16072. }
  16073. else
  16074. {
  16075. rightGroup.kill();
  16076. }
  16077. break;
  16078. }
  16079. if(rightGroup.ordinality() > atmostLimit)
  16080. {
  16081. atmostsTriggered++;
  16082. rightGroup.kill();
  16083. break;
  16084. }
  16085. }
  16086. rightGroupIndex = 0;
  16087. return readRightGroup();
  16088. }
  16089. void failLimit()
  16090. {
  16091. helper.onMatchAbortLimitExceeded();
  16092. CommonXmlWriter xmlwrite(XWFtrim|XWFopt );
  16093. if(!ctx->isBlind() && input->queryOutputMeta() && input->queryOutputMeta()->hasXML())
  16094. {
  16095. input->queryOutputMeta()->toXML(static_cast<const unsigned char *>(left), xmlwrite);
  16096. }
  16097. throw MakeStringException(ROXIE_TOO_MANY_RESULTS, "More than %u match candidates in join %d for row %s", limitLimit, queryId(), xmlwrite.str());
  16098. }
  16099. };
  16100. unsigned const CRoxieServerLookupJoinActivity::FewLookupTable::BadIndex(static_cast<unsigned>(-1));
  16101. class CRoxieServerLookupJoinActivityFactory : public CRoxieServerJoinActivityFactory
  16102. {
  16103. public:
  16104. CRoxieServerLookupJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  16105. : CRoxieServerJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  16106. {
  16107. Owned<IHThorHashJoinArg> helper = (IHThorHashJoinArg *) helperFactory();
  16108. useFewTable = _graphNode.getPropBool("hint[@name='usefewtable']/@value", false);
  16109. if((helper->getJoinFlags() & (JFfirst | JFfirstleft | JFfirstright | JFslidingmatch)) != 0)
  16110. throw MakeStringException(ROXIE_INVALID_FLAGS, "Invalid flags for lookup join activity"); // code generator should never create such an activity
  16111. }
  16112. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  16113. {
  16114. return new CRoxieServerLookupJoinActivity(this, _probeManager, useFewTable);
  16115. }
  16116. protected:
  16117. bool useFewTable;
  16118. };
  16119. IRoxieServerActivityFactory *createRoxieServerLookupJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  16120. {
  16121. return new CRoxieServerLookupJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  16122. }
  16123. //=====================================================================================================
  16124. class CRoxieServerAllJoinActivity : public CRoxieServerTwoInputActivity
  16125. {
  16126. private:
  16127. IHThorAllJoinArg &helper;
  16128. bool leftOuterJoin;
  16129. bool rightOuterJoin;
  16130. bool exclude;
  16131. OwnedConstRoxieRow defaultRight;
  16132. OwnedConstRoxieRow defaultLeft;
  16133. Owned<IEngineRowAllocator> defaultRightAllocator;
  16134. Owned<IEngineRowAllocator> defaultLeftAllocator;
  16135. const void *left;
  16136. unsigned countForLeft;
  16137. ConstPointerArray rightset;
  16138. BoolArray matchedRight; // MORE - could use a bitset...
  16139. unsigned keepLimit;
  16140. bool started;
  16141. bool eog;
  16142. bool eos;
  16143. bool matchedLeft;
  16144. bool matchedGroup;
  16145. bool leftIsGrouped;
  16146. bool cloneLeft;
  16147. unsigned rightIndex;
  16148. unsigned joinCounter;
  16149. unsigned rightOrdinality;
  16150. ThorActivityKind activityKind;
  16151. ConstPointerArray filteredRight;
  16152. void createDefaultLeft()
  16153. {
  16154. if (!defaultLeft)
  16155. {
  16156. if (!defaultLeftAllocator)
  16157. defaultLeftAllocator.setown(ctx->queryCodeContext()->getRowAllocator(input->queryOutputMeta(), activityId));
  16158. RtlDynamicRowBuilder rowBuilder(defaultLeftAllocator);
  16159. size32_t thisSize = helper.createDefaultLeft(rowBuilder);
  16160. defaultLeft.setown(rowBuilder.finalizeRowClear(thisSize));
  16161. }
  16162. }
  16163. void createDefaultRight()
  16164. {
  16165. if (!defaultRight)
  16166. {
  16167. if (!defaultRightAllocator)
  16168. defaultRightAllocator.setown(ctx->queryCodeContext()->getRowAllocator(input1->queryOutputMeta(), activityId));
  16169. RtlDynamicRowBuilder rowBuilder(defaultRightAllocator);
  16170. size32_t thisSize = helper.createDefaultRight(rowBuilder);
  16171. defaultRight.setown(rowBuilder.finalizeRowClear(thisSize));
  16172. }
  16173. }
  16174. public:
  16175. CRoxieServerAllJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  16176. : CRoxieServerTwoInputActivity(_factory, _probeManager), helper((IHThorAllJoinArg &)basehelper)
  16177. {
  16178. unsigned joinFlags = helper.getJoinFlags();
  16179. leftOuterJoin = (joinFlags & JFleftouter) != 0;
  16180. rightOuterJoin = (joinFlags & JFrightouter) != 0;
  16181. cloneLeft = (joinFlags & JFtransformmatchesleft) != 0;
  16182. keepLimit = (unsigned) -1;
  16183. exclude = (joinFlags & JFexclude) != 0;
  16184. left = NULL;
  16185. started = true;
  16186. eog = false;
  16187. eos = false;
  16188. matchedLeft = false;
  16189. matchedGroup = false;
  16190. activityKind = factory->getKind();
  16191. rightIndex = 0;
  16192. rightOrdinality = 0;
  16193. leftIsGrouped = false;
  16194. countForLeft = 0;
  16195. joinCounter = 0;
  16196. }
  16197. virtual void reset()
  16198. {
  16199. defaultRight.clear();
  16200. defaultLeft.clear();
  16201. ReleaseRoxieRowSet(rightset);
  16202. matchedRight.kill();
  16203. CRoxieServerTwoInputActivity::reset();
  16204. }
  16205. virtual bool needsAllocator() const { return true; }
  16206. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  16207. {
  16208. eog = false;
  16209. eos = false;
  16210. matchedLeft = false;
  16211. matchedGroup = false;
  16212. started = false;
  16213. left = NULL;
  16214. CRoxieServerTwoInputActivity::start(parentExtractSize, parentExtract, paused);
  16215. keepLimit = helper.getKeepLimit();
  16216. if(keepLimit==0)
  16217. keepLimit = (unsigned) -1;
  16218. countForLeft = keepLimit;
  16219. joinCounter = 0;
  16220. leftIsGrouped = input->queryOutputMeta()->isGrouped();
  16221. if((activityKind==TAKalljoin || activityKind==TAKalldenormalizegroup) && leftOuterJoin)
  16222. createDefaultRight();
  16223. if(rightOuterJoin)
  16224. createDefaultLeft();
  16225. }
  16226. void loadRight()
  16227. {
  16228. const void * next;
  16229. while(true)
  16230. {
  16231. next = input1->nextInGroup();
  16232. if(!next)
  16233. next = input1->nextInGroup();
  16234. if(!next)
  16235. break;
  16236. rightset.append(next);
  16237. matchedRight.append(false);
  16238. }
  16239. rightIndex = 0;
  16240. joinCounter = 0;
  16241. rightOrdinality = rightset.ordinality();
  16242. }
  16243. virtual void setInput(unsigned idx, IRoxieInput *_in)
  16244. {
  16245. if (idx==1)
  16246. input1 = _in;
  16247. else
  16248. {
  16249. if ((helper.getJoinFlags() & JFparallel) != 0)
  16250. {
  16251. puller.setown(new CRoxieServerReadAheadInput(0)); // MORE - cant ask context for parallelJoinPreload as context is not yet set up.
  16252. puller->setInput(0, _in);
  16253. _in = puller;
  16254. }
  16255. CRoxieServerActivity::setInput(idx, _in);
  16256. }
  16257. }
  16258. const void * joinRecords(const void * left, const void * right, unsigned counter)
  16259. {
  16260. // MORE - could share some code with lookup join
  16261. if (cloneLeft)
  16262. {
  16263. LinkRoxieRow(left);
  16264. return left;
  16265. }
  16266. try
  16267. {
  16268. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  16269. unsigned outSize = helper.transform(rowBuilder, left, right, counter);
  16270. if (outSize)
  16271. return rowBuilder.finalizeRowClear(outSize);
  16272. else
  16273. return NULL;
  16274. }
  16275. catch (IException *E)
  16276. {
  16277. throw makeWrappedException(E);
  16278. }
  16279. }
  16280. const void * denormalizeRecords(const void * curLeft, ConstPointerArray & rows)
  16281. {
  16282. try
  16283. {
  16284. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  16285. unsigned numRows = rows.ordinality();
  16286. const void * right = numRows ? rows.item(0) : defaultRight.get();
  16287. unsigned outSize = helper.transform(rowBuilder, curLeft, right, numRows, rows.getArray());
  16288. if (outSize)
  16289. return rowBuilder.finalizeRowClear(outSize);
  16290. else
  16291. return NULL;
  16292. }
  16293. catch (IException *E)
  16294. {
  16295. throw makeWrappedException(E);
  16296. }
  16297. }
  16298. virtual const void *nextInGroup()
  16299. {
  16300. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  16301. if(!started)
  16302. {
  16303. started = true;
  16304. left = input->nextInGroup();
  16305. matchedLeft = false;
  16306. countForLeft = keepLimit;
  16307. joinCounter = 0;
  16308. if(left == NULL)
  16309. {
  16310. eos = true;
  16311. return NULL;
  16312. }
  16313. loadRight();
  16314. }
  16315. const void * ret;
  16316. const void * right;
  16317. if(eos)
  16318. return NULL;
  16319. while(true)
  16320. {
  16321. ret = NULL;
  16322. if((rightIndex == rightOrdinality) || (countForLeft==0))
  16323. {
  16324. if(leftOuterJoin && left && !matchedLeft)
  16325. {
  16326. switch(activityKind)
  16327. {
  16328. case TAKalljoin:
  16329. ret = joinRecords(left, defaultRight, 0);
  16330. break;
  16331. case TAKalldenormalize:
  16332. ret = left;
  16333. left = NULL;
  16334. break;
  16335. case TAKalldenormalizegroup:
  16336. filteredRight.kill();
  16337. ret = denormalizeRecords(left, filteredRight);
  16338. break;
  16339. default:
  16340. throwUnexpected();
  16341. }
  16342. }
  16343. rightIndex = 0;
  16344. joinCounter = 0;
  16345. ReleaseRoxieRow(left);
  16346. left = NULL;
  16347. if(ret)
  16348. {
  16349. matchedGroup = true;
  16350. processed++;
  16351. return ret;
  16352. }
  16353. }
  16354. if(!left)
  16355. {
  16356. left = input->nextInGroup();
  16357. matchedLeft = false;
  16358. countForLeft = keepLimit;
  16359. joinCounter = 0;
  16360. }
  16361. if(!left)
  16362. {
  16363. if(eog)
  16364. {
  16365. eos = true;
  16366. matchedGroup = false;
  16367. return NULL;
  16368. }
  16369. eog = true;
  16370. if (matchedGroup && leftIsGrouped)
  16371. {
  16372. matchedGroup = false;
  16373. return NULL;
  16374. }
  16375. matchedGroup = false;
  16376. continue;
  16377. }
  16378. eog = false;
  16379. switch(activityKind)
  16380. {
  16381. case TAKalljoin:
  16382. while(rightIndex < rightOrdinality)
  16383. {
  16384. right = rightset.item(rightIndex);
  16385. if(helper.match(left, right))
  16386. {
  16387. matchedLeft = true;
  16388. matchedRight.replace(true, rightIndex);
  16389. if(!exclude)
  16390. ret = joinRecords(left, right, ++joinCounter);
  16391. }
  16392. rightIndex++;
  16393. if(ret)
  16394. {
  16395. countForLeft--;
  16396. matchedGroup = true;
  16397. processed++;
  16398. return ret;
  16399. }
  16400. }
  16401. break;
  16402. case TAKalldenormalize:
  16403. {
  16404. OwnedConstRoxieRow newLeft;
  16405. newLeft.set(left);
  16406. unsigned rowSize = 0;
  16407. unsigned leftCount = 0;
  16408. while((rightIndex < rightOrdinality) && countForLeft)
  16409. {
  16410. right = rightset.item(rightIndex);
  16411. if(helper.match(left, right))
  16412. {
  16413. matchedLeft = true;
  16414. matchedRight.replace(true, rightIndex);
  16415. if(!exclude)
  16416. {
  16417. try
  16418. {
  16419. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  16420. unsigned thisSize = helper.transform(rowBuilder, newLeft, right, ++leftCount);
  16421. if(thisSize)
  16422. {
  16423. rowSize = thisSize;
  16424. newLeft.setown(rowBuilder.finalizeRowClear(rowSize));
  16425. --countForLeft;
  16426. }
  16427. }
  16428. catch (IException *e)
  16429. {
  16430. throw makeWrappedException(e);
  16431. }
  16432. }
  16433. }
  16434. rightIndex++;
  16435. }
  16436. if(rowSize)
  16437. {
  16438. processed++;
  16439. return newLeft.getClear();
  16440. }
  16441. }
  16442. break;
  16443. case TAKalldenormalizegroup:
  16444. filteredRight.kill();
  16445. while((rightIndex < rightOrdinality) && countForLeft)
  16446. {
  16447. right = rightset.item(rightIndex);
  16448. if(helper.match(left, right))
  16449. {
  16450. matchedLeft = true;
  16451. matchedRight.replace(true, rightIndex);
  16452. filteredRight.append(right);
  16453. --countForLeft;
  16454. }
  16455. ++rightIndex;
  16456. }
  16457. if(!exclude && filteredRight.ordinality())
  16458. {
  16459. ret = denormalizeRecords(left, filteredRight);
  16460. filteredRight.kill();
  16461. if(ret)
  16462. {
  16463. processed++;
  16464. return ret;
  16465. }
  16466. }
  16467. break;
  16468. default:
  16469. throwUnexpected();
  16470. }
  16471. }
  16472. }
  16473. };
  16474. class CRoxieServerAllJoinActivityFactory : public CRoxieServerJoinActivityFactory
  16475. {
  16476. public:
  16477. CRoxieServerAllJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  16478. : CRoxieServerJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  16479. {
  16480. Owned<IHThorAllJoinArg> helper = (IHThorAllJoinArg *) helperFactory();
  16481. if((helper->getJoinFlags() & (JFfirst | JFfirstleft | JFfirstright)) != 0)
  16482. throw MakeStringException(ROXIE_INVALID_FLAGS, "Invalid flags for join all activity"); // code generator should never create such an activity
  16483. }
  16484. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  16485. {
  16486. return new CRoxieServerAllJoinActivity(this, _probeManager);
  16487. }
  16488. };
  16489. IRoxieServerActivityFactory *createRoxieServerAllJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  16490. {
  16491. return new CRoxieServerAllJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  16492. }
  16493. //=====================================================================================================
  16494. class CRoxieServerTopNActivity : public CRoxieServerLateStartActivity
  16495. {
  16496. unsigned limit;
  16497. bool hasBest;
  16498. bool eoi;
  16499. const void **sorted;
  16500. unsigned sortedCount;
  16501. unsigned curIndex;
  16502. IHThorTopNArg &helper;
  16503. ICompare &compare;
  16504. public:
  16505. CRoxieServerTopNActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  16506. : CRoxieServerLateStartActivity(_factory, _probeManager), helper((IHThorTopNArg &)basehelper), compare(*helper.queryCompare())
  16507. {
  16508. sorted = NULL;
  16509. sortedCount = 0;
  16510. curIndex = 0;
  16511. limit = 0;
  16512. eoi = false;
  16513. hasBest = false;
  16514. }
  16515. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  16516. {
  16517. assertex(sorted == NULL);
  16518. sortedCount = 0;
  16519. curIndex = 0;
  16520. eoi = false;
  16521. CRoxieServerLateStartActivity::start(parentExtractSize, parentExtract, paused);
  16522. limit = (unsigned) helper.getLimit();
  16523. hasBest = helper.hasBest();
  16524. lateStart(parentExtractSize, parentExtract, limit > 0);
  16525. // MORE - should we use an expanding array instead?
  16526. if (limit > 0)
  16527. sorted = (const void **) ctx->queryRowManager().allocate((limit+1) * sizeof(const void *), activityId);
  16528. }
  16529. virtual void reset()
  16530. {
  16531. if (sorted)
  16532. {
  16533. while(curIndex < sortedCount)
  16534. ReleaseRoxieRow(sorted[curIndex++]);
  16535. ReleaseRoxieRow(sorted);
  16536. }
  16537. sorted = NULL;
  16538. CRoxieServerLateStartActivity::reset();
  16539. }
  16540. bool abortEarly()
  16541. {
  16542. if (hasBest && (sortedCount == limit))
  16543. {
  16544. int compare = helper.compareBest(sorted[sortedCount-1]);
  16545. if (compare == 0)
  16546. {
  16547. if (meta.isGrouped())
  16548. {
  16549. //MORE: This would be more efficient if we had a away of skipping to the end of the incoming group.
  16550. const void * next;
  16551. while ((next = input->nextInGroup()) != NULL)
  16552. ReleaseRoxieRow(next);
  16553. }
  16554. else
  16555. eoi = true;
  16556. return true;
  16557. }
  16558. //This only checks the lowest element - we could check all elements inserted, but it would increase the number of compares
  16559. if (compare < 0)
  16560. throw MakeStringException(ROXIE_TOPN_ROW_ERROR, "TOPN: row found that exceeds the best value");
  16561. }
  16562. return false;
  16563. }
  16564. void getSorted()
  16565. {
  16566. curIndex = 0;
  16567. sortedCount = 0;
  16568. if(eoi)
  16569. return;
  16570. const void * next;
  16571. while ((next = input->nextInGroup()) != NULL)
  16572. {
  16573. if (sortedCount < limit)
  16574. {
  16575. binary_vec_insert_stable(next, sorted, sortedCount, compare);
  16576. sortedCount++;
  16577. if(abortEarly())
  16578. return;
  16579. }
  16580. else
  16581. {
  16582. if(limit && compare.docompare(sorted[sortedCount-1], next) > 0) // MORE - if stability is an issue, need to consider whether this should be > or >=
  16583. {
  16584. binary_vec_insert_stable(next, sorted, sortedCount, compare); // MORE - not sure this is stable!
  16585. ReleaseRoxieRow(sorted[sortedCount]);
  16586. if(abortEarly())
  16587. return;
  16588. }
  16589. else
  16590. {
  16591. ReleaseRoxieRow(next); // do not bother with insertion sort if we know next will fall off the end
  16592. }
  16593. }
  16594. }
  16595. }
  16596. virtual const void * nextInGroup()
  16597. {
  16598. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  16599. if (eof)
  16600. return NULL;
  16601. if (curIndex >= sortedCount)
  16602. {
  16603. bool eog = sortedCount != 0;
  16604. getSorted();
  16605. if(sortedCount == 0)
  16606. {
  16607. eof = true;
  16608. return NULL;
  16609. }
  16610. if (eog)
  16611. return NULL;
  16612. }
  16613. processed++;
  16614. return sorted[curIndex++];
  16615. }
  16616. };
  16617. class CRoxieServerTopNActivityFactory : public CRoxieServerActivityFactory
  16618. {
  16619. public:
  16620. CRoxieServerTopNActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  16621. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  16622. {
  16623. }
  16624. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  16625. {
  16626. return new CRoxieServerTopNActivity(this, _probeManager);
  16627. }
  16628. };
  16629. IRoxieServerActivityFactory *createRoxieServerTopNActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  16630. {
  16631. return new CRoxieServerTopNActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  16632. }
  16633. //=================================================================================
  16634. class CRoxieServerLimitActivity : public CRoxieServerActivity
  16635. {
  16636. protected:
  16637. unsigned __int64 rowLimit;
  16638. IHThorLimitArg &helper;
  16639. public:
  16640. CRoxieServerLimitActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  16641. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorLimitArg &)basehelper)
  16642. {
  16643. rowLimit = 0;
  16644. }
  16645. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  16646. {
  16647. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  16648. rowLimit = helper.getRowLimit(); // could conceivably depend on context so should not compute any earlier than this
  16649. }
  16650. virtual const void *nextInGroup()
  16651. {
  16652. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  16653. const void * ret = input->nextInGroup();
  16654. if (ret)
  16655. {
  16656. processed++;
  16657. if (processed > rowLimit)
  16658. {
  16659. ReleaseRoxieRow(ret);
  16660. if (traceLevel > 4)
  16661. DBGLOG("activityid = %d line = %d", activityId, __LINE__);
  16662. helper.onLimitExceeded();
  16663. }
  16664. }
  16665. return ret;
  16666. }
  16667. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  16668. {
  16669. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  16670. const void * ret = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  16671. if (ret)
  16672. {
  16673. if (wasCompleteMatch)
  16674. processed++;
  16675. if (processed > rowLimit)
  16676. {
  16677. ReleaseRoxieRow(ret);
  16678. if (traceLevel > 4)
  16679. DBGLOG("activityid = %d line = %d", activityId, __LINE__);
  16680. helper.onLimitExceeded();
  16681. }
  16682. }
  16683. return ret;
  16684. }
  16685. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  16686. {
  16687. return input->gatherConjunctions(collector);
  16688. }
  16689. virtual void resetEOF()
  16690. {
  16691. //Do not reset the rowLimit
  16692. input->resetEOF();
  16693. }
  16694. IInputSteppingMeta * querySteppingMeta()
  16695. {
  16696. return input->querySteppingMeta();
  16697. }
  16698. };
  16699. class CRoxieServerLimitActivityFactory : public CRoxieServerActivityFactory
  16700. {
  16701. public:
  16702. CRoxieServerLimitActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  16703. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  16704. {
  16705. }
  16706. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  16707. {
  16708. return new CRoxieServerLimitActivity(this, _probeManager);
  16709. }
  16710. };
  16711. IRoxieServerActivityFactory *createRoxieServerLimitActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  16712. {
  16713. return new CRoxieServerLimitActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  16714. }
  16715. //=====================================================================================================
  16716. class CRoxieServerSkipLimitActivity : public CRoxieServerLimitActivity
  16717. {
  16718. ConstPointerArray buff;
  16719. bool started;
  16720. unsigned index;
  16721. IHThorLimitTransformExtra * transformExtra;
  16722. public:
  16723. CRoxieServerSkipLimitActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _onFail)
  16724. : CRoxieServerLimitActivity(_factory, _probeManager)
  16725. {
  16726. transformExtra = NULL;
  16727. started = false;
  16728. index = 0;
  16729. if (_onFail)
  16730. transformExtra = static_cast<IHThorLimitTransformExtra *>(helper.selectInterface(TAIlimittransformextra_1));
  16731. }
  16732. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  16733. {
  16734. started = false;
  16735. index = 0;
  16736. CRoxieServerLimitActivity::start(parentExtractSize, parentExtract, paused);
  16737. }
  16738. virtual void reset()
  16739. {
  16740. while (buff.isItem(index))
  16741. ReleaseRoxieRow(buff.item(index++));
  16742. buff.kill();
  16743. started = false;
  16744. CRoxieServerLimitActivity::reset();
  16745. }
  16746. virtual const void *nextInGroup()
  16747. {
  16748. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  16749. if (!started)
  16750. pullInput();
  16751. if (buff.isItem(index))
  16752. {
  16753. const void * next = buff.item(index++);
  16754. if(next)
  16755. processed++;
  16756. return next;
  16757. }
  16758. return NULL;
  16759. }
  16760. protected:
  16761. void pullInput()
  16762. {
  16763. unsigned count = 0;
  16764. loop
  16765. {
  16766. const void * next = input->nextInGroup();
  16767. if (next == NULL)
  16768. {
  16769. next = input->nextInGroup();
  16770. if(next == NULL)
  16771. break;
  16772. buff.append(NULL);
  16773. }
  16774. count++;
  16775. if (count > rowLimit)
  16776. {
  16777. ReleaseRoxieRow(next);
  16778. ReleaseRoxieRowSet(buff);
  16779. if (ctx->queryDebugContext())
  16780. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  16781. if (transformExtra)
  16782. {
  16783. createRowAllocator();
  16784. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  16785. size32_t outSize = transformExtra->transformOnLimitExceeded(rowBuilder);
  16786. if (outSize)
  16787. buff.append(rowBuilder.finalizeRowClear(outSize));
  16788. }
  16789. break;
  16790. }
  16791. buff.append(next);
  16792. }
  16793. started = true;
  16794. }
  16795. };
  16796. class CRoxieServerSkipLimitActivityFactory : public CRoxieServerActivityFactory
  16797. {
  16798. public:
  16799. CRoxieServerSkipLimitActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  16800. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  16801. {
  16802. }
  16803. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  16804. {
  16805. return new CRoxieServerSkipLimitActivity(this, _probeManager, kind==TAKcreaterowlimit);
  16806. }
  16807. };
  16808. IRoxieServerActivityFactory *createRoxieServerSkipLimitActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  16809. {
  16810. return new CRoxieServerSkipLimitActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  16811. }
  16812. //=================================================================================
  16813. class CRoxieServerCatchActivity : public CRoxieServerActivity
  16814. {
  16815. IHThorCatchArg &helper;
  16816. public:
  16817. CRoxieServerCatchActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  16818. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorCatchArg &)basehelper)
  16819. {
  16820. }
  16821. virtual const void *nextInGroup()
  16822. {
  16823. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  16824. try
  16825. {
  16826. const void *ret = input->nextInGroup();
  16827. if (ret)
  16828. processed++;
  16829. return ret;
  16830. }
  16831. catch (IException *E)
  16832. {
  16833. E->Release();
  16834. helper.onExceptionCaught();
  16835. }
  16836. catch (...)
  16837. {
  16838. helper.onExceptionCaught();
  16839. }
  16840. throwUnexpected(); // onExceptionCaught should have thrown something
  16841. }
  16842. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  16843. {
  16844. try
  16845. {
  16846. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  16847. const void * ret = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  16848. if (ret && wasCompleteMatch)
  16849. processed++;
  16850. return ret;
  16851. }
  16852. catch (IException *E)
  16853. {
  16854. E->Release();
  16855. helper.onExceptionCaught();
  16856. }
  16857. catch (...)
  16858. {
  16859. helper.onExceptionCaught();
  16860. }
  16861. throwUnexpected(); // onExceptionCaught should have thrown something
  16862. }
  16863. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  16864. {
  16865. return input->gatherConjunctions(collector);
  16866. }
  16867. virtual void resetEOF()
  16868. {
  16869. input->resetEOF(); // MORE - why not in base class?
  16870. }
  16871. IInputSteppingMeta * querySteppingMeta()
  16872. {
  16873. return input->querySteppingMeta();
  16874. }
  16875. };
  16876. class CRoxieServerSkipCatchActivity : public CRoxieServerActivity
  16877. {
  16878. ConstPointerArray buff;
  16879. bool started;
  16880. unsigned index;
  16881. IHThorCatchArg &helper;
  16882. bool createRow;
  16883. public:
  16884. CRoxieServerSkipCatchActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _createRow)
  16885. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorCatchArg &)basehelper), createRow(_createRow)
  16886. {
  16887. started = false;
  16888. index = 0;
  16889. }
  16890. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  16891. {
  16892. started = false;
  16893. index = 0;
  16894. try
  16895. {
  16896. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  16897. }
  16898. catch (IException *E)
  16899. {
  16900. onException(E);
  16901. started = true;
  16902. }
  16903. catch (...)
  16904. {
  16905. onException(MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught"));
  16906. started = true;
  16907. }
  16908. }
  16909. virtual void reset()
  16910. {
  16911. while (buff.isItem(index))
  16912. ReleaseRoxieRow(buff.item(index++));
  16913. buff.kill();
  16914. started = false;
  16915. CRoxieServerActivity::reset();
  16916. }
  16917. virtual const void *nextInGroup()
  16918. {
  16919. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  16920. if (!started)
  16921. pullInput();
  16922. if (buff.isItem(index))
  16923. {
  16924. const void * next = buff.item(index++);
  16925. if(next)
  16926. processed++;
  16927. return next;
  16928. }
  16929. return NULL;
  16930. }
  16931. protected:
  16932. void onException(IException *E)
  16933. {
  16934. input->stop(true);
  16935. ReleaseRoxieRowSet(buff);
  16936. if (createRow)
  16937. {
  16938. createRowAllocator();
  16939. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  16940. size32_t outSize = helper.transformOnExceptionCaught(rowBuilder, E);
  16941. if (outSize)
  16942. buff.append(rowBuilder.finalizeRowClear(outSize));
  16943. }
  16944. E->Release();
  16945. }
  16946. void pullInput()
  16947. {
  16948. try
  16949. {
  16950. bool EOGseen = false;
  16951. loop
  16952. {
  16953. const void * next = input->nextInGroup();
  16954. buff.append(next);
  16955. if (next == NULL)
  16956. {
  16957. if (EOGseen)
  16958. break;
  16959. EOGseen = true;
  16960. }
  16961. else
  16962. EOGseen = false;
  16963. }
  16964. }
  16965. catch (IException *E)
  16966. {
  16967. onException(E);
  16968. }
  16969. catch (...)
  16970. {
  16971. onException(MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught"));
  16972. }
  16973. started = true;
  16974. }
  16975. };
  16976. class CRoxieServerCatchActivityFactory : public CRoxieServerActivityFactory
  16977. {
  16978. public:
  16979. CRoxieServerCatchActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  16980. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  16981. {
  16982. }
  16983. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  16984. {
  16985. switch (kind)
  16986. {
  16987. case TAKcatch:
  16988. return new CRoxieServerCatchActivity(this, _probeManager);
  16989. case TAKskipcatch:
  16990. return new CRoxieServerSkipCatchActivity(this, _probeManager, false);
  16991. case TAKcreaterowcatch:
  16992. return new CRoxieServerSkipCatchActivity(this, _probeManager, true);
  16993. default:
  16994. throwUnexpected();
  16995. }
  16996. }
  16997. };
  16998. IRoxieServerActivityFactory *createRoxieServerCatchActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  16999. {
  17000. return new CRoxieServerCatchActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  17001. }
  17002. //=================================================================================
  17003. class CRoxieServerCaseActivity : public CRoxieServerActivity
  17004. {
  17005. IHThorCaseArg &helper;
  17006. IRoxieInput **inputs;
  17007. unsigned cond;
  17008. bool unusedStopped;
  17009. IRoxieInput *in;
  17010. unsigned numInputs;
  17011. public:
  17012. CRoxieServerCaseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  17013. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorCaseArg &)basehelper), numInputs(_numInputs)
  17014. {
  17015. unusedStopped = false;
  17016. cond = 0;
  17017. inputs = new IRoxieInput*[numInputs];
  17018. for (unsigned i = 0; i < numInputs; i++)
  17019. inputs[i] = NULL;
  17020. in = NULL;
  17021. }
  17022. ~CRoxieServerCaseActivity()
  17023. {
  17024. delete [] inputs;
  17025. }
  17026. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  17027. {
  17028. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  17029. cond = helper.getBranch();
  17030. //CHOOSE defaults to the last argument if out of range.
  17031. if (cond >= numInputs)
  17032. cond = numInputs - 1;
  17033. inputs[cond]->start(parentExtractSize, parentExtract, paused);
  17034. for (unsigned idx = 0; idx < numInputs; idx++)
  17035. {
  17036. if (idx!=cond)
  17037. inputs[idx]->stop(false); // Note: stopping unused branches early helps us avoid buffering splits too long.
  17038. }
  17039. in = inputs[cond];
  17040. unusedStopped = true;
  17041. }
  17042. virtual void stop(bool aborting)
  17043. {
  17044. for (unsigned idx = 0; idx < numInputs; idx++)
  17045. {
  17046. if (idx==cond || !unusedStopped)
  17047. inputs[idx]->stop(aborting);
  17048. }
  17049. CRoxieServerActivity::stop(aborting);
  17050. }
  17051. virtual void reset()
  17052. {
  17053. for (unsigned idx = 0; idx < numInputs; idx++)
  17054. {
  17055. inputs[idx]->reset();
  17056. }
  17057. unusedStopped = false;
  17058. in = NULL;
  17059. CRoxieServerActivity::reset();
  17060. }
  17061. virtual void setInput(unsigned idx, IRoxieInput *_in)
  17062. {
  17063. assertex(idx < numInputs);
  17064. inputs[idx] = _in;
  17065. }
  17066. virtual const void *nextInGroup()
  17067. {
  17068. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  17069. if (in)
  17070. {
  17071. const void *ret = in->nextInGroup();
  17072. if (ret)
  17073. processed++;
  17074. return ret;
  17075. }
  17076. return NULL;
  17077. }
  17078. };
  17079. class CRoxieServerCaseActivityFactory : public CRoxieServerMultiInputFactory
  17080. {
  17081. bool graphInvariant;
  17082. public:
  17083. CRoxieServerCaseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _graphInvariant)
  17084. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  17085. {
  17086. graphInvariant = _graphInvariant;
  17087. }
  17088. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  17089. {
  17090. return new CRoxieServerCaseActivity(this, _probeManager, numInputs());
  17091. }
  17092. virtual bool isGraphInvariant() const
  17093. {
  17094. return graphInvariant;
  17095. }
  17096. };
  17097. IRoxieServerActivityFactory *createRoxieServerCaseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _graphInvariant)
  17098. {
  17099. return new CRoxieServerCaseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphInvariant);
  17100. }
  17101. //=================================================================================
  17102. class CRoxieServerIfActivity : public CRoxieServerActivity
  17103. {
  17104. IHThorIfArg &helper;
  17105. IRoxieInput *inputTrue;
  17106. IRoxieInput *inputFalse;
  17107. bool cond;
  17108. bool unusedStopped;
  17109. public:
  17110. CRoxieServerIfActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  17111. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorIfArg &)basehelper)
  17112. {
  17113. inputFalse = NULL;
  17114. inputTrue = NULL;
  17115. unusedStopped = false;
  17116. cond = false;
  17117. }
  17118. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  17119. {
  17120. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  17121. cond = helper.getCondition();
  17122. if (cond)
  17123. {
  17124. inputTrue->start(parentExtractSize, parentExtract, paused);
  17125. if (inputFalse)
  17126. inputFalse->stop(false); // Note: stopping unused branches early helps us avoid buffering splits too long.
  17127. }
  17128. else
  17129. {
  17130. if (inputFalse)
  17131. inputFalse->start(parentExtractSize, parentExtract, paused);
  17132. inputTrue->stop(false);
  17133. }
  17134. unusedStopped = true;
  17135. }
  17136. virtual void stop(bool aborting)
  17137. {
  17138. if (!unusedStopped || cond)
  17139. inputTrue->stop(aborting);
  17140. if (inputFalse && (!unusedStopped || !cond))
  17141. inputFalse->stop(aborting);
  17142. CRoxieServerActivity::stop(aborting);
  17143. }
  17144. virtual unsigned __int64 queryLocalCycles() const
  17145. {
  17146. __int64 localCycles = totalCycles;
  17147. localCycles -= inputTrue->queryTotalCycles();
  17148. if (inputFalse)
  17149. localCycles -= inputFalse->queryTotalCycles();
  17150. if (localCycles < 0)
  17151. localCycles = 0;
  17152. return localCycles;
  17153. }
  17154. virtual IRoxieInput *queryInput(unsigned idx) const
  17155. {
  17156. switch (idx)
  17157. {
  17158. case 0:
  17159. return inputTrue;
  17160. case 1:
  17161. return inputFalse;
  17162. default:
  17163. return NULL;
  17164. }
  17165. }
  17166. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  17167. {
  17168. IRoxieInput *in = cond ? inputTrue : inputFalse;
  17169. if (in)
  17170. return in->queryIndexReadActivity();
  17171. return NULL;
  17172. }
  17173. virtual void reset()
  17174. {
  17175. CRoxieServerActivity::reset();
  17176. inputTrue->reset();
  17177. if (inputFalse)
  17178. inputFalse->reset();
  17179. unusedStopped = false;
  17180. }
  17181. virtual void setInput(unsigned idx, IRoxieInput *_in)
  17182. {
  17183. if (idx==1)
  17184. inputFalse = _in;
  17185. else
  17186. {
  17187. assertex(!idx);
  17188. inputTrue = _in;
  17189. }
  17190. }
  17191. virtual const void *nextInGroup()
  17192. {
  17193. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  17194. IRoxieInput *in = cond ? inputTrue : inputFalse;
  17195. if (in)
  17196. {
  17197. const void * ret;
  17198. if ((ret = in->nextInGroup()) != NULL)
  17199. processed++;
  17200. return ret;
  17201. }
  17202. return NULL;
  17203. }
  17204. };
  17205. class CRoxieServerIfActivityFactory : public CRoxieServerActivityFactory
  17206. {
  17207. unsigned input2;
  17208. unsigned input2idx;
  17209. bool graphInvariant;
  17210. public:
  17211. CRoxieServerIfActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _graphInvariant)
  17212. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  17213. {
  17214. graphInvariant = _graphInvariant;
  17215. input2 = (unsigned)-1;
  17216. input2idx = (unsigned)-1;
  17217. }
  17218. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  17219. {
  17220. return new CRoxieServerIfActivity(this, _probeManager);
  17221. }
  17222. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  17223. {
  17224. if (idx==1)
  17225. {
  17226. input2 = source;
  17227. input2idx = sourceidx;
  17228. }
  17229. else
  17230. CRoxieServerActivityFactory::setInput(idx, source, sourceidx);
  17231. }
  17232. virtual unsigned getInput(unsigned idx, unsigned &sourceidx) const
  17233. {
  17234. switch (idx)
  17235. {
  17236. case 1:
  17237. sourceidx = input2idx;
  17238. return input2;
  17239. case 0:
  17240. return CRoxieServerActivityFactory::getInput(idx, sourceidx);
  17241. default:
  17242. return (unsigned) -1;
  17243. }
  17244. }
  17245. virtual unsigned numInputs() const { return (input2 == (unsigned)-1) ? 1 : 2; }
  17246. virtual bool isGraphInvariant() const
  17247. {
  17248. return graphInvariant;
  17249. }
  17250. };
  17251. IRoxieServerActivityFactory *createRoxieServerIfActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _graphInvariant)
  17252. {
  17253. return new CRoxieServerIfActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphInvariant);
  17254. }
  17255. //=================================================================================
  17256. class CRoxieServerActionBaseActivity : public CRoxieServerActivity
  17257. {
  17258. CriticalSection ecrit;
  17259. Owned<IException> exception;
  17260. bool executed;
  17261. public:
  17262. CRoxieServerActionBaseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  17263. : CRoxieServerActivity(_factory, _probeManager)
  17264. {
  17265. executed = false;
  17266. }
  17267. virtual void doExecuteAction(unsigned parentExtractSize, const byte * parentExtract) = 0;
  17268. virtual void execute(unsigned parentExtractSize, const byte * parentExtract)
  17269. {
  17270. CriticalBlock b(ecrit);
  17271. if (exception)
  17272. throw(exception.getLink());
  17273. if (!executed)
  17274. {
  17275. try
  17276. {
  17277. executed = true;
  17278. start(parentExtractSize, parentExtract, false);
  17279. doExecuteAction(parentExtractSize, parentExtract);
  17280. stop(false);
  17281. }
  17282. catch (IException * E)
  17283. {
  17284. ctx->notifyAbort(E);
  17285. stop(true);
  17286. exception.set(E);
  17287. throw;
  17288. }
  17289. }
  17290. }
  17291. virtual void reset()
  17292. {
  17293. executed = false;
  17294. exception.clear();
  17295. CRoxieServerActivity::reset();
  17296. }
  17297. virtual unsigned __int64 queryLocalCycles() const
  17298. {
  17299. return totalCycles;
  17300. }
  17301. virtual const void *nextInGroup()
  17302. {
  17303. throwUnexpected(); // I am nobody's input
  17304. }
  17305. virtual IRoxieInput *queryInput(unsigned idx) const
  17306. {
  17307. throwUnexpected(); // I am nobody's input
  17308. }
  17309. };
  17310. class CRoxieServerIfActionActivity : public CRoxieServerActionBaseActivity
  17311. {
  17312. IHThorIfArg &helper;
  17313. public:
  17314. CRoxieServerIfActionActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  17315. : CRoxieServerActionBaseActivity(_factory, _probeManager), helper((IHThorIfArg &)basehelper)
  17316. {
  17317. }
  17318. virtual void doExecuteAction(unsigned parentExtractSize, const byte * parentExtract)
  17319. {
  17320. bool cond;
  17321. {
  17322. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  17323. cond = helper.getCondition();
  17324. }
  17325. stopDependencies(parentExtractSize, parentExtract, cond ? 2 : 1);
  17326. executeDependencies(parentExtractSize, parentExtract, cond ? 1 : 2);
  17327. }
  17328. };
  17329. class CRoxieServerIfActionActivityFactory : public CRoxieServerActivityFactory
  17330. {
  17331. bool isRoot;
  17332. public:
  17333. CRoxieServerIfActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  17334. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
  17335. {
  17336. }
  17337. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  17338. {
  17339. return new CRoxieServerIfActionActivity(this, _probeManager);
  17340. }
  17341. virtual bool isSink() const
  17342. {
  17343. return isRoot;
  17344. }
  17345. };
  17346. IRoxieServerActivityFactory *createRoxieServerIfActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  17347. {
  17348. return new CRoxieServerIfActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
  17349. }
  17350. //=================================================================================
  17351. class CRoxieServerParallelActionActivity : public CRoxieServerActionBaseActivity
  17352. {
  17353. public:
  17354. CRoxieServerParallelActionActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  17355. : CRoxieServerActionBaseActivity(_factory, _probeManager)
  17356. {
  17357. }
  17358. virtual void doExecuteAction(unsigned parentExtractSize, const byte * parentExtract)
  17359. {
  17360. #ifdef PARALLEL_EXECUTE
  17361. CParallelActivityExecutor afor(dependencies, parentExtractSize, parentExtract);
  17362. afor.For(dependencies.ordinality(), dependencies.ordinality(), true);
  17363. #else
  17364. ForEachItemIn(idx, dependencies)
  17365. {
  17366. dependencies.item(idx).execute(parentExtractSize, parentExtract);
  17367. }
  17368. #endif
  17369. }
  17370. };
  17371. class CRoxieServerParallelActionActivityFactory : public CRoxieServerActivityFactory
  17372. {
  17373. bool isRoot;
  17374. public:
  17375. CRoxieServerParallelActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  17376. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
  17377. {
  17378. assertex(!isRoot); // non-internal should be expanded out..
  17379. }
  17380. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  17381. {
  17382. return new CRoxieServerParallelActionActivity(this, _probeManager);
  17383. }
  17384. virtual bool isSink() const
  17385. {
  17386. return isRoot;
  17387. }
  17388. };
  17389. IRoxieServerActivityFactory *createRoxieServerParallelActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  17390. {
  17391. return new CRoxieServerParallelActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
  17392. }
  17393. //=================================================================================
  17394. class CRoxieServerSequentialActionActivity : public CRoxieServerActionBaseActivity
  17395. {
  17396. IHThorSequentialArg &helper;
  17397. public:
  17398. CRoxieServerSequentialActionActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  17399. : CRoxieServerActionBaseActivity(_factory, _probeManager), helper((IHThorSequentialArg &)basehelper)
  17400. {
  17401. }
  17402. virtual void doExecuteAction(unsigned parentExtractSize, const byte * parentExtract)
  17403. {
  17404. unsigned numBranches = helper.numBranches();
  17405. for (unsigned branch=1; branch <= numBranches; branch++)
  17406. executeDependencies(parentExtractSize, parentExtract, branch);
  17407. }
  17408. };
  17409. class CRoxieServerSequentialActionActivityFactory : public CRoxieServerActivityFactory
  17410. {
  17411. bool isRoot;
  17412. public:
  17413. CRoxieServerSequentialActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  17414. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
  17415. {
  17416. }
  17417. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  17418. {
  17419. return new CRoxieServerSequentialActionActivity(this, _probeManager);
  17420. }
  17421. virtual bool isSink() const
  17422. {
  17423. return isRoot;
  17424. }
  17425. };
  17426. IRoxieServerActivityFactory *createRoxieServerSequentialActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  17427. {
  17428. return new CRoxieServerSequentialActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
  17429. }
  17430. //=================================================================================
  17431. class CRoxieServerWhenActivity : public CRoxieServerActivity
  17432. {
  17433. public:
  17434. CRoxieServerWhenActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  17435. : CRoxieServerActivity(_factory, _probeManager)
  17436. {
  17437. savedExtractSize = 0;
  17438. savedExtract = NULL;
  17439. }
  17440. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  17441. {
  17442. savedExtractSize = parentExtractSize;
  17443. savedExtract = parentExtract;
  17444. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  17445. executeDependencies(parentExtractSize, parentExtract, WhenBeforeId);
  17446. executeDependencies(parentExtractSize, parentExtract, WhenParallelId); // MORE: This should probably be done in parallel!
  17447. }
  17448. virtual void stop(bool aborting)
  17449. {
  17450. if (state != STATEstopped)
  17451. {
  17452. stopDependencies(savedExtractSize, savedExtract, aborting ? WhenSuccessId : WhenFailureId); // These ones don't get executed
  17453. executeDependencies(savedExtractSize, savedExtract, aborting ? WhenFailureId : WhenSuccessId); // These ones do
  17454. }
  17455. CRoxieServerActivity::stop(aborting);
  17456. }
  17457. virtual const void *nextInGroup()
  17458. {
  17459. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext()); // bit of a waste of time....
  17460. return input->nextInGroup();
  17461. }
  17462. protected:
  17463. unsigned savedExtractSize;
  17464. const byte *savedExtract;
  17465. };
  17466. class CRoxieServerWhenActivityFactory : public CRoxieServerActivityFactory
  17467. {
  17468. public:
  17469. CRoxieServerWhenActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  17470. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  17471. {
  17472. }
  17473. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  17474. {
  17475. return new CRoxieServerWhenActivity(this, _probeManager);
  17476. }
  17477. };
  17478. extern IRoxieServerActivityFactory *createRoxieServerWhenActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  17479. {
  17480. return new CRoxieServerWhenActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  17481. }
  17482. //=================================================================================
  17483. class CRoxieServerWhenActionActivity : public CRoxieServerActionBaseActivity
  17484. {
  17485. public:
  17486. CRoxieServerWhenActionActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  17487. : CRoxieServerActionBaseActivity(_factory, _probeManager)
  17488. {
  17489. savedExtractSize = 0;
  17490. savedExtract = NULL;
  17491. }
  17492. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  17493. {
  17494. savedExtractSize = parentExtractSize;
  17495. savedExtract = parentExtract;
  17496. CRoxieServerActionBaseActivity::start(parentExtractSize, parentExtract, paused);
  17497. executeDependencies(parentExtractSize, parentExtract, WhenBeforeId);
  17498. executeDependencies(parentExtractSize, parentExtract, WhenParallelId); // MORE: This should probably be done in parallel!
  17499. }
  17500. virtual void stop(bool aborting)
  17501. {
  17502. if (state != STATEstopped)
  17503. {
  17504. stopDependencies(savedExtractSize, savedExtract, aborting ? WhenSuccessId : WhenFailureId); // these are NOT going to execute
  17505. executeDependencies(savedExtractSize, savedExtract, aborting ? WhenFailureId : WhenSuccessId);
  17506. }
  17507. CRoxieServerActionBaseActivity::stop(aborting);
  17508. }
  17509. virtual void doExecuteAction(unsigned parentExtractSize, const byte * parentExtract)
  17510. {
  17511. executeDependencies(parentExtractSize, parentExtract, 1);
  17512. }
  17513. protected:
  17514. unsigned savedExtractSize;
  17515. const byte *savedExtract;
  17516. };
  17517. class CRoxieServerWhenActionActivityFactory : public CRoxieServerActivityFactory
  17518. {
  17519. public:
  17520. CRoxieServerWhenActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  17521. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
  17522. {
  17523. }
  17524. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  17525. {
  17526. return new CRoxieServerWhenActionActivity(this, _probeManager);
  17527. }
  17528. virtual bool isSink() const
  17529. {
  17530. return isRoot;
  17531. }
  17532. private:
  17533. bool isRoot;
  17534. };
  17535. extern IRoxieServerActivityFactory *createRoxieServerWhenActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  17536. {
  17537. return new CRoxieServerWhenActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
  17538. }
  17539. //=================================================================================
  17540. class CRoxieServerParseActivity : public CRoxieServerActivity, implements IMatchedAction
  17541. {
  17542. IHThorParseArg &helper;
  17543. INlpParser * parser;
  17544. INlpResultIterator * rowIter;
  17545. const void * in;
  17546. char * curSearchText;
  17547. INlpParseAlgorithm * algorithm;
  17548. size32_t curSearchTextLen;
  17549. bool anyThisGroup;
  17550. bool processRecord(const void * inRec)
  17551. {
  17552. if (helper.searchTextNeedsFree())
  17553. rtlFree(curSearchText);
  17554. curSearchTextLen = 0;
  17555. curSearchText = NULL;
  17556. helper.getSearchText(curSearchTextLen, curSearchText, inRec);
  17557. return parser->performMatch(*this, in, curSearchTextLen, curSearchText);
  17558. }
  17559. public:
  17560. CRoxieServerParseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, INlpParseAlgorithm * _algorithm)
  17561. : CRoxieServerActivity(_factory, _probeManager),
  17562. helper((IHThorParseArg &)basehelper), algorithm(_algorithm)
  17563. {
  17564. parser = NULL;
  17565. rowIter = NULL;
  17566. in = NULL;
  17567. curSearchText = NULL;
  17568. anyThisGroup = false;
  17569. curSearchTextLen = 0;
  17570. }
  17571. ~CRoxieServerParseActivity()
  17572. {
  17573. ::Release(parser);
  17574. }
  17575. virtual bool needsAllocator() const { return true; }
  17576. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  17577. {
  17578. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  17579. parser = algorithm->createParser(_ctx->queryCodeContext(), activityId, helper.queryHelper(), &helper);
  17580. rowIter = parser->queryResultIter();
  17581. }
  17582. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  17583. {
  17584. anyThisGroup = false;
  17585. curSearchTextLen = 0;
  17586. curSearchText = NULL;
  17587. in = NULL;
  17588. parser->reset();
  17589. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  17590. }
  17591. virtual void reset()
  17592. {
  17593. if (helper.searchTextNeedsFree())
  17594. rtlFree(curSearchText);
  17595. curSearchText = NULL;
  17596. ReleaseClearRoxieRow(in);
  17597. CRoxieServerActivity::reset();
  17598. }
  17599. virtual unsigned onMatch(ARowBuilder & self, const void * curRecord, IMatchedResults * results, IMatchWalker * walker)
  17600. {
  17601. try
  17602. {
  17603. return helper.transform(self, curRecord, results, walker);
  17604. }
  17605. catch (IException *E)
  17606. {
  17607. throw makeWrappedException(E);
  17608. }
  17609. }
  17610. virtual const void * nextInGroup()
  17611. {
  17612. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  17613. loop
  17614. {
  17615. if (rowIter->isValid())
  17616. {
  17617. anyThisGroup = true;
  17618. OwnedConstRoxieRow out = rowIter->getRow();
  17619. rowIter->next();
  17620. processed++;
  17621. return out.getClear();
  17622. }
  17623. ReleaseClearRoxieRow(in);
  17624. in = input->nextInGroup();
  17625. if (!in)
  17626. {
  17627. if (anyThisGroup)
  17628. {
  17629. anyThisGroup = false;
  17630. return NULL;
  17631. }
  17632. in = input->nextInGroup();
  17633. if (!in)
  17634. return NULL;
  17635. }
  17636. processRecord(in);
  17637. rowIter->first();
  17638. }
  17639. }
  17640. };
  17641. class CRoxieServerParseActivityFactory : public CRoxieServerActivityFactory
  17642. {
  17643. Owned<INlpParseAlgorithm> algorithm;
  17644. Owned<IHThorParseArg> helper;
  17645. public:
  17646. CRoxieServerParseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IResourceContext *rc)
  17647. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  17648. {
  17649. helper.setown((IHThorParseArg *) helperFactory());
  17650. algorithm.setown(createThorParser(rc, *helper));
  17651. }
  17652. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  17653. {
  17654. return new CRoxieServerParseActivity(this, _probeManager, algorithm);
  17655. }
  17656. };
  17657. IRoxieServerActivityFactory *createRoxieServerParseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IResourceContext *rc)
  17658. {
  17659. return new CRoxieServerParseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, rc);
  17660. }
  17661. //=====================================================================================================
  17662. class CRoxieServerWorkUnitWriteActivity : public CRoxieServerInternalSinkActivity
  17663. {
  17664. IHThorWorkUnitWriteArg &helper;
  17665. bool isReread;
  17666. bool grouped;
  17667. IRoxieServerContext *serverContext;
  17668. public:
  17669. CRoxieServerWorkUnitWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _isReread, unsigned _numOutputs)
  17670. : CRoxieServerInternalSinkActivity(_factory, _probeManager, _numOutputs), helper((IHThorWorkUnitWriteArg &)basehelper), isReread(_isReread)
  17671. {
  17672. grouped = (helper.getFlags() & POFgrouped) != 0;
  17673. serverContext = NULL;
  17674. }
  17675. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  17676. {
  17677. CRoxieServerInternalSinkActivity::onCreate(_ctx, _colocalParent);
  17678. serverContext = ctx->queryServerContext();
  17679. if (!serverContext)
  17680. {
  17681. throw MakeStringException(ROXIE_PIPE_ERROR, "Pipe output activity cannot be executed in slave context");
  17682. }
  17683. }
  17684. virtual bool needsAllocator() const { return true; }
  17685. virtual void onExecute()
  17686. {
  17687. int sequence = helper.getSequence();
  17688. const char *storedName = helper.queryName();
  17689. if (!storedName)
  17690. storedName = "Dataset";
  17691. MemoryBuffer result;
  17692. FlushingStringBuffer *response = NULL;
  17693. bool saveInContext = (int) sequence < 0 || isReread;
  17694. if (!meta.queryOriginal()) // this is a bit of a hack - don't know why no meta on an output....
  17695. meta.set(input->queryOutputMeta());
  17696. Owned<IOutputRowSerializer> rowSerializer;
  17697. Owned<IXmlWriter> writer;
  17698. if ((int) sequence >= 0)
  17699. {
  17700. response = serverContext->queryResult(sequence);
  17701. if (response)
  17702. {
  17703. const IProperties *xmlns = serverContext->queryXmlns(sequence);
  17704. response->startDataset("Dataset", helper.queryName(), sequence, (helper.getFlags() & POFextend) != 0, xmlns);
  17705. if (response->mlFmt==MarkupFmt_XML || response->mlFmt==MarkupFmt_JSON)
  17706. {
  17707. unsigned int writeFlags = serverContext->getXmlFlags();
  17708. if (response->mlFmt==MarkupFmt_JSON)
  17709. writeFlags |= XWFnoindent;
  17710. writer.setown(createIXmlWriter(writeFlags, 1, response, (response->mlFmt==MarkupFmt_JSON) ? WTJSON : WTStandard));
  17711. writer->outputBeginArray("Row");
  17712. }
  17713. }
  17714. }
  17715. size32_t outputLimitBytes = 0;
  17716. IConstWorkUnit *workunit = serverContext->queryWorkUnit();
  17717. if (workunit)
  17718. {
  17719. size32_t outputLimit;
  17720. if (helper.getFlags() & POFmaxsize)
  17721. outputLimit = helper.getMaxSize();
  17722. else
  17723. outputLimit = workunit->getDebugValueInt("outputLimit", DALI_RESULT_LIMIT_DEFAULT);
  17724. if (outputLimit>DALI_RESULT_OUTPUTMAX)
  17725. 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.", DALI_RESULT_OUTPUTMAX, DALI_RESULT_LIMIT_DEFAULT);
  17726. assertex(outputLimit<=0x1000); // 32bit limit because MemoryBuffer/CMessageBuffers involved etc.
  17727. outputLimitBytes = outputLimit * 0x100000;
  17728. }
  17729. if (workunit != NULL || (response && response->isRaw))
  17730. {
  17731. createRowAllocator();
  17732. rowSerializer.setown(rowAllocator->createDiskSerializer(ctx->queryCodeContext()));
  17733. }
  17734. __int64 initialProcessed = processed;
  17735. RtlLinkedDatasetBuilder builder(rowAllocator);
  17736. loop
  17737. {
  17738. const void *row = input->nextInGroup();
  17739. if (saveInContext)
  17740. {
  17741. if (row || grouped)
  17742. builder.append(row);
  17743. }
  17744. if (grouped && (processed != initialProcessed))
  17745. {
  17746. if (workunit)
  17747. result.append(row == NULL);
  17748. if (response)
  17749. {
  17750. if (response->isRaw)
  17751. response->append(row == NULL);
  17752. else
  17753. {
  17754. response->append("<Row __GroupBreak__=\"1\"/>"); // sensible, but need to handle on input
  17755. }
  17756. }
  17757. }
  17758. if (!row)
  17759. {
  17760. row = input->nextInGroup();
  17761. if (!row)
  17762. break;
  17763. if (saveInContext)
  17764. builder.append(row);
  17765. }
  17766. processed++;
  17767. if (workunit)
  17768. {
  17769. CThorDemoRowSerializer serializerTarget(result);
  17770. rowSerializer->serialize(serializerTarget, (const byte *) row);
  17771. }
  17772. if (response)
  17773. {
  17774. if (response->isRaw)
  17775. {
  17776. // MORE - should be able to serialize straight to the response...
  17777. MemoryBuffer rowbuff;
  17778. CThorDemoRowSerializer serializerTarget(rowbuff);
  17779. rowSerializer->serialize(serializerTarget, (const byte *) row);
  17780. response->append(rowbuff.length(), rowbuff.toByteArray());
  17781. }
  17782. else if (writer)
  17783. {
  17784. writer->outputBeginNested("Row", false);
  17785. helper.serializeXml((byte *) row, *writer);
  17786. writer->outputEndNested("Row");
  17787. }
  17788. else
  17789. {
  17790. SimpleOutputWriter x;
  17791. helper.serializeXml((byte *) row, x);
  17792. x.newline();
  17793. response->append(x.str());
  17794. }
  17795. response->incrementRowCount();
  17796. response->flush(false);
  17797. }
  17798. ReleaseRoxieRow(row);
  17799. if (outputLimitBytes && result.length() > outputLimitBytes)
  17800. {
  17801. StringBuffer errMsg("Dataset too large to output to workunit (limit ");
  17802. errMsg.append(outputLimitBytes/0x100000).append(" megabytes), in result (");
  17803. const char *name = helper.queryName();
  17804. if (name)
  17805. errMsg.append("name=").append(name);
  17806. else
  17807. errMsg.append("sequence=").append(helper.getSequence());
  17808. errMsg.append(")");
  17809. throw MakeStringExceptionDirect(0, errMsg.str());
  17810. }
  17811. }
  17812. if (writer)
  17813. writer->outputEndArray("Row");
  17814. if (saveInContext)
  17815. serverContext->appendResultDeserialized(storedName, sequence, builder.getcount(), builder.linkrows(), (helper.getFlags() & POFextend) != 0, LINK(meta.queryOriginal()));
  17816. if (workunit)
  17817. serverContext->appendResultRawContext(storedName, sequence, result.length(), result.toByteArray(), processed, (helper.getFlags() & POFextend) != 0, false); // MORE - shame to do extra copy...
  17818. }
  17819. };
  17820. class CRoxieServerWorkUnitWriteActivityFactory : public CRoxieServerInternalSinkFactory
  17821. {
  17822. bool isReread;
  17823. public:
  17824. CRoxieServerWorkUnitWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
  17825. : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot)
  17826. {
  17827. isReread = usageCount > 0;
  17828. Owned<IHThorWorkUnitWriteArg> helper = (IHThorWorkUnitWriteArg *) helperFactory();
  17829. isInternal = (helper->getSequence()==ResultSequenceInternal);
  17830. }
  17831. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  17832. {
  17833. return new CRoxieServerWorkUnitWriteActivity(this, _probeManager, isReread, usageCount);
  17834. }
  17835. };
  17836. IRoxieServerActivityFactory *createRoxieServerWorkUnitWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
  17837. {
  17838. return new CRoxieServerWorkUnitWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot);
  17839. }
  17840. //=====================================================================================================
  17841. class CRoxieServerWorkUnitWriteDictActivity : public CRoxieServerInternalSinkActivity
  17842. {
  17843. IHThorDictionaryWorkUnitWriteArg &helper;
  17844. IRoxieServerContext *serverContext;
  17845. public:
  17846. CRoxieServerWorkUnitWriteDictActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _usageCount)
  17847. : CRoxieServerInternalSinkActivity(_factory, _probeManager, _usageCount), helper((IHThorDictionaryWorkUnitWriteArg &)basehelper)
  17848. {
  17849. serverContext = NULL;
  17850. }
  17851. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  17852. {
  17853. CRoxieServerInternalSinkActivity::onCreate(_ctx, _colocalParent);
  17854. serverContext = ctx->queryServerContext();
  17855. if (!serverContext)
  17856. {
  17857. throw MakeStringException(ROXIE_PIPE_ERROR, "Write Dictionary activity cannot be executed in slave context");
  17858. }
  17859. }
  17860. virtual bool needsAllocator() const { return true; }
  17861. virtual void onExecute()
  17862. {
  17863. int sequence = helper.getSequence();
  17864. const char *storedName = helper.queryName();
  17865. assertex(storedName && *storedName);
  17866. assertex(sequence < 0);
  17867. RtlLinkedDictionaryBuilder builder(rowAllocator, helper.queryHashLookupInfo());
  17868. loop
  17869. {
  17870. const void *row = input->nextInGroup();
  17871. if (!row)
  17872. {
  17873. row = input->nextInGroup();
  17874. if (!row)
  17875. break;
  17876. }
  17877. builder.appendOwn(row);
  17878. processed++;
  17879. }
  17880. serverContext->appendResultDeserialized(storedName, sequence, builder.getcount(), builder.linkrows(), (helper.getFlags() & POFextend) != 0, LINK(meta.queryOriginal()));
  17881. }
  17882. };
  17883. class CRoxieServerWorkUnitWriteDictActivityFactory : public CRoxieServerInternalSinkFactory
  17884. {
  17885. public:
  17886. CRoxieServerWorkUnitWriteDictActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
  17887. : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot)
  17888. {
  17889. Owned<IHThorDictionaryWorkUnitWriteArg> helper = (IHThorDictionaryWorkUnitWriteArg *) helperFactory();
  17890. isInternal = (helper->getSequence()==ResultSequenceInternal);
  17891. }
  17892. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  17893. {
  17894. return new CRoxieServerWorkUnitWriteDictActivity(this, _probeManager, usageCount);
  17895. }
  17896. };
  17897. IRoxieServerActivityFactory *createRoxieServerWorkUnitWriteDictActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
  17898. {
  17899. return new CRoxieServerWorkUnitWriteDictActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot);
  17900. }
  17901. //=================================================================================
  17902. class CRoxieServerRemoteResultActivity : public CRoxieServerInternalSinkActivity
  17903. {
  17904. IHThorRemoteResultArg &helper;
  17905. public:
  17906. CRoxieServerRemoteResultActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numOutputs)
  17907. : CRoxieServerInternalSinkActivity(_factory, _probeManager, _numOutputs), helper((IHThorRemoteResultArg &)basehelper)
  17908. {
  17909. }
  17910. virtual void onExecute()
  17911. {
  17912. OwnedConstRoxieRow row = input->nextInGroup();
  17913. helper.sendResult(row); // should be only one row or something has gone wrong!
  17914. }
  17915. };
  17916. class CRoxieServerRemoteResultActivityFactory : public CRoxieServerInternalSinkFactory
  17917. {
  17918. public:
  17919. CRoxieServerRemoteResultActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
  17920. : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot)
  17921. {
  17922. Owned<IHThorRemoteResultArg> helper = (IHThorRemoteResultArg *) helperFactory();
  17923. isInternal = (helper->getSequence()==ResultSequenceInternal);
  17924. }
  17925. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  17926. {
  17927. return new CRoxieServerRemoteResultActivity(this, _probeManager, usageCount);
  17928. }
  17929. };
  17930. IRoxieServerActivityFactory *createRoxieServerRemoteResultActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
  17931. {
  17932. return new CRoxieServerRemoteResultActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot);
  17933. }
  17934. //=================================================================================
  17935. class CRoxieServerXmlParseActivity : public CRoxieServerActivity, implements IXMLSelect
  17936. {
  17937. IHThorXmlParseArg &helper;
  17938. Owned<IXMLParse> xmlParser;
  17939. const void * in;
  17940. char * srchStr;
  17941. unsigned numProcessedLastGroup;
  17942. bool srchStrNeedsFree;
  17943. Owned<IColumnProvider> lastMatch;
  17944. public:
  17945. IMPLEMENT_IINTERFACE;
  17946. CRoxieServerXmlParseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  17947. : CRoxieServerActivity(_factory, _probeManager),
  17948. helper((IHThorXmlParseArg &)basehelper)
  17949. {
  17950. srchStrNeedsFree = helper.searchTextNeedsFree();
  17951. numProcessedLastGroup = 0;
  17952. srchStr = NULL;
  17953. in = NULL;
  17954. }
  17955. ~CRoxieServerXmlParseActivity()
  17956. {
  17957. }
  17958. virtual bool needsAllocator() const { return true; }
  17959. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  17960. {
  17961. numProcessedLastGroup = 0;
  17962. srchStr = NULL;
  17963. in = NULL;
  17964. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  17965. }
  17966. virtual void reset()
  17967. {
  17968. if (helper.searchTextNeedsFree())
  17969. rtlFree(srchStr);
  17970. srchStr = NULL;
  17971. ReleaseClearRoxieRow(in);
  17972. xmlParser.clear();
  17973. CRoxieServerActivity::reset();
  17974. }
  17975. virtual void match(IColumnProvider &entry, offset_t startOffset, offset_t endOffset)
  17976. {
  17977. lastMatch.set(&entry);
  17978. }
  17979. virtual const void *nextInGroup()
  17980. {
  17981. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  17982. loop
  17983. {
  17984. if(xmlParser)
  17985. {
  17986. loop
  17987. {
  17988. if(!xmlParser->next())
  17989. {
  17990. if (srchStrNeedsFree)
  17991. {
  17992. rtlFree(srchStr);
  17993. srchStr = NULL;
  17994. }
  17995. xmlParser.clear();
  17996. break;
  17997. }
  17998. if(lastMatch)
  17999. {
  18000. try
  18001. {
  18002. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  18003. size32_t outSize = helper.transform(rowBuilder, in, lastMatch);
  18004. lastMatch.clear();
  18005. if (outSize)
  18006. {
  18007. processed++;
  18008. return rowBuilder.finalizeRowClear(outSize);
  18009. }
  18010. }
  18011. catch (IException *E)
  18012. {
  18013. throw makeWrappedException(E);
  18014. }
  18015. }
  18016. }
  18017. }
  18018. ReleaseClearRoxieRow(in);
  18019. in = input->nextInGroup();
  18020. if(!in)
  18021. {
  18022. if(numProcessedLastGroup == processed)
  18023. in = input->nextInGroup();
  18024. if(!in)
  18025. {
  18026. numProcessedLastGroup = processed;
  18027. return NULL;
  18028. }
  18029. }
  18030. size32_t srchLen;
  18031. helper.getSearchText(srchLen, srchStr, in);
  18032. OwnedRoxieString xmlIteratorPath(helper.getXmlIteratorPath());
  18033. xmlParser.setown(createXMLParse(srchStr, srchLen, xmlIteratorPath, *this));
  18034. }
  18035. }
  18036. };
  18037. class CRoxieServerXmlParseActivityFactory : public CRoxieServerActivityFactory
  18038. {
  18039. public:
  18040. CRoxieServerXmlParseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  18041. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  18042. {
  18043. }
  18044. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  18045. {
  18046. return new CRoxieServerXmlParseActivity(this, _probeManager);
  18047. }
  18048. };
  18049. IRoxieServerActivityFactory *createRoxieServerXmlParseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  18050. {
  18051. return new CRoxieServerXmlParseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  18052. }
  18053. //=====================================================================================================
  18054. class CRoxieServerDiskReadBaseActivity : public CRoxieServerActivity, implements IRoxieServerErrorHandler, implements IIndexReadContext
  18055. {
  18056. protected:
  18057. IHThorDiskReadBaseArg &helper;
  18058. IHThorCompoundExtra * compoundHelper;
  18059. RemoteActivityId remoteId; // Note we copy it rather than reference
  18060. Owned<CSkippableRemoteResultAdaptor> remote;
  18061. unsigned numParts;
  18062. unsigned __int64 rowLimit;
  18063. unsigned __int64 stopAfter;
  18064. Linked<IInMemoryIndexManager> manager;
  18065. Owned<IInMemoryIndexCursor> cursor;
  18066. Owned<IDirectReader> reader;
  18067. CThorContiguousRowBuffer deserializeSource;
  18068. Owned<ISourceRowPrefetcher> prefetcher;
  18069. bool eof;
  18070. bool isKeyed;
  18071. bool variableFileName;
  18072. bool isOpt;
  18073. bool sorted;
  18074. bool maySkip;
  18075. bool isLocal;
  18076. CachedOutputMetaData diskSize;
  18077. Owned<const IResolvedFile> varFileInfo;
  18078. Owned<IFileIOArray> varFiles;
  18079. inline bool useRemote()
  18080. {
  18081. return remote != NULL && numParts > 1;
  18082. }
  18083. public:
  18084. IMPLEMENT_IINTERFACE;
  18085. CRoxieServerDiskReadBaseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, bool _sorted, bool _maySkip, IInMemoryIndexManager *_manager)
  18086. : CRoxieServerActivity(_factory, _probeManager),
  18087. helper((IHThorDiskReadBaseArg &)basehelper),
  18088. numParts(_numParts),
  18089. remoteId(_remoteId),
  18090. manager(_manager),
  18091. isLocal(_isLocal),
  18092. sorted(_sorted),
  18093. maySkip(_maySkip),
  18094. deserializeSource(NULL)
  18095. {
  18096. if (numParts != 1 && !isLocal) // NOTE : when numParts == 0 (variable case) we create, even though we may not use
  18097. remote.setown(new CSkippableRemoteResultAdaptor(remoteId, meta.queryOriginal(), helper, *this, sorted, false, _maySkip));
  18098. compoundHelper = NULL;
  18099. eof = false;
  18100. rowLimit = (unsigned __int64) -1;
  18101. isKeyed = false;
  18102. stopAfter = I64C(0x7FFFFFFFFFFFFFFF);
  18103. diskSize.set(helper.queryDiskRecordSize());
  18104. variableFileName = allFilesDynamic || factory->queryQueryFactory().isDynamic() || ((helper.getFlags() & (TDXvarfilename|TDXdynamicfilename)) != 0);
  18105. isOpt = (helper.getFlags() & TDRoptional) != 0;
  18106. }
  18107. virtual const IResolvedFile *queryVarFileInfo() const
  18108. {
  18109. return varFileInfo;
  18110. }
  18111. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  18112. {
  18113. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  18114. if (remote)
  18115. remote->onCreate(this, this, _ctx, _colocalParent);
  18116. }
  18117. virtual bool needsAllocator() const { return true; }
  18118. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  18119. {
  18120. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  18121. if (compoundHelper)
  18122. {
  18123. rowLimit = compoundHelper->getRowLimit();
  18124. stopAfter = compoundHelper->getChooseNLimit();
  18125. }
  18126. if (!helper.canMatchAny())
  18127. eof = true;
  18128. else
  18129. {
  18130. if (variableFileName)
  18131. {
  18132. OwnedRoxieString fileName(helper.getFileName());
  18133. varFileInfo.setown(resolveLFN(fileName, isOpt));
  18134. numParts = 0;
  18135. if (varFileInfo)
  18136. {
  18137. Owned<IFilePartMap> map = varFileInfo->getFileMap();
  18138. if (map)
  18139. numParts = map->getNumParts();
  18140. }
  18141. }
  18142. if (!numParts)
  18143. {
  18144. eof = true;
  18145. }
  18146. else if (useRemote())
  18147. {
  18148. remote->onStart(parentExtractSize, parentExtract);
  18149. remote->setLimits(rowLimit, (unsigned __int64) -1, stopAfter);
  18150. unsigned fileNo = 0; // MORE - superfiles require us to do this per file part... maybe (needs thought)
  18151. // Translation into a message per channel done elsewhere....
  18152. remote->getMem(0, fileNo, 0);
  18153. remote->flush();
  18154. remote->senddone();
  18155. }
  18156. else
  18157. {
  18158. if (variableFileName)
  18159. {
  18160. unsigned channel = isLocal ? factory->queryQueryFactory().queryChannel() : 0;
  18161. varFiles.setown(varFileInfo->getIFileIOArray(isOpt, channel));
  18162. manager.setown(varFileInfo->getIndexManager(isOpt, channel, varFiles, diskSize, false, 0));
  18163. }
  18164. assertex(manager != NULL);
  18165. helper.createSegmentMonitors(this);
  18166. if (cursor)
  18167. {
  18168. isKeyed = cursor->selectKey();
  18169. cursor->reset();
  18170. }
  18171. if (!isKeyed)
  18172. {
  18173. reader.setown(manager->createReader(0, 0, 1));
  18174. deserializeSource.setStream(reader);
  18175. prefetcher.setown(diskSize.queryOriginal()->createDiskPrefetcher(ctx->queryCodeContext(), activityId));
  18176. }
  18177. helper.setCallback(reader ? reader->queryThorDiskCallback() : cursor);
  18178. }
  18179. }
  18180. }
  18181. virtual void append(IKeySegmentMonitor *segment)
  18182. {
  18183. if (!segment->isWild())
  18184. {
  18185. if (!cursor)
  18186. cursor.setown(manager->createCursor());
  18187. cursor->append(segment);
  18188. }
  18189. }
  18190. virtual unsigned ordinality() const
  18191. {
  18192. return cursor ? cursor->ordinality() : 0;
  18193. }
  18194. virtual IKeySegmentMonitor *item(unsigned idx) const
  18195. {
  18196. return cursor ? cursor->item(idx) : 0;
  18197. }
  18198. virtual void setMergeBarrier(unsigned barrierOffset)
  18199. {
  18200. // no merging so no issue...
  18201. }
  18202. virtual void stop(bool aborting)
  18203. {
  18204. if (useRemote())
  18205. remote->onStop(aborting);
  18206. CRoxieServerActivity::stop(aborting);
  18207. }
  18208. virtual void reset()
  18209. {
  18210. if (useRemote())
  18211. {
  18212. processed = remote->processed;
  18213. remote->processed = 0;
  18214. remote->onReset();
  18215. }
  18216. varFileInfo.clear();
  18217. eof = false;
  18218. if (cursor)
  18219. cursor->reset();
  18220. deserializeSource.clearStream();
  18221. CRoxieServerActivity::reset();
  18222. }
  18223. virtual void setInput(unsigned idx, IRoxieInput *_in)
  18224. {
  18225. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  18226. }
  18227. virtual void onLimitExceeded(bool isKeyed)
  18228. {
  18229. if (traceLevel > 4)
  18230. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  18231. assertex(compoundHelper);
  18232. if (isKeyed) // MORE does this exist for diskread? should it?
  18233. {
  18234. if (helper.getFlags() & (TDRkeyedlimitskips|TDRkeyedlimitcreates))
  18235. {
  18236. if (ctx->queryDebugContext())
  18237. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  18238. throw makeLimitSkipException(true);
  18239. }
  18240. else
  18241. {
  18242. UNIMPLEMENTED;
  18243. //compoundHelper->onKeyedLimitExceeded(); Doesn't exist - though the flags do... interesting...
  18244. }
  18245. }
  18246. else
  18247. {
  18248. if (helper.getFlags() & (TDRlimitskips|TDRlimitcreates))
  18249. {
  18250. if (ctx->queryDebugContext())
  18251. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  18252. throw makeLimitSkipException(false);
  18253. }
  18254. else
  18255. compoundHelper->onLimitExceeded();
  18256. }
  18257. }
  18258. virtual const void * createLimitFailRow(bool isKeyed)
  18259. {
  18260. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  18261. IHThorSourceLimitTransformExtra *limitTransformExtra = static_cast<IHThorSourceLimitTransformExtra *>(helper.selectInterface(TAIsourcelimittransformextra_1));
  18262. assertex(limitTransformExtra);
  18263. size32_t outSize = isKeyed ? limitTransformExtra->transformOnKeyedLimitExceeded(rowBuilder) : limitTransformExtra->transformOnLimitExceeded(rowBuilder);
  18264. if (outSize)
  18265. return rowBuilder.finalizeRowClear(outSize);
  18266. return NULL;
  18267. }
  18268. };
  18269. class CRoxieServerDiskReadActivity : public CRoxieServerDiskReadBaseActivity
  18270. {
  18271. IHThorCompoundReadExtra * readHelper;
  18272. ConstPointerArray readrows;
  18273. bool readAheadDone;
  18274. unsigned readIndex;
  18275. public:
  18276. CRoxieServerDiskReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, bool _sorted, bool _maySkip, IInMemoryIndexManager *_manager)
  18277. : CRoxieServerDiskReadBaseActivity(_factory, _probeManager, _remoteId, _numParts, _isLocal, _sorted, _maySkip, _manager)
  18278. {
  18279. compoundHelper = (IHThorDiskReadArg *)&helper;
  18280. readHelper = (IHThorDiskReadArg *)&helper;
  18281. readAheadDone = false;
  18282. readIndex = 0;
  18283. }
  18284. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  18285. {
  18286. rowLimit = compoundHelper->getRowLimit();
  18287. stopAfter = compoundHelper->getChooseNLimit();
  18288. CRoxieServerDiskReadBaseActivity::start(parentExtractSize, parentExtract, paused);
  18289. readAheadDone = false;
  18290. readIndex = 0;
  18291. }
  18292. virtual void reset()
  18293. {
  18294. while (readrows.isItem(readIndex))
  18295. ReleaseRoxieRow(readrows.item(readIndex++));
  18296. readrows.kill();
  18297. readAheadDone = false;
  18298. readIndex = 0;
  18299. CRoxieServerDiskReadBaseActivity::reset();
  18300. }
  18301. virtual const void *nextInGroup()
  18302. {
  18303. if (eof)
  18304. return NULL;
  18305. else if (useRemote())
  18306. return remote->nextInGroup();
  18307. else if (maySkip)
  18308. {
  18309. if (!readAheadDone)
  18310. {
  18311. unsigned preprocessed = 0;
  18312. while (!eof)
  18313. {
  18314. const void *row = _nextInGroup();
  18315. if (row)
  18316. preprocessed++;
  18317. if (preprocessed > rowLimit)
  18318. {
  18319. ReleaseRoxieRow(row);
  18320. while (readrows.isItem(readIndex))
  18321. ReleaseRoxieRow(readrows.item(readIndex++));
  18322. readrows.kill();
  18323. eof = true;
  18324. if (ctx->queryDebugContext())
  18325. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  18326. if (helper.getFlags() & TDRlimitskips)
  18327. return NULL;
  18328. else if (helper.getFlags() & TDRlimitcreates)
  18329. return createLimitFailRow(false);
  18330. else
  18331. throwUnexpected();
  18332. }
  18333. if (preprocessed > stopAfter) // MORE - bit of a strange place to check
  18334. {
  18335. eof = true;
  18336. ReleaseRoxieRow(row);
  18337. break;
  18338. }
  18339. readrows.append(row);
  18340. }
  18341. readAheadDone = true;
  18342. }
  18343. if (readrows.isItem(readIndex))
  18344. {
  18345. const void *ret = readrows.item(readIndex++);
  18346. if (ret)
  18347. processed++;
  18348. return ret;
  18349. }
  18350. else
  18351. {
  18352. eof = true;
  18353. return NULL;
  18354. }
  18355. }
  18356. else
  18357. {
  18358. const void *ret = _nextInGroup();
  18359. if (ret)
  18360. {
  18361. processed++;
  18362. if (processed > rowLimit)
  18363. {
  18364. if (traceLevel > 4)
  18365. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  18366. ReleaseRoxieRow(ret);
  18367. compoundHelper->onLimitExceeded();
  18368. throwUnexpected(); // onLimitExceeded is not supposed to return
  18369. }
  18370. if (processed > stopAfter) // MORE - bit of a strange place to check
  18371. {
  18372. eof = true;
  18373. ReleaseRoxieRow(ret);
  18374. return NULL;
  18375. }
  18376. }
  18377. return ret;
  18378. }
  18379. }
  18380. const void *_nextInGroup()
  18381. {
  18382. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  18383. unsigned transformedSize = 0;
  18384. if (isKeyed)
  18385. {
  18386. loop
  18387. {
  18388. const void *nextCandidate = cursor->nextMatch();
  18389. if (!nextCandidate)
  18390. {
  18391. eof = true;
  18392. return NULL;
  18393. }
  18394. transformedSize = readHelper->transform(rowBuilder, nextCandidate);
  18395. if (transformedSize)
  18396. break;
  18397. }
  18398. }
  18399. else // use reader...
  18400. {
  18401. assertex(reader != NULL);
  18402. loop
  18403. {
  18404. if (deserializeSource.eos())
  18405. {
  18406. eof = true;
  18407. return NULL;
  18408. }
  18409. prefetcher->readAhead(deserializeSource);
  18410. const byte *nextRec = deserializeSource.queryRow();
  18411. if (cursor && cursor->isFiltered(nextRec))
  18412. transformedSize = 0;
  18413. else
  18414. transformedSize = readHelper->transform(rowBuilder, nextRec);
  18415. deserializeSource.finishedRow();
  18416. if (transformedSize)
  18417. break;
  18418. }
  18419. }
  18420. return rowBuilder.finalizeRowClear(transformedSize);
  18421. }
  18422. };
  18423. class CRoxieServerXmlReadActivity : public CRoxieServerDiskReadBaseActivity, implements IXMLSelect
  18424. {
  18425. IHThorXmlReadArg * readHelper;
  18426. Owned<IXmlToRowTransformer> rowTransformer;
  18427. Owned<IXMLParse> xmlParser;
  18428. Owned<IColumnProvider> lastMatch;
  18429. unsigned __int64 localOffset;
  18430. public:
  18431. IMPLEMENT_IINTERFACE;
  18432. CRoxieServerXmlReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, bool _sorted, bool _maySkip, IInMemoryIndexManager *_manager)
  18433. : CRoxieServerDiskReadBaseActivity(_factory, _probeManager, _remoteId, _numParts, _isLocal, _sorted, _maySkip, _manager)
  18434. {
  18435. compoundHelper = NULL;
  18436. readHelper = (IHThorXmlReadArg *)&helper;
  18437. localOffset = 0;
  18438. }
  18439. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  18440. {
  18441. rowLimit = readHelper->getRowLimit();
  18442. stopAfter = readHelper->getChooseNLimit();
  18443. CRoxieServerDiskReadBaseActivity::start(parentExtractSize, parentExtract, paused);
  18444. if (!useRemote())
  18445. {
  18446. rowTransformer.set(readHelper->queryTransformer());
  18447. assertex(reader != NULL);
  18448. OwnedRoxieString xmlIterator(readHelper->getXmlIteratorPath());
  18449. xmlParser.setown(createXMLParse(*reader->querySimpleStream(), xmlIterator, *this, (0 != (TDRxmlnoroot & readHelper->getFlags()))?ptr_noRoot:ptr_none, (readHelper->getFlags() & TDRusexmlcontents) != 0));
  18450. }
  18451. }
  18452. virtual void reset()
  18453. {
  18454. CRoxieServerDiskReadBaseActivity::reset();
  18455. rowTransformer.clear();
  18456. xmlParser.clear();
  18457. }
  18458. virtual void match(IColumnProvider &entry, offset_t startOffset, offset_t endOffset)
  18459. {
  18460. localOffset = startOffset;
  18461. lastMatch.set(&entry);
  18462. }
  18463. virtual const void *nextInGroup()
  18464. {
  18465. if (eof)
  18466. return NULL;
  18467. else if (useRemote())
  18468. return remote->nextInGroup();
  18469. assertex(xmlParser != NULL);
  18470. try
  18471. {
  18472. while (!eof)
  18473. {
  18474. //call to next() will callback on the IXmlSelect interface
  18475. bool gotNext = false;
  18476. gotNext = xmlParser->next();
  18477. if(!gotNext)
  18478. eof = true;
  18479. else if (lastMatch)
  18480. {
  18481. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  18482. unsigned sizeGot = rowTransformer->transform(rowBuilder, lastMatch, reader->queryThorDiskCallback());
  18483. lastMatch.clear();
  18484. localOffset = 0;
  18485. if (sizeGot)
  18486. {
  18487. OwnedConstRoxieRow ret = rowBuilder.finalizeRowClear(sizeGot);
  18488. if (processed > rowLimit)
  18489. {
  18490. if (traceLevel > 4)
  18491. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  18492. readHelper->onLimitExceeded();
  18493. throwUnexpected(); // onLimitExceeded is not supposed to return
  18494. }
  18495. processed++;
  18496. if (processed > stopAfter) // MORE - bit of a strange place to check
  18497. {
  18498. eof = true;
  18499. return NULL;
  18500. }
  18501. return ret.getClear();
  18502. }
  18503. }
  18504. }
  18505. return NULL;
  18506. }
  18507. catch(IException *E)
  18508. {
  18509. throw makeWrappedException(E);
  18510. }
  18511. }
  18512. };
  18513. class CRoxieServerCsvReadActivity : public CRoxieServerDiskReadBaseActivity
  18514. {
  18515. IHThorCsvReadArg *readHelper;
  18516. ICsvParameters * csvInfo;
  18517. unsigned headerLines;
  18518. unsigned maxDiskSize;
  18519. CSVSplitter csvSplitter;
  18520. unsigned __int64 localOffset;
  18521. const char *quotes;
  18522. const char *separators;
  18523. const char *terminators;
  18524. const char *escapes;
  18525. public:
  18526. CRoxieServerCsvReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  18527. unsigned _numParts, bool _isLocal, bool _sorted, bool _maySkip, IInMemoryIndexManager *_manager,
  18528. const char *_quotes, const char *_separators, const char *_terminators, const char *_escapes)
  18529. : CRoxieServerDiskReadBaseActivity(_factory, _probeManager, _remoteId, _numParts, _isLocal, _sorted, _maySkip, _manager),
  18530. quotes(_quotes), separators(_separators), terminators(_terminators), escapes(_escapes)
  18531. {
  18532. compoundHelper = NULL;
  18533. readHelper = (IHThorCsvReadArg *)&helper;
  18534. rowLimit = readHelper->getRowLimit();
  18535. stopAfter = readHelper->getChooseNLimit();
  18536. csvInfo = readHelper->queryCsvParameters();
  18537. maxDiskSize = csvInfo->queryMaxSize();
  18538. localOffset = 0;
  18539. headerLines = 0;
  18540. }
  18541. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  18542. {
  18543. rowLimit = readHelper->getRowLimit();
  18544. stopAfter = readHelper->getChooseNLimit();
  18545. CRoxieServerDiskReadBaseActivity::start(parentExtractSize, parentExtract, paused);
  18546. if (!useRemote())
  18547. {
  18548. headerLines = csvInfo->queryHeaderLen();
  18549. if (headerLines && isLocal && reader->queryFilePart() != 1)
  18550. 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...
  18551. if (!eof)
  18552. {
  18553. if (varFileInfo)
  18554. {
  18555. const IPropertyTree *options = varFileInfo->queryProperties();
  18556. if (options)
  18557. {
  18558. quotes = options->queryProp("@csvQuote");
  18559. separators = options->queryProp("@csvSeparate");
  18560. terminators = options->queryProp("@csvTerminate");
  18561. escapes = options->queryProp("@csvEscape");
  18562. }
  18563. }
  18564. csvSplitter.init(readHelper->getMaxColumns(), csvInfo, quotes, separators, terminators, escapes);
  18565. }
  18566. }
  18567. }
  18568. virtual const void *nextInGroup()
  18569. {
  18570. if (eof)
  18571. return NULL;
  18572. else if (useRemote())
  18573. return remote->nextInGroup();
  18574. try
  18575. {
  18576. while (!eof)
  18577. {
  18578. if (reader->eos())
  18579. {
  18580. eof = true;
  18581. break;
  18582. }
  18583. // MORE - there are rumours of a csvSplitter that operates on a stream... if/when it exists, this should use it
  18584. size32_t rowSize = 4096; // MORE - make configurable
  18585. size32_t maxRowSize = 10*1024*1024; // MORE - make configurable
  18586. size32_t thisLineLength;
  18587. loop
  18588. {
  18589. size32_t avail;
  18590. const void *peek = reader->peek(rowSize, avail);
  18591. thisLineLength = csvSplitter.splitLine(avail, (const byte *)peek);
  18592. if (thisLineLength < rowSize || avail < rowSize)
  18593. break;
  18594. if (rowSize == maxRowSize)
  18595. throw MakeStringException(0, "Row too big");
  18596. if (rowSize >= maxRowSize/2)
  18597. rowSize = maxRowSize;
  18598. else
  18599. rowSize += rowSize;
  18600. }
  18601. if (headerLines)
  18602. {
  18603. headerLines--;
  18604. reader->skip(thisLineLength);
  18605. }
  18606. else
  18607. {
  18608. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  18609. unsigned transformedSize = readHelper->transform(rowBuilder, csvSplitter.queryLengths(), (const char * *)csvSplitter.queryData());
  18610. reader->skip(thisLineLength);
  18611. if (transformedSize)
  18612. {
  18613. OwnedConstRoxieRow ret = rowBuilder.finalizeRowClear(transformedSize);
  18614. if (processed > rowLimit)
  18615. {
  18616. readHelper->onLimitExceeded();
  18617. throwUnexpected(); // onLimitExceeded is not supposed to return
  18618. }
  18619. processed++;
  18620. if (processed > stopAfter) // MORE - bit of a strange place to check
  18621. {
  18622. eof = true;
  18623. return NULL;
  18624. }
  18625. return ret.getClear();
  18626. }
  18627. }
  18628. }
  18629. return NULL;
  18630. }
  18631. catch(IException *E)
  18632. {
  18633. throw makeWrappedException(E);
  18634. }
  18635. }
  18636. virtual void reset()
  18637. {
  18638. CRoxieServerDiskReadBaseActivity::reset();
  18639. csvSplitter.reset();
  18640. localOffset = 0;
  18641. }
  18642. virtual unsigned __int64 getFilePosition(const void * row)
  18643. {
  18644. UNIMPLEMENTED; // we know offset in the reader but not sure it helps us much
  18645. }
  18646. virtual unsigned __int64 getLocalFilePosition(const void * row)
  18647. {
  18648. UNIMPLEMENTED;
  18649. }
  18650. };
  18651. class CRoxieServerDiskNormalizeActivity : public CRoxieServerDiskReadBaseActivity
  18652. {
  18653. IHThorDiskNormalizeArg *normalizeHelper;
  18654. bool firstPending;
  18655. public:
  18656. CRoxieServerDiskNormalizeActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, bool _sorted, IInMemoryIndexManager *_manager)
  18657. : CRoxieServerDiskReadBaseActivity(_factory, _probeManager, _remoteId, _numParts, _isLocal, _sorted, false, _manager)
  18658. {
  18659. compoundHelper = (IHThorDiskNormalizeArg *)&helper;
  18660. normalizeHelper = (IHThorDiskNormalizeArg *)&helper;
  18661. firstPending = true;
  18662. }
  18663. virtual void reset()
  18664. {
  18665. firstPending = true;
  18666. CRoxieServerDiskReadBaseActivity::reset();
  18667. }
  18668. virtual const void *nextInGroup()
  18669. {
  18670. if (eof)
  18671. return NULL;
  18672. else if (useRemote())
  18673. return remote->nextInGroup();
  18674. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  18675. unsigned transformedSize = 0;
  18676. if (isKeyed)
  18677. {
  18678. loop
  18679. {
  18680. while (firstPending)
  18681. {
  18682. const void *nextCandidate = cursor->nextMatch();
  18683. if (!nextCandidate)
  18684. {
  18685. eof = true;
  18686. return NULL;
  18687. }
  18688. if (normalizeHelper->first(nextCandidate))
  18689. {
  18690. firstPending = false;
  18691. break;
  18692. }
  18693. }
  18694. transformedSize = normalizeHelper->transform(rowBuilder);
  18695. firstPending = !normalizeHelper->next();
  18696. if (transformedSize)
  18697. break;
  18698. }
  18699. }
  18700. else
  18701. {
  18702. assertex(reader != NULL);
  18703. loop
  18704. {
  18705. while (firstPending)
  18706. {
  18707. if (deserializeSource.eos())
  18708. {
  18709. eof = true;
  18710. return NULL;
  18711. }
  18712. prefetcher->readAhead(deserializeSource);
  18713. const byte *nextRec = deserializeSource.queryRow();
  18714. if (!cursor || !cursor->isFiltered(nextRec))
  18715. {
  18716. if (normalizeHelper->first(nextRec))
  18717. firstPending = false;
  18718. }
  18719. deserializeSource.finishedRow();
  18720. }
  18721. transformedSize = normalizeHelper->transform(rowBuilder);
  18722. firstPending = !normalizeHelper->next();
  18723. if (transformedSize)
  18724. break;
  18725. }
  18726. }
  18727. OwnedConstRoxieRow recBuffer = rowBuilder.finalizeRowClear(transformedSize);
  18728. processed++;
  18729. if (processed > rowLimit)
  18730. {
  18731. compoundHelper->onLimitExceeded();
  18732. throwUnexpected(); // onLimitExceeded is not supposed to return
  18733. }
  18734. if (processed > stopAfter) // MORE - bit of a strange place to check
  18735. {
  18736. eof = true;
  18737. return NULL;
  18738. }
  18739. return recBuffer.getClear();
  18740. }
  18741. };
  18742. class CRoxieServerDiskAggregateBaseActivity : public CRoxieServerDiskReadBaseActivity
  18743. {
  18744. protected:
  18745. bool done;
  18746. public:
  18747. CRoxieServerDiskAggregateBaseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, IInMemoryIndexManager *_manager)
  18748. : CRoxieServerDiskReadBaseActivity(_factory, _probeManager, _remoteId, _numParts, _isLocal, false, false, _manager),
  18749. done(false)
  18750. {
  18751. }
  18752. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  18753. {
  18754. done = false;
  18755. CRoxieServerDiskReadBaseActivity::start(parentExtractSize, parentExtract, paused);
  18756. }
  18757. virtual IRoxieInput *queryOutput(unsigned idx)
  18758. {
  18759. if (idx==(unsigned)-1)
  18760. idx = 0;
  18761. return idx ? NULL: this;
  18762. }
  18763. };
  18764. class CRoxieServerDiskCountActivity : public CRoxieServerDiskAggregateBaseActivity
  18765. {
  18766. IHThorDiskCountArg & countHelper;
  18767. unsigned __int64 choosenLimit;
  18768. IHThorSourceCountLimit *limitHelper;
  18769. unsigned __int64 getSkippedCount()
  18770. {
  18771. unsigned flags = countHelper.getFlags();
  18772. if (flags & TDRlimitskips)
  18773. return 0;
  18774. else if (flags & TDRlimitcreates)
  18775. return 1;
  18776. else
  18777. {
  18778. assertex(limitHelper);
  18779. if (traceLevel > 4)
  18780. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  18781. limitHelper->onLimitExceeded();
  18782. throwUnexpected(); // onLimitExceeded should always throw exception
  18783. }
  18784. }
  18785. public:
  18786. CRoxieServerDiskCountActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, IInMemoryIndexManager *_manager)
  18787. : CRoxieServerDiskAggregateBaseActivity(_factory, _probeManager, _remoteId, _numParts, _isLocal, _manager),
  18788. countHelper((IHThorDiskCountArg &)basehelper)
  18789. {
  18790. limitHelper = static_cast<IHThorSourceCountLimit *>(basehelper.selectInterface(TAIsourcecountlimit_1));
  18791. choosenLimit = 0;
  18792. }
  18793. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  18794. {
  18795. choosenLimit = countHelper.getChooseNLimit();
  18796. if (limitHelper)
  18797. {
  18798. rowLimit = limitHelper->getRowLimit();
  18799. // keyedLimit = limitHelper->getKeyedLimit(); // more - should there be one?
  18800. }
  18801. CRoxieServerDiskAggregateBaseActivity::start(parentExtractSize, parentExtract, paused);
  18802. }
  18803. virtual const void *nextInGroup()
  18804. {
  18805. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  18806. if (done) return NULL;
  18807. done = true;
  18808. unsigned __int64 totalCount = 0;
  18809. if (helper.canMatchAny() && !eof)
  18810. {
  18811. if (useRemote())
  18812. {
  18813. loop
  18814. {
  18815. const void * next = remote->nextInGroup();
  18816. if (!next)
  18817. break;
  18818. if (meta.getFixedSize() == 1)
  18819. totalCount += *(byte *)next;
  18820. else
  18821. totalCount += *(unsigned __int64 *)next;
  18822. ReleaseRoxieRow(next);
  18823. if (totalCount > rowLimit)
  18824. {
  18825. totalCount = getSkippedCount();
  18826. break;
  18827. }
  18828. else if (totalCount >= choosenLimit)
  18829. {
  18830. totalCount = choosenLimit;
  18831. break;
  18832. }
  18833. }
  18834. }
  18835. else
  18836. {
  18837. if (isKeyed)
  18838. {
  18839. loop
  18840. {
  18841. const void *nextCandidate = cursor->nextMatch();
  18842. if (!nextCandidate)
  18843. break;
  18844. totalCount += countHelper.numValid(nextCandidate);
  18845. if (totalCount > rowLimit)
  18846. {
  18847. totalCount = getSkippedCount();
  18848. break;
  18849. }
  18850. else if (totalCount >= choosenLimit)
  18851. {
  18852. totalCount = choosenLimit;
  18853. break;
  18854. }
  18855. }
  18856. }
  18857. else
  18858. {
  18859. assertex(reader != NULL);
  18860. while (!deserializeSource.eos())
  18861. {
  18862. prefetcher->readAhead(deserializeSource);
  18863. const byte *nextRec = deserializeSource.queryRow();
  18864. if (!cursor || !cursor->isFiltered(nextRec))
  18865. {
  18866. totalCount += countHelper.numValid(nextRec);
  18867. }
  18868. deserializeSource.finishedRow();
  18869. if (totalCount > rowLimit)
  18870. {
  18871. totalCount = getSkippedCount();
  18872. break;
  18873. }
  18874. else if (totalCount >= choosenLimit)
  18875. {
  18876. totalCount = choosenLimit;
  18877. break;
  18878. }
  18879. }
  18880. }
  18881. }
  18882. }
  18883. size32_t rowSize = meta.getFixedSize();
  18884. void * result = rowAllocator->createRow();
  18885. if (rowSize == 1)
  18886. *(byte *)result = (byte)totalCount;
  18887. else
  18888. {
  18889. assertex(rowSize == sizeof(unsigned __int64));
  18890. *(unsigned __int64 *)result = totalCount;
  18891. }
  18892. return rowAllocator->finalizeRow(rowSize, result, rowSize);
  18893. }
  18894. };
  18895. class CRoxieServerDiskAggregateActivity : public CRoxieServerDiskAggregateBaseActivity
  18896. {
  18897. IHThorCompoundAggregateExtra & aggregateHelper;
  18898. public:
  18899. CRoxieServerDiskAggregateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  18900. unsigned _numParts, bool _isLocal, IInMemoryIndexManager *_manager)
  18901. : CRoxieServerDiskAggregateBaseActivity(_factory, _probeManager, _remoteId, _numParts, _isLocal, _manager),
  18902. aggregateHelper((IHThorDiskAggregateArg &)basehelper)
  18903. {
  18904. }
  18905. const void * gatherMerged()
  18906. {
  18907. RtlDynamicRowBuilder rowBuilder(rowAllocator, false);
  18908. size32_t finalSize = 0;
  18909. if (useRemote())
  18910. {
  18911. const void * firstRow = remote->nextInGroup();
  18912. if (!firstRow)
  18913. {
  18914. rowBuilder.ensureRow();
  18915. finalSize = aggregateHelper.clearAggregate(rowBuilder);
  18916. }
  18917. else
  18918. {
  18919. // NOTE need to clone this because going to modify below, could special case 1 row only
  18920. finalSize = cloneRow(rowBuilder, firstRow, meta);
  18921. ReleaseRoxieRow(firstRow);
  18922. }
  18923. loop
  18924. {
  18925. const void * next = remote->nextInGroup();
  18926. if (!next)
  18927. break;
  18928. finalSize = aggregateHelper.mergeAggregate(rowBuilder, next);
  18929. ReleaseRoxieRow(next);
  18930. }
  18931. }
  18932. else
  18933. {
  18934. aggregateHelper.clearAggregate(rowBuilder);
  18935. if (helper.canMatchAny() && !eof)
  18936. {
  18937. if (isKeyed)
  18938. {
  18939. loop
  18940. {
  18941. const void *next = cursor->nextMatch();
  18942. if (!next)
  18943. break;
  18944. aggregateHelper.processRow(rowBuilder, next);
  18945. }
  18946. }
  18947. else
  18948. {
  18949. assertex(reader != NULL);
  18950. while (!deserializeSource.eos())
  18951. {
  18952. prefetcher->readAhead(deserializeSource);
  18953. const byte *nextRec = deserializeSource.queryRow();
  18954. if (!cursor || !cursor->isFiltered(nextRec))
  18955. {
  18956. aggregateHelper.processRow(rowBuilder, nextRec);
  18957. }
  18958. deserializeSource.finishedRow();
  18959. }
  18960. }
  18961. }
  18962. finalSize = meta.getRecordSize(rowBuilder.getSelf());
  18963. }
  18964. return rowBuilder.finalizeRowClear(finalSize);
  18965. }
  18966. virtual const void *nextInGroup()
  18967. {
  18968. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  18969. if (done) return NULL;
  18970. const void * ret = gatherMerged();
  18971. done = true;
  18972. return ret;
  18973. }
  18974. };
  18975. class CRoxieServerDiskGroupAggregateActivity : public CRoxieServerDiskAggregateBaseActivity
  18976. {
  18977. IHThorDiskGroupAggregateArg & aggregateHelper;
  18978. RowAggregator resultAggregator;
  18979. bool gathered;
  18980. public:
  18981. IMPLEMENT_IINTERFACE;
  18982. CRoxieServerDiskGroupAggregateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, IInMemoryIndexManager *_manager)
  18983. : CRoxieServerDiskAggregateBaseActivity(_factory, _probeManager, _remoteId, _numParts, _isLocal, _manager),
  18984. aggregateHelper((IHThorDiskGroupAggregateArg &)basehelper),
  18985. resultAggregator(aggregateHelper, aggregateHelper),
  18986. gathered(false)
  18987. {
  18988. }
  18989. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  18990. {
  18991. gathered= false;
  18992. CRoxieServerDiskAggregateBaseActivity::start(parentExtractSize, parentExtract, paused);
  18993. resultAggregator.start(rowAllocator);
  18994. }
  18995. virtual void reset()
  18996. {
  18997. resultAggregator.reset();
  18998. CRoxieServerDiskAggregateBaseActivity::reset();
  18999. }
  19000. void gatherMerged()
  19001. {
  19002. if (useRemote())
  19003. {
  19004. loop
  19005. {
  19006. const void * next = remote->nextInGroup();
  19007. if (!next)
  19008. break;
  19009. resultAggregator.mergeElement(next);
  19010. ReleaseRoxieRow(next);
  19011. }
  19012. }
  19013. else
  19014. {
  19015. if (helper.canMatchAny() && !eof)
  19016. {
  19017. Owned<IInMemoryFileProcessor> processor = isKeyed ?
  19018. createKeyedGroupAggregateRecordProcessor(cursor, resultAggregator, aggregateHelper) :
  19019. createUnkeyedGroupAggregateRecordProcessor(cursor, resultAggregator, aggregateHelper, manager->createReader(0, 0, 1),
  19020. ctx->queryCodeContext(), activityId);
  19021. processor->doQuery(NULL, 0, 0, 0);
  19022. }
  19023. }
  19024. gathered = true;
  19025. }
  19026. virtual const void *nextInGroup()
  19027. {
  19028. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  19029. if (done)
  19030. return NULL;
  19031. if (!gathered)
  19032. gatherMerged();
  19033. Owned<AggregateRowBuilder> next = resultAggregator.nextResult();
  19034. if (next)
  19035. {
  19036. processed++;
  19037. return next->finalizeRowClear();
  19038. }
  19039. done = true;
  19040. return NULL;
  19041. }
  19042. };
  19043. class CRoxieServerDiskReadActivityFactory : public CRoxieServerActivityFactory
  19044. {
  19045. public:
  19046. RemoteActivityId remoteId;
  19047. bool isLocal;
  19048. bool sorted;
  19049. bool maySkip;
  19050. bool variableFileName;
  19051. Owned<IFilePartMap> map;
  19052. Owned<IFileIOArray> files;
  19053. Owned<IInMemoryIndexManager> manager;
  19054. Owned<const IResolvedFile> datafile;
  19055. const char *quotes;
  19056. const char *separators;
  19057. const char *terminators;
  19058. const char *escapes;
  19059. CRoxieServerDiskReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  19060. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), remoteId(_remoteId)
  19061. {
  19062. isLocal = _graphNode.getPropBool("att[@name='local']/@value") && queryFactory.queryChannel()!=0;
  19063. Owned<IHThorDiskReadBaseArg> helper = (IHThorDiskReadBaseArg *) helperFactory();
  19064. sorted = (helper->getFlags() & TDRunsorted) == 0;
  19065. variableFileName = allFilesDynamic || _queryFactory.isDynamic() || ((helper->getFlags() & (TDXvarfilename|TDXdynamicfilename)) != 0);
  19066. maySkip = (helper->getFlags() & (TDRkeyedlimitskips|TDRkeyedlimitcreates|TDRlimitskips|TDRlimitcreates)) != 0;
  19067. quotes = separators = terminators = escapes = NULL;
  19068. if (!variableFileName)
  19069. {
  19070. bool isOpt = (helper->getFlags() & TDRoptional) != 0;
  19071. OwnedRoxieString fileName(helper->getFileName());
  19072. datafile.setown(_queryFactory.queryPackage().lookupFileName(fileName, isOpt, true, true, _queryFactory.queryWorkUnit()));
  19073. if (datafile)
  19074. map.setown(datafile->getFileMap());
  19075. bool isSimple = (map && map->getNumParts()==1 && !_queryFactory.getDebugValueBool("disableLocalOptimizations", false));
  19076. if (isLocal || isSimple)
  19077. {
  19078. if (datafile)
  19079. {
  19080. unsigned channel = isLocal ? queryFactory.queryChannel() : 0;
  19081. files.setown(datafile->getIFileIOArray(isOpt, channel));
  19082. manager.setown(datafile->getIndexManager(isOpt, channel, files, helper->queryDiskRecordSize(), _graphNode.getPropBool("att[@name=\"preload\"]/@value", false), _graphNode.getPropInt("att[@name=\"_preloadSize\"]/@value", 0)));
  19083. const IPropertyTree *options = datafile->queryProperties();
  19084. if (options)
  19085. {
  19086. quotes = options->queryProp("@csvQuote");
  19087. separators = options->queryProp("@csvSeparate");
  19088. terminators = options->queryProp("@csvTerminate");
  19089. escapes = options->queryProp("@csvEscape");
  19090. }
  19091. }
  19092. else
  19093. manager.setown(getEmptyIndexManager());
  19094. }
  19095. }
  19096. }
  19097. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  19098. {
  19099. unsigned numParts = map ? map->getNumParts() : 0;
  19100. switch (kind)
  19101. {
  19102. case TAKcsvread:
  19103. return new CRoxieServerCsvReadActivity(this, _probeManager, remoteId, numParts, isLocal, sorted, maySkip, manager,
  19104. quotes, separators, terminators, escapes);
  19105. case TAKxmlread:
  19106. return new CRoxieServerXmlReadActivity(this, _probeManager, remoteId, numParts, isLocal, sorted, maySkip, manager);
  19107. case TAKdiskread:
  19108. return new CRoxieServerDiskReadActivity(this, _probeManager, remoteId, numParts, isLocal, sorted, maySkip, manager);
  19109. case TAKdisknormalize:
  19110. return new CRoxieServerDiskNormalizeActivity(this, _probeManager, remoteId, numParts, isLocal, sorted, manager);
  19111. case TAKdiskcount:
  19112. return new CRoxieServerDiskCountActivity(this, _probeManager, remoteId, numParts, isLocal, manager);
  19113. case TAKdiskaggregate:
  19114. return new CRoxieServerDiskAggregateActivity(this, _probeManager, remoteId, numParts, isLocal, manager);
  19115. case TAKdiskgroupaggregate:
  19116. return new CRoxieServerDiskGroupAggregateActivity(this, _probeManager, remoteId, numParts, isLocal, manager);
  19117. }
  19118. throwUnexpected();
  19119. }
  19120. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  19121. {
  19122. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for %s activity", getActivityText(kind));
  19123. }
  19124. virtual void getXrefInfo(IPropertyTree &reply, const IRoxieContextLogger &logctx) const
  19125. {
  19126. if (datafile)
  19127. addXrefFileInfo(reply, datafile);
  19128. }
  19129. };
  19130. IRoxieServerActivityFactory *createRoxieServerDiskReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  19131. {
  19132. return new CRoxieServerDiskReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode);
  19133. }
  19134. //=================================================================================
  19135. class CRoxieServerIndexActivity : public CRoxieServerActivity, implements IRoxieServerErrorHandler
  19136. {
  19137. protected:
  19138. IHThorIndexReadBaseArg &indexHelper;
  19139. IHThorSteppedSourceExtra * steppedExtra;
  19140. Linked<IKeyArray> keySet;
  19141. Linked<TranslatorArray> translators;
  19142. CSkippableRemoteResultAdaptor remote;
  19143. CIndexTransformCallback callback;
  19144. bool sorted;
  19145. bool variableFileName;
  19146. bool variableInfoPending;
  19147. bool isOpt;
  19148. bool isLocal;
  19149. unsigned __int64 rowLimit;
  19150. unsigned __int64 keyedLimit;
  19151. unsigned __int64 choosenLimit;
  19152. unsigned accepted;
  19153. unsigned rejected;
  19154. unsigned seekGEOffset;
  19155. Owned<IKeyManager> tlk;
  19156. Owned<const IResolvedFile> varFileInfo;
  19157. const RemoteActivityId &remoteId;
  19158. void setVariableFileInfo()
  19159. {
  19160. OwnedRoxieString indexName(indexHelper.getFileName());
  19161. varFileInfo.setown(resolveLFN(indexName, isOpt));
  19162. if (varFileInfo)
  19163. {
  19164. translators.setown(new TranslatorArray) ;
  19165. keySet.setown(varFileInfo->getKeyArray(factory->queryActivityMeta(), translators, isOpt, isLocal ? factory->queryQueryFactory().queryChannel() : 0, factory->queryQueryFactory().getEnableFieldTranslation()));
  19166. }
  19167. variableInfoPending = false;
  19168. }
  19169. public:
  19170. CRoxieServerIndexActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  19171. IKeyArray * _keySet, TranslatorArray *_translators, bool _sorted, bool _isLocal, bool _maySkip)
  19172. : CRoxieServerActivity(_factory, _probeManager),
  19173. keySet(_keySet),
  19174. translators(_translators),
  19175. indexHelper((IHThorIndexReadBaseArg &)basehelper),
  19176. remote(_remoteId, meta.queryOriginal(), indexHelper, *this, _sorted, false, _maySkip),
  19177. remoteId(_remoteId),
  19178. sorted(_sorted),
  19179. isLocal(_isLocal)
  19180. {
  19181. indexHelper.setCallback(&callback);
  19182. steppedExtra = static_cast<IHThorSteppedSourceExtra *>(indexHelper.selectInterface(TAIsteppedsourceextra_1));
  19183. variableFileName = allFilesDynamic || factory->queryQueryFactory().isDynamic() || ((indexHelper.getFlags() & (TIRvarfilename|TIRdynamicfilename)) != 0);
  19184. variableInfoPending = false;
  19185. isOpt = (indexHelper.getFlags() & TIRoptional) != 0;
  19186. seekGEOffset = 0;
  19187. // started = false;
  19188. rejected = accepted = 0;
  19189. rowLimit = choosenLimit = keyedLimit = 0;
  19190. }
  19191. virtual const IResolvedFile *queryVarFileInfo() const
  19192. {
  19193. return varFileInfo;
  19194. }
  19195. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  19196. {
  19197. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  19198. remote.onCreate(this, this, _ctx, _colocalParent);
  19199. }
  19200. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  19201. {
  19202. accepted = 0;
  19203. rejected = 0;
  19204. rowLimit = (unsigned __int64) -1;
  19205. keyedLimit = (unsigned __int64 ) -1;
  19206. choosenLimit = I64C(0x7fffffffffffffff);
  19207. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  19208. remote.onStart(parentExtractSize, parentExtract);
  19209. variableInfoPending = variableFileName;
  19210. }
  19211. void processAllKeys()
  19212. {
  19213. try
  19214. {
  19215. if (indexHelper.canMatchAny())
  19216. {
  19217. if (variableInfoPending)
  19218. setVariableFileInfo();
  19219. remote.setLimits(rowLimit, keyedLimit, choosenLimit);
  19220. if (keySet)
  19221. {
  19222. // MORE - this recreates the segmonitors per part but not per fileno (which is a little backwards).
  19223. // 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
  19224. // However order is probably better to iterate fileno's inside partnos
  19225. // MORE - also not properly supporting STEPPED I fear.
  19226. // A superkey that mixes single and multipart or tlk and roroot keys might be hard
  19227. for (unsigned partNo = 0; partNo < keySet->length(); partNo++)
  19228. {
  19229. IKeyIndexBase *thisBase = keySet->queryKeyPart(partNo);
  19230. if (thisBase)
  19231. {
  19232. unsigned fileNo = 0;
  19233. IKeyIndex *thisKey = thisBase->queryPart(fileNo);
  19234. if (!thisKey->isTopLevelKey())
  19235. {
  19236. if (keyedLimit != (unsigned __int64) -1)
  19237. {
  19238. if ((indexHelper.getFlags() & TIRcountkeyedlimit) != 0)
  19239. {
  19240. Owned<IKeyManager> countKey;
  19241. countKey.setown(createKeyManager(thisKey, 0, this));
  19242. countKey->setLayoutTranslator(translators->item(fileNo));
  19243. createSegmentMonitors(countKey);
  19244. unsigned __int64 count = countKey->checkCount(keyedLimit);
  19245. if (count > keyedLimit)
  19246. {
  19247. if (traceLevel > 4)
  19248. DBGLOG("activityid = %d line = %d", activityId, __LINE__);
  19249. onLimitExceeded(true);
  19250. }
  19251. }
  19252. }
  19253. }
  19254. if (seekGEOffset && !thisKey->isTopLevelKey())
  19255. {
  19256. tlk.setown(createSingleKeyMerger(thisKey, 0, seekGEOffset, this));
  19257. }
  19258. else
  19259. {
  19260. tlk.setown(createKeyManager(thisKey, 0, this));
  19261. tlk->setLayoutTranslator(translators->item(fileNo));
  19262. }
  19263. createSegmentMonitors(tlk);
  19264. if (queryTraceLevel() > 3 || ctx->queryProbeManager())
  19265. {
  19266. StringBuffer out;
  19267. printKeyedValues(out, tlk, indexHelper.queryDiskRecordSize());
  19268. CTXLOG("Using filter %s", out.str());
  19269. if (ctx->queryProbeManager())
  19270. ctx->queryProbeManager()->setNodeProperty(this, "filter", out.str());
  19271. }
  19272. tlk->reset();
  19273. loop // for each file part
  19274. {
  19275. //block for TransformCallbackAssociation
  19276. {
  19277. TransformCallbackAssociation associate(callback, tlk);
  19278. if (thisKey->isTopLevelKey())
  19279. {
  19280. if (thisKey->isFullySorted())
  19281. {
  19282. while (tlk->lookup(false))
  19283. {
  19284. unsigned slavePart = (unsigned) tlk->queryFpos();
  19285. if (slavePart)
  19286. {
  19287. accepted++;
  19288. remote.getMem(slavePart, fileNo, 0); // the cached context is all we need to send
  19289. if (sorted && numChannels>1)
  19290. remote.flush(); // don't combine parts if we need result sorted, except on a 1-way
  19291. }
  19292. }
  19293. }
  19294. else
  19295. {
  19296. // MORE - we could check whether there are any matching parts if we wanted.
  19297. // If people are in the habit of sending null values that would be worthwhile
  19298. remote.getMem(0, fileNo, 0);
  19299. }
  19300. }
  19301. else
  19302. {
  19303. if (processSingleKey(thisKey, translators->item(fileNo)))
  19304. break;
  19305. }
  19306. }
  19307. if (++fileNo < thisBase->numParts())
  19308. {
  19309. thisKey = thisBase->queryPart(fileNo);
  19310. tlk->setKey(thisKey);
  19311. tlk->setLayoutTranslator(translators->item(fileNo));
  19312. tlk->reset();
  19313. }
  19314. else
  19315. break;
  19316. }
  19317. tlk->releaseSegmentMonitors();
  19318. tlk->setKey(NULL);
  19319. }
  19320. }
  19321. }
  19322. }
  19323. remote.flush();
  19324. remote.senddone();
  19325. }
  19326. catch (IException *E)
  19327. {
  19328. remote.setException(E);
  19329. }
  19330. }
  19331. virtual void createSegmentMonitors(IKeyManager *key)
  19332. {
  19333. indexHelper.createSegmentMonitors(key);
  19334. key->finishSegmentMonitors();
  19335. }
  19336. virtual bool processSingleKey(IKeyIndex *key, IRecordLayoutTranslator * trans) = 0;
  19337. virtual void reset()
  19338. {
  19339. if (accepted)
  19340. noteStatistic(STATS_ACCEPTED, accepted, 1);
  19341. if (rejected)
  19342. noteStatistic(STATS_REJECTED, rejected, 1);
  19343. remote.onReset();
  19344. CRoxieServerActivity::reset();
  19345. if (varFileInfo)
  19346. {
  19347. keySet.clear();
  19348. varFileInfo.clear();
  19349. }
  19350. variableInfoPending = false;
  19351. }
  19352. virtual void stop(bool aborting)
  19353. {
  19354. remote.onStop(aborting);
  19355. CRoxieServerActivity::stop(aborting);
  19356. }
  19357. virtual void setInput(unsigned idx, IRoxieInput *_in)
  19358. {
  19359. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  19360. }
  19361. };
  19362. class CRoxieServerIndexReadBaseActivity : public CRoxieServerIndexActivity
  19363. {
  19364. IHThorSourceLimitTransformExtra * limitTransformExtra;
  19365. public:
  19366. CRoxieServerIndexReadBaseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  19367. IKeyArray * _keySet, TranslatorArray *_translators, bool _sorted, bool _isLocal, bool _maySkip)
  19368. : CRoxieServerIndexActivity(_factory, _probeManager, _remoteId, _keySet, _translators, _sorted, _isLocal, _maySkip)
  19369. {
  19370. limitTransformExtra = static_cast<IHThorSourceLimitTransformExtra *>(indexHelper.selectInterface(TAIsourcelimittransformextra_1));
  19371. }
  19372. virtual void reset()
  19373. {
  19374. remote.onReset();
  19375. CRoxieServerIndexActivity::reset();
  19376. }
  19377. virtual const void *nextInGroup()
  19378. {
  19379. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  19380. try
  19381. {
  19382. const void *ret = remote.nextInGroup();
  19383. if (ret)
  19384. processed++;
  19385. return ret;
  19386. }
  19387. catch (IException *E)
  19388. {
  19389. throw makeWrappedException(E);
  19390. }
  19391. }
  19392. protected:
  19393. virtual const void * createLimitFailRow(bool isKeyed)
  19394. {
  19395. createRowAllocator();
  19396. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  19397. size32_t outSize = isKeyed ? limitTransformExtra->transformOnKeyedLimitExceeded(rowBuilder) : limitTransformExtra->transformOnLimitExceeded(rowBuilder);
  19398. if (outSize)
  19399. return rowBuilder.finalizeRowClear(outSize);
  19400. return NULL;
  19401. }
  19402. };
  19403. class CRoxieServerIndexReadActivity : public CRoxieServerIndexReadBaseActivity, implements IIndexReadActivityInfo
  19404. {
  19405. protected:
  19406. IHThorCompoundReadExtra & readHelper;
  19407. ISteppingMeta *rawMeta;
  19408. CSteppingMeta steppingMeta;
  19409. unsigned * seekSizes;
  19410. bool optimizeSteppedPostFilter;
  19411. ISteppingMeta * projectedMeta;
  19412. unsigned maxSeekLookahead;
  19413. public:
  19414. CRoxieServerIndexReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  19415. IKeyArray * _keySet, TranslatorArray *_translators, bool _sorted, bool _isLocal, bool _maySkip, unsigned _maxSeekLookahead)
  19416. : CRoxieServerIndexReadBaseActivity(_factory, _probeManager, _remoteId, _keySet, _translators, _sorted, _isLocal, _maySkip),
  19417. readHelper((IHThorIndexReadArg &)basehelper)
  19418. {
  19419. rawMeta = readHelper.queryRawSteppingMeta();
  19420. unsigned flags = indexHelper.getFlags();
  19421. optimizeSteppedPostFilter = (flags & TIRunfilteredtransform) != 0;
  19422. seekSizes = NULL;
  19423. maxSeekLookahead = _maxSeekLookahead;
  19424. if (rawMeta)
  19425. {
  19426. const CFieldOffsetSize * fields = rawMeta->queryFields();
  19427. unsigned maxFields = rawMeta->getNumFields();
  19428. seekGEOffset = fields[0].offset;
  19429. seekSizes = new unsigned[maxFields];
  19430. seekSizes[0] = fields[0].size;
  19431. for (unsigned i=1; i < maxFields; i++)
  19432. seekSizes[i] = seekSizes[i-1] + fields[i].size;
  19433. projectedMeta = readHelper.queryProjectedSteppingMeta();
  19434. ISteppingMeta *useMeta = projectedMeta ? projectedMeta : rawMeta;
  19435. remote.setMergeInfo(useMeta); // also need to consider superfile case where there is a mix of multiway and singleparts.. ?
  19436. bool hasPostFilter = readHelper.transformMayFilter() && optimizeSteppedPostFilter;
  19437. steppingMeta.init(useMeta, hasPostFilter);
  19438. }
  19439. }
  19440. ~CRoxieServerIndexReadActivity()
  19441. {
  19442. delete [] seekSizes;
  19443. }
  19444. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  19445. {
  19446. CRoxieServerIndexReadBaseActivity::start(parentExtractSize, parentExtract, paused);
  19447. steppingMeta.setDistributed();
  19448. if (steppedExtra)
  19449. steppingMeta.setExtra(steppedExtra);
  19450. rowLimit = readHelper.getRowLimit();
  19451. keyedLimit = readHelper.getKeyedLimit();
  19452. choosenLimit = readHelper.getChooseNLimit();
  19453. if (!paused)
  19454. processAllKeys();
  19455. }
  19456. class LazyLocalKeyReader : public CInterface, implements IMessageResult, implements IMessageUnpackCursor
  19457. {
  19458. public:
  19459. IMPLEMENT_IINTERFACE;
  19460. virtual IMessageUnpackCursor *getCursor(roxiemem::IRowManager *rowMgr) const
  19461. {
  19462. Link();
  19463. return const_cast<LazyLocalKeyReader*> (this);
  19464. }
  19465. virtual const void *getMessageHeader(unsigned &length) const
  19466. {
  19467. length = 0;
  19468. return NULL;
  19469. }
  19470. virtual const void *getMessageMetadata(unsigned &length) const
  19471. {
  19472. length = 0;
  19473. return NULL;
  19474. }
  19475. virtual void discard() const
  19476. {
  19477. // nothing to do.
  19478. }
  19479. unsigned keyedCount;
  19480. unsigned matched;
  19481. bool EOFseen;
  19482. Owned<IKeyIndexSet> keySet;
  19483. Owned<IKeyManager> tlk;
  19484. CRoxieServerIndexReadActivity &owner;
  19485. LazyLocalKeyReader(CRoxieServerIndexReadActivity &_owner, IKeyIndex *key, IRecordLayoutTranslator * trans)
  19486. : owner(_owner)
  19487. {
  19488. keyedCount = 0;
  19489. matched = 0;
  19490. EOFseen = false;
  19491. keySet.setown(createKeyIndexSet());
  19492. keySet->addIndex(LINK(key));
  19493. if (owner.seekGEOffset)
  19494. tlk.setown(createKeyMerger(keySet, 0, owner.seekGEOffset, &owner));
  19495. else
  19496. tlk.setown(createKeyManager(keySet->queryPart(0), 0, &owner));
  19497. tlk->setLayoutTranslator(trans);
  19498. owner.indexHelper.createSegmentMonitors(tlk);
  19499. tlk->finishSegmentMonitors();
  19500. tlk->reset();
  19501. }
  19502. virtual const void *getNext(int length)
  19503. {
  19504. TransformCallbackAssociation associate(owner.callback, tlk);
  19505. while (tlk->lookup(true))
  19506. {
  19507. keyedCount++;
  19508. if (keyedCount > owner.keyedLimit)
  19509. {
  19510. owner.onLimitExceeded(true); // Should throw exception
  19511. throwUnexpected();
  19512. }
  19513. size32_t transformedSize;
  19514. RtlDynamicRowBuilder rowBuilder(owner.rowAllocator);
  19515. byte const * keyRow = tlk->queryKeyBuffer(owner.callback.getFPosRef());
  19516. try
  19517. {
  19518. transformedSize = owner.readHelper.transform(rowBuilder, keyRow);
  19519. owner.callback.finishedRow();
  19520. }
  19521. catch (IException *E)
  19522. {
  19523. throw owner.makeWrappedException(E);
  19524. }
  19525. if (transformedSize)
  19526. {
  19527. OwnedConstRoxieRow result = rowBuilder.finalizeRowClear(transformedSize);
  19528. matched++;
  19529. if (matched > owner.rowLimit)
  19530. {
  19531. owner.onLimitExceeded(false); // Should throw exception
  19532. throwUnexpected();
  19533. }
  19534. if (matched > owner.choosenLimit) // MORE - bit of a strange place to check
  19535. {
  19536. break;
  19537. }
  19538. owner.accepted++;
  19539. return result.getClear();
  19540. }
  19541. else
  19542. owner.rejected++;
  19543. }
  19544. EOFseen = true;
  19545. return NULL;
  19546. }
  19547. virtual bool atEOF() const
  19548. {
  19549. return EOFseen;
  19550. }
  19551. virtual bool isSerialized() const
  19552. {
  19553. return false;
  19554. }
  19555. };
  19556. virtual bool processSingleKey(IKeyIndex *key, IRecordLayoutTranslator * trans)
  19557. {
  19558. createRowAllocator();
  19559. remote.injectResult(new LazyLocalKeyReader(*this, key, trans));
  19560. return false;
  19561. }
  19562. virtual void onLimitExceeded(bool isKeyed)
  19563. {
  19564. if (traceLevel > 4)
  19565. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  19566. if (isKeyed)
  19567. {
  19568. if (indexHelper.getFlags() & (TIRkeyedlimitskips|TIRkeyedlimitcreates))
  19569. {
  19570. if (ctx->queryDebugContext())
  19571. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  19572. throw makeLimitSkipException(true);
  19573. }
  19574. else
  19575. readHelper.onKeyedLimitExceeded();
  19576. }
  19577. else
  19578. {
  19579. if (indexHelper.getFlags() & (TIRlimitskips|TIRlimitcreates))
  19580. {
  19581. if (ctx->queryDebugContext())
  19582. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  19583. throw makeLimitSkipException(false);
  19584. }
  19585. else
  19586. readHelper.onLimitExceeded();
  19587. }
  19588. }
  19589. virtual void serializeSkipInfo(MemoryBuffer &out, unsigned seekLen, const void *rawSeek, unsigned numFields, const void * seek, const SmartStepExtra &stepExtra) const
  19590. {
  19591. out.append((unsigned short) numFields);
  19592. out.append((unsigned short) seekLen);
  19593. out.append((unsigned short) stepExtra.queryFlags());
  19594. IMultipleStepSeekInfo *seeks = stepExtra.queryExtraSeeks();
  19595. if (seeks)
  19596. {
  19597. unsigned lookahead = 40000/seekLen;
  19598. if (maxSeekLookahead && (lookahead > maxSeekLookahead))
  19599. lookahead = maxSeekLookahead;
  19600. seeks->ensureFilled(seek, numFields, lookahead);
  19601. out.append(lookahead != seeks->ordinality()); // seeksAreEof flag
  19602. unsigned serialized = 1; // rawseek is always serialized...
  19603. unsigned patchLength = out.length();
  19604. out.append(serialized); // NOTE - we come back and patch with the actual value...
  19605. out.append(seekLen, rawSeek);
  19606. if (seeks->ordinality())
  19607. {
  19608. const void *lastSeek = rawSeek;
  19609. byte *nextSeek = NULL;
  19610. if (projectedMeta)
  19611. nextSeek = (byte *) alloca(seekLen);
  19612. for (unsigned i = 0; i < seeks->ordinality(); i++)
  19613. {
  19614. if (projectedMeta)
  19615. {
  19616. RtlStaticRowBuilder rowBuilder(nextSeek-seekGEOffset, seekGEOffset+seekLen);
  19617. readHelper.mapOutputToInput(rowBuilder, seeks->querySeek(i), numFields); // NOTE - weird interface to mapOutputToInput means that it STARTS writing at seekGEOffset...
  19618. }
  19619. else
  19620. nextSeek = (byte *) seeks->querySeek(i)+seekGEOffset;
  19621. int diff = memcmp(nextSeek, lastSeek, seekLen);
  19622. if (diff > 0)
  19623. {
  19624. serialized++;
  19625. out.append(seekLen, nextSeek);
  19626. lastSeek = (const byte *) out.reserve(0) - seekLen;
  19627. }
  19628. }
  19629. unsigned length = out.length();
  19630. out.setWritePos(patchLength);
  19631. out.append(serialized);
  19632. out.setWritePos(length);
  19633. }
  19634. }
  19635. else
  19636. {
  19637. out.append(false);
  19638. out.append(1);
  19639. out.append(seekLen, rawSeek);
  19640. }
  19641. }
  19642. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  19643. {
  19644. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  19645. try
  19646. {
  19647. unsigned seeklen = 0;
  19648. const void *rawSeek = NULL;
  19649. if (seek && numFields)
  19650. {
  19651. seeklen = seekSizes[numFields-1];
  19652. rawSeek = (const byte *)seek + seekGEOffset;
  19653. if (projectedMeta)
  19654. {
  19655. byte * temp = (byte *) alloca(seeklen);
  19656. RtlStaticRowBuilder rawBuilder(temp-seekGEOffset, seekGEOffset+seeklen);
  19657. readHelper.mapOutputToInput(rawBuilder, seek, numFields); // NOTE - weird interface to mapOutputToInput means that it STARTS writing at seekGEOffset...
  19658. rawSeek = (byte *)temp;
  19659. }
  19660. }
  19661. const void *ret = remote.nextSteppedGE(seek, rawSeek, numFields, seeklen, wasCompleteMatch, stepExtra);
  19662. if (ret && wasCompleteMatch) // GH pleas confirm the wasCompleteMatch I just added here is right
  19663. processed++;
  19664. return ret;
  19665. }
  19666. catch (IException *E)
  19667. {
  19668. throw makeWrappedException(E);
  19669. }
  19670. }
  19671. virtual IInputSteppingMeta * querySteppingMeta()
  19672. {
  19673. if (rawMeta && steppingEnabled && ((indexHelper.getFlags() & (TIRlimitskips|TIRlimitcreates|TIRkeyedlimitskips|TIRkeyedlimitcreates)) == 0))
  19674. return &steppingMeta;
  19675. return NULL;
  19676. }
  19677. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  19678. {
  19679. if (variableInfoPending)
  19680. setVariableFileInfo();
  19681. return this;
  19682. }
  19683. virtual IKeyArray *getKeySet() const
  19684. {
  19685. return keySet.getLink();
  19686. }
  19687. virtual const IResolvedFile *getVarFileInfo() const
  19688. {
  19689. return varFileInfo.getLink();
  19690. }
  19691. virtual TranslatorArray *getTranslators() const
  19692. {
  19693. return translators.getLink();
  19694. }
  19695. virtual void mergeSegmentMonitors(IIndexReadContext *irc) const
  19696. {
  19697. indexHelper.createSegmentMonitors(irc); // NOTE: they will merge
  19698. }
  19699. virtual IRoxieServerActivity *queryActivity() { return this; }
  19700. virtual const RemoteActivityId& queryRemoteId() const
  19701. {
  19702. return remoteId;
  19703. }
  19704. };
  19705. class CRoxieServerSimpleIndexReadActivity : public CRoxieServerActivity, implements IIndexReadActivityInfo
  19706. {
  19707. IHThorCompoundReadExtra & readHelper;
  19708. IHThorIndexReadBaseArg & indexHelper;
  19709. IHThorSourceLimitTransformExtra * limitTransformExtra;
  19710. IHThorSteppedSourceExtra * steppedExtra;
  19711. bool eof;
  19712. Linked<IKeyArray>keySet;
  19713. Owned<IKeyIndexSet>keyIndexSet;
  19714. Owned<IKeyManager> tlk;
  19715. Linked<TranslatorArray> translators;
  19716. CIndexTransformCallback callback;
  19717. unsigned __int64 keyedLimit;
  19718. unsigned rowLimit;
  19719. unsigned chooseNLimit;
  19720. unsigned accepted;
  19721. unsigned rejected;
  19722. unsigned keyedCount;
  19723. ISteppingMeta * rawMeta;
  19724. ISteppingMeta * projectedMeta;
  19725. size32_t seekGEOffset;
  19726. unsigned * seekSizes;
  19727. CSteppingMeta steppingMeta;
  19728. Owned<const IResolvedFile> varFileInfo;
  19729. const RemoteActivityId &remoteId;
  19730. bool firstRead;
  19731. bool variableFileName;
  19732. bool variableInfoPending;
  19733. bool isOpt;
  19734. bool isLocal;
  19735. bool optimizeSteppedPostFilter;
  19736. // MORE there may be enough in common between this and CRoxieServerIndexActivity to warrant some refactoring
  19737. void initKeySet()
  19738. {
  19739. if ((keySet->length() > 1 || rawMeta != NULL) && translators->needsTranslation())
  19740. {
  19741. throw MakeStringException(ROXIE_UNIMPLEMENTED_ERROR, "Layout translation is not available when merging key parts or smart-stepping, as it may change record order");
  19742. }
  19743. keyIndexSet.setown(createKeyIndexSet());
  19744. for (unsigned part = 0; part < keySet->length(); part++)
  19745. {
  19746. IKeyIndexBase *kib = keySet->queryKeyPart(part);
  19747. if (kib)
  19748. {
  19749. for (unsigned subpart = 0; subpart < kib->numParts(); subpart++)
  19750. {
  19751. IKeyIndex *k = kib->queryPart(subpart);
  19752. if (k)
  19753. {
  19754. assertex(!k->isTopLevelKey());
  19755. keyIndexSet->addIndex(LINK(k));
  19756. }
  19757. }
  19758. }
  19759. }
  19760. }
  19761. void setVariableFileInfo()
  19762. {
  19763. OwnedRoxieString indexName(indexHelper.getFileName());
  19764. varFileInfo.setown(resolveLFN(indexName, isOpt));
  19765. translators.setown(new TranslatorArray) ;
  19766. keySet.setown(varFileInfo->getKeyArray(factory->queryActivityMeta(), translators, isOpt, isLocal ? factory->queryQueryFactory().queryChannel() : 0, factory->queryQueryFactory().getEnableFieldTranslation()));
  19767. initKeySet();
  19768. variableInfoPending = false;
  19769. }
  19770. void onEOF()
  19771. {
  19772. callback.setManager(NULL);
  19773. eof = true;
  19774. tlk.clear();
  19775. }
  19776. public:
  19777. CRoxieServerSimpleIndexReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  19778. IKeyArray *_keyArray, TranslatorArray *_translatorArray, bool _isLocal)
  19779. : CRoxieServerActivity(_factory, _probeManager),
  19780. readHelper((IHThorIndexReadArg &)basehelper),
  19781. indexHelper((IHThorIndexReadArg &)basehelper),
  19782. translators(_translatorArray),
  19783. keySet(_keyArray),
  19784. isLocal(_isLocal),
  19785. remoteId(_remoteId)
  19786. {
  19787. rowLimit = 0;
  19788. keyedLimit = 0;
  19789. chooseNLimit = 0;
  19790. indexHelper.setCallback(&callback);
  19791. steppedExtra = static_cast<IHThorSteppedSourceExtra *>(indexHelper.selectInterface(TAIsteppedsourceextra_1));
  19792. limitTransformExtra = static_cast<IHThorSourceLimitTransformExtra *>(indexHelper.selectInterface(TAIsourcelimittransformextra_1));
  19793. unsigned flags = indexHelper.getFlags();
  19794. variableFileName = allFilesDynamic || factory->queryQueryFactory().isDynamic() || ((flags & (TIRvarfilename|TIRdynamicfilename)) != 0);
  19795. variableInfoPending = false;
  19796. isOpt = (flags & TIRoptional) != 0;
  19797. optimizeSteppedPostFilter = (flags & TIRunfilteredtransform) != 0;
  19798. firstRead = true;
  19799. accepted = 0;
  19800. rejected = 0;
  19801. keyedCount = 0;
  19802. eof = false;
  19803. rawMeta = readHelper.queryRawSteppingMeta();
  19804. projectedMeta = readHelper.queryProjectedSteppingMeta();
  19805. seekGEOffset = 0;
  19806. seekSizes = NULL;
  19807. if (rawMeta)
  19808. {
  19809. // MORE - should check all keys in maxFields list can actually be keyed.
  19810. const CFieldOffsetSize * fields = rawMeta->queryFields();
  19811. unsigned maxFields = rawMeta->getNumFields();
  19812. seekGEOffset = fields[0].offset;
  19813. seekSizes = new unsigned[maxFields];
  19814. seekSizes[0] = fields[0].size;
  19815. for (unsigned i=1; i < maxFields; i++)
  19816. seekSizes[i] = seekSizes[i-1] + fields[i].size;
  19817. bool hasPostFilter = readHelper.transformMayFilter() && optimizeSteppedPostFilter;
  19818. if (projectedMeta)
  19819. steppingMeta.init(projectedMeta, hasPostFilter);
  19820. else
  19821. steppingMeta.init(rawMeta, hasPostFilter);
  19822. }
  19823. }
  19824. virtual const IResolvedFile *queryVarFileInfo() const
  19825. {
  19826. return varFileInfo;
  19827. }
  19828. ~CRoxieServerSimpleIndexReadActivity()
  19829. {
  19830. delete [] seekSizes;
  19831. }
  19832. virtual bool needsAllocator() const { return true; }
  19833. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  19834. {
  19835. firstRead = true;
  19836. accepted = 0;
  19837. rejected = 0;
  19838. keyedCount = 0;
  19839. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  19840. if (steppedExtra)
  19841. steppingMeta.setExtra(steppedExtra);
  19842. eof = !indexHelper.canMatchAny();
  19843. if (variableFileName)
  19844. variableInfoPending = true;
  19845. else
  19846. {
  19847. variableInfoPending = false;
  19848. if (!keyIndexSet)
  19849. initKeySet();
  19850. }
  19851. }
  19852. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  19853. {
  19854. if (variableInfoPending)
  19855. setVariableFileInfo();
  19856. return this;
  19857. }
  19858. virtual IKeyArray *getKeySet() const
  19859. {
  19860. return keySet.getLink();
  19861. }
  19862. virtual const IResolvedFile *getVarFileInfo() const
  19863. {
  19864. return varFileInfo.getLink();
  19865. }
  19866. virtual TranslatorArray *getTranslators() const
  19867. {
  19868. return translators.getLink();
  19869. }
  19870. virtual void mergeSegmentMonitors(IIndexReadContext *irc) const
  19871. {
  19872. indexHelper.createSegmentMonitors(irc); // NOTE: they will merge
  19873. }
  19874. virtual IRoxieServerActivity *queryActivity() { return this; }
  19875. virtual const RemoteActivityId& queryRemoteId() const
  19876. {
  19877. return remoteId;
  19878. }
  19879. const void *nextInGroup()
  19880. {
  19881. bool matched = true;
  19882. return nextSteppedGE(NULL, 0, matched, dummySmartStepExtra);
  19883. }
  19884. unsigned __int64 checkCount(unsigned __int64 limit)
  19885. {
  19886. unsigned numParts = keyIndexSet->numParts();
  19887. unsigned __int64 result = 0;
  19888. for (unsigned i = 0; i < numParts; i++)
  19889. {
  19890. Owned<IKeyManager> countTlk = createKeyManager(keyIndexSet->queryPart(i), 0, this);
  19891. countTlk->setLayoutTranslator(translators->item(i));
  19892. indexHelper.createSegmentMonitors(countTlk);
  19893. countTlk->finishSegmentMonitors();
  19894. result += countTlk->checkCount(limit-result);
  19895. if (result > limit)
  19896. break;
  19897. }
  19898. return result;
  19899. }
  19900. virtual const void *nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  19901. {
  19902. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  19903. if (eof)
  19904. return NULL;
  19905. if (firstRead)
  19906. {
  19907. if (variableInfoPending)
  19908. setVariableFileInfo();
  19909. rowLimit = (unsigned) readHelper.getRowLimit();
  19910. chooseNLimit = (unsigned) readHelper.getChooseNLimit();
  19911. unsigned numParts = keyIndexSet->numParts();
  19912. if (!numParts)
  19913. {
  19914. onEOF();
  19915. return NULL;
  19916. }
  19917. if (numParts > 1 || seekGEOffset)
  19918. {
  19919. tlk.setown(createKeyMerger(keyIndexSet, 0, seekGEOffset, this));
  19920. // note that we don't set up translator because we don't support it. If that ever changes...
  19921. }
  19922. else
  19923. {
  19924. tlk.setown(createKeyManager(keyIndexSet->queryPart(0), 0, this));
  19925. tlk->setLayoutTranslator(translators->item(0));
  19926. }
  19927. indexHelper.createSegmentMonitors(tlk);
  19928. tlk->finishSegmentMonitors();
  19929. if (queryTraceLevel() > 3 || ctx->queryProbeManager())
  19930. {
  19931. StringBuffer out;
  19932. printKeyedValues(out, tlk, indexHelper.queryDiskRecordSize());
  19933. CTXLOG("Using filter %s", out.str());
  19934. if (ctx->queryProbeManager())
  19935. ctx->queryProbeManager()->setNodeProperty(this, "filter", out.str());
  19936. }
  19937. tlk->reset();
  19938. callback.setManager(tlk);
  19939. keyedLimit = readHelper.getKeyedLimit();
  19940. if (keyedLimit != (unsigned __int64) -1)
  19941. {
  19942. if ((indexHelper.getFlags() & TIRcountkeyedlimit) != 0)
  19943. {
  19944. unsigned __int64 count = checkCount(keyedLimit);
  19945. if (count > keyedLimit)
  19946. {
  19947. if ((indexHelper.getFlags() & (TIRkeyedlimitskips|TIRkeyedlimitcreates)) == 0)
  19948. readHelper.onKeyedLimitExceeded();
  19949. const void * ret = NULL;
  19950. if (indexHelper.getFlags() & TIRkeyedlimitcreates)
  19951. ret = createKeyedLimitOnFailRow();
  19952. onEOF();
  19953. return ret;
  19954. }
  19955. keyedLimit = (unsigned __int64) -1;
  19956. }
  19957. }
  19958. firstRead = false;
  19959. }
  19960. if (accepted == chooseNLimit)
  19961. {
  19962. onEOF();
  19963. return NULL;
  19964. }
  19965. const byte * rawSeek = NULL;
  19966. unsigned seekSize = 0;
  19967. if (seek)
  19968. {
  19969. seekSize = seekSizes[numFields-1];
  19970. rawSeek = (const byte *)seek + seekGEOffset;
  19971. if (projectedMeta)
  19972. {
  19973. byte *temp = (byte *) alloca(seekSize);
  19974. RtlStaticRowBuilder rawBuilder(temp-seekGEOffset, seekGEOffset+seekSize);
  19975. readHelper.mapOutputToInput(rawBuilder, seek, numFields);// NOTE - weird interface to mapOutputToInput means that it STARTS writing at seekGEOffset...
  19976. rawSeek = (byte *)temp;
  19977. }
  19978. #ifdef _DEBUG
  19979. // StringBuffer seekStr;
  19980. // for (unsigned i = 0; i < seekSize; i++)
  19981. // {
  19982. // seekStr.appendf("%02x ", ((unsigned char *) rawSeek)[i]);
  19983. // }
  19984. // DBGLOG("nextSteppedGE can skip offset %d size %d value %s", seekGEOffset, seekSize, seekStr.str());
  19985. #endif
  19986. }
  19987. const byte * originalRawSeek = rawSeek;
  19988. RtlDynamicRowBuilder rowBuilder(rowAllocator, false);
  19989. while (rawSeek ? tlk->lookupSkip(rawSeek, seekGEOffset, seekSize) : tlk->lookup(true))
  19990. {
  19991. checkAbort();
  19992. keyedCount++;
  19993. if (keyedCount > keyedLimit)
  19994. {
  19995. readHelper.onKeyedLimitExceeded();
  19996. break;
  19997. }
  19998. byte const * keyRow = tlk->queryKeyBuffer(callback.getFPosRef());
  19999. #ifdef _DEBUG
  20000. // StringBuffer recstr;
  20001. // unsigned size = (tlk->queryRecordSize()<80) ? tlk->queryRecordSize() : 80;
  20002. // for (unsigned i = 0; i < size; i++)
  20003. // {
  20004. // recstr.appendf("%02x ", ((unsigned char *) keyRow)[i]);
  20005. // }
  20006. // DBGLOG("nextSteppedGE Got %s", recstr.str());
  20007. if (originalRawSeek && memcmp(keyRow + seekGEOffset, originalRawSeek, seekSize) < 0)
  20008. assertex(!"smart seek failure");
  20009. #endif
  20010. size32_t transformedSize;
  20011. rowBuilder.ensureRow();
  20012. try
  20013. {
  20014. transformedSize = readHelper.transform(rowBuilder, keyRow);
  20015. //if the post filter causes a mismatch, and the stepping condition no longer matches
  20016. //then return a mismatch record - so the join code can start seeking on the other input.
  20017. if (transformedSize == 0 && optimizeSteppedPostFilter && stepExtra.returnMismatches())
  20018. {
  20019. if (memcmp(keyRow + seekGEOffset, originalRawSeek, seekSize) != 0)
  20020. {
  20021. transformedSize = readHelper.unfilteredTransform(rowBuilder, keyRow);
  20022. if (transformedSize != 0)
  20023. wasCompleteMatch = false;
  20024. }
  20025. }
  20026. callback.finishedRow();
  20027. }
  20028. catch (IException *E)
  20029. {
  20030. throw makeWrappedException(E);
  20031. }
  20032. if (transformedSize)
  20033. {
  20034. accepted++;
  20035. if (accepted > rowLimit)
  20036. {
  20037. if ((indexHelper.getFlags() & (TIRlimitskips|TIRlimitcreates)) != 0)
  20038. {
  20039. throwUnexpected(); // should not have used simple variant if maySkip set...
  20040. }
  20041. if (traceLevel > 4)
  20042. DBGLOG("activityid = %d line = %d", activityId, __LINE__);
  20043. readHelper.onLimitExceeded();
  20044. break;
  20045. }
  20046. processed++;
  20047. #ifdef _DEBUG
  20048. // const byte *ret = (const byte *) out.get();
  20049. // CommonXmlWriter xmlwrite(XWFnoindent|XWFtrim|XWFopt);
  20050. // queryOutputMeta()->toXML(ret, xmlwrite);
  20051. // DBGLOG("ROW: {%p} %s", ret, xmlwrite.str());
  20052. #endif
  20053. return rowBuilder.finalizeRowClear(transformedSize);
  20054. }
  20055. else
  20056. rejected++;
  20057. rawSeek = NULL;
  20058. }
  20059. onEOF();
  20060. return NULL;
  20061. }
  20062. virtual void reset()
  20063. {
  20064. onEOF();
  20065. if (accepted)
  20066. noteStatistic(STATS_ACCEPTED, accepted, 1);
  20067. if (rejected)
  20068. noteStatistic(STATS_REJECTED, rejected, 1);
  20069. if (variableFileName)
  20070. {
  20071. varFileInfo.clear();
  20072. translators.clear();
  20073. }
  20074. variableInfoPending = false;
  20075. CRoxieServerActivity::reset();
  20076. }
  20077. virtual void setInput(unsigned idx, IRoxieInput *_in)
  20078. {
  20079. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  20080. }
  20081. virtual IInputSteppingMeta * querySteppingMeta()
  20082. {
  20083. if (rawMeta && steppingEnabled && ((indexHelper.getFlags() & (TIRlimitskips|TIRlimitcreates|TIRkeyedlimitskips|TIRkeyedlimitcreates)) == 0))
  20084. return &steppingMeta;
  20085. return NULL;
  20086. }
  20087. protected:
  20088. const void * createKeyedLimitOnFailRow()
  20089. {
  20090. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  20091. size32_t outSize = limitTransformExtra->transformOnKeyedLimitExceeded(rowBuilder);
  20092. if (outSize)
  20093. return rowBuilder.finalizeRowClear(outSize);
  20094. return NULL;
  20095. }
  20096. };
  20097. class CRoxieServerBaseIndexActivityFactory : public CRoxieServerActivityFactory
  20098. {
  20099. public:
  20100. Owned<IKeyArray> keySet;
  20101. Owned<TranslatorArray> translatorArray;
  20102. Owned<IDefRecordMeta> activityMeta;
  20103. RemoteActivityId remoteId;
  20104. bool isSimple;
  20105. bool isLocal;
  20106. bool maySkip;
  20107. bool sorted;
  20108. bool variableFileName;
  20109. bool enableFieldTranslation;
  20110. unsigned maxSeekLookahead;
  20111. Owned<const IResolvedFile> indexfile;
  20112. CRoxieServerSideCache *cache;
  20113. CRoxieServerBaseIndexActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  20114. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), remoteId(_remoteId)
  20115. {
  20116. Owned<IHThorIndexReadBaseArg> indexHelper = (IHThorIndexReadBaseArg *) helperFactory();
  20117. unsigned flags = indexHelper->getFlags();
  20118. sorted = (flags & TIRunordered) == 0;
  20119. isLocal = _graphNode.getPropBool("att[@name='local']/@value") && queryFactory.queryChannel()!=0;
  20120. rtlDataAttr indexLayoutMeta;
  20121. size32_t indexLayoutSize;
  20122. if(!indexHelper->getIndexLayout(indexLayoutSize, indexLayoutMeta.refdata()))
  20123. assertex(indexLayoutSize==0);
  20124. MemoryBuffer m;
  20125. m.setBuffer(indexLayoutSize, indexLayoutMeta.getdata());
  20126. activityMeta.setown(deserializeRecordMeta(m, true));
  20127. enableFieldTranslation = queryFactory.getEnableFieldTranslation();
  20128. translatorArray.setown(new TranslatorArray);
  20129. variableFileName = allFilesDynamic || _queryFactory.isDynamic() || ((flags & (TIRvarfilename|TIRdynamicfilename)) != 0);
  20130. if (!variableFileName)
  20131. {
  20132. bool isOpt = (flags & TIRoptional) != 0;
  20133. OwnedRoxieString indexName(indexHelper->getFileName());
  20134. indexfile.setown(queryFactory.queryPackage().lookupFileName(indexName, isOpt, true, true, queryFactory.queryWorkUnit()));
  20135. if (indexfile)
  20136. keySet.setown(indexfile->getKeyArray(activityMeta, translatorArray, isOpt, isLocal ? queryFactory.queryChannel() : 0, enableFieldTranslation));
  20137. }
  20138. isSimple = isLocal;
  20139. maySkip = (flags & (TIRkeyedlimitskips|TIRlimitskips|TIRlimitcreates|TIRkeyedlimitcreates)) != 0;
  20140. if (keySet && keySet->length()==1 && !isLocal && (flags & (TIRlimitskips|TIRlimitcreates|TIRkeyedlimitskips|TIRkeyedlimitcreates))==0)
  20141. {
  20142. IKeyIndexBase *thisBase = keySet->queryKeyPart(0);
  20143. if (thisBase->numParts()==1 && !thisBase->queryPart(0)->isTopLevelKey() && !_queryFactory.getDebugValueBool("disableLocalOptimizations", false))
  20144. isSimple = true;
  20145. }
  20146. int cacheSize = _graphNode.getPropInt("hint[@name='cachehits']/@value", serverSideCacheSize);
  20147. cache = cacheSize ? new CRoxieServerSideCache(cacheSize) : NULL;
  20148. maxSeekLookahead = _graphNode.getPropInt("hint[@name='maxseeklookahead']/@value", 0);
  20149. }
  20150. ~CRoxieServerBaseIndexActivityFactory()
  20151. {
  20152. delete cache;
  20153. }
  20154. virtual void getXrefInfo(IPropertyTree &reply, const IRoxieContextLogger &logctx) const
  20155. {
  20156. if (indexfile)
  20157. addXrefFileInfo(reply, indexfile);
  20158. }
  20159. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  20160. {
  20161. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for indexread activity");
  20162. }
  20163. virtual IRoxieServerSideCache *queryServerSideCache() const
  20164. {
  20165. return cache;
  20166. }
  20167. virtual bool getEnableFieldTranslation() const
  20168. {
  20169. return enableFieldTranslation;
  20170. }
  20171. virtual IDefRecordMeta *queryActivityMeta() const
  20172. {
  20173. return activityMeta;
  20174. }
  20175. };
  20176. class CRoxieServerIndexReadActivityFactory : public CRoxieServerBaseIndexActivityFactory
  20177. {
  20178. public:
  20179. CRoxieServerIndexReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  20180. : CRoxieServerBaseIndexActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode)
  20181. {
  20182. }
  20183. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  20184. {
  20185. if (!variableFileName && (keySet==NULL || keySet->length()==0))
  20186. return new CRoxieServerNullActivity(this, _probeManager);
  20187. else if (isSimple && !maySkip)
  20188. return new CRoxieServerSimpleIndexReadActivity(this, _probeManager, remoteId, keySet, translatorArray, isLocal);
  20189. else
  20190. return new CRoxieServerIndexReadActivity(this, _probeManager, remoteId, keySet, translatorArray, sorted, isLocal, maySkip, maxSeekLookahead);
  20191. }
  20192. };
  20193. IRoxieServerActivityFactory *createRoxieServerIndexReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  20194. {
  20195. return new CRoxieServerIndexReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode);
  20196. }
  20197. //--------------------------------------------------------------------------------------------------------------------------
  20198. class CRoxieServerNullCountActivity : public CRoxieServerActivity
  20199. {
  20200. bool done;
  20201. public:
  20202. CRoxieServerNullCountActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  20203. : CRoxieServerActivity(_factory, _probeManager)
  20204. {
  20205. done = false;
  20206. }
  20207. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  20208. {
  20209. done = false;
  20210. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  20211. }
  20212. virtual bool needsAllocator() const { return true; }
  20213. virtual const void *nextInGroup()
  20214. {
  20215. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  20216. if (done) return NULL;
  20217. done = true;
  20218. size32_t rowSize = meta.getFixedSize();
  20219. void * nullRow = rowAllocator->createRow();
  20220. if (rowSize == 1)
  20221. *(byte *)nullRow = 0;
  20222. else
  20223. {
  20224. assertex(rowSize == sizeof(unsigned __int64));
  20225. *(unsigned __int64 *)nullRow = 0;
  20226. }
  20227. return rowAllocator->finalizeRow(rowSize, nullRow, rowSize);
  20228. }
  20229. };
  20230. class CRoxieServerIndexCountActivity : public CRoxieServerIndexActivity
  20231. {
  20232. IHThorCompoundCountExtra & countHelper;
  20233. IHThorSourceCountLimit * limitHelper;
  20234. bool done;
  20235. public:
  20236. CRoxieServerIndexCountActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, IKeyArray * _keySet, TranslatorArray *_translators, bool _isLocal)
  20237. : CRoxieServerIndexActivity(_factory, _probeManager, _remoteId, _keySet, _translators, false, _isLocal, false),
  20238. countHelper((IHThorIndexCountArg &)basehelper),
  20239. done(false)
  20240. {
  20241. limitHelper = static_cast<IHThorSourceCountLimit *>(basehelper.selectInterface(TAIsourcecountlimit_1));
  20242. }
  20243. virtual bool needsAllocator() const { return true; }
  20244. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  20245. {
  20246. done = false;
  20247. CRoxieServerIndexActivity::start(parentExtractSize, parentExtract, paused);
  20248. choosenLimit = countHelper.getChooseNLimit();
  20249. if (limitHelper)
  20250. {
  20251. rowLimit = limitHelper->getRowLimit();
  20252. keyedLimit = limitHelper->getKeyedLimit();
  20253. }
  20254. if (!paused)
  20255. processAllKeys();
  20256. }
  20257. virtual bool processSingleKey(IKeyIndex *key, IRecordLayoutTranslator * trans)
  20258. {
  20259. unsigned __int64 count = 0;
  20260. if (countHelper.hasFilter())
  20261. {
  20262. while (tlk->lookup(true))
  20263. {
  20264. try
  20265. {
  20266. count += countHelper.numValid(tlk->queryKeyBuffer(callback.getFPosRef()));
  20267. callback.finishedRow();
  20268. }
  20269. catch (IException *E)
  20270. {
  20271. throw makeWrappedException(E);
  20272. }
  20273. accepted++;
  20274. if (count >= choosenLimit) // MORE - what about limit?
  20275. break;
  20276. }
  20277. }
  20278. else
  20279. count = tlk->getCount(); //MORE: GH->RKC There should be value in providing a max limit to getCount()
  20280. if (count)
  20281. {
  20282. Owned<CRowArrayMessageResult> result = new CRowArrayMessageResult(ctx->queryRowManager(), false);
  20283. if (count > choosenLimit)
  20284. count = choosenLimit;
  20285. void * recBuffer = rowAllocator->createRow();
  20286. if (meta.getFixedSize() == 1)
  20287. *(byte *)recBuffer = (byte)count;
  20288. else
  20289. {
  20290. assertex(meta.getFixedSize() == sizeof(unsigned __int64));
  20291. *(unsigned __int64 *)recBuffer = count;
  20292. }
  20293. recBuffer = rowAllocator->finalizeRow(meta.getFixedSize(), recBuffer, meta.getFixedSize());
  20294. result->append(recBuffer);
  20295. remote.injectResult(result.getClear());
  20296. //GH->RKC for count(,choosen)/exists passing in the previous count would short-circuit this much earlier
  20297. if (count >= choosenLimit)
  20298. return true;
  20299. }
  20300. return false;
  20301. }
  20302. virtual void onLimitExceeded(bool isKeyed)
  20303. {
  20304. if (traceLevel > 4)
  20305. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  20306. if (isKeyed)
  20307. {
  20308. if (indexHelper.getFlags() & (TIRkeyedlimitskips|TIRkeyedlimitcreates))
  20309. {
  20310. if (ctx->queryDebugContext())
  20311. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  20312. throw makeLimitSkipException(true);
  20313. }
  20314. else
  20315. {
  20316. assertex(limitHelper); // Should not be able to generate exception if there was not one...
  20317. limitHelper->onKeyedLimitExceeded();
  20318. }
  20319. }
  20320. else
  20321. {
  20322. if (indexHelper.getFlags() & (TIRlimitskips|TIRlimitcreates))
  20323. {
  20324. if (ctx->queryDebugContext())
  20325. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  20326. throw makeLimitSkipException(false);
  20327. }
  20328. else
  20329. {
  20330. assertex(limitHelper);
  20331. limitHelper->onLimitExceeded();
  20332. }
  20333. }
  20334. }
  20335. virtual const void *createLimitFailRow(bool isKeyed)
  20336. {
  20337. throwUnexpected();
  20338. }
  20339. virtual const void *nextInGroup()
  20340. {
  20341. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  20342. if (done) return NULL;
  20343. done = true;
  20344. unsigned __int64 totalCount = 0;
  20345. bool hasLimit = rowLimit != (unsigned __int64) -1;
  20346. try
  20347. {
  20348. loop
  20349. {
  20350. const void * next = remote.nextInGroup();
  20351. if (!next)
  20352. break;
  20353. if (meta.getFixedSize() == 1)
  20354. totalCount += *(byte *)next;
  20355. else
  20356. totalCount += *(unsigned __int64 *) next;
  20357. ReleaseRoxieRow(next);
  20358. if (totalCount > rowLimit || (totalCount > choosenLimit && !hasLimit)) // can't break out early if there is a possibility of later slave throwing limit exception
  20359. break;
  20360. }
  20361. if (totalCount > rowLimit)
  20362. {
  20363. unsigned flags = indexHelper.getFlags();
  20364. if (flags & TIRlimitskips)
  20365. totalCount = 0;
  20366. else if (flags & TIRlimitcreates)
  20367. totalCount = 1;
  20368. else
  20369. {
  20370. assertex(limitHelper);
  20371. limitHelper->onLimitExceeded();
  20372. }
  20373. }
  20374. else if (totalCount > choosenLimit)
  20375. totalCount = choosenLimit;
  20376. }
  20377. catch (IException *E)
  20378. {
  20379. if (QUERYINTERFACE(E, LimitSkipException))
  20380. {
  20381. totalCount = 0;
  20382. unsigned flags = indexHelper.getFlags();
  20383. if (E->errorCode() == KeyedLimitSkipErrorCode)
  20384. {
  20385. if (flags & TIRkeyedlimitcreates)
  20386. totalCount++;
  20387. }
  20388. else
  20389. {
  20390. if (flags & TIRlimitcreates)
  20391. totalCount++;
  20392. }
  20393. if (totalCount > choosenLimit)
  20394. totalCount = choosenLimit; // would have to be weird code (and escape the optimizer...)
  20395. E->Release();
  20396. }
  20397. else
  20398. throw ;
  20399. }
  20400. void * result = rowAllocator->createRow();
  20401. if (meta.getFixedSize() == 1)
  20402. *(byte *)result = (byte)totalCount;
  20403. else
  20404. {
  20405. assertex(meta.getFixedSize() == sizeof(unsigned __int64));
  20406. *(unsigned __int64 *)result = totalCount;
  20407. }
  20408. return rowAllocator->finalizeRow(meta.getFixedSize(), result, meta.getFixedSize());
  20409. }
  20410. };
  20411. class CRoxieServerIndexCountActivityFactory : public CRoxieServerBaseIndexActivityFactory
  20412. {
  20413. public:
  20414. CRoxieServerIndexCountActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  20415. : CRoxieServerBaseIndexActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode)
  20416. {
  20417. }
  20418. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  20419. {
  20420. if (!variableFileName && (keySet==NULL || keySet->length()==0))
  20421. return new CRoxieServerNullCountActivity(this, _probeManager);
  20422. // else if (isSimple)
  20423. // return new CRoxieServerSimpleIndexCountActivity(this, keySet->queryKeyPart(0)->queryPart(0));
  20424. else
  20425. return new CRoxieServerIndexCountActivity(this, _probeManager, remoteId, keySet, translatorArray, isLocal);
  20426. }
  20427. };
  20428. IRoxieServerActivityFactory *createRoxieServerIndexCountActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  20429. {
  20430. return new CRoxieServerIndexCountActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode);
  20431. }
  20432. //--------------------------------------------------------------------------------------------------------------------------
  20433. class CRoxieServerNullIndexAggregateActivity : public CRoxieServerActivity
  20434. {
  20435. IHThorIndexAggregateArg &aggregateHelper;
  20436. bool done;
  20437. public:
  20438. CRoxieServerNullIndexAggregateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  20439. : CRoxieServerActivity(_factory, _probeManager),
  20440. aggregateHelper((IHThorIndexAggregateArg &)basehelper)
  20441. {
  20442. done = false;
  20443. }
  20444. virtual bool needsAllocator() const { return true; }
  20445. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  20446. {
  20447. done = false;
  20448. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  20449. }
  20450. virtual const void *nextInGroup()
  20451. {
  20452. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  20453. if (done) return NULL;
  20454. done = true;
  20455. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  20456. size32_t thisSize = aggregateHelper.clearAggregate(rowBuilder);
  20457. return rowBuilder.finalizeRowClear(thisSize);
  20458. }
  20459. };
  20460. class CRoxieServerIndexAggregateActivity : public CRoxieServerIndexActivity
  20461. {
  20462. IHThorCompoundAggregateExtra & aggregateHelper;
  20463. bool done;
  20464. public:
  20465. CRoxieServerIndexAggregateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  20466. IKeyArray * _keySet, TranslatorArray *_translators, bool _isLocal)
  20467. : CRoxieServerIndexActivity(_factory, _probeManager, _remoteId, _keySet, _translators, false, _isLocal, false),
  20468. aggregateHelper((IHThorIndexAggregateArg &)basehelper),
  20469. done(false)
  20470. {
  20471. }
  20472. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  20473. {
  20474. done = false;
  20475. CRoxieServerIndexActivity::start(parentExtractSize, parentExtract, paused);
  20476. if (!paused)
  20477. processAllKeys();
  20478. }
  20479. virtual bool needsAllocator() const { return true; }
  20480. virtual bool processSingleKey(IKeyIndex *key, IRecordLayoutTranslator * trans)
  20481. {
  20482. RtlDynamicRowBuilder rowBuilder(rowAllocator, false);
  20483. while (tlk->lookup(true))
  20484. {
  20485. if (!rowBuilder.exists())
  20486. {
  20487. rowBuilder.ensureRow();
  20488. aggregateHelper.clearAggregate(rowBuilder);
  20489. }
  20490. try
  20491. {
  20492. aggregateHelper.processRow(rowBuilder, tlk->queryKeyBuffer(callback.getFPosRef()));
  20493. callback.finishedRow();
  20494. }
  20495. catch (IException *E)
  20496. {
  20497. throw makeWrappedException(E);
  20498. }
  20499. accepted++;
  20500. }
  20501. if (aggregateHelper.processedAnyRows())
  20502. {
  20503. size32_t size = meta.getRecordSize(rowBuilder.getSelf());
  20504. const void * recBuffer = rowBuilder.finalizeRowClear(size);
  20505. Owned<CRowArrayMessageResult> result = new CRowArrayMessageResult(ctx->queryRowManager(), meta.isVariableSize());
  20506. result->append(recBuffer);
  20507. remote.injectResult(result.getClear());
  20508. }
  20509. return false;
  20510. }
  20511. virtual void onLimitExceeded(bool isKeyed)
  20512. {
  20513. if (traceLevel > 4)
  20514. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  20515. throwUnexpected();
  20516. }
  20517. virtual const void *createLimitFailRow(bool isKeyed)
  20518. {
  20519. throwUnexpected();
  20520. }
  20521. const void * gatherMerged()
  20522. {
  20523. RtlDynamicRowBuilder rowBuilder(rowAllocator, false);
  20524. const void * firstRow = remote.nextInGroup();
  20525. size32_t finalSize = 0;
  20526. if (!firstRow)
  20527. {
  20528. rowBuilder.ensureRow();
  20529. finalSize = aggregateHelper.clearAggregate(rowBuilder);
  20530. }
  20531. else
  20532. {
  20533. // NOTE need to clone this because going to modify below, could special case 1 row only
  20534. finalSize = cloneRow(rowBuilder, firstRow, meta);
  20535. ReleaseRoxieRow(firstRow);
  20536. }
  20537. loop
  20538. {
  20539. const void * next = remote.nextInGroup();
  20540. if (!next)
  20541. break;
  20542. finalSize = aggregateHelper.mergeAggregate(rowBuilder, next);
  20543. ReleaseRoxieRow(next);
  20544. }
  20545. return rowBuilder.finalizeRowClear(finalSize);
  20546. }
  20547. virtual const void *nextInGroup()
  20548. {
  20549. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  20550. if (done) return NULL;
  20551. const void * ret = gatherMerged();
  20552. done = true;
  20553. return ret;
  20554. }
  20555. };
  20556. class CRoxieServerIndexAggregateActivityFactory : public CRoxieServerBaseIndexActivityFactory
  20557. {
  20558. public:
  20559. CRoxieServerIndexAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  20560. : CRoxieServerBaseIndexActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode)
  20561. {
  20562. }
  20563. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  20564. {
  20565. if (!variableFileName && (keySet==NULL || keySet->length()==0))
  20566. return new CRoxieServerNullIndexAggregateActivity(this, _probeManager);
  20567. // else if (isSimple)
  20568. // return new CRoxieServerSimpleIndexAggregateActivity(this, keySet->queryKeyPart(0)->queryPart(0));
  20569. else
  20570. return new CRoxieServerIndexAggregateActivity(this, _probeManager, remoteId, keySet, translatorArray, isLocal);
  20571. }
  20572. };
  20573. IRoxieServerActivityFactory *createRoxieServerIndexAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  20574. {
  20575. return new CRoxieServerIndexAggregateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode);
  20576. }
  20577. //--------------------------------------------------------------------------------------------------------------------------
  20578. class CRoxieServerIndexGroupAggregateActivity : public CRoxieServerIndexActivity, implements IHThorGroupAggregateCallback
  20579. {
  20580. IHThorCompoundGroupAggregateExtra & aggregateHelper;
  20581. RowAggregator singleAggregator;
  20582. RowAggregator resultAggregator;
  20583. unsigned groupSegCount;
  20584. bool gathered;
  20585. bool eof;
  20586. public:
  20587. CRoxieServerIndexGroupAggregateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  20588. IKeyArray * _keySet, TranslatorArray *_translators, bool _isLocal)
  20589. : CRoxieServerIndexActivity(_factory, _probeManager, _remoteId, _keySet, _translators, false, _isLocal, false),
  20590. aggregateHelper((IHThorIndexGroupAggregateArg &)basehelper),
  20591. singleAggregator(aggregateHelper, aggregateHelper),
  20592. resultAggregator(aggregateHelper, aggregateHelper),
  20593. gathered(false), eof(true)
  20594. {
  20595. groupSegCount = 0;
  20596. }
  20597. IMPLEMENT_IINTERFACE
  20598. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  20599. {
  20600. eof = false;
  20601. gathered= false;
  20602. CRoxieServerIndexActivity::start(parentExtractSize, parentExtract, paused);
  20603. groupSegCount = 0;
  20604. if (!paused)
  20605. processAllKeys();
  20606. resultAggregator.start(rowAllocator);
  20607. }
  20608. virtual bool needsAllocator() const { return true; }
  20609. virtual void reset()
  20610. {
  20611. resultAggregator.reset();
  20612. CRoxieServerIndexActivity::reset();
  20613. }
  20614. virtual void processRow(const void * next)
  20615. {
  20616. singleAggregator.addRow(next);
  20617. }
  20618. virtual void createSegmentMonitors(IKeyManager *key)
  20619. {
  20620. unsigned groupSegSize;
  20621. ThorActivityKind kind = factory->getKind();
  20622. if ((kind==TAKindexgroupcount || kind==TAKindexgroupexists))
  20623. groupSegSize = aggregateHelper.getGroupSegmentMonitorsSize();
  20624. else
  20625. groupSegSize = 0;
  20626. if (groupSegSize)
  20627. {
  20628. key->setMergeBarrier(groupSegSize);
  20629. CRoxieServerIndexActivity::createSegmentMonitors(key);
  20630. unsigned numSegs = tlk->ordinality();
  20631. for (unsigned segNo = 0; segNo < numSegs; segNo++)
  20632. {
  20633. IKeySegmentMonitor *seg = tlk->item(segNo);
  20634. if (seg->getOffset()+seg->getSize()==groupSegSize)
  20635. {
  20636. groupSegCount = segNo+1;
  20637. break;
  20638. }
  20639. }
  20640. assertex(groupSegCount);
  20641. }
  20642. else
  20643. CRoxieServerIndexActivity::createSegmentMonitors(key);
  20644. }
  20645. virtual bool processSingleKey(IKeyIndex *key, IRecordLayoutTranslator * trans)
  20646. {
  20647. Owned<CRowArrayMessageResult> result = new CRowArrayMessageResult(ctx->queryRowManager(), meta.isVariableSize());
  20648. singleAggregator.start(rowAllocator);
  20649. ThorActivityKind kind = factory->getKind();
  20650. while (tlk->lookup(true))
  20651. {
  20652. try
  20653. {
  20654. if (groupSegCount && !trans)
  20655. {
  20656. AggregateRowBuilder &rowBuilder = singleAggregator.addRow(tlk->queryKeyBuffer(callback.getFPosRef()));
  20657. callback.finishedRow();
  20658. if (kind==TAKindexgroupcount)
  20659. {
  20660. unsigned __int64 count = tlk->getCurrentRangeCount(groupSegCount);
  20661. aggregateHelper.processCountGrouping(rowBuilder, count-1);
  20662. }
  20663. if (!tlk->nextRange(groupSegCount))
  20664. break;
  20665. }
  20666. else
  20667. {
  20668. aggregateHelper.processRow(tlk->queryKeyBuffer(callback.getFPosRef()), this);
  20669. callback.finishedRow();
  20670. }
  20671. }
  20672. catch (IException *E)
  20673. {
  20674. throw makeWrappedException(E);
  20675. }
  20676. accepted++;
  20677. }
  20678. loop
  20679. {
  20680. Owned<AggregateRowBuilder> next = singleAggregator.nextResult();
  20681. if (!next)
  20682. break;
  20683. size32_t size = next->querySize();
  20684. result->append(next->finalizeRowClear());
  20685. }
  20686. remote.injectResult(result.getClear());
  20687. singleAggregator.reset();
  20688. return false;
  20689. }
  20690. virtual void onLimitExceeded(bool isKeyed)
  20691. {
  20692. if (traceLevel > 4)
  20693. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);DBGLOG("%d activityid = %d", __LINE__, activityId);
  20694. throwUnexpected();
  20695. }
  20696. virtual const void *createLimitFailRow(bool isKeyed)
  20697. {
  20698. throwUnexpected();
  20699. }
  20700. void gatherMerged()
  20701. {
  20702. gathered = true;
  20703. loop
  20704. {
  20705. const void * next = remote.nextInGroup();
  20706. if (!next)
  20707. break;
  20708. resultAggregator.mergeElement(next);
  20709. ReleaseRoxieRow(next);
  20710. }
  20711. }
  20712. virtual const void *nextInGroup()
  20713. {
  20714. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  20715. if (eof)
  20716. return NULL;
  20717. if (!gathered)
  20718. gatherMerged();
  20719. Owned<AggregateRowBuilder> next = resultAggregator.nextResult();
  20720. if (next)
  20721. {
  20722. processed++;
  20723. return next->finalizeRowClear();
  20724. }
  20725. eof = true;
  20726. return NULL;
  20727. }
  20728. };
  20729. class CRoxieServerIndexGroupAggregateActivityFactory : public CRoxieServerBaseIndexActivityFactory
  20730. {
  20731. public:
  20732. CRoxieServerIndexGroupAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  20733. : CRoxieServerBaseIndexActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode)
  20734. {
  20735. }
  20736. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  20737. {
  20738. if (!variableFileName && (keySet==NULL || keySet->length()==0))
  20739. return new CRoxieServerNullActivity(this, _probeManager);
  20740. // else if (isSimple)
  20741. // return new CRoxieServerSimpleIndexGroupAggregateActivity(this, keySet->queryKeyPart(0)->queryPart(0));
  20742. else
  20743. return new CRoxieServerIndexGroupAggregateActivity(this, _probeManager, remoteId, keySet, translatorArray, isLocal);
  20744. }
  20745. };
  20746. IRoxieServerActivityFactory *createRoxieServerIndexGroupAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  20747. {
  20748. return new CRoxieServerIndexGroupAggregateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode);
  20749. }
  20750. //--------------------------------------------------------------------------------------------------------------------------
  20751. class CRoxieServerIndexNormalizeActivity : public CRoxieServerIndexReadBaseActivity
  20752. {
  20753. IHThorCompoundNormalizeExtra & readHelper;
  20754. public:
  20755. CRoxieServerIndexNormalizeActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  20756. IKeyArray * _keySet, TranslatorArray *_translators, bool _sorted, bool _isLocal)
  20757. : CRoxieServerIndexReadBaseActivity(_factory, _probeManager, _remoteId, _keySet, _translators, _sorted, _isLocal, false),
  20758. readHelper((IHThorIndexNormalizeArg &)basehelper)
  20759. {
  20760. }
  20761. virtual bool needsAllocator() const { return true; }
  20762. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  20763. {
  20764. CRoxieServerIndexReadBaseActivity::start(parentExtractSize, parentExtract, paused);
  20765. rowLimit = readHelper.getRowLimit();
  20766. keyedLimit = readHelper.getKeyedLimit();
  20767. if (!paused)
  20768. processAllKeys();
  20769. }
  20770. virtual bool processSingleKey(IKeyIndex *key, IRecordLayoutTranslator * trans)
  20771. {
  20772. unsigned keyedCount = 0;
  20773. RtlDynamicRowBuilder rowBuilder(rowAllocator, false);
  20774. while (tlk->lookup(true))
  20775. {
  20776. keyedCount++;
  20777. if (keyedCount > keyedLimit)
  20778. {
  20779. if (traceLevel > 4)
  20780. DBGLOG("activityid = %d line = %d", activityId, __LINE__);
  20781. onLimitExceeded(true);
  20782. break;
  20783. }
  20784. size32_t transformedSize;
  20785. if (readHelper.first(tlk->queryKeyBuffer(callback.getFPosRef())))
  20786. {
  20787. Owned<CRowArrayMessageResult> result = new CRowArrayMessageResult(ctx->queryRowManager(), meta.isVariableSize());
  20788. do
  20789. {
  20790. rowBuilder.ensureRow();
  20791. try
  20792. {
  20793. transformedSize = readHelper.transform(rowBuilder);
  20794. }
  20795. catch (IException *E)
  20796. {
  20797. throw makeWrappedException(E);
  20798. }
  20799. if (transformedSize)
  20800. {
  20801. // MORE - would be a good idea to stop these asap if rowlimit exceeded
  20802. result->append(rowBuilder.finalizeRowClear(transformedSize));
  20803. accepted++;
  20804. }
  20805. else
  20806. rejected++;
  20807. } while (readHelper.next());
  20808. remote.injectResult(result.getClear());
  20809. callback.finishedRow();
  20810. }
  20811. }
  20812. return false;
  20813. }
  20814. virtual void onLimitExceeded(bool isKeyed)
  20815. {
  20816. if (traceLevel > 4)
  20817. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  20818. if (isKeyed)
  20819. {
  20820. if (indexHelper.getFlags() & (TIRkeyedlimitskips|TIRkeyedlimitcreates))
  20821. {
  20822. if (ctx->queryDebugContext())
  20823. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  20824. throw makeLimitSkipException(true);
  20825. }
  20826. else
  20827. readHelper.onKeyedLimitExceeded();
  20828. }
  20829. else
  20830. {
  20831. if (indexHelper.getFlags() & (TIRlimitskips||TIRlimitcreates))
  20832. {
  20833. if (ctx->queryDebugContext())
  20834. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  20835. throw makeLimitSkipException(false);
  20836. }
  20837. else
  20838. readHelper.onLimitExceeded();
  20839. }
  20840. }
  20841. virtual const void *createLimitFailRow(bool isKeyed)
  20842. {
  20843. UNIMPLEMENTED;
  20844. }
  20845. };
  20846. class CRoxieServerIndexNormalizeActivityFactory : public CRoxieServerBaseIndexActivityFactory
  20847. {
  20848. public:
  20849. CRoxieServerIndexNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  20850. : CRoxieServerBaseIndexActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode)
  20851. {
  20852. }
  20853. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  20854. {
  20855. if (!variableFileName && (keySet==NULL || keySet->length()==0))
  20856. return new CRoxieServerNullActivity(this, _probeManager);
  20857. else
  20858. return new CRoxieServerIndexNormalizeActivity(this, _probeManager, remoteId, keySet, translatorArray, sorted, isLocal);
  20859. }
  20860. };
  20861. IRoxieServerActivityFactory *createRoxieServerIndexNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  20862. {
  20863. return new CRoxieServerIndexNormalizeActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode);
  20864. }
  20865. //=================================================================================
  20866. class CRoxieServerFetchActivity : public CRoxieServerActivity, implements IRecordPullerCallback, implements IRoxieServerErrorHandler
  20867. {
  20868. IHThorFetchBaseArg &helper;
  20869. IHThorFetchContext * fetchContext;
  20870. Linked<IFilePartMap> map;
  20871. CRemoteResultAdaptor remote;
  20872. RecordPullerThread puller;
  20873. bool needsRHS;
  20874. bool variableFileName;
  20875. bool isOpt;
  20876. Owned<const IResolvedFile> varFileInfo;
  20877. public:
  20878. CRoxieServerFetchActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, IFilePartMap *_map)
  20879. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorFetchBaseArg &)basehelper), map(_map), remote(_remoteId, meta.queryOriginal(), helper, *this, true, true), puller(false)
  20880. {
  20881. fetchContext = static_cast<IHThorFetchContext *>(helper.selectInterface(TAIfetchcontext_1));
  20882. needsRHS = helper.transformNeedsRhs();
  20883. variableFileName = allFilesDynamic || factory->queryQueryFactory().isDynamic() || ((fetchContext->getFetchFlags() & (FFvarfilename|FFdynamicfilename)) != 0);
  20884. isOpt = (fetchContext->getFetchFlags() & FFdatafileoptional) != 0;
  20885. }
  20886. virtual const IResolvedFile *queryVarFileInfo() const
  20887. {
  20888. return varFileInfo;
  20889. }
  20890. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  20891. {
  20892. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  20893. remote.onCreate(this, this, _ctx, _colocalParent);
  20894. }
  20895. virtual void setInput(unsigned idx, IRoxieInput *_in)
  20896. {
  20897. if (idx)
  20898. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
  20899. puller.setInput(this, _in);
  20900. }
  20901. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  20902. {
  20903. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  20904. remote.onStart(parentExtractSize, parentExtract);
  20905. remote.setLimits(helper.getRowLimit(), (unsigned __int64) -1, I64C(0x7FFFFFFFFFFFFFFF));
  20906. if (variableFileName)
  20907. {
  20908. OwnedRoxieString fname(fetchContext->getFileName());
  20909. varFileInfo.setown(resolveLFN(fname, isOpt));
  20910. if (varFileInfo)
  20911. map.setown(varFileInfo->getFileMap());
  20912. }
  20913. puller.start(parentExtractSize, parentExtract, paused, ctx->fetchPreload(), false, ctx);
  20914. }
  20915. virtual void stop(bool aborting)
  20916. {
  20917. // Called from remote, so no need to call back to it....
  20918. puller.stop(aborting);
  20919. CRoxieServerActivity::stop(aborting);
  20920. }
  20921. virtual void reset()
  20922. {
  20923. processed = remote.processed;
  20924. remote.processed = 0;
  20925. puller.reset();
  20926. if (variableFileName)
  20927. {
  20928. varFileInfo.clear();
  20929. map.clear();
  20930. }
  20931. CRoxieServerActivity::reset();
  20932. }
  20933. virtual IRoxieInput *queryOutput(unsigned idx)
  20934. {
  20935. if (idx==(unsigned)-1)
  20936. idx = 0;
  20937. return idx ? NULL : &remote;
  20938. }
  20939. virtual void processRow(const void *row)
  20940. {
  20941. // called from puller thread
  20942. offset_t rp = fetchContext->extractPosition(row);
  20943. unsigned partNo;
  20944. if (isLocalFpos(rp))
  20945. partNo = getLocalFposPart(rp) + 1;
  20946. else
  20947. partNo = map->mapOffset(rp);
  20948. if (needsRHS)
  20949. {
  20950. Owned<IEngineRowAllocator> extractAllocator = ctx->queryCodeContext()->getRowAllocator(helper.queryExtractedSize(), activityId);
  20951. RtlDynamicRowBuilder rb(extractAllocator, true);
  20952. unsigned rhsSize = helper.extractJoinFields(rb, row);
  20953. char * block = (char *) remote.getMem(partNo, 0, sizeof(rp) + sizeof(rhsSize) + rhsSize); // MORE - superfiles
  20954. *(offset_t *) block = rp;
  20955. block += sizeof(rp);
  20956. *(unsigned *) block = rhsSize;
  20957. block += sizeof(rhsSize);
  20958. memcpy(block, rb.row(), rhsSize);
  20959. }
  20960. else
  20961. *(offset_t *) remote.getMem(partNo, 0, sizeof(rp)) = rp; // MORE - superfiles
  20962. ReleaseRoxieRow(row);
  20963. }
  20964. void processEOG()
  20965. {
  20966. #ifdef FETCH_PRESERVES_GROUPING
  20967. UNIMPLEMENTED;
  20968. #endif
  20969. // else discard is correct
  20970. }
  20971. void processGroup(const ConstPointerArray &)
  20972. {
  20973. throwUnexpected();
  20974. }
  20975. void processDone()
  20976. {
  20977. // called from puller thread
  20978. remote.flush();
  20979. remote.senddone();
  20980. }
  20981. virtual bool fireException(IException *e)
  20982. {
  20983. return remote.fireException(e);
  20984. }
  20985. virtual void onLimitExceeded(bool isKeyed)
  20986. {
  20987. if (traceLevel > 4)
  20988. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  20989. if (isKeyed)
  20990. throwUnexpected();
  20991. helper.onLimitExceeded();
  20992. }
  20993. virtual const void *createLimitFailRow(bool isKeyed)
  20994. {
  20995. UNIMPLEMENTED;
  20996. }
  20997. virtual const void *nextInGroup()
  20998. {
  20999. throwUnexpected(); // I am nobody's input
  21000. }
  21001. };
  21002. class CRoxieServerFetchActivityFactory : public CRoxieServerActivityFactory
  21003. {
  21004. RemoteActivityId remoteId;
  21005. Owned<IFilePartMap> map;
  21006. bool variableFileName;
  21007. Owned<const IResolvedFile> datafile;
  21008. public:
  21009. CRoxieServerFetchActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  21010. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), remoteId(_remoteId)
  21011. {
  21012. Owned<IHThorFetchBaseArg> helper = (IHThorFetchBaseArg *) helperFactory();
  21013. IHThorFetchContext *fetchContext = static_cast<IHThorFetchContext *>(helper->selectInterface(TAIfetchcontext_1));
  21014. variableFileName = allFilesDynamic || _queryFactory.isDynamic() || ((fetchContext->getFetchFlags() & (FFvarfilename|FFdynamicfilename)) != 0);
  21015. if (!variableFileName)
  21016. {
  21017. OwnedRoxieString fname(fetchContext->getFileName());
  21018. datafile.setown(_queryFactory.queryPackage().lookupFileName(fname,
  21019. (fetchContext->getFetchFlags() & FFdatafileoptional) != 0,
  21020. true, true,
  21021. _queryFactory.queryWorkUnit()));
  21022. if (datafile)
  21023. map.setown(datafile->getFileMap());
  21024. }
  21025. }
  21026. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  21027. {
  21028. return new CRoxieServerFetchActivity(this, _probeManager, remoteId, map);
  21029. }
  21030. virtual void getXrefInfo(IPropertyTree &reply, const IRoxieContextLogger &logctx) const
  21031. {
  21032. if (datafile)
  21033. addXrefFileInfo(reply, datafile);
  21034. }
  21035. };
  21036. IRoxieServerActivityFactory *createRoxieServerFetchActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  21037. {
  21038. return new CRoxieServerFetchActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode);
  21039. }
  21040. // MORE - is there any point keeping this now?
  21041. class CRoxieServerDummyActivityFactory : public CRoxieServerActivityFactory // not a real activity - just used to properly link files
  21042. {
  21043. public:
  21044. Owned<const IResolvedFile> indexfile;
  21045. Owned<const IResolvedFile> datafile;
  21046. Owned<IKeyArray> keySet;
  21047. Owned<IFileIOArray> files;
  21048. Owned<IFilePartMap> map;
  21049. TranslatorArray layoutTranslators;
  21050. CRoxieServerDummyActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool isLoadDataOnly)
  21051. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  21052. {
  21053. try // does not want any missing file errors to be fatal, or throw traps - just log it
  21054. {
  21055. if (_graphNode.getPropBool("att[@name='_isSpill']/@value", false) || _graphNode.getPropBool("att[@name='_isSpillGlobal']/@value", false))
  21056. return; // ignore 'spills'
  21057. bool isLocal = _graphNode.getPropBool("att[@name='local']/@value") && queryFactory.queryChannel()!=0;
  21058. ThorActivityKind kind = getActivityKind(_graphNode);
  21059. if (kind != TAKdiskwrite && kind != TAKindexwrite && kind != TAKpiperead && kind != TAKpipewrite)
  21060. {
  21061. const char *fileName = queryNodeFileName(_graphNode, kind);
  21062. const char *indexName = queryNodeIndexName(_graphNode, kind);
  21063. if (indexName)
  21064. {
  21065. bool isOpt = pretendAllOpt || _graphNode.getPropBool("att[@name='_isIndexOpt']/@value");
  21066. indexfile.setown(queryFactory.queryPackage().lookupFileName(indexName, isOpt, true, true, queryFactory.queryWorkUnit()));
  21067. if (indexfile)
  21068. keySet.setown(indexfile->getKeyArray(NULL, &layoutTranslators, isOpt, isLocal ? queryFactory.queryChannel() : 0, false));
  21069. }
  21070. if (fileName)
  21071. {
  21072. bool isOpt = pretendAllOpt || _graphNode.getPropBool("att[@name='_isOpt']/@value");
  21073. datafile.setown(_queryFactory.queryPackage().lookupFileName(fileName, isOpt, true, true, queryFactory.queryWorkUnit()));
  21074. if (datafile)
  21075. {
  21076. if (isLocal)
  21077. files.setown(datafile->getIFileIOArray(isOpt, queryFactory.queryChannel()));
  21078. else
  21079. map.setown(datafile->getFileMap());
  21080. }
  21081. }
  21082. }
  21083. }
  21084. catch(IException *E)
  21085. {
  21086. StringBuffer errors;
  21087. E->errorMessage(errors);
  21088. DBGLOG("%s File error = %s", (isLoadDataOnly) ? "LOADDATAONLY" : "SUSPENDED QUERY", errors.str());
  21089. E->Release();
  21090. }
  21091. }
  21092. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const { throw MakeStringException(ROXIE_INTERNAL_ERROR, "%s query %s is suspended and cannot be executed - error occurred at %s(%d)", (queryFactory.isQueryLibrary()) ? "Library" : " ", queryFactory.queryQueryName(), __FILE__, __LINE__); }
  21093. virtual void getXrefInfo(IPropertyTree &reply, const IRoxieContextLogger &logctx) const
  21094. {
  21095. if (datafile)
  21096. addXrefFileInfo(reply, datafile);
  21097. if (indexfile)
  21098. addXrefFileInfo(reply, indexfile);
  21099. }
  21100. };
  21101. IRoxieServerActivityFactory *createRoxieServerDummyActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool isLoadDataOnly)
  21102. {
  21103. return new CRoxieServerDummyActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, isLoadDataOnly);
  21104. }
  21105. //=====================================================================================================
  21106. // Keyed joins...
  21107. //
  21108. // Input records are pulled by a puller thread, which checks each LHS record to determine which (if any) channels it
  21109. // may have RHS matches on, and sends the relevant fields to the relevant slaves.
  21110. // 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
  21111. // the transform and returns rows that are created.
  21112. // 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)
  21113. //
  21114. //=====================================================================================================
  21115. class CJoinGroup;
  21116. interface IJoinProcessor
  21117. {
  21118. virtual void processEOG() = 0;
  21119. virtual CJoinGroup *createJoinGroup(const void *row) = 0;
  21120. virtual void noteEndReceived(CJoinGroup *jg, unsigned candidateCount) = 0;
  21121. virtual bool fireException(IException *E) = 0;
  21122. virtual void processCompletedGroups() = 0;
  21123. };
  21124. //------------------------------------------------------------------------------------------------------
  21125. // Class CJoinGroup has a record per LHS row, plus (if preserving grouping) a 'head of group' record
  21126. // It gathers all the corresponding RHS rows, keeping track of how may slave transactions are pending in endMarkersPending
  21127. // If preserving groups, the 'head of group' record keeps track of how many LHS records in the group are still incomplete.
  21128. // CJoinGroup records are allocated out of the Roxie row memory manager by overloading operator new, so that they are included in the
  21129. // per-query limits etc (Note that the pointer array block is not though).
  21130. // Because of that, the exact size is significant - especially whether fit just under or just over a chunking threshold...
  21131. //
  21132. // There are two phases to the life of a JoinGroup - it is created by the puller thread that is also firing off slave requests
  21133. // notePending will be called once for every slave request. Puller thread calls noteEndReceived(0) once when done - this corresponds to the
  21134. // initial count when created.
  21135. // Slave replies and are noted by the consumer thread calling addRightMatch() and noteEndReceived(n).
  21136. // Once endMarkersPending reaches 0, JoinGroup is complete. Last thread to call noteEndReceived will process the rows and destroy the group.
  21137. // There is no need for a critsec because although multiple threads will access at different times, only the consumer thread will
  21138. // access any modifiable member variables while endMarkersPending != 0 (i.e. complete() is false). Once complete returns true there is a single
  21139. // remaining reference and the JoinGroup will be processed and destroyed.
  21140. //
  21141. //------------------------------------------------------------------------------------------------------
  21142. class CJoinGroup : public CInterface, implements IInterface
  21143. {
  21144. protected:
  21145. const void *left; // LHS row
  21146. PointerArrayOf<KeyedJoinHeader> rows; // matching RHS rows
  21147. atomic_t endMarkersPending; // How many slave responses still waiting for
  21148. CJoinGroup *groupStart; // Head of group, or NULL if not grouping
  21149. unsigned lastPartNo;
  21150. unsigned pos;
  21151. unsigned candidates; // Number of RHS keyed candidates - note this may not be the same as rows.ordinality()
  21152. public:
  21153. #undef new
  21154. void *operator new(size_t size, IRowManager *a, unsigned activityId)
  21155. {
  21156. return a->allocate(size, activityId);
  21157. }
  21158. #if defined(_DEBUG) && defined(_WIN32) && !defined(USING_MPATROL)
  21159. #define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
  21160. #endif
  21161. void operator delete(void *ptr, IRowManager *a, unsigned activityId)
  21162. {
  21163. ReleaseRoxieRow(ptr);
  21164. }
  21165. void operator delete(void *ptr)
  21166. {
  21167. ReleaseRoxieRow(ptr);
  21168. }
  21169. public:
  21170. IMPLEMENT_IINTERFACE;
  21171. CJoinGroup(const void *_left, CJoinGroup *_groupStart)
  21172. {
  21173. #ifdef TRACE_JOINGROUPS
  21174. DBGLOG("Creating joinGroup %p, groupstart %p", this, _groupStart);
  21175. #endif
  21176. candidates = 0;
  21177. lastPartNo = 0;
  21178. pos = 0;
  21179. left = _left;
  21180. groupStart = _groupStart;
  21181. if (_groupStart)
  21182. {
  21183. atomic_inc(&_groupStart->endMarkersPending);
  21184. }
  21185. atomic_set(&endMarkersPending, 1);
  21186. }
  21187. ~CJoinGroup()
  21188. {
  21189. #ifdef TRACE_JOINGROUPS
  21190. DBGLOG("Destroying joinGroup %p", this);
  21191. #endif
  21192. if (left)
  21193. {
  21194. ReleaseRoxieRow(left);
  21195. ForEachItemIn(idx, rows)
  21196. ReleaseRoxieRow(rows.item(idx));
  21197. rows.kill();
  21198. }
  21199. }
  21200. inline bool isHeadRecord() const
  21201. {
  21202. return left==NULL;
  21203. }
  21204. inline bool complete() const
  21205. {
  21206. return atomic_read(&endMarkersPending) == 0;
  21207. }
  21208. #ifdef TRACE_JOINGROUPS
  21209. inline void notePending(unsigned lineNo)
  21210. #else
  21211. inline void notePending()
  21212. #endif
  21213. {
  21214. assert(!complete());
  21215. atomic_inc(&endMarkersPending);
  21216. #ifdef TRACE_JOINGROUPS
  21217. DBGLOG("CJoinGroup::notePending %p from %d, count became %d group count %d", this, lineNo, atomic_read(&endMarkersPending), groupStart ? atomic_read(&groupStart->endMarkersPending) : 0);
  21218. #endif
  21219. }
  21220. inline bool inGroup(CJoinGroup *leader) const
  21221. {
  21222. return groupStart==leader;
  21223. }
  21224. inline const KeyedJoinHeader *queryRow(unsigned idx) const
  21225. {
  21226. // Single threaded by now
  21227. assert(complete());
  21228. return rows.item(idx);
  21229. }
  21230. #ifdef TRACE_JOINGROUPS
  21231. bool noteEndReceived(unsigned candidateCount, unsigned lineNo)
  21232. #else
  21233. bool noteEndReceived(unsigned candidateCount)
  21234. #endif
  21235. {
  21236. assert(!complete());
  21237. if (candidateCount)
  21238. {
  21239. candidates += candidateCount;
  21240. }
  21241. #ifdef TRACE_JOINGROUPS
  21242. 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);
  21243. #endif
  21244. // NOTE - as soon as endMarkersPending and groupStart->endMarkersPending are decremented to zero this object may get released asynchronously by other threads
  21245. // There must therefore be nothing in this method after them that acceses member variables. Think of it as a delete this...
  21246. // In particular, we can't safely reference groupStart after the dec_and_test of endMarkersPending, hence copy local first
  21247. CJoinGroup *localGroupStart = groupStart;
  21248. if (atomic_dec_and_test(&endMarkersPending))
  21249. {
  21250. if (localGroupStart)
  21251. return atomic_dec_and_test(&localGroupStart->endMarkersPending);
  21252. else
  21253. return true;
  21254. }
  21255. else
  21256. return false;
  21257. }
  21258. inline const void *queryLeft() const
  21259. {
  21260. return left;
  21261. }
  21262. void addRightMatch(KeyedJoinHeader *right)
  21263. {
  21264. assert(!complete());
  21265. unsigned short partNo = right->partNo;
  21266. if (partNo != lastPartNo)
  21267. {
  21268. // MORE - should we binchop? If we did we would need to be careful to find LAST match
  21269. if (partNo > lastPartNo)
  21270. pos = rows.length();
  21271. while (pos>0)
  21272. {
  21273. if (rows.item(pos-1)->partNo <= partNo)
  21274. break;
  21275. pos--;
  21276. }
  21277. lastPartNo = partNo;
  21278. }
  21279. rows.add(right, pos);
  21280. pos++;
  21281. }
  21282. inline unsigned rowsSeen() const
  21283. {
  21284. assert(complete());
  21285. return rows.length();
  21286. }
  21287. inline unsigned candidateCount() const
  21288. {
  21289. assert(complete());
  21290. return candidates;
  21291. }
  21292. };
  21293. #ifdef TRACE_JOINGROUPS
  21294. #define notePending() notePending(__LINE__)
  21295. #define noteEndReceived(a) noteEndReceived(a, __LINE__)
  21296. #endif
  21297. class KeyedJoinRemoteAdaptor : public CRemoteResultAdaptor // MORE - not sure it should be derived from this - makes processed all wrong, for example
  21298. {
  21299. private:
  21300. SafeQueueOf<const void, true> ready;
  21301. public:
  21302. IHThorKeyedJoinArg &helper;
  21303. unsigned joinProcessed;
  21304. bool isFullKey;
  21305. bool eof;
  21306. bool isSimple;
  21307. bool allPulled;
  21308. unsigned __int64 totalCycles;
  21309. unsigned activityId;
  21310. RecordPullerThread &puller;
  21311. SafeQueueOf<const void, true> injected; // Used in isSimple mode
  21312. Owned<IEngineRowAllocator> ccdRecordAllocator;
  21313. IJoinProcessor &processor;
  21314. KeyedJoinRemoteAdaptor(const RemoteActivityId &_remoteId, IHThorKeyedJoinArg &_helper, IRoxieServerActivity &_activity, bool _isFullKey, bool _isSimple,
  21315. RecordPullerThread &_puller, IJoinProcessor &_processor)
  21316. : helper(_helper),
  21317. CRemoteResultAdaptor(_remoteId, 0, _helper, _activity, true, true),
  21318. isFullKey(_isFullKey),
  21319. isSimple(_isSimple),
  21320. puller(_puller),
  21321. processor(_processor),
  21322. activityId(_activity.queryId())
  21323. {
  21324. joinProcessed = 0;
  21325. totalCycles = 0;
  21326. allPulled = false;
  21327. eof = false;
  21328. }
  21329. virtual void onCreate(IRoxieInput *_owner, IRoxieServerErrorHandler *_errorHandler, IRoxieSlaveContext *_ctx, IHThorArg *_colocalArg)
  21330. {
  21331. CRemoteResultAdaptor::onCreate(_owner, _errorHandler, _ctx, _colocalArg);
  21332. ccdRecordAllocator.setown(ctx->queryCodeContext()->getRowAllocator(QUERYINTERFACE(helper.queryJoinFieldsRecordSize(), IOutputMetaData), activityId));
  21333. }
  21334. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  21335. {
  21336. eof = false;
  21337. joinProcessed = 0;
  21338. totalCycles = 0;
  21339. allPulled = false;
  21340. assertex(ready.ordinality()==0);
  21341. CRemoteResultAdaptor::start(parentExtractSize, parentExtract, paused);
  21342. }
  21343. virtual void reset()
  21344. {
  21345. CRemoteResultAdaptor::reset();
  21346. while (ready.ordinality())
  21347. {
  21348. const void *goer = ready.dequeue();
  21349. if (goer)
  21350. ReleaseRoxieRow(goer);
  21351. }
  21352. while (injected.ordinality())
  21353. {
  21354. const void *goer = injected.dequeue();
  21355. if (goer)
  21356. ReleaseRoxieRow(goer);
  21357. }
  21358. }
  21359. inline void addResult(const void *row)
  21360. {
  21361. ready.enqueue(row);
  21362. }
  21363. virtual unsigned __int64 queryTotalCycles() const
  21364. {
  21365. return totalCycles;
  21366. }
  21367. virtual IOutputMetaData * queryOutputMeta() const
  21368. {
  21369. return owner->queryOutputMeta();
  21370. }
  21371. virtual const void *nextInGroup()
  21372. {
  21373. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  21374. loop
  21375. {
  21376. if (eof)
  21377. return NULL;
  21378. processSlaveResults();
  21379. if (ready.ordinality())
  21380. {
  21381. const void *result = ready.dequeue();
  21382. if (result)
  21383. joinProcessed++;
  21384. return result;
  21385. }
  21386. else
  21387. eof = true;
  21388. }
  21389. }
  21390. private:
  21391. void processSlaveResults()
  21392. {
  21393. while (!ready.ordinality())
  21394. {
  21395. KeyedJoinHeader *fetchedData;
  21396. if (isSimple)
  21397. {
  21398. while (!allPulled && !injected.ordinality())
  21399. {
  21400. if (!puller.pullRecords(1))
  21401. {
  21402. puller.done();
  21403. allPulled = true;
  21404. }
  21405. }
  21406. fetchedData = (KeyedJoinHeader *) injected.dequeue();
  21407. }
  21408. else
  21409. fetchedData = (KeyedJoinHeader *) CRemoteResultAdaptor::nextInGroup();
  21410. if (fetchedData)
  21411. {
  21412. CJoinGroup *thisGroup = fetchedData->thisGroup;
  21413. if (fetchedData->partNo == (unsigned short) -1)
  21414. {
  21415. #ifdef TRACE_JOINGROUPS
  21416. CTXLOG("Got end for group %p", thisGroup);
  21417. #endif
  21418. unsigned candidateCount = (unsigned) fetchedData->fpos;
  21419. ReleaseRoxieRow(fetchedData);
  21420. processor.noteEndReceived(thisGroup, candidateCount); // note - this can throw exception. So release fetchdata before calling
  21421. }
  21422. else
  21423. {
  21424. #ifdef TRACE_JOINGROUPS
  21425. CTXLOG("Reading another %d bytes for group %p data", ccdRecordSize, thisGroup);
  21426. #endif
  21427. thisGroup->addRightMatch(fetchedData);
  21428. if (isFullKey)
  21429. {
  21430. #ifdef TRACE_JOINGROUPS
  21431. CTXLOG("Calling noteEndReceived for record returned from FETCH of full keyed join");
  21432. #endif
  21433. processor.noteEndReceived(thisGroup, 0); // note - this can throw exception. So release fetchdata before calling
  21434. }
  21435. }
  21436. }
  21437. else
  21438. break;
  21439. }
  21440. }
  21441. };
  21442. class CRoxieServerFullKeyedJoinHead: public CRoxieServerActivity, implements IRecordPullerCallback, implements IRoxieServerErrorHandler
  21443. {
  21444. IHThorKeyedJoinArg &helper;
  21445. Owned<IKeyManager> tlk;
  21446. Linked<IKeyArray> keySet;
  21447. Linked<TranslatorArray> translators;
  21448. CRemoteResultAdaptor remote;
  21449. RecordPullerThread puller;
  21450. IOutputMetaData *indexReadMeta;
  21451. IJoinProcessor *joinHandler;
  21452. bool variableIndexFileName;
  21453. bool indexReadInputRecordVariable;
  21454. bool isLocal;
  21455. Owned<IEngineRowAllocator> indexReadAllocator;
  21456. Owned<const IResolvedFile> varFileInfo;
  21457. IRoxieInput *indexReadInput;
  21458. IIndexReadActivityInfo *rootIndex;
  21459. public:
  21460. CRoxieServerFullKeyedJoinHead(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, IKeyArray * _keySet, TranslatorArray *_translators, IOutputMetaData *_indexReadMeta, IJoinProcessor *_joinHandler, bool _isLocal)
  21461. : CRoxieServerActivity(_factory, _probeManager),
  21462. helper((IHThorKeyedJoinArg &)basehelper),
  21463. tlk(createKeyManager(NULL, 0, this)),
  21464. translators(_translators),
  21465. keySet(_keySet),
  21466. remote(_remoteId, 0, helper, *this, true, true),
  21467. indexReadMeta(_indexReadMeta),
  21468. joinHandler(_joinHandler),
  21469. puller(false),
  21470. isLocal(_isLocal)
  21471. {
  21472. variableIndexFileName = allFilesDynamic || factory->queryQueryFactory().isDynamic() || ((helper.getJoinFlags() & (JFvarindexfilename|JFdynamicindexfilename)) != 0);
  21473. indexReadInputRecordVariable = indexReadMeta->isVariableSize();
  21474. indexReadInput = NULL;
  21475. rootIndex = NULL;
  21476. }
  21477. virtual const IResolvedFile *queryVarFileInfo() const
  21478. {
  21479. return varFileInfo;
  21480. }
  21481. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  21482. {
  21483. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  21484. remote.onCreate(this, this, _ctx, _colocalParent);
  21485. indexReadAllocator.setown(ctx->queryCodeContext()->getRowAllocator(indexReadMeta, activityId));
  21486. }
  21487. virtual void setInput(unsigned idx, IRoxieInput *_in)
  21488. {
  21489. if (!idx)
  21490. puller.setInput(this, _in);
  21491. else if (idx==1)
  21492. indexReadInput = _in;
  21493. else
  21494. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
  21495. }
  21496. virtual void serializeExtra(MemoryBuffer &out)
  21497. {
  21498. if (helper.getJoinFlags() & JFindexfromactivity)
  21499. {
  21500. assertex(rootIndex);
  21501. const RemoteActivityId& indexId = rootIndex->queryRemoteId();
  21502. indexId.serialize(out);
  21503. // could mess about reserving space for length then patching it again, to avoid copy, but probably not worth it
  21504. MemoryBuffer tmp;
  21505. rootIndex->queryActivity()->serializeCreateStartContext(tmp);
  21506. if (rootIndex->queryActivity()->queryVarFileInfo())
  21507. {
  21508. rootIndex->queryActivity()->queryVarFileInfo()->queryTimeStamp().serialize(tmp);
  21509. tmp.append(rootIndex->queryActivity()->queryVarFileInfo()->queryCheckSum());
  21510. }
  21511. unsigned ctxlen = tmp.length();
  21512. out.append(ctxlen).append(tmp);
  21513. }
  21514. }
  21515. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  21516. {
  21517. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  21518. if (indexReadInput)
  21519. {
  21520. indexReadInput->start(parentExtractSize, parentExtract, true); // paused=true because we don't want to actually run the index read
  21521. rootIndex = indexReadInput->queryIndexReadActivity();
  21522. if (!rootIndex)
  21523. throw MakeStringException(ROXIE_INTERNAL_ERROR,"Index in keyed join %d could not be resolved", queryId());
  21524. }
  21525. remote.onStart(parentExtractSize, parentExtract);
  21526. remote.setLimits(helper.getRowLimit(), (unsigned __int64) -1, I64C(0x7FFFFFFFFFFFFFFF));
  21527. if (rootIndex)
  21528. {
  21529. varFileInfo.setown(rootIndex->getVarFileInfo());
  21530. translators.setown(rootIndex->getTranslators());
  21531. keySet.setown(rootIndex->getKeySet());
  21532. }
  21533. else if (variableIndexFileName)
  21534. {
  21535. OwnedRoxieString indexFileName(helper.getIndexFileName());
  21536. varFileInfo.setown(resolveLFN(indexFileName, (helper.getJoinFlags() & JFindexoptional) != 0));
  21537. if (varFileInfo)
  21538. {
  21539. translators.setown(new TranslatorArray);
  21540. keySet.setown(varFileInfo->getKeyArray(factory->queryActivityMeta(), translators, false, isLocal ? factory->queryQueryFactory().queryChannel() : 0, factory->queryQueryFactory().getEnableFieldTranslation())); // MORE - isLocal?
  21541. }
  21542. }
  21543. puller.start(parentExtractSize, parentExtract, paused, ctx->fullKeyedJoinPreload(), false, ctx);
  21544. }
  21545. virtual void stop(bool aborting)
  21546. {
  21547. puller.stop(aborting);
  21548. CRoxieServerActivity::stop(aborting);
  21549. }
  21550. virtual void reset()
  21551. {
  21552. CRoxieServerActivity::reset();
  21553. puller.reset();
  21554. if (varFileInfo)
  21555. {
  21556. keySet.clear();
  21557. varFileInfo.clear();
  21558. }
  21559. }
  21560. virtual IRoxieInput *queryOutput(unsigned idx)
  21561. {
  21562. if (idx==(unsigned)-1)
  21563. idx = 0;
  21564. return idx ? NULL : &remote;
  21565. }
  21566. virtual void processRow(const void *row)
  21567. {
  21568. // MORE - this code seems to be pretty much duplicated below in half-keyed....
  21569. // called from front puller thread
  21570. // buffer up an IndexRead request
  21571. if (helper.leftCanMatch(row))
  21572. {
  21573. RtlDynamicRowBuilder extractedBuilder(indexReadAllocator);
  21574. unsigned indexReadSize = helper.extractIndexReadFields(extractedBuilder, row);
  21575. OwnedConstRoxieRow extracted;
  21576. if (indexReadSize)
  21577. extracted.setown(extractedBuilder.finalizeRowClear(indexReadSize));
  21578. CJoinGroup *jg = joinHandler->createJoinGroup(row);
  21579. for (unsigned partNo = 0; partNo < keySet->length(); partNo++)
  21580. {
  21581. IKeyIndexBase *thisBase = keySet->queryKeyPart(partNo);
  21582. if (thisBase)
  21583. {
  21584. unsigned fileNo = 0;
  21585. IKeyIndex *thisKey = thisBase->queryPart(fileNo);
  21586. try
  21587. {
  21588. tlk->setKey(thisKey);
  21589. tlk->setLayoutTranslator(translators->item(fileNo));
  21590. helper.createSegmentMonitors(tlk, extracted);
  21591. if (rootIndex)
  21592. rootIndex->mergeSegmentMonitors(tlk);
  21593. tlk->finishSegmentMonitors();
  21594. tlk->reset();
  21595. loop
  21596. {
  21597. typedef const void * cvp;
  21598. if (thisKey->isTopLevelKey())
  21599. {
  21600. bool locallySorted = !thisKey->isFullySorted();
  21601. while (locallySorted || tlk->lookup(false))
  21602. {
  21603. unsigned slavePart = locallySorted ? 0 : (unsigned) tlk->queryFpos();
  21604. if (locallySorted || slavePart)
  21605. {
  21606. cvp *outputBuffer = (cvp *) remote.getMem(slavePart, fileNo, indexReadSize + sizeof(cvp) + (indexReadInputRecordVariable ? sizeof(unsigned) : 0));
  21607. *outputBuffer++ = jg;
  21608. if (indexReadInputRecordVariable)
  21609. {
  21610. *(unsigned *) outputBuffer = indexReadSize;
  21611. outputBuffer = (cvp*) (((unsigned *) outputBuffer) + 1);
  21612. }
  21613. jg->notePending();
  21614. memcpy(outputBuffer, extracted, indexReadSize);
  21615. if (locallySorted)
  21616. {
  21617. for (unsigned i = 1; i < numChannels; i++)
  21618. jg->notePending();
  21619. break;
  21620. }
  21621. }
  21622. }
  21623. }
  21624. else
  21625. {
  21626. // MORE - this code seems to be duplicated in half keyed
  21627. unsigned accepted = 0;
  21628. unsigned rejected = 0;
  21629. Owned<CRowArrayMessageResult> result = new CRowArrayMessageResult(ctx->queryRowManager(), true);
  21630. jg->notePending();
  21631. unsigned candidateCount = 0;
  21632. while (tlk->lookup(true))
  21633. {
  21634. candidateCount++;
  21635. atomic_inc(&indexRecordsRead);
  21636. KLBlobProviderAdapter adapter(tlk);
  21637. offset_t recptr;
  21638. const byte *indexRow = tlk->queryKeyBuffer(recptr);
  21639. if (helper.indexReadMatch(extracted, indexRow, recptr, &adapter))
  21640. {
  21641. KeyedJoinHeader *rhs = (KeyedJoinHeader *) ctx->queryRowManager().allocate(KEYEDJOIN_RECORD_SIZE(0), activityId);
  21642. rhs->fpos = recptr;
  21643. rhs->thisGroup = jg;
  21644. rhs->partNo = partNo;
  21645. result->append(rhs);
  21646. }
  21647. else
  21648. {
  21649. rejected++;
  21650. atomic_inc(&postFiltered);
  21651. }
  21652. }
  21653. // output an end marker for the matches to this group
  21654. KeyedJoinHeader *endMarker = (KeyedJoinHeader *) ctx->queryRowManager().allocate(KEYEDJOIN_RECORD_SIZE(0), activityId);
  21655. endMarker->fpos = (offset_t) candidateCount;
  21656. endMarker->thisGroup = jg;
  21657. endMarker->partNo = (unsigned short) -1;
  21658. result->append(endMarker);
  21659. remote.injectResult(result.getClear());
  21660. if (accepted)
  21661. noteStatistic(STATS_ACCEPTED, accepted, 1);
  21662. if (rejected)
  21663. noteStatistic(STATS_REJECTED, rejected, 1);
  21664. }
  21665. if (++fileNo < thisBase->numParts())
  21666. {
  21667. thisKey = thisBase->queryPart(fileNo);
  21668. tlk->setKey(thisKey);
  21669. tlk->setLayoutTranslator(translators->item(fileNo));
  21670. tlk->reset();
  21671. }
  21672. else
  21673. break;
  21674. }
  21675. tlk->releaseSegmentMonitors();
  21676. tlk->setKey(NULL);
  21677. }
  21678. catch (...)
  21679. {
  21680. tlk->releaseSegmentMonitors();
  21681. tlk->setKey(NULL);
  21682. throw;
  21683. }
  21684. }
  21685. }
  21686. joinHandler->noteEndReceived(jg, 0);
  21687. }
  21688. else
  21689. {
  21690. joinHandler->noteEndReceived(joinHandler->createJoinGroup(row), 0);
  21691. }
  21692. }
  21693. void processGroup(const ConstPointerArray &)
  21694. {
  21695. throwUnexpected();
  21696. }
  21697. virtual void processEOG()
  21698. {
  21699. joinHandler->processEOG();
  21700. }
  21701. virtual void processDone()
  21702. {
  21703. // called from puller thread
  21704. remote.flush();
  21705. remote.senddone();
  21706. }
  21707. virtual void onLimitExceeded(bool isKeyed)
  21708. {
  21709. if (traceLevel > 4)
  21710. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  21711. if (isKeyed)
  21712. throwUnexpected();
  21713. helper.onLimitExceeded();
  21714. }
  21715. virtual const void *createLimitFailRow(bool isKeyed)
  21716. {
  21717. throwUnexpected();
  21718. }
  21719. virtual bool fireException(IException *e)
  21720. {
  21721. // called from puller thread on failure
  21722. remote.fireException(LINK(e));
  21723. return joinHandler->fireException(e);
  21724. }
  21725. virtual const void *nextInGroup()
  21726. {
  21727. throwUnexpected(); // I am nobody's input
  21728. }
  21729. };
  21730. class CRoxieServerKeyedJoinBase : public CRoxieServerActivity, implements IRecordPullerCallback, implements IRoxieServerErrorHandler, implements IJoinProcessor
  21731. {
  21732. protected:
  21733. IHThorKeyedJoinArg &helper;
  21734. KeyedJoinRemoteAdaptor remote;
  21735. RecordPullerThread puller;
  21736. OwnedConstRoxieRow defaultRight;
  21737. Owned<IEngineRowAllocator> defaultRightAllocator;
  21738. unsigned joinFlags;
  21739. unsigned atMost;
  21740. unsigned atmostsTriggered;
  21741. unsigned abortLimit;
  21742. unsigned keepLimit;
  21743. bool limitFail;
  21744. bool limitOnFail;
  21745. bool preserveGroups;
  21746. bool cloneLeft;
  21747. bool isSimple;
  21748. bool isLocal;
  21749. ThorActivityKind activityKind;
  21750. CJoinGroup *groupStart;
  21751. CriticalSection groupsCrit;
  21752. QueueOf<CJoinGroup, false> groups;
  21753. IRoxieInput *indexReadInput;
  21754. IIndexReadActivityInfo *rootIndex;
  21755. void createDefaultRight()
  21756. {
  21757. if (!defaultRight)
  21758. {
  21759. if (!defaultRightAllocator)
  21760. defaultRightAllocator.setown(ctx->queryCodeContext()->getRowAllocator(helper.queryJoinFieldsRecordSize(), activityId));
  21761. RtlDynamicRowBuilder rowBuilder(defaultRightAllocator);
  21762. size32_t thisSize = helper.createDefaultRight(rowBuilder);
  21763. defaultRight.setown(rowBuilder.finalizeRowClear(thisSize));
  21764. }
  21765. }
  21766. public:
  21767. CRoxieServerKeyedJoinBase(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _joinFlags
  21768. , bool isFull, bool _isSimple, bool _isLocal)
  21769. : CRoxieServerActivity(_factory, _probeManager),
  21770. helper((IHThorKeyedJoinArg &)basehelper),
  21771. remote(_remoteId, helper, *this, isFull, _isSimple, puller, *this),
  21772. joinFlags(_joinFlags),
  21773. preserveGroups(meta.isGrouped()),
  21774. puller(false),
  21775. isSimple(_isSimple),
  21776. isLocal(_isLocal),
  21777. abortLimit(0),
  21778. keepLimit(0),
  21779. atMost(0),
  21780. limitFail(false),
  21781. limitOnFail(false),
  21782. cloneLeft(false)
  21783. {
  21784. groupStart = NULL;
  21785. activityKind = _factory->getKind();
  21786. indexReadInput = NULL;
  21787. rootIndex = NULL;
  21788. atmostsTriggered = 0;
  21789. // MORE - code would be easier to read if I got more values from helper rather than passing from factory
  21790. }
  21791. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  21792. {
  21793. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  21794. remote.onCreate(this, this, _ctx, _colocalParent);
  21795. }
  21796. virtual void setInput(unsigned idx, IRoxieInput *_in)
  21797. {
  21798. if (!idx)
  21799. puller.setInput(this, _in);
  21800. else if (idx==1)
  21801. indexReadInput = _in;
  21802. else
  21803. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
  21804. }
  21805. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  21806. {
  21807. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  21808. if (indexReadInput)
  21809. {
  21810. indexReadInput->start(parentExtractSize, parentExtract, true); // paused=true because we don't want to actually run the index read
  21811. rootIndex = indexReadInput->queryIndexReadActivity();
  21812. if (!rootIndex)
  21813. throw MakeStringException(ROXIE_INTERNAL_ERROR,"Index in keyed join %d could not be resolved", queryId());
  21814. }
  21815. remote.onStart(parentExtractSize, parentExtract);
  21816. remote.setLimits(helper.getRowLimit(), (unsigned __int64) -1, I64C(0x7FFFFFFFFFFFFFFF));
  21817. atmostsTriggered = 0;
  21818. atMost = helper.getJoinLimit();
  21819. if (atMost == 0) atMost = (unsigned)-1;
  21820. abortLimit = helper.getMatchAbortLimit();
  21821. if (abortLimit == 0 || atMost != (unsigned) -1) abortLimit = (unsigned)-1;
  21822. keepLimit = helper.getKeepLimit();
  21823. if (keepLimit == 0) keepLimit = (unsigned)-1;
  21824. getLimitType(joinFlags, limitFail, limitOnFail);
  21825. cloneLeft = (joinFlags & JFtransformmatchesleft) != 0;
  21826. if (joinFlags & JFleftouter)
  21827. createDefaultRight();
  21828. }
  21829. virtual void stop(bool aborting)
  21830. {
  21831. puller.stop(aborting);
  21832. if (indexReadInput)
  21833. indexReadInput->stop(aborting);
  21834. CRoxieServerActivity::stop(aborting);
  21835. }
  21836. virtual unsigned __int64 queryLocalCycles() const
  21837. {
  21838. __int64 localCycles = remote.totalCycles;
  21839. localCycles -= puller.queryTotalCycles(); // MORE - debatable... but probably fair.
  21840. if (localCycles < 0)
  21841. localCycles = 0;
  21842. return localCycles;
  21843. }
  21844. virtual IRoxieInput *queryInput(unsigned idx)
  21845. {
  21846. if (idx==0)
  21847. return puller.queryInput();
  21848. else if (idx==1)
  21849. return indexReadInput;
  21850. else
  21851. return NULL;
  21852. }
  21853. virtual void reset()
  21854. {
  21855. totalCycles = remote.totalCycles;
  21856. remote.totalCycles = 0;
  21857. processed = remote.joinProcessed;
  21858. remote.joinProcessed = 0;
  21859. defaultRight.clear();
  21860. if (indexReadInput)
  21861. indexReadInput->reset();
  21862. if (atmostsTriggered)
  21863. noteStatistic(STATS_ATMOST, atmostsTriggered, 1);
  21864. CRoxieServerActivity::reset();
  21865. puller.reset();
  21866. while (groups.ordinality())
  21867. {
  21868. ::Release(groups.dequeue());
  21869. }
  21870. }
  21871. virtual IRoxieInput *queryOutput(unsigned idx)
  21872. {
  21873. if (idx==(unsigned)-1)
  21874. idx = 0;
  21875. return idx ? NULL : &remote;
  21876. }
  21877. #undef new
  21878. virtual CJoinGroup *createJoinGroup(const void *row)
  21879. {
  21880. // NOTE - we need to protect access to queue, since it's also modified by consumer thread. Groupstart is only modified by puller thread.
  21881. CriticalBlock c(groupsCrit);
  21882. if (preserveGroups && !groupStart)
  21883. {
  21884. groupStart = new (&ctx->queryRowManager(), activityId) CJoinGroup(NULL, NULL);
  21885. groups.enqueue(groupStart);
  21886. }
  21887. CJoinGroup *jg = new (&ctx->queryRowManager(), activityId) CJoinGroup(row, groupStart);
  21888. groups.enqueue(jg);
  21889. return jg;
  21890. }
  21891. #if defined(_DEBUG) && defined(_WIN32) && !defined(USING_MPATROL)
  21892. #define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
  21893. #endif
  21894. void endGroup()
  21895. {
  21896. CriticalBlock c(groupsCrit);
  21897. if (groupStart)
  21898. noteEndReceived(groupStart, 0);
  21899. groupStart = NULL;
  21900. }
  21901. virtual void noteEndReceived(CJoinGroup *jg, unsigned candidateCount)
  21902. {
  21903. if (jg->noteEndReceived(candidateCount))
  21904. processCompletedGroups();
  21905. }
  21906. void processCompletedGroups()
  21907. {
  21908. loop
  21909. {
  21910. CriticalBlock c(groupsCrit);
  21911. if (!groups.head()->complete())
  21912. break;
  21913. Owned<CJoinGroup> head = groups.dequeue();
  21914. if (preserveGroups)
  21915. {
  21916. assert(head->isHeadRecord());
  21917. assert(groups.head()->inGroup(head));
  21918. unsigned joinGroupSize = 0;
  21919. while (groups.ordinality() && groups.head()->inGroup(head))
  21920. {
  21921. Owned<CJoinGroup> finger = groups.dequeue();
  21922. joinGroupSize += doJoinGroup(finger);
  21923. }
  21924. if (joinGroupSize)
  21925. remote.addResult(NULL);
  21926. }
  21927. else
  21928. doJoinGroup(head);
  21929. if (!groups.ordinality())
  21930. break;
  21931. }
  21932. }
  21933. void failLimit(const void * left)
  21934. {
  21935. helper.onMatchAbortLimitExceeded();
  21936. CommonXmlWriter xmlwrite(0);
  21937. if (input && input->queryOutputMeta() && input->queryOutputMeta()->hasXML())
  21938. {
  21939. input->queryOutputMeta()->toXML((byte *) left, xmlwrite);
  21940. }
  21941. throw MakeStringException(ROXIE_JOIN_ERROR, "More than %d match candidates in keyed join %d for row %s", abortLimit, queryId(), xmlwrite.str());
  21942. }
  21943. virtual bool needsAllocator() const { return true; }
  21944. unsigned doTransform(const void *left, const void *right, offset_t fpos_or_count, IException *except, const void **group, unsigned counter)
  21945. {
  21946. if (cloneLeft && !except)
  21947. {
  21948. LinkRoxieRow(left);
  21949. remote.addResult((void *) left);
  21950. return 1;
  21951. }
  21952. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  21953. unsigned outSize;
  21954. try
  21955. {
  21956. outSize = except ? helper.onFailTransform(rowBuilder, left, right, fpos_or_count, except) :
  21957. (activityKind == TAKkeyeddenormalizegroup) ? helper.transform(rowBuilder, left, right, (unsigned) fpos_or_count, group) :
  21958. helper.transform(rowBuilder, left, right, fpos_or_count, counter);
  21959. }
  21960. catch (IException *E)
  21961. {
  21962. throw makeWrappedException(E);
  21963. }
  21964. if (outSize)
  21965. {
  21966. const void *shrunk = rowBuilder.finalizeRowClear(outSize);
  21967. remote.addResult(shrunk);
  21968. return 1;
  21969. }
  21970. else
  21971. return 0;
  21972. }
  21973. unsigned doJoinGroup(CJoinGroup *jg)
  21974. {
  21975. unsigned matched = jg->rowsSeen();
  21976. unsigned added = 0;
  21977. const void *left = jg->queryLeft();
  21978. if (jg->candidateCount() > abortLimit)
  21979. {
  21980. if (limitFail)
  21981. failLimit(left);
  21982. if (ctx->queryDebugContext())
  21983. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  21984. if (limitOnFail)
  21985. {
  21986. Owned<IException> except;
  21987. try
  21988. {
  21989. failLimit(left);
  21990. }
  21991. catch(IException * e)
  21992. {
  21993. except.setown(e);
  21994. }
  21995. added = doTransform(left, defaultRight, 0, except, NULL, 0);
  21996. }
  21997. }
  21998. else if (!matched || jg->candidateCount() > atMost)
  21999. {
  22000. if (jg->candidateCount() > atMost)
  22001. atmostsTriggered++;
  22002. switch (joinFlags & JFtypemask)
  22003. {
  22004. case JFleftouter:
  22005. case JFleftonly:
  22006. switch (activityKind)
  22007. {
  22008. case TAKkeyedjoin:
  22009. case TAKkeyeddenormalizegroup:
  22010. added = doTransform(left, defaultRight, 0, NULL, NULL, 0);
  22011. break;
  22012. case TAKkeyeddenormalize:
  22013. LinkRoxieRow(left);
  22014. remote.addResult((void *) left);
  22015. added++;
  22016. break;
  22017. }
  22018. break;
  22019. }
  22020. }
  22021. else if (!(joinFlags & JFexclude))
  22022. {
  22023. unsigned idx = 0;
  22024. switch (activityKind)
  22025. {
  22026. case TAKkeyedjoin:
  22027. while (idx < matched)
  22028. {
  22029. const KeyedJoinHeader *rhs = jg->queryRow(idx);
  22030. added += doTransform(left, &rhs->rhsdata, rhs->fpos, NULL, NULL, idx+1);
  22031. if (added==keepLimit)
  22032. break;
  22033. idx++;
  22034. }
  22035. break;
  22036. case TAKkeyeddenormalize:
  22037. {
  22038. OwnedConstRoxieRow newLeft;
  22039. newLeft.set(left);
  22040. unsigned rowSize = 0;
  22041. unsigned rightAdded = 0;
  22042. while (idx < matched)
  22043. {
  22044. const KeyedJoinHeader *rhs = jg->queryRow(idx);
  22045. try
  22046. {
  22047. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  22048. size32_t transformedSize = helper.transform(rowBuilder, newLeft, &rhs->rhsdata, rhs->fpos, idx+1);
  22049. if (transformedSize)
  22050. {
  22051. rowSize = transformedSize;
  22052. newLeft.setown(rowBuilder.finalizeRowClear(rowSize));
  22053. rightAdded++;
  22054. if (rightAdded==keepLimit)
  22055. break;
  22056. }
  22057. idx++;
  22058. }
  22059. catch (IException *E)
  22060. {
  22061. throw makeWrappedException(E);
  22062. }
  22063. }
  22064. if (rowSize)
  22065. {
  22066. remote.addResult(newLeft.getClear());
  22067. added++;
  22068. }
  22069. }
  22070. break;
  22071. case TAKkeyeddenormalizegroup:
  22072. {
  22073. ConstPointerArray extractedRows;
  22074. while (idx < matched && idx < keepLimit)
  22075. {
  22076. const KeyedJoinHeader *rhs = jg->queryRow(idx);
  22077. extractedRows.append((void *) &rhs->rhsdata);
  22078. idx++;
  22079. }
  22080. added += doTransform(left, extractedRows.item(0), extractedRows.ordinality(), NULL, (const void * *)extractedRows.getArray(), 0);
  22081. }
  22082. break;
  22083. }
  22084. }
  22085. return added;
  22086. }
  22087. virtual void processDone()
  22088. {
  22089. // called from puller thread
  22090. remote.flush();
  22091. remote.senddone();
  22092. }
  22093. virtual void onLimitExceeded(bool isKeyed)
  22094. {
  22095. if (traceLevel > 4)
  22096. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  22097. if (isKeyed)
  22098. throwUnexpected();
  22099. helper.onLimitExceeded();
  22100. }
  22101. virtual const void *createLimitFailRow(bool isKeyed)
  22102. {
  22103. throwUnexpected();
  22104. }
  22105. virtual bool fireException(IException *e)
  22106. {
  22107. // called from puller thread on failure
  22108. return remote.fireException(e);
  22109. }
  22110. virtual const void *nextInGroup()
  22111. {
  22112. throwUnexpected(); // I am nobody's input
  22113. }
  22114. };
  22115. #ifdef _MSC_VER
  22116. #pragma warning ( push )
  22117. #pragma warning ( disable: 4355 )
  22118. #endif
  22119. class CRoxieServerKeyedJoinActivity : public CRoxieServerKeyedJoinBase
  22120. {
  22121. CRoxieServerFullKeyedJoinHead head;
  22122. Owned<IEngineRowAllocator> fetchInputAllocator;
  22123. Linked<IFilePartMap> map;
  22124. bool variableFetchFileName;
  22125. Owned<const IResolvedFile> varFetchFileInfo;
  22126. CachedOutputMetaData fetchInputFields;
  22127. public:
  22128. CRoxieServerKeyedJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_headId, IKeyArray * _key, TranslatorArray *_translators, IOutputMetaData *_indexReadMeta,
  22129. const RemoteActivityId &_tailId, IFilePartMap *_map, unsigned _joinFlags, bool _isLocal)
  22130. : CRoxieServerKeyedJoinBase(_factory, _probeManager, _tailId, _joinFlags, true, false, _isLocal),
  22131. head(_factory, _probeManager, _headId, _key, _translators, _indexReadMeta, this, _isLocal),
  22132. map(_map)
  22133. {
  22134. CRoxieServerKeyedJoinBase::setInput(0, head.queryOutput(0));
  22135. variableFetchFileName = allFilesDynamic || factory->queryQueryFactory().isDynamic() || ((helper.getFetchFlags() & (FFvarfilename|FFdynamicfilename)) != 0);
  22136. }
  22137. virtual const IResolvedFile *queryVarFileInfo() const
  22138. {
  22139. return varFetchFileInfo;
  22140. }
  22141. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  22142. {
  22143. CRoxieServerKeyedJoinBase::onCreate(_ctx, _colocalParent);
  22144. head.onCreate(_ctx, _colocalParent);
  22145. fetchInputFields.set(helper.queryFetchInputRecordSize());
  22146. fetchInputAllocator.setown(ctx->queryCodeContext()->getRowAllocator(helper.queryFetchInputRecordSize(), activityId));
  22147. }
  22148. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  22149. {
  22150. CRoxieServerKeyedJoinBase::start(parentExtractSize, parentExtract, paused);
  22151. if (variableFetchFileName)
  22152. {
  22153. bool isFetchOpt = (helper.getFetchFlags() & FFdatafileoptional) != 0;
  22154. OwnedRoxieString fname(helper.getFileName());
  22155. varFetchFileInfo.setown(resolveLFN(fname, isFetchOpt));
  22156. if (varFetchFileInfo)
  22157. map.setown(varFetchFileInfo->getFileMap());
  22158. }
  22159. puller.start(parentExtractSize, parentExtract, paused, ctx->keyedJoinPreload(), false, ctx);
  22160. }
  22161. virtual void setInput(unsigned idx, IRoxieInput *in)
  22162. {
  22163. head.setInput(idx, in);
  22164. }
  22165. virtual void processRow(const void *_rhs)
  22166. {
  22167. // called from puller thread
  22168. KeyedJoinHeader *rhs = (KeyedJoinHeader *) _rhs;
  22169. CJoinGroup *jg = rhs->thisGroup;
  22170. if (rhs->partNo != (unsigned short) -1)
  22171. {
  22172. unsigned partNo = map->mapOffset(rhs->fpos);
  22173. RtlDynamicRowBuilder fetchBuilder(fetchInputAllocator, true);
  22174. size32_t fisize = helper.extractFetchFields(fetchBuilder, jg->queryLeft());
  22175. if (fetchInputFields.isVariableSize())
  22176. {
  22177. KeyedJoinHeader *outRow = (KeyedJoinHeader *) remote.getMem(partNo, 0, KEYEDJOIN_RECORD_SIZE(fisize + sizeof(fisize)));
  22178. memcpy(outRow, rhs, KEYEDJOIN_RECORD_SIZE(0)); // MORE - copy constructor might be more appropriate....
  22179. ReleaseRoxieRow(rhs);
  22180. jg->notePending();
  22181. memcpy(&outRow->rhsdata, &fisize, sizeof(fisize));
  22182. memcpy((&outRow->rhsdata)+sizeof(fisize), fetchBuilder.row(), fisize);
  22183. }
  22184. else
  22185. {
  22186. KeyedJoinHeader *outRow = (KeyedJoinHeader *) remote.getMem(partNo, 0, KEYEDJOIN_RECORD_SIZE(fisize));
  22187. memcpy(outRow, rhs, KEYEDJOIN_RECORD_SIZE(0)); // MORE - copy constructor might be more appropriate....
  22188. ReleaseRoxieRow(rhs);
  22189. jg->notePending();
  22190. memcpy(&outRow->rhsdata, fetchBuilder.row(), fisize);
  22191. }
  22192. }
  22193. else
  22194. {
  22195. unsigned candidateCount = (unsigned) rhs->fpos;
  22196. // CTXLOG("Full keyed join - all results back from index");
  22197. ReleaseRoxieRow(rhs);
  22198. noteEndReceived(jg, candidateCount); // may throw exception - so release row before calling
  22199. }
  22200. }
  22201. virtual void processEOG()
  22202. {
  22203. // called from front puller thread
  22204. if (preserveGroups)
  22205. endGroup();
  22206. }
  22207. void processGroup(const ConstPointerArray &)
  22208. {
  22209. throwUnexpected();
  22210. }
  22211. };
  22212. #ifdef _MSC_VER
  22213. #pragma warning ( pop )
  22214. #endif
  22215. class CRoxieServerHalfKeyedJoinActivity : public CRoxieServerKeyedJoinBase
  22216. {
  22217. IOutputMetaData *indexReadMeta;
  22218. Owned<IEngineRowAllocator> indexReadAllocator;
  22219. Owned<IKeyManager> tlk;
  22220. bool variableIndexFileName;
  22221. bool indexReadInputRecordVariable;
  22222. Owned<const IResolvedFile> varFileInfo;
  22223. Linked<TranslatorArray> translators;
  22224. Linked<IKeyArray> keySet;
  22225. Owned<IOutputMetaData> joinPrefixedMeta;
  22226. Owned<IEngineRowAllocator> joinFieldsAllocator;
  22227. public:
  22228. CRoxieServerHalfKeyedJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, IKeyArray * _keySet, TranslatorArray *_translators,
  22229. IOutputMetaData *_indexReadMeta, unsigned _joinFlags, bool _isSimple, bool _isLocal)
  22230. : CRoxieServerKeyedJoinBase(_factory, _probeManager, _remoteId, _joinFlags, false, _isSimple, _isLocal),
  22231. indexReadMeta(_indexReadMeta),
  22232. tlk(createKeyManager(NULL, 0, this)),
  22233. keySet(_keySet),
  22234. translators(_translators)
  22235. {
  22236. variableIndexFileName = allFilesDynamic || factory->queryQueryFactory().isDynamic() || ((helper.getJoinFlags() & (JFvarindexfilename|JFdynamicindexfilename)) != 0);
  22237. indexReadInputRecordVariable = indexReadMeta->isVariableSize();
  22238. }
  22239. virtual void serializeExtra(MemoryBuffer &out)
  22240. {
  22241. if (helper.getJoinFlags() & JFindexfromactivity)
  22242. {
  22243. assertex(rootIndex);
  22244. const RemoteActivityId& indexId = rootIndex->queryRemoteId();
  22245. indexId.serialize(out);
  22246. // could mess about reserving space for length then patching it again, to avoid copy, but probably not worth it
  22247. MemoryBuffer tmp;
  22248. rootIndex->queryActivity()->serializeCreateStartContext(tmp);
  22249. if (rootIndex->queryActivity()->queryVarFileInfo())
  22250. {
  22251. rootIndex->queryActivity()->queryVarFileInfo()->queryTimeStamp().serialize(tmp);
  22252. tmp.append(rootIndex->queryActivity()->queryVarFileInfo()->queryCheckSum());
  22253. }
  22254. unsigned ctxlen = tmp.length();
  22255. out.append(ctxlen).append(tmp);
  22256. }
  22257. }
  22258. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  22259. {
  22260. CRoxieServerKeyedJoinBase::onCreate(_ctx, _colocalParent);
  22261. indexReadAllocator.setown(ctx->queryCodeContext()->getRowAllocator(indexReadMeta, activityId));
  22262. IOutputMetaData *joinFieldsMeta = helper.queryJoinFieldsRecordSize();
  22263. joinPrefixedMeta.setown(new CPrefixedOutputMeta(KEYEDJOIN_RECORD_SIZE(0), joinFieldsMeta)); // MORE - not sure if we really need this
  22264. joinFieldsAllocator.setown(ctx->queryCodeContext()->getRowAllocator(joinPrefixedMeta, activityId));
  22265. }
  22266. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  22267. {
  22268. CRoxieServerKeyedJoinBase::start(parentExtractSize, parentExtract, paused);
  22269. if (rootIndex)
  22270. {
  22271. varFileInfo.setown(rootIndex->getVarFileInfo());
  22272. translators.setown(rootIndex->getTranslators());
  22273. keySet.setown(rootIndex->getKeySet());
  22274. }
  22275. else if (variableIndexFileName)
  22276. {
  22277. OwnedRoxieString indexFileName(helper.getIndexFileName());
  22278. varFileInfo.setown(resolveLFN(indexFileName, (helper.getJoinFlags() & JFindexoptional) != 0));
  22279. if (varFileInfo)
  22280. {
  22281. translators.setown(new TranslatorArray);
  22282. keySet.setown(varFileInfo->getKeyArray(factory->queryActivityMeta(), translators, false, isLocal ? factory->queryQueryFactory().queryChannel() : 0, factory->queryQueryFactory().getEnableFieldTranslation()));
  22283. }
  22284. }
  22285. puller.start(parentExtractSize, parentExtract, paused, ctx->keyedJoinPreload(), isSimple, ctx);
  22286. }
  22287. virtual const IResolvedFile *queryVarFileInfo() const
  22288. {
  22289. return varFileInfo;
  22290. }
  22291. virtual void reset()
  22292. {
  22293. CRoxieServerKeyedJoinBase::reset();
  22294. if (varFileInfo)
  22295. {
  22296. keySet.clear();
  22297. varFileInfo.clear();
  22298. }
  22299. }
  22300. virtual void processRow(const void *row)
  22301. {
  22302. // called from front puller thread
  22303. // buffer up an IndexRead request
  22304. if (helper.leftCanMatch(row) && keySet)
  22305. {
  22306. RtlDynamicRowBuilder extractBuilder(indexReadAllocator);
  22307. unsigned indexReadRecordSize = helper.extractIndexReadFields(extractBuilder, row);
  22308. OwnedConstRoxieRow extracted;
  22309. if (indexReadRecordSize)
  22310. extracted.setown(extractBuilder.finalizeRowClear(indexReadRecordSize));
  22311. CJoinGroup *jg = createJoinGroup(row);
  22312. for (unsigned partNo = 0; partNo < keySet->length(); partNo++)
  22313. {
  22314. IKeyIndexBase *thisBase = keySet->queryKeyPart(partNo);
  22315. if (thisBase)
  22316. {
  22317. unsigned fileNo = 0;
  22318. IKeyIndex *thisKey = thisBase->queryPart(fileNo);
  22319. tlk->setKey(thisKey);
  22320. tlk->setLayoutTranslator(translators->item(fileNo));
  22321. helper.createSegmentMonitors(tlk, extracted);
  22322. if (rootIndex)
  22323. rootIndex->mergeSegmentMonitors(tlk);
  22324. tlk->finishSegmentMonitors();
  22325. try
  22326. {
  22327. tlk->reset();
  22328. loop
  22329. {
  22330. typedef const void * cvp;
  22331. if (thisKey && thisKey->isTopLevelKey())
  22332. {
  22333. bool locallySorted = (!thisKey->isFullySorted());
  22334. while (locallySorted || tlk->lookup(false))
  22335. {
  22336. unsigned slavePart = locallySorted ? 0 : (unsigned) tlk->queryFpos();
  22337. if (locallySorted || slavePart)
  22338. {
  22339. cvp *outputBuffer = (cvp *) remote.getMem(slavePart, fileNo, indexReadRecordSize + sizeof(cvp) + (indexReadInputRecordVariable ? sizeof(unsigned) : 0));
  22340. *outputBuffer++ = jg;
  22341. if (indexReadInputRecordVariable)
  22342. {
  22343. *(unsigned *) outputBuffer = indexReadRecordSize;
  22344. outputBuffer = (cvp *) (((unsigned *) outputBuffer) + 1);
  22345. }
  22346. jg->notePending();
  22347. memcpy(outputBuffer, extracted, indexReadRecordSize);
  22348. if (locallySorted)
  22349. {
  22350. for (unsigned i = 1; i < numChannels; i++)
  22351. jg->notePending();
  22352. break;
  22353. }
  22354. }
  22355. }
  22356. }
  22357. else
  22358. {
  22359. unsigned accepted = 0;
  22360. unsigned rejected = 0;
  22361. Owned<CRowArrayMessageResult> result;
  22362. if (!isSimple)
  22363. result.setown(new CRowArrayMessageResult(ctx->queryRowManager(), true));
  22364. // MORE - This code seems to be duplicated in keyedJoinHead
  22365. jg->notePending();
  22366. unsigned candidateCount = 0;
  22367. while (tlk->lookup(true))
  22368. {
  22369. candidateCount++;
  22370. atomic_inc(&indexRecordsRead);
  22371. KLBlobProviderAdapter adapter(tlk);
  22372. offset_t recptr;
  22373. const byte *indexRow = tlk->queryKeyBuffer(recptr);
  22374. if (helper.indexReadMatch(extracted, indexRow, recptr, &adapter))
  22375. {
  22376. RtlDynamicRowBuilder rb(joinFieldsAllocator, true);
  22377. CPrefixedRowBuilder pb(KEYEDJOIN_RECORD_SIZE(0), rb);
  22378. accepted++;
  22379. KLBlobProviderAdapter adapter(tlk);
  22380. size32_t joinFieldsSize = helper.extractJoinFields(pb, indexRow, recptr, &adapter);
  22381. KeyedJoinHeader *rec = (KeyedJoinHeader *) rb.getUnfinalizedClear(); // lack of finalize ok as unserialized data here.
  22382. rec->fpos = recptr;
  22383. rec->thisGroup = jg;
  22384. rec->partNo = partNo;
  22385. if (isSimple)
  22386. remote.injected.enqueue(rec);
  22387. else
  22388. result->append(rec);
  22389. }
  22390. else
  22391. {
  22392. rejected++;
  22393. atomic_inc(&postFiltered);
  22394. }
  22395. }
  22396. // output an end marker for the matches to this group
  22397. KeyedJoinHeader *rec = (KeyedJoinHeader *) ctx->queryRowManager().allocate(KEYEDJOIN_RECORD_SIZE(0), activityId);
  22398. rec->fpos = (offset_t) candidateCount;
  22399. rec->thisGroup = jg;
  22400. rec->partNo = (unsigned short) -1;
  22401. if (isSimple)
  22402. remote.injected.enqueue(rec);
  22403. else
  22404. {
  22405. result->append(rec);
  22406. remote.injectResult(result.getClear());
  22407. }
  22408. if (accepted)
  22409. noteStatistic(STATS_ACCEPTED, accepted, 1);
  22410. if (rejected)
  22411. noteStatistic(STATS_REJECTED, rejected, 1);
  22412. }
  22413. if (++fileNo < thisBase->numParts())
  22414. {
  22415. thisKey = thisBase->queryPart(fileNo);
  22416. tlk->setKey(thisKey);
  22417. tlk->setLayoutTranslator(translators->item(fileNo));
  22418. tlk->reset();
  22419. }
  22420. else
  22421. break;
  22422. }
  22423. tlk->releaseSegmentMonitors();
  22424. tlk->setKey(NULL);
  22425. }
  22426. catch (...)
  22427. {
  22428. tlk->releaseSegmentMonitors();
  22429. tlk->setKey(NULL);
  22430. throw;
  22431. }
  22432. }
  22433. }
  22434. noteEndReceived(jg, 0);
  22435. }
  22436. else
  22437. {
  22438. noteEndReceived(createJoinGroup(row), 0);
  22439. }
  22440. }
  22441. virtual void processEOG()
  22442. {
  22443. // called from front puller thread
  22444. if (preserveGroups)
  22445. endGroup();
  22446. }
  22447. void processGroup(const ConstPointerArray &)
  22448. {
  22449. throwUnexpected();
  22450. }
  22451. };
  22452. class CRoxieServerKeyedJoinActivityFactory : public CRoxieServerMultiInputFactory
  22453. {
  22454. Owned<const IResolvedFile> indexfile;
  22455. Owned<const IResolvedFile> datafile;
  22456. Owned<IKeyArray> keySet;
  22457. Owned<TranslatorArray> translatorArray;
  22458. Owned<IDefRecordMeta> activityMeta;
  22459. RemoteActivityId headId;
  22460. RemoteActivityId tailId;
  22461. IOutputMetaData *indexReadMeta;
  22462. Owned<IFilePartMap> map;
  22463. Owned<IFileIOArray> files;
  22464. unsigned joinFlags;
  22465. bool isHalfKeyed;
  22466. bool isLocal;
  22467. bool enableFieldTranslation;
  22468. bool variableFetchFileName;
  22469. bool variableIndexFileName;
  22470. bool isSimple;
  22471. public:
  22472. CRoxieServerKeyedJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_headId, const RemoteActivityId &_tailId, IPropertyTree &_graphNode)
  22473. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), headId(_headId), tailId(_tailId)
  22474. {
  22475. Owned<IHThorKeyedJoinArg> helper = (IHThorKeyedJoinArg *) helperFactory();
  22476. isLocal = _graphNode.getPropBool("att[@name='local']/@value") && queryFactory.queryChannel()!=0;
  22477. isSimple = isLocal;
  22478. rtlDataAttr indexLayoutMeta;
  22479. size32_t indexLayoutSize;
  22480. if(!helper->getIndexLayout(indexLayoutSize, indexLayoutMeta.refdata()))
  22481. assertex(indexLayoutSize== 0);
  22482. MemoryBuffer m;
  22483. m.setBuffer(indexLayoutSize, indexLayoutMeta.getdata());
  22484. activityMeta.setown(deserializeRecordMeta(m, true));
  22485. enableFieldTranslation = queryFactory.getEnableFieldTranslation();
  22486. translatorArray.setown(new TranslatorArray);
  22487. joinFlags = helper->getJoinFlags();
  22488. variableIndexFileName = allFilesDynamic || _queryFactory.isDynamic() || ((joinFlags & (JFvarindexfilename|JFdynamicindexfilename)) != 0);
  22489. variableFetchFileName = allFilesDynamic || _queryFactory.isDynamic() || ((helper->getFetchFlags() & (FFvarfilename|FFdynamicfilename)) != 0);
  22490. if (!variableIndexFileName)
  22491. {
  22492. bool isOpt = (joinFlags & JFindexoptional) != 0;
  22493. OwnedRoxieString indexFileName(helper->getIndexFileName());
  22494. indexfile.setown(queryFactory.queryPackage().lookupFileName(indexFileName, isOpt, true, true, queryFactory.queryWorkUnit()));
  22495. if (indexfile)
  22496. keySet.setown(indexfile->getKeyArray(activityMeta, translatorArray, isOpt, isLocal ? queryFactory.queryChannel() : 0, enableFieldTranslation));
  22497. }
  22498. if (keySet && keySet->length()==1 && !isSimple)
  22499. {
  22500. IKeyIndexBase *thisBase = keySet->queryKeyPart(0);
  22501. if (thisBase->numParts()==1 && !thisBase->queryPart(0)->isTopLevelKey() && !_queryFactory.getDebugValueBool("disableLocalOptimizations", false))
  22502. isSimple = true;
  22503. // MORE - if it's a variable filename then it MAY be simple, we don't know. Tough.
  22504. }
  22505. if (!simpleLocalKeyedJoins)
  22506. isSimple = false;
  22507. isHalfKeyed = !helper->diskAccessRequired();
  22508. indexReadMeta = QUERYINTERFACE(helper->queryIndexReadInputRecordSize(), IOutputMetaData);
  22509. if (!isHalfKeyed && !variableFetchFileName)
  22510. {
  22511. bool isFetchOpt = (helper->getFetchFlags() & FFdatafileoptional) != 0;
  22512. datafile.setown(_queryFactory.queryPackage().lookupFileName(queryNodeFileName(_graphNode, _kind), isFetchOpt, true, true, _queryFactory.queryWorkUnit()));
  22513. if (datafile)
  22514. {
  22515. if (isLocal)
  22516. files.setown(datafile->getIFileIOArray(isFetchOpt, queryFactory.queryChannel()));
  22517. else
  22518. map.setown(datafile->getFileMap());
  22519. }
  22520. }
  22521. }
  22522. virtual bool getEnableFieldTranslation() const
  22523. {
  22524. return enableFieldTranslation;
  22525. }
  22526. virtual IDefRecordMeta *queryActivityMeta() const
  22527. {
  22528. return activityMeta;
  22529. }
  22530. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  22531. {
  22532. if (isHalfKeyed)
  22533. return new CRoxieServerHalfKeyedJoinActivity(this, _probeManager,
  22534. headId, keySet, translatorArray, indexReadMeta, joinFlags, isSimple, isLocal);
  22535. else
  22536. return new CRoxieServerKeyedJoinActivity(this, _probeManager,
  22537. headId, keySet, translatorArray, indexReadMeta,
  22538. tailId, map, joinFlags, isLocal);
  22539. }
  22540. virtual void getXrefInfo(IPropertyTree &reply, const IRoxieContextLogger &logctx) const
  22541. {
  22542. if (datafile)
  22543. addXrefFileInfo(reply, datafile);
  22544. if (indexfile)
  22545. addXrefFileInfo(reply, indexfile);
  22546. }
  22547. };
  22548. IRoxieServerActivityFactory *createRoxieServerKeyedJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, const RemoteActivityId &_remoteId2, IPropertyTree &_graphNode)
  22549. {
  22550. return new CRoxieServerKeyedJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _remoteId2, _graphNode);
  22551. }
  22552. //=================================================================================
  22553. class CRoxieServerSoapActivityBase : public CRoxieServerActivity, implements ISoapCallRowProvider, implements IRoxieAbortMonitor
  22554. {
  22555. protected:
  22556. Owned<ISoapCallHelper> soaphelper;
  22557. IHThorSoapActionArg & helper;
  22558. StringBuffer authToken;
  22559. bool eof;
  22560. CriticalSection crit;
  22561. ClientCertificate *pClientCert;
  22562. public:
  22563. IMPLEMENT_IINTERFACE;
  22564. CRoxieServerSoapActivityBase(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  22565. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorSoapActionArg &)basehelper)
  22566. {
  22567. eof = false;
  22568. if (clientCert.certificate.length() > 0 && clientCert.privateKey.length() > 0 && clientCert.passphrase.length() > 0)
  22569. pClientCert = &clientCert;
  22570. else
  22571. pClientCert = NULL;
  22572. }
  22573. // ISoapCallRowProvider
  22574. virtual IHThorSoapActionArg * queryActionHelper() { return &helper; };
  22575. virtual IHThorSoapCallArg * queryCallHelper() { return NULL; };
  22576. virtual const void * getNextRow() { return NULL; };
  22577. virtual void releaseRow(const void * r) { ReleaseRoxieRow(r); };
  22578. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  22579. {
  22580. eof = false;
  22581. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  22582. authToken.append(ctx->queryAuthToken());
  22583. }
  22584. virtual void reset()
  22585. {
  22586. // MORE - Shouldn't we make sure thread is stopped etc???
  22587. soaphelper.clear();
  22588. CRoxieServerActivity::reset();
  22589. }
  22590. // IRoxieAbortMonitor
  22591. virtual void checkForAbort() { checkAbort(); }
  22592. };
  22593. //---------------------------------------------------------------------------
  22594. class CRoxieServerSoapRowCallActivity : public CRoxieServerSoapActivityBase
  22595. {
  22596. IHThorSoapCallArg & callHelper;
  22597. public:
  22598. CRoxieServerSoapRowCallActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  22599. : CRoxieServerSoapActivityBase(_factory, _probeManager), callHelper((IHThorSoapCallArg &)basehelper)
  22600. {
  22601. }
  22602. virtual IHThorSoapCallArg * queryCallHelper()
  22603. {
  22604. return &callHelper;
  22605. }
  22606. virtual bool needsAllocator() const { return true; }
  22607. virtual const void *nextInGroup()
  22608. {
  22609. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  22610. if(eof) return NULL;
  22611. if (soaphelper == NULL)
  22612. {
  22613. if (factory->getKind()==TAKhttp_rowdataset)
  22614. soaphelper.setown(createHttpCallHelper(this, rowAllocator, authToken.str(), SCrow, pClientCert, *ctx, this));
  22615. else
  22616. soaphelper.setown(createSoapCallHelper(this, rowAllocator, authToken.str(), SCrow, pClientCert, *ctx, this));
  22617. soaphelper->start();
  22618. }
  22619. OwnedConstRoxieRow ret = soaphelper->getRow();
  22620. if (!ret)
  22621. {
  22622. eof = true;
  22623. return NULL;
  22624. }
  22625. ++processed;
  22626. return ret.getClear();
  22627. }
  22628. };
  22629. class CRoxieServerSoapRowCallActivityFactory : public CRoxieServerActivityFactory
  22630. {
  22631. public:
  22632. CRoxieServerSoapRowCallActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  22633. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  22634. {
  22635. }
  22636. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  22637. {
  22638. return new CRoxieServerSoapRowCallActivity(this, _probeManager);
  22639. }
  22640. };
  22641. IRoxieServerActivityFactory *createRoxieServerSoapRowCallActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  22642. {
  22643. return new CRoxieServerSoapRowCallActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  22644. }
  22645. //---------------------------------------------------------------------------
  22646. class CRoxieServerSoapRowActionActivity : public CRoxieServerSoapActivityBase
  22647. {
  22648. public:
  22649. CRoxieServerSoapRowActionActivity (const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  22650. : CRoxieServerSoapActivityBase(_factory, _probeManager)
  22651. {}
  22652. virtual void execute(unsigned parentExtractSize, const byte * parentExtract)
  22653. {
  22654. //MORE: parentExtract not passed to start - although shouldn't be a problem.
  22655. soaphelper.setown(createSoapCallHelper(this, NULL, ctx->queryAuthToken(), SCrow, pClientCert, *ctx, this));
  22656. soaphelper->start();
  22657. soaphelper->waitUntilDone();
  22658. IException *e = soaphelper->getError();
  22659. soaphelper.clear();
  22660. if (e)
  22661. throw e;
  22662. }
  22663. virtual IRoxieInput *queryOutput(unsigned idx)
  22664. {
  22665. return NULL;
  22666. }
  22667. virtual const void *nextInGroup()
  22668. {
  22669. throwUnexpected(); // I am nobody's input
  22670. }
  22671. };
  22672. class CRoxieServerSoapRowActionActivityFactory : public CRoxieServerActivityFactory
  22673. {
  22674. bool isRoot;
  22675. public:
  22676. CRoxieServerSoapRowActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  22677. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
  22678. {
  22679. }
  22680. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  22681. {
  22682. return new CRoxieServerSoapRowActionActivity(this, _probeManager);
  22683. }
  22684. virtual bool isSink() const
  22685. {
  22686. return isRoot;
  22687. }
  22688. };
  22689. IRoxieServerActivityFactory *createRoxieServerSoapRowActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  22690. {
  22691. return new CRoxieServerSoapRowActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
  22692. }
  22693. //---------------------------------------------------------------------------
  22694. class CRoxieServerSoapDatasetCallActivity : public CRoxieServerSoapActivityBase
  22695. {
  22696. IHThorSoapCallArg & callHelper;
  22697. public:
  22698. CRoxieServerSoapDatasetCallActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  22699. : CRoxieServerSoapActivityBase(_factory, _probeManager), callHelper((IHThorSoapCallArg &)basehelper)
  22700. {
  22701. }
  22702. virtual IHThorSoapCallArg * queryCallHelper()
  22703. {
  22704. return &callHelper;
  22705. }
  22706. virtual const void *getNextRow()
  22707. {
  22708. CriticalBlock b(crit);
  22709. const void *nextrec = input->nextInGroup();
  22710. if (!nextrec)
  22711. {
  22712. nextrec = input->nextInGroup();
  22713. }
  22714. return nextrec;
  22715. }
  22716. virtual bool needsAllocator() const { return true; }
  22717. virtual const void *nextInGroup()
  22718. {
  22719. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  22720. if(eof) return NULL;
  22721. if (soaphelper == NULL)
  22722. {
  22723. soaphelper.setown(createSoapCallHelper(this, rowAllocator, authToken.str(), SCdataset, pClientCert, *ctx, this));
  22724. soaphelper->start();
  22725. }
  22726. OwnedConstRoxieRow ret = soaphelper->getRow();
  22727. if (!ret)
  22728. {
  22729. eof = true;
  22730. return NULL;
  22731. }
  22732. ++processed;
  22733. return ret.getClear();
  22734. }
  22735. };
  22736. class CRoxieServerSoapDatasetCallActivityFactory : public CRoxieServerActivityFactory
  22737. {
  22738. public:
  22739. CRoxieServerSoapDatasetCallActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  22740. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  22741. {
  22742. }
  22743. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  22744. {
  22745. return new CRoxieServerSoapDatasetCallActivity(this, _probeManager);
  22746. }
  22747. };
  22748. IRoxieServerActivityFactory *createRoxieServerSoapDatasetCallActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  22749. {
  22750. return new CRoxieServerSoapDatasetCallActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  22751. }
  22752. //---------------------------------------------------------------------------
  22753. class CRoxieServerSoapDatasetActionActivity : public CRoxieServerSoapActivityBase
  22754. {
  22755. public:
  22756. CRoxieServerSoapDatasetActionActivity (const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  22757. : CRoxieServerSoapActivityBase(_factory, _probeManager)
  22758. {}
  22759. virtual const void *getNextRow()
  22760. {
  22761. CriticalBlock b(crit);
  22762. const void *nextrec = input->nextInGroup();
  22763. if (!nextrec)
  22764. {
  22765. nextrec = input->nextInGroup();
  22766. }
  22767. if (nextrec)
  22768. processed++;
  22769. return nextrec;
  22770. }
  22771. virtual void execute(unsigned parentExtractSize, const byte * parentExtract)
  22772. {
  22773. try
  22774. {
  22775. start(parentExtractSize, parentExtract, false);
  22776. soaphelper.setown(createSoapCallHelper(this, NULL, ctx->queryAuthToken(), SCdataset, pClientCert, *ctx, this));
  22777. soaphelper->start();
  22778. soaphelper->waitUntilDone();
  22779. IException *e = soaphelper->getError();
  22780. soaphelper.clear();
  22781. if (e)
  22782. throw e;
  22783. stop(false);
  22784. }
  22785. catch (IException *E)
  22786. {
  22787. ctx->notifyAbort(E);
  22788. stop(true);
  22789. throw;
  22790. }
  22791. catch(...)
  22792. {
  22793. Owned<IException> E = MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught at %s:%d", __FILE__, __LINE__);
  22794. ctx->notifyAbort(E);
  22795. stop(true);
  22796. throw;
  22797. }
  22798. }
  22799. virtual IRoxieInput *queryOutput(unsigned idx)
  22800. {
  22801. return NULL;
  22802. }
  22803. virtual const void *nextInGroup()
  22804. {
  22805. throwUnexpected(); // I am nobody's input
  22806. }
  22807. };
  22808. class CRoxieServerSoapDatasetActionActivityFactory : public CRoxieServerActivityFactory
  22809. {
  22810. bool isRoot;
  22811. public:
  22812. CRoxieServerSoapDatasetActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  22813. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
  22814. {
  22815. }
  22816. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  22817. {
  22818. return new CRoxieServerSoapDatasetActionActivity(this, _probeManager);
  22819. }
  22820. virtual bool isSink() const
  22821. {
  22822. return isRoot;
  22823. }
  22824. };
  22825. IRoxieServerActivityFactory *createRoxieServerSoapDatasetActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  22826. {
  22827. return new CRoxieServerSoapDatasetActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
  22828. }
  22829. //=====================================================================================================
  22830. class CGraphResults : public CInterface, implements IRoxieGraphResults
  22831. {
  22832. IArrayOf<IGraphResult> results;
  22833. CriticalSection cs;
  22834. IGraphResult & select(unsigned idx)
  22835. {
  22836. CriticalBlock procedure(cs);
  22837. if (idx >= results.ordinality())
  22838. throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Error reading graph result %d before it is calculated", idx);
  22839. return results.item(idx);
  22840. }
  22841. public:
  22842. IMPLEMENT_IINTERFACE
  22843. void clear()
  22844. {
  22845. CriticalBlock procedure(cs);
  22846. results.kill();
  22847. }
  22848. IRoxieInput * createIterator(unsigned id)
  22849. {
  22850. return select(id).createIterator();
  22851. }
  22852. virtual void getLinkedResult(unsigned & count, byte * * & ret, unsigned id)
  22853. {
  22854. select(id).getLinkedResult(count, ret);
  22855. }
  22856. virtual void getDictionaryResult(unsigned & count, byte * * & ret, unsigned id)
  22857. {
  22858. select(id).getLinkedResult(count, ret);
  22859. }
  22860. virtual const void * getLinkedRowResult(unsigned id)
  22861. {
  22862. return select(id).getLinkedRowResult();
  22863. }
  22864. void setResult(unsigned id, IGraphResult * result)
  22865. {
  22866. CriticalBlock procedure(cs);
  22867. if (results.ordinality() <= id)
  22868. {
  22869. while (results.ordinality() < id)
  22870. results.append(*new CGraphResult);
  22871. results.append(*LINK(result));
  22872. }
  22873. else
  22874. results.replace(*LINK(result), id);
  22875. }
  22876. void appendResult(IGraphResult * result)
  22877. {
  22878. CriticalBlock procedure(cs);
  22879. results.append(*LINK(result));
  22880. }
  22881. };
  22882. //===================================================================================================================
  22883. class CPseudoArg : public CInterface, implements IHThorArg
  22884. {
  22885. public:
  22886. IMPLEMENT_IINTERFACE
  22887. virtual IOutputMetaData * queryOutputMeta() { return NULL; }
  22888. };
  22889. class CPseudoActivity : public CRoxieServerActivity
  22890. {
  22891. public:
  22892. CPseudoActivity(IHThorArg & _helper) : CRoxieServerActivity(_helper) {}
  22893. virtual const void *nextInGroup()
  22894. {
  22895. throwUnexpected(); // I am nobody's input
  22896. }
  22897. };
  22898. class CActivityGraph : public CInterface, implements IActivityGraph, implements IThorChildGraph, implements ILocalGraphEx, implements IRoxieServerChildGraph
  22899. {
  22900. protected:
  22901. IArrayOf<IRoxieServerActivity> activities;
  22902. IArrayOf<IRoxieInput> probes;
  22903. IRoxieServerActivityCopyArray sinks;
  22904. StringAttr graphName;
  22905. Owned<CGraphResults> results;
  22906. CGraphResults graphLoopResults;
  22907. ActivityArray & graphDefinition;
  22908. CriticalSection evaluateCrit;
  22909. IProbeManager *probeManager;
  22910. unsigned id;
  22911. unsigned loopCounter;
  22912. class ActivityGraphSlaveContext : public IndirectSlaveContext
  22913. {
  22914. SpinLock abortLock;
  22915. bool aborted;
  22916. Owned<IException> exception;
  22917. public:
  22918. ActivityGraphSlaveContext(const IRoxieContextLogger &_logctx) : logctx(_logctx), loopCounter(0), codeContext(NULL)
  22919. {
  22920. aborted = false;
  22921. }
  22922. // Note - we must track exceptions at the child level in case there is a CATCH in parent
  22923. virtual void notifyAbort(IException *E)
  22924. {
  22925. SpinBlock b(abortLock);
  22926. if (!aborted && QUERYINTERFACE(E, InterruptedSemaphoreException) == NULL)
  22927. {
  22928. aborted = true;
  22929. exception.set(E);
  22930. }
  22931. }
  22932. virtual void checkAbort()
  22933. {
  22934. if (aborted) // NOTE - don't bother getting lock before reading this (for speed) - a false read is very unlikely and not a problem
  22935. {
  22936. SpinBlock b(abortLock);
  22937. if (!exception)
  22938. exception.setown(MakeStringException(ROXIE_INTERNAL_ERROR, "Query was aborted"));
  22939. throw exception.getLink();
  22940. }
  22941. IndirectSlaveContext::checkAbort();
  22942. }
  22943. virtual ICodeContext *queryCodeContext()
  22944. {
  22945. return codeContext;
  22946. }
  22947. void setCodeContext(ICodeContext * _codeContext)
  22948. {
  22949. codeContext = _codeContext;
  22950. }
  22951. void setLoopCounter(unsigned _loopCounter)
  22952. {
  22953. loopCounter = _loopCounter;
  22954. }
  22955. virtual void noteChildGraph(unsigned id, IActivityGraph *childGraph)
  22956. {
  22957. childGraphs.setValue(id, childGraph);
  22958. }
  22959. virtual IActivityGraph * queryChildGraph(unsigned id)
  22960. {
  22961. if (queryTraceLevel() > 10)
  22962. CTXLOG("resolveChildGraph %d", id);
  22963. IActivityGraph *childGraph = childGraphs.getValue(id);
  22964. assertex(childGraph);
  22965. return childGraph;
  22966. }
  22967. // 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
  22968. virtual StringBuffer &getLogPrefix(StringBuffer &ret) const
  22969. {
  22970. logctx.getLogPrefix(ret);
  22971. if (loopCounter)
  22972. ret.appendf("{%u}", loopCounter);
  22973. return ret;
  22974. }
  22975. protected:
  22976. const IRoxieContextLogger &logctx;
  22977. unsigned loopCounter;
  22978. ICodeContext * codeContext;
  22979. MapXToMyClass<unsigned, unsigned, IActivityGraph> childGraphs;
  22980. } graphSlaveContext;
  22981. class ActivityGraphCodeContext : public IndirectCodeContext
  22982. {
  22983. public:
  22984. virtual IEclGraphResults * resolveLocalQuery(__int64 activityId)
  22985. {
  22986. if ((unsigned) activityId == container->queryId())
  22987. return container;
  22988. IActivityGraph * match = slaveContext->queryChildGraph((unsigned) activityId);
  22989. if (match)
  22990. return match->queryLocalGraph();
  22991. return IndirectCodeContext::resolveLocalQuery(activityId);
  22992. }
  22993. virtual IThorChildGraph * resolveChildQuery(__int64 activityId, IHThorArg * colocal)
  22994. {
  22995. IActivityGraph * match = slaveContext->queryChildGraph((unsigned) activityId);
  22996. return LINK(match->queryChildGraph());
  22997. }
  22998. virtual unsigned getGraphLoopCounter() const
  22999. {
  23000. return container->queryLoopCounter(); // only called if value is valid
  23001. }
  23002. void setContainer(IRoxieSlaveContext * _slaveContext, CActivityGraph * _container)
  23003. {
  23004. slaveContext = _slaveContext;
  23005. container = _container;
  23006. }
  23007. protected:
  23008. IRoxieSlaveContext * slaveContext;
  23009. CActivityGraph * container;
  23010. } graphCodeContext;
  23011. public:
  23012. IMPLEMENT_IINTERFACE;
  23013. CActivityGraph(const char *_graphName, unsigned _id, ActivityArray &x, IProbeManager *_probeManager, const IRoxieContextLogger &_logctx)
  23014. : probeManager(_probeManager), graphDefinition(x), graphName(_graphName), graphSlaveContext(_logctx)
  23015. {
  23016. id = x.getLibraryGraphId();
  23017. if (!id)
  23018. id = _id;
  23019. loopCounter = 0;
  23020. graphSlaveContext.setCodeContext(&graphCodeContext);
  23021. graphCodeContext.setContainer(&graphSlaveContext, this);
  23022. }
  23023. ~CActivityGraph()
  23024. {
  23025. if (probeManager)
  23026. probeManager->deleteGraph((IArrayOf<IActivityBase>*)&activities, (IArrayOf<IInputBase>*)&probes);
  23027. }
  23028. virtual const char *queryName() const
  23029. {
  23030. return graphName.get();
  23031. }
  23032. void createGraph()
  23033. {
  23034. ForEachItemIn(idx, graphDefinition)
  23035. {
  23036. IRoxieServerActivityFactory &donor = graphDefinition.serverItem(idx);
  23037. IRoxieServerActivity &activity = *donor.createActivity(probeManager);
  23038. activities.append(activity);
  23039. if (donor.isSink())
  23040. {
  23041. sinks.append(activity);
  23042. if (probeManager)
  23043. probeManager->noteSink(&activity);
  23044. }
  23045. }
  23046. ForEachItemIn(idx1, graphDefinition)
  23047. {
  23048. IRoxieServerActivityFactory &donor = graphDefinition.serverItem(idx1);
  23049. IRoxieServerActivity &activity = activities.item(idx1);
  23050. unsigned inputidx = 0;
  23051. loop
  23052. {
  23053. unsigned outputidx;
  23054. unsigned source = donor.getInput(inputidx, outputidx);
  23055. if (source==(unsigned) -1)
  23056. break;
  23057. connectInput(idx1, inputidx, source, outputidx, 0);
  23058. inputidx++;
  23059. }
  23060. IntArray &dependencies = donor.queryDependencies();
  23061. IntArray &dependencyIndexes = donor.queryDependencyIndexes();
  23062. IntArray &dependencyControlIds = donor.queryDependencyControlIds();
  23063. StringArray &dependencyEdgeIds = donor.queryDependencyEdgeIds();
  23064. ForEachItemIn(idx2, dependencies)
  23065. {
  23066. IRoxieServerActivity &dependencySourceActivity = activities.item(dependencies.item(idx2));
  23067. unsigned dependencySourceIndex = dependencyIndexes.item(idx2);
  23068. unsigned dependencyControlId = dependencyControlIds.item(idx2);
  23069. activity.addDependency(dependencySourceActivity, dependencySourceIndex, dependencyControlId);
  23070. if (probeManager)
  23071. probeManager->noteDependency( &dependencySourceActivity, dependencySourceIndex, dependencyControlId, dependencyEdgeIds.item(idx2), &activity);
  23072. }
  23073. }
  23074. }
  23075. void connectInput(unsigned target, unsigned targetIdx, unsigned source, unsigned sourceIdx, unsigned iteration)
  23076. {
  23077. IRoxieServerActivity &targetActivity = activities.item(target);
  23078. IRoxieServerActivity &sourceActivity = activities.item(source);
  23079. IRoxieInput * output = sourceActivity.queryOutput(sourceIdx);
  23080. if (probeManager)
  23081. {
  23082. IInputBase * inputBase = probeManager->createProbe(static_cast<IInputBase*>(output), &sourceActivity, &targetActivity, sourceIdx, targetIdx, iteration);
  23083. output = static_cast<IRoxieInput*>(inputBase);
  23084. probes.append(*LINK(output));
  23085. }
  23086. targetActivity.setInput(targetIdx, output);
  23087. }
  23088. virtual void onCreate(IRoxieSlaveContext *ctx, IHThorArg *_colocalParent)
  23089. {
  23090. graphSlaveContext.set(ctx);
  23091. if (graphDefinition.isMultiInstance())
  23092. {
  23093. graphCodeContext.set(ctx->queryCodeContext());
  23094. ctx = &graphSlaveContext;
  23095. }
  23096. ForEachItemIn(idx, activities)
  23097. {
  23098. IRoxieServerActivity *activity = &activities.item(idx);
  23099. if (activity)
  23100. activity->onCreate(ctx, _colocalParent);
  23101. }
  23102. }
  23103. virtual void abort()
  23104. {
  23105. ForEachItemIn(idx, sinks)
  23106. {
  23107. IRoxieServerActivity &sink = sinks.item(idx);
  23108. sink.stop(true);
  23109. }
  23110. }
  23111. virtual void reset()
  23112. {
  23113. ForEachItemIn(idx, sinks)
  23114. {
  23115. IRoxieServerActivity &sink = sinks.item(idx);
  23116. sink.reset();
  23117. }
  23118. }
  23119. Linked<IException> exception;
  23120. CriticalSection eCrit;
  23121. virtual void noteException(IException *E)
  23122. {
  23123. CriticalBlock b(eCrit);
  23124. if (!exception)
  23125. {
  23126. if (graphSlaveContext.queryDebugContext())
  23127. {
  23128. graphSlaveContext.queryDebugContext()->checkBreakpoint(DebugStateException, NULL, exception);
  23129. }
  23130. exception.set(E);
  23131. }
  23132. }
  23133. virtual void checkAbort()
  23134. {
  23135. CriticalBlock b(eCrit);
  23136. if (exception)
  23137. throw exception.getLink();
  23138. }
  23139. virtual void execute()
  23140. {
  23141. results.setown(new CGraphResults);
  23142. doExecute(0, NULL);
  23143. }
  23144. //New child query code...
  23145. virtual IThorChildGraph * queryChildGraph()
  23146. {
  23147. return this;
  23148. }
  23149. virtual IEclGraphResults * queryLocalGraph()
  23150. {
  23151. return this;
  23152. }
  23153. virtual IRoxieServerChildGraph * queryLoopGraph()
  23154. {
  23155. return this;
  23156. }
  23157. inline unsigned queryId() const
  23158. {
  23159. return id;
  23160. }
  23161. inline unsigned queryLoopCounter() const
  23162. {
  23163. return loopCounter;
  23164. }
  23165. void doExecute(unsigned parentExtractSize, const byte * parentExtract)
  23166. {
  23167. if (sinks.ordinality()==1)
  23168. sinks.item(0).execute(parentExtractSize, parentExtract);
  23169. #ifdef PARALLEL_EXECUTE
  23170. else if (!probeManager && !graphDefinition.isSequential())
  23171. {
  23172. class casyncfor: public CAsyncFor
  23173. {
  23174. public:
  23175. IActivityGraph &parent;
  23176. unsigned parentExtractSize;
  23177. const byte * parentExtract;
  23178. casyncfor(IRoxieServerActivityCopyArray &_sinks, IActivityGraph &_parent, unsigned _parentExtractSize, const byte * _parentExtract) :
  23179. sinks(_sinks), parent(_parent), parentExtractSize(_parentExtractSize), parentExtract(_parentExtract) { }
  23180. void Do(unsigned i)
  23181. {
  23182. try
  23183. {
  23184. sinks.item(i).execute(parentExtractSize, parentExtract);
  23185. }
  23186. catch (IException *E)
  23187. {
  23188. parent.noteException(E);
  23189. throw;
  23190. }
  23191. }
  23192. private:
  23193. IRoxieServerActivityCopyArray &sinks;
  23194. } afor(sinks, *this, parentExtractSize, parentExtract);
  23195. afor.For(sinks.ordinality(), sinks.ordinality());
  23196. }
  23197. #endif
  23198. else
  23199. {
  23200. ForEachItemIn(idx, sinks)
  23201. {
  23202. IRoxieServerActivity &sink = sinks.item(idx);
  23203. sink.execute(parentExtractSize, parentExtract);
  23204. }
  23205. }
  23206. }
  23207. virtual IEclGraphResults *evaluate(unsigned parentExtractSize, const byte * parentExtract)
  23208. {
  23209. CriticalBlock block(evaluateCrit);
  23210. results.setown(new CGraphResults);
  23211. try
  23212. {
  23213. doExecute(parentExtractSize, parentExtract);
  23214. }
  23215. catch (...)
  23216. {
  23217. DBGLOG("Exception thrown in child query - cleaning up");
  23218. reset();
  23219. throw;
  23220. }
  23221. reset();
  23222. return results.getClear();
  23223. }
  23224. //interface IRoxieServerChildGraph
  23225. virtual void beforeExecute()
  23226. {
  23227. results.setown(new CGraphResults);
  23228. }
  23229. virtual IRoxieInput * startOutput(unsigned id, unsigned parentExtractSize, const byte *parentExtract, bool paused)
  23230. {
  23231. IRoxieInput * ret = selectOutput(id);
  23232. ret->start(parentExtractSize, parentExtract, paused);
  23233. return ret;
  23234. }
  23235. virtual IRoxieInput * selectOutput(unsigned id)
  23236. {
  23237. ForEachItemIn(i, sinks)
  23238. {
  23239. IRoxieInput * ret = sinks.item(i).querySelectOutput(id);
  23240. if (ret)
  23241. return ret;
  23242. }
  23243. throwUnexpected();
  23244. return NULL;
  23245. }
  23246. virtual void setInputResult(unsigned id, IGraphResult * result)
  23247. {
  23248. results->setResult(id, result);
  23249. }
  23250. virtual bool querySetInputResult(unsigned id, IRoxieInput * input)
  23251. {
  23252. ForEachItemIn(i, activities)
  23253. {
  23254. if (activities.item(i).querySetStreamInput(id, input))
  23255. return true;
  23256. }
  23257. return false;
  23258. }
  23259. virtual void stopUnusedOutputs()
  23260. {
  23261. //Hmm not sure how to do this...
  23262. }
  23263. virtual void afterExecute()
  23264. {
  23265. ForEachItemIn(i, sinks)
  23266. {
  23267. sinks.item(i).stop(false);
  23268. }
  23269. if (graphSlaveContext.queryDebugContext())
  23270. {
  23271. graphSlaveContext.queryDebugContext()->checkBreakpoint(DebugStateGraphFinished, NULL, NULL);
  23272. }
  23273. reset();
  23274. }
  23275. virtual IRoxieGraphResults * execute(size32_t parentExtractSize, const byte *parentExtract)
  23276. {
  23277. doExecute(parentExtractSize, parentExtract);
  23278. return LINK(results);
  23279. }
  23280. virtual void getLinkedResult(unsigned & count, byte * * & ret, unsigned id)
  23281. {
  23282. results->getLinkedResult(count, ret, id);
  23283. }
  23284. virtual void getDictionaryResult(unsigned & count, byte * * & ret, unsigned id)
  23285. {
  23286. results->getLinkedResult(count, ret, id);
  23287. }
  23288. virtual const void * getLinkedRowResult(unsigned id)
  23289. {
  23290. return results->getLinkedRowResult(id);
  23291. }
  23292. virtual void setResult(unsigned id, IGraphResult * result)
  23293. {
  23294. results->setResult(id, result);
  23295. }
  23296. virtual IRoxieInput * createResultIterator(unsigned id)
  23297. {
  23298. return results->createIterator(id);
  23299. }
  23300. virtual void setGraphLoopResult(IGraphResult * result)
  23301. {
  23302. graphLoopResults.appendResult(result);
  23303. }
  23304. virtual IRoxieInput * createGraphLoopResultIterator(unsigned id)
  23305. {
  23306. try
  23307. {
  23308. return graphLoopResults.createIterator(id);
  23309. }
  23310. catch (IException * e)
  23311. {
  23312. e->Release();
  23313. throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Error reading graph result %d before it is calculated", id);
  23314. }
  23315. }
  23316. virtual void clearGraphLoopResults()
  23317. {
  23318. graphLoopResults.clear();
  23319. }
  23320. virtual void executeGraphLoop(size32_t parentExtractSize, const byte *parentExtract)
  23321. {
  23322. doExecute(parentExtractSize, parentExtract);
  23323. }
  23324. virtual void setGraphLoopResult(unsigned id, IGraphResult * result)
  23325. {
  23326. graphLoopResults.setResult(id, result);
  23327. }
  23328. virtual IRoxieInput * getGraphLoopResult(unsigned id)
  23329. {
  23330. return graphLoopResults.createIterator(id);
  23331. }
  23332. virtual void getProbeResponse(IPropertyTree *query)
  23333. {
  23334. if (probeManager)
  23335. probeManager->getProbeResponse(query);
  23336. }
  23337. virtual IRoxieServerChildGraph * createGraphLoopInstance(unsigned loopCounter, unsigned parentExtractSize, const byte * parentExtract, const IRoxieContextLogger &logctx)
  23338. {
  23339. throwUnexpected();
  23340. }
  23341. virtual CGraphIterationInfo *selectGraphLoopOutput()
  23342. {
  23343. return NULL;
  23344. }
  23345. virtual void gatherIterationUsage(IRoxieServerLoopResultProcessor & processor)
  23346. {
  23347. throwUnexpected();
  23348. }
  23349. virtual void associateIterationOutputs(IRoxieServerLoopResultProcessor & processor)
  23350. {
  23351. throwUnexpected();
  23352. }
  23353. };
  23354. class CIterationActivityGraph : public CActivityGraph
  23355. {
  23356. IHThorArg * colocalParent;
  23357. unsigned fixedParentExtractSize;
  23358. const byte * fixedParentExtract;
  23359. unsigned graphOutputActivityIndex;
  23360. public:
  23361. CIterationActivityGraph(const char *_graphName, unsigned _id, ActivityArray &x, IProbeManager *_probeManager,
  23362. unsigned _loopCounter, IRoxieSlaveContext *ctx, IHThorArg * _colocalParent, unsigned parentExtractSize, const byte * parentExtract, const IRoxieContextLogger &_logctx)
  23363. : CActivityGraph(_graphName, _id, x, _probeManager, _logctx)
  23364. {
  23365. graphOutputActivityIndex = 0;
  23366. loopCounter = _loopCounter;
  23367. colocalParent = _colocalParent;
  23368. graphSlaveContext.set(ctx);
  23369. graphSlaveContext.setLoopCounter(loopCounter);
  23370. graphCodeContext.set(ctx->queryCodeContext());
  23371. fixedParentExtractSize = parentExtractSize;
  23372. fixedParentExtract = parentExtract;
  23373. }
  23374. void createIterationGraph()
  23375. {
  23376. Owned<IRoxieServerActivity> pseudoActivity = new CPseudoActivity(*new CPseudoArg);
  23377. ForEachItemIn(idx1, graphDefinition)
  23378. activities.append(*LINK(pseudoActivity));
  23379. graphOutputActivityIndex = queryGraphOutputIndex();
  23380. recursiveCreateGraph(graphOutputActivityIndex);
  23381. }
  23382. unsigned queryGraphOutputIndex() const
  23383. {
  23384. ForEachItemIn(i, graphDefinition)
  23385. if (graphDefinition.serverItem(i).getKind() == TAKgraphloopresultwrite)
  23386. return i;
  23387. throwUnexpected();
  23388. }
  23389. void recursiveCreateGraph(unsigned whichActivity)
  23390. {
  23391. //Check to see if already created
  23392. IRoxieServerActivity & prevActivity = activities.item(whichActivity);
  23393. if (prevActivity.queryId() != 0)
  23394. {
  23395. prevActivity.noteOutputUsed(); //We need to patch up the number of outputs for splitters.
  23396. return;
  23397. }
  23398. IRoxieServerActivityFactory &donor = graphDefinition.serverItem(whichActivity);
  23399. IRoxieServerActivity * activity = NULL;
  23400. if (donor.isGraphInvariant())
  23401. {
  23402. ThorActivityKind kind = donor.getKind();
  23403. switch (kind)
  23404. {
  23405. case TAKif:
  23406. case TAKchildif:
  23407. case TAKcase:
  23408. case TAKchildcase: // MORE RKC->GH - what about FILTER with a graph-invariant condition and other latestart activities?
  23409. {
  23410. Owned<IHThorArg> helper = &donor.getHelper();
  23411. helper->onCreate(&graphCodeContext, colocalParent, NULL);
  23412. helper->onStart(fixedParentExtract, NULL);
  23413. unsigned branch;
  23414. switch (kind)
  23415. {
  23416. case TAKif: case TAKchildif:
  23417. branch = static_cast<IHThorIfArg *>(helper.get())->getCondition() ? 0 : 1;
  23418. break;
  23419. case TAKcase: case TAKchildcase:
  23420. branch = static_cast<IHThorCaseArg *>(helper.get())->getBranch();
  23421. if (branch >= donor.numInputs())
  23422. branch = donor.numInputs() - 1;
  23423. break;
  23424. default:
  23425. throwUnexpected();
  23426. }
  23427. helper.clear();
  23428. unsigned outputidx;
  23429. unsigned source = donor.getInput(branch, outputidx);
  23430. if (source ==(unsigned) -1)
  23431. activity = createRoxieServerNullActivity(&donor, probeManager);
  23432. else
  23433. activity = createRoxieServerPassThroughActivity(&donor, probeManager);
  23434. activities.replace(*activity, whichActivity);
  23435. activity->onCreate(&graphSlaveContext, colocalParent);
  23436. if (source ==(unsigned) -1)
  23437. return;
  23438. recursiveCreateGraph(source);
  23439. connectInput(whichActivity, 0, source, outputidx, loopCounter);
  23440. break;
  23441. }
  23442. }
  23443. }
  23444. if (!activity)
  23445. {
  23446. activity = donor.createActivity(probeManager);
  23447. activities.replace(*activity, whichActivity);
  23448. activity->onCreate(&graphSlaveContext, colocalParent);
  23449. activity->resetOutputsUsed();
  23450. unsigned inputidx = 0;
  23451. loop
  23452. {
  23453. unsigned outputidx;
  23454. unsigned source = donor.getInput(inputidx, outputidx);
  23455. if (source==(unsigned) -1)
  23456. break;
  23457. recursiveCreateGraph(source);
  23458. connectInput(whichActivity, inputidx, source, outputidx, loopCounter);
  23459. inputidx++;
  23460. }
  23461. }
  23462. IntArray &dependencies = donor.queryDependencies();
  23463. IntArray &dependencyIndexes = donor.queryDependencyIndexes();
  23464. IntArray &dependencyControlIds = donor.queryDependencyControlIds();
  23465. ForEachItemIn(idx2, dependencies)
  23466. {
  23467. unsigned input = dependencies.item(idx2);
  23468. recursiveCreateGraph(input);
  23469. activity->addDependency(activities.item(input),dependencyIndexes.item(idx2),dependencyControlIds.item(idx2));
  23470. }
  23471. }
  23472. virtual CGraphIterationInfo *selectGraphLoopOutput()
  23473. {
  23474. IRoxieServerActivity &sourceActivity = activities.item(graphOutputActivityIndex);
  23475. return new CGraphIterationInfo(&sourceActivity, sourceActivity.queryOutput(0), 0, loopCounter);
  23476. }
  23477. virtual void gatherIterationUsage(IRoxieServerLoopResultProcessor & processor)
  23478. {
  23479. ForEachItemIn(i, activities)
  23480. activities.item(i).gatherIterationUsage(processor, fixedParentExtractSize, fixedParentExtract);
  23481. }
  23482. virtual void associateIterationOutputs(IRoxieServerLoopResultProcessor & processor)
  23483. {
  23484. ForEachItemIn(i, activities)
  23485. activities.item(i).associateIterationOutputs(processor, fixedParentExtractSize, fixedParentExtract, probeManager, probes);
  23486. }
  23487. };
  23488. class CDelayedActivityGraph : public CInterface, implements IActivityGraph
  23489. {
  23490. StringAttr graphName;
  23491. ActivityArray & graphDefinition;
  23492. IProbeManager *probeManager;
  23493. unsigned id;
  23494. IRoxieSlaveContext * ctx;
  23495. IHThorArg * colocalParent;
  23496. public:
  23497. IMPLEMENT_IINTERFACE;
  23498. CDelayedActivityGraph(const char *_graphName, unsigned _id, ActivityArray &x, IProbeManager *_probeManager)
  23499. : probeManager(_probeManager), graphDefinition(x)
  23500. {
  23501. graphName.set(_graphName);
  23502. id = _id;
  23503. ctx = NULL;
  23504. colocalParent = NULL;
  23505. }
  23506. virtual const char *queryName() const { return graphName.get(); }
  23507. virtual void abort() { throwUnexpected(); }
  23508. virtual void reset() { }
  23509. virtual void execute() { throwUnexpected(); }
  23510. virtual void getProbeResponse(IPropertyTree *query) { throwUnexpected(); }
  23511. virtual void noteException(IException *E) { throwUnexpected(); }
  23512. virtual void checkAbort() { throwUnexpected(); }
  23513. virtual IThorChildGraph * queryChildGraph() { throwUnexpected(); }
  23514. virtual IEclGraphResults * queryLocalGraph() { throwUnexpected(); }
  23515. virtual IRoxieServerChildGraph * queryLoopGraph() { throwUnexpected(); }
  23516. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  23517. {
  23518. ctx = _ctx;
  23519. colocalParent = _colocalParent;
  23520. }
  23521. virtual IRoxieServerChildGraph * createGraphLoopInstance(unsigned loopCounter, unsigned parentExtractSize, const byte * parentExtract, const IRoxieContextLogger &logctx)
  23522. {
  23523. Owned<CIterationActivityGraph> ret = new CIterationActivityGraph(graphName, id, graphDefinition, probeManager, loopCounter, ctx, colocalParent, parentExtractSize, parentExtract, logctx);
  23524. ret->createIterationGraph();
  23525. return ret.getClear();
  23526. }
  23527. };
  23528. IActivityGraph *createActivityGraph(const char *_graphName, unsigned id, ActivityArray &childFactories, IRoxieServerActivity *parentActivity, IProbeManager *_probeManager, const IRoxieContextLogger &_logctx)
  23529. {
  23530. if (childFactories.isDelayed())
  23531. {
  23532. return new CDelayedActivityGraph(_graphName, id, childFactories, _probeManager);
  23533. }
  23534. else
  23535. {
  23536. Owned<IProbeManager> childProbe;
  23537. if (_probeManager)
  23538. childProbe.setown(_probeManager->startChildGraph(id, parentActivity));
  23539. Owned<CActivityGraph> ret = new CActivityGraph(_graphName, id, childFactories, childProbe, _logctx);
  23540. ret->createGraph();
  23541. if (_probeManager)
  23542. _probeManager->endChildGraph(childProbe, parentActivity);
  23543. return ret.getClear();
  23544. }
  23545. }
  23546. //================================================================================================================
  23547. #ifdef _USE_CPPUNIT
  23548. #include "unittests.hpp"
  23549. // 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...
  23550. #if _MSC_VER==1200
  23551. #undef protected
  23552. #endif
  23553. static const char *sortAlgorithm;
  23554. class TestMetaData : public CInterface, implements IOutputMetaData
  23555. {
  23556. public:
  23557. IMPLEMENT_IINTERFACE;
  23558. virtual size32_t getRecordSize(const void *) { return 10; }
  23559. virtual size32_t getMinRecordSize() const { return 10; }
  23560. virtual size32_t getFixedSize() const { return 10; }
  23561. virtual void toXML(const byte * self, IXmlWriter & out) {}
  23562. virtual unsigned getVersion() const { return OUTPUTMETADATA_VERSION; }
  23563. virtual unsigned getMetaFlags() { return 0; }
  23564. virtual void destruct(byte * self) {}
  23565. virtual IOutputRowSerializer * createDiskSerializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
  23566. virtual IOutputRowDeserializer * createDiskDeserializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
  23567. virtual ISourceRowPrefetcher * createDiskPrefetcher(ICodeContext * ctx, unsigned activityId) { return NULL; }
  23568. virtual IOutputMetaData * querySerializedDiskMeta() { return NULL; }
  23569. virtual IOutputRowSerializer * createInternalSerializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
  23570. virtual IOutputRowDeserializer * createInternalDeserializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
  23571. virtual void walkIndirectMembers(const byte * self, IIndirectMemberVisitor & visitor) {}
  23572. virtual IOutputMetaData * queryChildMeta(unsigned i) { return NULL; }
  23573. } testMeta;
  23574. class TestInput : public CInterface, implements IRoxieInput
  23575. {
  23576. char const * const *input;
  23577. IRoxieSlaveContext *ctx;
  23578. unsigned endSeen;
  23579. bool eof;
  23580. unsigned count;
  23581. unsigned __int64 totalCycles;
  23582. size32_t recordSize;
  23583. unsigned activityId;
  23584. public:
  23585. enum { STATEreset, STATEstarted, STATEstopped } state;
  23586. bool allRead;
  23587. IMPLEMENT_IINTERFACE;
  23588. TestInput(IRoxieSlaveContext *_ctx, char const * const *_input)
  23589. {
  23590. ctx = _ctx;
  23591. input = _input;
  23592. count = 0;
  23593. eof = false;
  23594. allRead = false;
  23595. endSeen = 0;
  23596. recordSize = testMeta.getFixedSize();
  23597. state = STATEreset;
  23598. totalCycles = 0;
  23599. activityId = 1;
  23600. }
  23601. virtual IOutputMetaData * queryOutputMeta() const { return &testMeta; }
  23602. virtual void prestart(unsigned parentExtractSize, const byte *parentExtract)
  23603. {
  23604. ASSERT(state == STATEreset);
  23605. }
  23606. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  23607. {
  23608. ASSERT(state == STATEreset);
  23609. state = STATEstarted;
  23610. }
  23611. virtual IRoxieServerActivity *queryActivity()
  23612. {
  23613. throwUnexpected();
  23614. }
  23615. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  23616. {
  23617. throwUnexpected();
  23618. }
  23619. virtual void stop(bool aborting)
  23620. {
  23621. state = STATEstopped;
  23622. }
  23623. virtual void reset()
  23624. {
  23625. ASSERT(state == STATEstopped);
  23626. eof = false; count = 0; endSeen = 0; allRead = false; state = STATEreset; totalCycles = 0;
  23627. }
  23628. virtual void resetEOF()
  23629. {
  23630. throwUnexpected();
  23631. }
  23632. virtual void checkAbort() {}
  23633. virtual unsigned queryId() const { return activityId; };
  23634. virtual const void *nextInGroup()
  23635. {
  23636. ActivityTimer t(totalCycles, ctx->queryTimeActivities(), ctx->queryDebugContext());
  23637. ASSERT(state == STATEstarted);
  23638. ASSERT(allRead || !eof);
  23639. if (eof)
  23640. return NULL;
  23641. const char *nextSource = input[count++];
  23642. if (nextSource)
  23643. {
  23644. endSeen = 0;
  23645. void *ret = ctx->queryRowManager().ALLOCATE(recordSize);
  23646. memset(ret, 0, recordSize);
  23647. strncpy((char *) ret, nextSource, recordSize);
  23648. return ret;
  23649. }
  23650. else
  23651. {
  23652. endSeen++;
  23653. if (endSeen==2)
  23654. eof = true;
  23655. return NULL;
  23656. }
  23657. }
  23658. virtual bool nextGroup(ConstPointerArray & group)
  23659. {
  23660. const void * next;
  23661. while ((next = nextInGroup()) != NULL)
  23662. group.append(next);
  23663. if (group.ordinality())
  23664. return true;
  23665. return false;
  23666. }
  23667. virtual unsigned __int64 queryTotalCycles() const { return totalCycles; }
  23668. virtual unsigned __int64 queryLocalCycles() const { return totalCycles; }
  23669. virtual IRoxieInput *queryInput(unsigned idx) const
  23670. {
  23671. return NULL;
  23672. }
  23673. };
  23674. struct SortActivityTest : public ccdserver_hqlhelper::CThorSortArg {
  23675. public:
  23676. struct CompareClass : public ICompare {
  23677. virtual int docompare(const void * _left, const void * _right) const {
  23678. return memcmp(_left, _right, 5);
  23679. }
  23680. } compare;
  23681. virtual ICompare * queryCompare() { return &compare; }
  23682. virtual IOutputMetaData * queryOutputMeta()
  23683. {
  23684. return &testMeta;
  23685. }
  23686. virtual unsigned getAlgorithmFlags() { return TAFunstable; }
  23687. virtual const char * getAlgorithm() { return sortAlgorithm; }
  23688. };
  23689. extern "C" IHThorArg * sortActivityTestFactory() { return new SortActivityTest; }
  23690. struct MergeActivityTest : public ccdserver_hqlhelper::CThorMergeArg {
  23691. static bool isDedup;
  23692. public:
  23693. struct CompareClass : public ICompare {
  23694. virtual int docompare(const void * _left, const void * _right) const {
  23695. return memcmp(_left, _right, 5);
  23696. }
  23697. } compare;
  23698. virtual ICompare * queryCompare() { return &compare; }
  23699. virtual IOutputMetaData * queryOutputMeta()
  23700. {
  23701. return &testMeta;
  23702. }
  23703. virtual bool dedup() { return isDedup; }
  23704. };
  23705. bool MergeActivityTest::isDedup = false;
  23706. extern "C" IHThorArg * mergeActivityTestFactory() { return new MergeActivityTest; }
  23707. class CcdServerTest : public CppUnit::TestFixture
  23708. {
  23709. CPPUNIT_TEST_SUITE(CcdServerTest);
  23710. CPPUNIT_TEST(testSetup);
  23711. CPPUNIT_TEST(testHeapSort);
  23712. CPPUNIT_TEST(testInsertionSort);
  23713. CPPUNIT_TEST(testQuickSort);
  23714. CPPUNIT_TEST(testMerge);
  23715. CPPUNIT_TEST(testMergeDedup);
  23716. CPPUNIT_TEST(testMiscellaneous);
  23717. CPPUNIT_TEST(testCleanup);
  23718. CPPUNIT_TEST_SUITE_END();
  23719. protected:
  23720. SlaveContextLogger logctx;
  23721. Owned<const IQueryDll> queryDll;
  23722. Owned<IRoxiePackage> package;
  23723. Owned<IRoxieSlaveContext> ctx;
  23724. Owned<IQueryFactory> queryFactory;
  23725. void testSetup()
  23726. {
  23727. roxiemem::setTotalMemoryLimit(false, 100 * 1024 * 1024, 0, NULL);
  23728. }
  23729. void testCleanup()
  23730. {
  23731. roxiemem::releaseRoxieHeap();
  23732. }
  23733. void init()
  23734. {
  23735. package.setown(createRoxiePackage(NULL, NULL));
  23736. ctx.setown(createSlaveContext(NULL, logctx, 0, 50*1024*1024, NULL));
  23737. queryDll.setown(createExeQueryDll("roxie"));
  23738. queryFactory.setown(createServerQueryFactory("test", queryDll.getLink(), *package, NULL, false, false));
  23739. timer->reset();
  23740. }
  23741. void testActivity(IRoxieServerActivity *activity, char const * const *input, char const * const *output)
  23742. {
  23743. testActivity(activity, input, NULL, output);
  23744. }
  23745. void testActivity(IRoxieServerActivity *activity, char const * const *input, char const * const *input2, char const * const *output)
  23746. {
  23747. TestInput in(ctx, input);
  23748. TestInput in2(ctx, input2);
  23749. IRoxieInput *out = activity->queryOutput(0);
  23750. IOutputMetaData *meta = out->queryOutputMeta();
  23751. activity->setInput(0, &in);
  23752. if (input2)
  23753. activity->setInput(1, &in2);
  23754. void *buf = alloca(meta->getFixedSize());
  23755. for (unsigned iteration = 0; iteration < 8; iteration++)
  23756. {
  23757. // 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)
  23758. // This should be true whether we read all, some, or none of the data.
  23759. // Should not matter if an activity is not started
  23760. if (iteration % 4 == 0)
  23761. activity->onCreate(ctx, NULL);
  23762. unsigned count = 0;
  23763. if (iteration % 4 != 3)
  23764. {
  23765. activity->start(0, NULL, false);
  23766. ASSERT(in.state == TestInput::STATEstarted);
  23767. ASSERT(!input2 || in2.state == TestInput::STATEstarted);
  23768. loop
  23769. {
  23770. const void *next = out->nextInGroup();
  23771. if (!next)
  23772. {
  23773. ASSERT(output[count++] == NULL);
  23774. next = out->nextInGroup();
  23775. if (!next)
  23776. {
  23777. ASSERT(output[count++] == NULL);
  23778. break;
  23779. }
  23780. }
  23781. ASSERT(output[count] != NULL);
  23782. unsigned outsize = meta->getRecordSize(next);
  23783. memset(buf, 0, outsize);
  23784. strncpy((char *) buf, output[count++], outsize);
  23785. ASSERT(memcmp(next, buf, outsize) == 0);
  23786. ReleaseRoxieRow(next);
  23787. if (iteration % 4 == 2)
  23788. break;
  23789. }
  23790. if (iteration % 4 != 2)
  23791. {
  23792. // Check that reading after end is harmless
  23793. in.allRead = true;
  23794. const void *next = out->nextInGroup();
  23795. ASSERT(next == NULL);
  23796. }
  23797. }
  23798. activity->stop(false);
  23799. ASSERT(in.state == TestInput::STATEstopped);
  23800. ASSERT(!input2 || in2.state == TestInput::STATEstopped);
  23801. activity->reset();
  23802. ASSERT(in.state == TestInput::STATEreset);
  23803. ASSERT(!input2 || in2.state == TestInput::STATEreset);
  23804. ctx->queryRowManager().reportLeaks();
  23805. ASSERT(ctx->queryRowManager().numPagesAfterCleanup(true) == 0);
  23806. }
  23807. }
  23808. static int compareFunc(const void *l, const void *r)
  23809. {
  23810. return strcmp(*(char **) l, *(char **) r);
  23811. }
  23812. void testSort(unsigned type)
  23813. {
  23814. init();
  23815. sortAlgorithm = NULL;
  23816. if (type==2)
  23817. sortAlgorithm = "heapSort";
  23818. else if (type == 1)
  23819. sortAlgorithm = "insertionSort";
  23820. else
  23821. sortAlgorithm = "quickSort";
  23822. DBGLOG("Testing %s activity", sortAlgorithm);
  23823. Owned <IRoxieServerActivityFactory> factory = createRoxieServerSortActivityFactory(1, 1, *queryFactory, sortActivityTestFactory, TAKsort);
  23824. Owned <IRoxieServerActivity> activity = factory->createActivity(NULL);
  23825. const char * test[] = { NULL, NULL };
  23826. const char * test12345[] = { "1", "2", "3", "4", "5", NULL, NULL };
  23827. const char * test54321[] = { "5", "4", "3", "2", "1", NULL, NULL };
  23828. const char * test11111[] = { "1", "1", "1", "1", "1", NULL, NULL };
  23829. const char * test11111_12345[] = { "1", "1", "1", "1", "1", NULL, "1", "2", "3", "4", "5", NULL, NULL };
  23830. const char * test11111_54321[] = { "1", "1", "1", "1", "1", NULL, "5", "4", "3", "2", "1", NULL, NULL };
  23831. const char * test54321_54321[] = { "5", "4", "3", "2", "1", NULL, "5", "4", "3", "2", "1", NULL, NULL };
  23832. const char * test12345_12345[] = { "1", "2", "3", "4", "5", NULL, "1", "2", "3", "4", "5", NULL, NULL };
  23833. testActivity(activity, test, test);
  23834. testActivity(activity, test12345, test12345);
  23835. testActivity(activity, test54321, test12345);
  23836. testActivity(activity, test11111, test11111);
  23837. testActivity(activity, test11111_12345, test11111_12345);
  23838. testActivity(activity, test11111_54321, test11111_12345);
  23839. testActivity(activity, test54321_54321, test12345_12345);
  23840. // A few larger tests
  23841. char *input[2002];
  23842. char *output[2002];
  23843. input[2000] = input[2001] = output[2000] = output[2001] = NULL;
  23844. unsigned i;
  23845. // identical
  23846. for (i=0; i<2000; i++)
  23847. {
  23848. input[i] = new char[11];
  23849. output[i] = new char[11];
  23850. sprintf(input[i], "1");
  23851. sprintf(output[i], "1");
  23852. }
  23853. testActivity(activity, input, output);
  23854. // Ascending
  23855. for (i=0; i<2000; i++)
  23856. {
  23857. sprintf(input[i], "%04d", i);
  23858. sprintf(output[i], "%04d", i);
  23859. }
  23860. testActivity(activity, input, output);
  23861. // Almost sorted
  23862. for (i=0; i<20; i++)
  23863. {
  23864. unsigned h = i*100;
  23865. sprintf(input[h], "%04d", 1900-h);
  23866. }
  23867. testActivity(activity, input, output);
  23868. // Descending
  23869. for (i=0; i<2000; i++)
  23870. {
  23871. sprintf(input[i], "%04d", 1999-i);
  23872. sprintf(output[i], "%04d", i);
  23873. }
  23874. testActivity(activity, input, output);
  23875. // Random
  23876. for (i=0; i<2000; i++)
  23877. {
  23878. unsigned r = rand() % 1500;
  23879. sprintf(input[i], "%04d", r);
  23880. sprintf(output[i], "%04d", r);
  23881. }
  23882. qsort(output, 2000, sizeof(output[0]), compareFunc);
  23883. testActivity(activity, input, output);
  23884. #if 0
  23885. // Random
  23886. #define BIGSORTSIZE 1000000
  23887. char **linput = new char*[BIGSORTSIZE +2];
  23888. char **loutput = new char *[BIGSORTSIZE+2];
  23889. linput[BIGSORTSIZE] = linput[BIGSORTSIZE+1] = loutput[BIGSORTSIZE] = loutput[BIGSORTSIZE+1] = NULL;
  23890. for (i=0; i<BIGSORTSIZE; i++)
  23891. {
  23892. unsigned r = rand() % 15000;
  23893. linput[i] = loutput[i] = new char[11];
  23894. sprintf(linput[i], "%04d", r);
  23895. }
  23896. qsort(loutput, BIGSORTSIZE, 4, compareFunc);
  23897. testActivity(activity, linput, loutput);
  23898. for (i=0; i<BIGSORTSIZE; i++)
  23899. {
  23900. delete [] linput[i];
  23901. }
  23902. delete [] linput;
  23903. delete [] loutput;
  23904. #endif
  23905. unsigned __int64 us = cycle_to_nanosec(factory->queryLocalCycles()/1000);
  23906. DBGLOG("Simple %s sorts: activity time %u.%u ms", type==2?"Heap" : (type==1 ? "Insertion" : "Quick"), (int)(us/1000), (int)(us%1000));
  23907. factory->resetNodeProgressInfo();
  23908. if (type)
  23909. {
  23910. // Other than quicksort, it's supposed to be stable. Let's check that it is
  23911. // All sort identical
  23912. for (i=0; i<2000; i++)
  23913. {
  23914. sprintf(input[i], "1 %d", i);
  23915. sprintf(output[i], "1 %d", i);
  23916. }
  23917. testActivity(activity, input, output);
  23918. // Already sorted
  23919. for (i=0; i<2000; i++)
  23920. {
  23921. sprintf(input[i], "%04d %d", i / 10, i);
  23922. sprintf(output[i], "%04d %d", i / 10, i);
  23923. }
  23924. testActivity(activity, input, output);
  23925. // Reverse order
  23926. for (i=0; i<2000; i++)
  23927. {
  23928. sprintf(input[i], "%04d %d", 199 - (i / 10), i%10);
  23929. sprintf(output[i], "%04d %d", i / 10, i%10);
  23930. }
  23931. testActivity(activity, input, output);
  23932. }
  23933. for (i=0; i<2000; i++)
  23934. {
  23935. delete [] input[i];
  23936. delete [] output[i];
  23937. }
  23938. DBGLOG("Finished testing %s sort", type==2?"Heap" : (type==1 ? "Insertion" : "Quick"));
  23939. }
  23940. void testQuickSort()
  23941. {
  23942. testSort(0);
  23943. }
  23944. void testInsertionSort()
  23945. {
  23946. testSort(1);
  23947. }
  23948. void testHeapSort()
  23949. {
  23950. testSort(2);
  23951. }
  23952. void testMerge()
  23953. {
  23954. DBGLOG("testMerge");
  23955. init();
  23956. Owned <IRoxieServerActivityFactory> factory = createRoxieServerMergeActivityFactory(1, 1, *queryFactory, mergeActivityTestFactory, TAKmerge);
  23957. factory->setInput(0,0,0);
  23958. factory->setInput(1,0,0);
  23959. Owned <IRoxieServerActivity> activity = factory->createActivity(NULL);
  23960. const char * test[] = { NULL, NULL };
  23961. const char * test12345[] = { "1", "2", "3", "4", "5", NULL, NULL };
  23962. const char * test1122334455[] = { "1", "1", "2", "2", "3", "3", "4", "4", "5", "5", NULL, NULL };
  23963. const char * test11111[] = { "1", "1", "1", "1", "1", NULL, NULL };
  23964. const char * test1111111111[] = { "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", NULL, NULL };
  23965. const char * test11111_12345[] = { "1", "1", "1", "1", "1", NULL, "1", "2", "3", "4", "5", NULL, NULL };
  23966. const char * test1111112345[] = { "1", "1", "1", "1", "1", "1", "2", "3", "4", "5", NULL, NULL };
  23967. 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 };
  23968. testActivity(activity, test, test, test);
  23969. testActivity(activity, test12345, test, test12345);
  23970. testActivity(activity, test, test12345, test12345);
  23971. testActivity(activity, test12345, test12345, test1122334455);
  23972. testActivity(activity, test11111, test, test11111);
  23973. testActivity(activity, test, test11111, test11111);
  23974. testActivity(activity, test11111, test11111, test1111111111);
  23975. testActivity(activity, test11111_12345, test, test1111112345);
  23976. testActivity(activity, test11111_12345, test11111_12345, test11111111111122334455);
  23977. // Should really test WHICH side gets kept...
  23978. // Should test with more than 2 inputs...
  23979. DBGLOG("testMerge done");
  23980. }
  23981. void testMergeDedup()
  23982. {
  23983. DBGLOG("testMergeDedup");
  23984. init();
  23985. MergeActivityTest::isDedup = true;
  23986. Owned <IRoxieServerActivityFactory> factory = createRoxieServerMergeActivityFactory(1, 1, *queryFactory, mergeActivityTestFactory, TAKmerge);
  23987. factory->setInput(0,0,0);
  23988. factory->setInput(1,0,0);
  23989. Owned <IRoxieServerActivity> activity = factory->createActivity(NULL);
  23990. const char * test[] = { NULL, NULL };
  23991. const char * test12345[] = { "1", "2", "3", "4", "5", NULL, NULL };
  23992. const char * test11111[] = { "1", "1", "1", "1", "1", NULL, NULL };
  23993. const char * test11111_12345[] = { "1", "1", "1", "1", "1", NULL, "1", "2", "3", "4", "5", NULL, NULL };
  23994. const char * test1111112345[] = { "1", "1", "1", "1", "1", "1", "2", "3", "4", "5", NULL, NULL };
  23995. testActivity(activity, test11111, test, test11111); // No dedup within a stream
  23996. testActivity(activity, test11111, test11111, test11111); // No dedup within a stream
  23997. testActivity(activity, test, test11111, test11111);
  23998. testActivity(activity, test, test, test);
  23999. testActivity(activity, test12345, test, test12345);
  24000. testActivity(activity, test, test12345, test12345);
  24001. testActivity(activity, test12345, test12345, test12345);
  24002. testActivity(activity, test11111_12345, test, test1111112345);
  24003. testActivity(activity, test11111_12345, test11111_12345, test1111112345);
  24004. // Should really test WHICH side gets kept...
  24005. // Should test with more than 2 inputs...
  24006. DBGLOG("testMergeDedup done");
  24007. }
  24008. void testMiscellaneous()
  24009. {
  24010. DBGLOG("sizeof(CriticalSection)=%u", (unsigned) sizeof(CriticalSection));
  24011. DBGLOG("sizeof(SpinLock)=%u", (unsigned) sizeof(SpinLock));
  24012. DBGLOG("sizeof(CJoinGroup)=%u", (unsigned) sizeof(CJoinGroup));
  24013. ASSERT(sizeof(CJoinGroup) <= 120);
  24014. }
  24015. };
  24016. CPPUNIT_TEST_SUITE_REGISTRATION( CcdServerTest );
  24017. CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( CcdServerTest, "CcdServerTest" );
  24018. #endif