123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988179891799017991179921799317994179951799617997179981799918000180011800218003180041800518006180071800818009180101801118012180131801418015180161801718018180191802018021180221802318024180251802618027180281802918030180311803218033180341803518036180371803818039180401804118042180431804418045180461804718048180491805018051180521805318054180551805618057180581805918060180611806218063180641806518066180671806818069180701807118072180731807418075180761807718078180791808018081180821808318084180851808618087180881808918090180911809218093180941809518096180971809818099181001810118102181031810418105181061810718108181091811018111181121811318114181151811618117181181811918120181211812218123181241812518126181271812818129181301813118132181331813418135181361813718138181391814018141181421814318144181451814618147181481814918150181511815218153181541815518156181571815818159181601816118162181631816418165181661816718168181691817018171181721817318174181751817618177181781817918180181811818218183181841818518186181871818818189181901819118192181931819418195181961819718198181991820018201182021820318204182051820618207182081820918210182111821218213182141821518216182171821818219182201822118222182231822418225182261822718228182291823018231182321823318234182351823618237182381823918240182411824218243182441824518246182471824818249182501825118252182531825418255182561825718258182591826018261182621826318264182651826618267182681826918270182711827218273182741827518276182771827818279182801828118282182831828418285182861828718288182891829018291182921829318294182951829618297182981829918300183011830218303183041830518306183071830818309183101831118312183131831418315183161831718318183191832018321183221832318324183251832618327183281832918330183311833218333183341833518336183371833818339183401834118342183431834418345183461834718348183491835018351183521835318354183551835618357183581835918360183611836218363183641836518366183671836818369183701837118372183731837418375183761837718378183791838018381183821838318384183851838618387183881838918390183911839218393183941839518396183971839818399184001840118402184031840418405184061840718408184091841018411184121841318414184151841618417184181841918420184211842218423184241842518426184271842818429184301843118432184331843418435184361843718438184391844018441184421844318444184451844618447184481844918450184511845218453184541845518456184571845818459184601846118462184631846418465184661846718468184691847018471184721847318474184751847618477184781847918480184811848218483184841848518486184871848818489184901849118492184931849418495184961849718498184991850018501185021850318504185051850618507185081850918510185111851218513185141851518516185171851818519185201852118522185231852418525185261852718528185291853018531185321853318534185351853618537185381853918540185411854218543185441854518546185471854818549185501855118552185531855418555185561855718558185591856018561185621856318564185651856618567185681856918570185711857218573185741857518576185771857818579185801858118582185831858418585185861858718588185891859018591185921859318594185951859618597185981859918600186011860218603186041860518606186071860818609186101861118612186131861418615186161861718618186191862018621186221862318624186251862618627186281862918630186311863218633186341863518636186371863818639186401864118642186431864418645186461864718648186491865018651186521865318654186551865618657186581865918660186611866218663186641866518666186671866818669186701867118672186731867418675186761867718678186791868018681186821868318684186851868618687186881868918690186911869218693186941869518696186971869818699187001870118702187031870418705187061870718708187091871018711187121871318714187151871618717187181871918720187211872218723187241872518726187271872818729187301873118732187331873418735187361873718738187391874018741187421874318744187451874618747187481874918750187511875218753187541875518756187571875818759187601876118762187631876418765187661876718768187691877018771187721877318774187751877618777187781877918780187811878218783187841878518786187871878818789187901879118792187931879418795187961879718798187991880018801188021880318804188051880618807188081880918810188111881218813188141881518816188171881818819188201882118822188231882418825188261882718828188291883018831188321883318834188351883618837188381883918840188411884218843188441884518846188471884818849188501885118852188531885418855188561885718858188591886018861188621886318864188651886618867188681886918870188711887218873188741887518876188771887818879188801888118882188831888418885188861888718888188891889018891188921889318894188951889618897188981889918900189011890218903189041890518906189071890818909189101891118912189131891418915189161891718918189191892018921189221892318924189251892618927189281892918930189311893218933189341893518936189371893818939189401894118942189431894418945189461894718948189491895018951189521895318954189551895618957189581895918960189611896218963189641896518966189671896818969189701897118972189731897418975189761897718978189791898018981189821898318984189851898618987189881898918990189911899218993189941899518996189971899818999190001900119002190031900419005190061900719008190091901019011190121901319014190151901619017190181901919020190211902219023190241902519026190271902819029190301903119032190331903419035190361903719038190391904019041190421904319044190451904619047190481904919050190511905219053190541905519056190571905819059190601906119062190631906419065190661906719068190691907019071190721907319074190751907619077190781907919080190811908219083190841908519086190871908819089190901909119092190931909419095190961909719098190991910019101191021910319104191051910619107191081910919110191111911219113191141911519116191171911819119191201912119122191231912419125191261912719128191291913019131191321913319134191351913619137191381913919140191411914219143191441914519146191471914819149191501915119152191531915419155191561915719158191591916019161191621916319164191651916619167191681916919170191711917219173191741917519176191771917819179191801918119182191831918419185191861918719188191891919019191191921919319194191951919619197191981919919200192011920219203192041920519206192071920819209192101921119212192131921419215192161921719218192191922019221192221922319224192251922619227192281922919230192311923219233192341923519236192371923819239192401924119242192431924419245192461924719248192491925019251192521925319254192551925619257192581925919260192611926219263192641926519266192671926819269192701927119272192731927419275192761927719278192791928019281192821928319284192851928619287192881928919290192911929219293192941929519296192971929819299193001930119302193031930419305193061930719308193091931019311193121931319314193151931619317193181931919320193211932219323193241932519326193271932819329193301933119332193331933419335193361933719338193391934019341193421934319344193451934619347193481934919350193511935219353193541935519356193571935819359193601936119362193631936419365193661936719368193691937019371193721937319374193751937619377193781937919380193811938219383193841938519386193871938819389193901939119392193931939419395193961939719398193991940019401194021940319404194051940619407194081940919410194111941219413194141941519416194171941819419194201942119422194231942419425194261942719428194291943019431194321943319434194351943619437194381943919440194411944219443194441944519446194471944819449194501945119452194531945419455194561945719458194591946019461194621946319464194651946619467194681946919470194711947219473194741947519476194771947819479194801948119482194831948419485194861948719488194891949019491194921949319494194951949619497194981949919500195011950219503195041950519506195071950819509195101951119512195131951419515195161951719518195191952019521195221952319524195251952619527195281952919530195311953219533195341953519536195371953819539195401954119542195431954419545195461954719548195491955019551195521955319554195551955619557195581955919560195611956219563195641956519566195671956819569195701957119572195731957419575195761957719578195791958019581195821958319584195851958619587195881958919590195911959219593195941959519596195971959819599196001960119602196031960419605196061960719608196091961019611196121961319614196151961619617196181961919620196211962219623196241962519626196271962819629196301963119632196331963419635196361963719638196391964019641196421964319644196451964619647196481964919650196511965219653196541965519656196571965819659196601966119662196631966419665196661966719668196691967019671196721967319674196751967619677196781967919680196811968219683196841968519686196871968819689196901969119692196931969419695196961969719698196991970019701197021970319704197051970619707197081970919710197111971219713197141971519716197171971819719197201972119722197231972419725197261972719728197291973019731197321973319734197351973619737197381973919740197411974219743197441974519746197471974819749197501975119752197531975419755197561975719758197591976019761197621976319764197651976619767197681976919770197711977219773197741977519776197771977819779197801978119782197831978419785197861978719788197891979019791197921979319794197951979619797197981979919800198011980219803198041980519806198071980819809198101981119812198131981419815198161981719818198191982019821198221982319824198251982619827198281982919830198311983219833198341983519836198371983819839198401984119842198431984419845198461984719848198491985019851198521985319854198551985619857198581985919860198611986219863198641986519866198671986819869198701987119872198731987419875198761987719878198791988019881198821988319884198851988619887198881988919890198911989219893198941989519896198971989819899199001990119902199031990419905199061990719908199091991019911199121991319914199151991619917199181991919920199211992219923199241992519926199271992819929199301993119932199331993419935199361993719938199391994019941199421994319944199451994619947199481994919950199511995219953199541995519956199571995819959199601996119962199631996419965199661996719968199691997019971199721997319974199751997619977199781997919980199811998219983199841998519986199871998819989199901999119992199931999419995199961999719998199992000020001200022000320004200052000620007200082000920010200112001220013200142001520016200172001820019200202002120022200232002420025200262002720028200292003020031200322003320034200352003620037200382003920040200412004220043200442004520046200472004820049200502005120052200532005420055200562005720058200592006020061200622006320064200652006620067200682006920070200712007220073200742007520076200772007820079200802008120082200832008420085200862008720088200892009020091200922009320094200952009620097200982009920100201012010220103201042010520106201072010820109201102011120112201132011420115201162011720118201192012020121201222012320124201252012620127201282012920130201312013220133201342013520136201372013820139201402014120142201432014420145201462014720148201492015020151201522015320154201552015620157201582015920160201612016220163201642016520166201672016820169201702017120172201732017420175201762017720178201792018020181201822018320184201852018620187201882018920190201912019220193201942019520196201972019820199202002020120202202032020420205202062020720208202092021020211202122021320214202152021620217202182021920220202212022220223202242022520226202272022820229202302023120232202332023420235202362023720238202392024020241202422024320244202452024620247202482024920250202512025220253202542025520256202572025820259202602026120262202632026420265202662026720268202692027020271202722027320274202752027620277202782027920280202812028220283202842028520286202872028820289202902029120292202932029420295202962029720298202992030020301203022030320304203052030620307203082030920310203112031220313203142031520316203172031820319203202032120322203232032420325203262032720328203292033020331203322033320334203352033620337203382033920340203412034220343203442034520346203472034820349203502035120352203532035420355203562035720358203592036020361203622036320364203652036620367203682036920370203712037220373203742037520376203772037820379203802038120382203832038420385203862038720388203892039020391203922039320394203952039620397203982039920400204012040220403204042040520406204072040820409204102041120412204132041420415204162041720418204192042020421204222042320424204252042620427204282042920430204312043220433204342043520436204372043820439204402044120442204432044420445204462044720448204492045020451204522045320454204552045620457204582045920460204612046220463204642046520466204672046820469204702047120472204732047420475204762047720478204792048020481204822048320484204852048620487204882048920490204912049220493204942049520496204972049820499205002050120502205032050420505205062050720508205092051020511205122051320514205152051620517205182051920520205212052220523205242052520526205272052820529205302053120532205332053420535205362053720538205392054020541205422054320544205452054620547205482054920550205512055220553205542055520556205572055820559205602056120562205632056420565205662056720568205692057020571205722057320574205752057620577205782057920580205812058220583205842058520586205872058820589205902059120592205932059420595205962059720598205992060020601206022060320604206052060620607206082060920610206112061220613206142061520616206172061820619206202062120622206232062420625206262062720628206292063020631206322063320634206352063620637206382063920640206412064220643206442064520646206472064820649206502065120652206532065420655206562065720658206592066020661206622066320664206652066620667206682066920670206712067220673206742067520676206772067820679206802068120682206832068420685206862068720688206892069020691206922069320694206952069620697206982069920700207012070220703207042070520706207072070820709207102071120712207132071420715207162071720718207192072020721207222072320724207252072620727207282072920730207312073220733207342073520736207372073820739207402074120742207432074420745207462074720748207492075020751207522075320754207552075620757207582075920760207612076220763207642076520766207672076820769207702077120772207732077420775207762077720778207792078020781207822078320784207852078620787207882078920790207912079220793207942079520796207972079820799208002080120802208032080420805208062080720808208092081020811208122081320814208152081620817208182081920820208212082220823208242082520826208272082820829208302083120832208332083420835208362083720838208392084020841208422084320844208452084620847208482084920850208512085220853208542085520856208572085820859208602086120862208632086420865208662086720868208692087020871208722087320874208752087620877208782087920880208812088220883208842088520886208872088820889208902089120892208932089420895208962089720898208992090020901209022090320904209052090620907209082090920910209112091220913209142091520916209172091820919209202092120922209232092420925209262092720928209292093020931209322093320934209352093620937209382093920940209412094220943209442094520946209472094820949209502095120952209532095420955209562095720958209592096020961209622096320964209652096620967209682096920970209712097220973209742097520976209772097820979209802098120982209832098420985209862098720988209892099020991209922099320994209952099620997209982099921000210012100221003210042100521006210072100821009210102101121012210132101421015210162101721018210192102021021210222102321024210252102621027210282102921030210312103221033210342103521036210372103821039210402104121042210432104421045210462104721048210492105021051210522105321054210552105621057210582105921060210612106221063210642106521066210672106821069210702107121072210732107421075210762107721078210792108021081210822108321084210852108621087210882108921090210912109221093210942109521096210972109821099211002110121102211032110421105211062110721108211092111021111211122111321114211152111621117211182111921120211212112221123211242112521126211272112821129211302113121132211332113421135211362113721138211392114021141211422114321144211452114621147211482114921150211512115221153211542115521156211572115821159211602116121162211632116421165211662116721168211692117021171211722117321174211752117621177211782117921180211812118221183211842118521186211872118821189211902119121192211932119421195211962119721198211992120021201212022120321204212052120621207212082120921210212112121221213212142121521216212172121821219212202122121222212232122421225212262122721228212292123021231212322123321234212352123621237212382123921240212412124221243212442124521246212472124821249212502125121252212532125421255212562125721258212592126021261212622126321264212652126621267212682126921270212712127221273212742127521276212772127821279212802128121282212832128421285212862128721288212892129021291212922129321294212952129621297212982129921300213012130221303213042130521306213072130821309213102131121312213132131421315213162131721318213192132021321213222132321324213252132621327213282132921330213312133221333213342133521336213372133821339213402134121342213432134421345213462134721348213492135021351213522135321354213552135621357213582135921360213612136221363213642136521366213672136821369213702137121372213732137421375213762137721378213792138021381213822138321384213852138621387213882138921390213912139221393213942139521396213972139821399214002140121402214032140421405214062140721408214092141021411214122141321414214152141621417214182141921420214212142221423214242142521426214272142821429214302143121432214332143421435214362143721438214392144021441214422144321444214452144621447214482144921450214512145221453214542145521456214572145821459214602146121462214632146421465214662146721468214692147021471214722147321474214752147621477214782147921480214812148221483214842148521486214872148821489214902149121492214932149421495214962149721498214992150021501215022150321504215052150621507215082150921510215112151221513215142151521516215172151821519215202152121522215232152421525215262152721528215292153021531215322153321534215352153621537215382153921540215412154221543215442154521546215472154821549215502155121552215532155421555215562155721558215592156021561215622156321564215652156621567215682156921570215712157221573215742157521576215772157821579215802158121582215832158421585215862158721588215892159021591215922159321594215952159621597215982159921600216012160221603216042160521606216072160821609216102161121612216132161421615216162161721618216192162021621216222162321624216252162621627216282162921630216312163221633216342163521636216372163821639216402164121642216432164421645216462164721648216492165021651216522165321654216552165621657216582165921660216612166221663216642166521666216672166821669216702167121672216732167421675216762167721678216792168021681216822168321684216852168621687216882168921690216912169221693216942169521696216972169821699217002170121702217032170421705217062170721708217092171021711217122171321714217152171621717217182171921720217212172221723217242172521726217272172821729217302173121732217332173421735217362173721738217392174021741217422174321744217452174621747217482174921750217512175221753217542175521756217572175821759217602176121762217632176421765217662176721768217692177021771217722177321774217752177621777217782177921780217812178221783217842178521786217872178821789217902179121792217932179421795217962179721798217992180021801218022180321804218052180621807218082180921810218112181221813218142181521816218172181821819218202182121822218232182421825218262182721828218292183021831218322183321834218352183621837218382183921840218412184221843218442184521846218472184821849218502185121852218532185421855218562185721858218592186021861218622186321864218652186621867218682186921870218712187221873218742187521876218772187821879218802188121882218832188421885218862188721888218892189021891218922189321894218952189621897218982189921900219012190221903219042190521906219072190821909219102191121912219132191421915219162191721918219192192021921219222192321924219252192621927219282192921930219312193221933219342193521936219372193821939219402194121942219432194421945219462194721948219492195021951219522195321954219552195621957219582195921960219612196221963219642196521966219672196821969219702197121972219732197421975219762197721978219792198021981219822198321984219852198621987219882198921990219912199221993219942199521996219972199821999220002200122002220032200422005220062200722008220092201022011220122201322014220152201622017220182201922020220212202222023220242202522026220272202822029220302203122032220332203422035220362203722038220392204022041220422204322044220452204622047220482204922050220512205222053220542205522056220572205822059220602206122062220632206422065220662206722068220692207022071220722207322074220752207622077220782207922080220812208222083220842208522086220872208822089220902209122092220932209422095220962209722098220992210022101221022210322104221052210622107221082210922110221112211222113221142211522116221172211822119221202212122122221232212422125221262212722128221292213022131221322213322134221352213622137221382213922140221412214222143221442214522146221472214822149221502215122152221532215422155221562215722158221592216022161221622216322164221652216622167221682216922170221712217222173221742217522176221772217822179221802218122182221832218422185221862218722188221892219022191221922219322194221952219622197221982219922200222012220222203222042220522206222072220822209222102221122212222132221422215222162221722218222192222022221222222222322224222252222622227222282222922230222312223222233222342223522236222372223822239222402224122242222432224422245222462224722248222492225022251222522225322254222552225622257222582225922260222612226222263222642226522266222672226822269222702227122272222732227422275222762227722278222792228022281222822228322284222852228622287222882228922290222912229222293222942229522296222972229822299223002230122302223032230422305223062230722308223092231022311223122231322314223152231622317223182231922320223212232222323223242232522326223272232822329223302233122332223332233422335223362233722338223392234022341223422234322344223452234622347223482234922350223512235222353223542235522356223572235822359223602236122362223632236422365223662236722368223692237022371223722237322374223752237622377223782237922380223812238222383223842238522386223872238822389223902239122392223932239422395223962239722398223992240022401224022240322404224052240622407224082240922410224112241222413224142241522416224172241822419224202242122422224232242422425224262242722428224292243022431224322243322434224352243622437224382243922440224412244222443224442244522446224472244822449224502245122452224532245422455224562245722458224592246022461224622246322464224652246622467224682246922470224712247222473224742247522476224772247822479224802248122482224832248422485224862248722488224892249022491224922249322494224952249622497224982249922500225012250222503225042250522506225072250822509225102251122512225132251422515225162251722518225192252022521225222252322524225252252622527225282252922530225312253222533225342253522536225372253822539225402254122542225432254422545225462254722548225492255022551225522255322554225552255622557225582255922560225612256222563225642256522566225672256822569225702257122572225732257422575225762257722578225792258022581225822258322584225852258622587225882258922590225912259222593225942259522596225972259822599226002260122602226032260422605226062260722608226092261022611226122261322614226152261622617226182261922620226212262222623226242262522626226272262822629226302263122632226332263422635226362263722638226392264022641226422264322644226452264622647226482264922650226512265222653226542265522656226572265822659226602266122662226632266422665226662266722668226692267022671226722267322674226752267622677226782267922680226812268222683226842268522686226872268822689226902269122692226932269422695226962269722698226992270022701227022270322704227052270622707227082270922710227112271222713227142271522716227172271822719227202272122722227232272422725227262272722728227292273022731227322273322734227352273622737227382273922740227412274222743227442274522746227472274822749227502275122752227532275422755227562275722758227592276022761227622276322764227652276622767227682276922770227712277222773227742277522776227772277822779227802278122782227832278422785227862278722788227892279022791227922279322794227952279622797227982279922800228012280222803228042280522806228072280822809228102281122812228132281422815228162281722818228192282022821228222282322824228252282622827228282282922830228312283222833228342283522836228372283822839228402284122842228432284422845228462284722848228492285022851228522285322854228552285622857228582285922860228612286222863228642286522866228672286822869228702287122872228732287422875228762287722878228792288022881228822288322884228852288622887228882288922890228912289222893228942289522896228972289822899229002290122902229032290422905229062290722908229092291022911229122291322914229152291622917229182291922920229212292222923229242292522926229272292822929229302293122932229332293422935229362293722938229392294022941229422294322944229452294622947229482294922950229512295222953229542295522956229572295822959229602296122962229632296422965229662296722968229692297022971229722297322974229752297622977229782297922980229812298222983229842298522986229872298822989229902299122992229932299422995229962299722998229992300023001230022300323004230052300623007230082300923010230112301223013230142301523016230172301823019230202302123022230232302423025230262302723028230292303023031230322303323034230352303623037230382303923040230412304223043230442304523046230472304823049230502305123052230532305423055230562305723058230592306023061230622306323064230652306623067230682306923070230712307223073230742307523076230772307823079230802308123082230832308423085230862308723088230892309023091230922309323094230952309623097230982309923100231012310223103231042310523106231072310823109231102311123112231132311423115231162311723118231192312023121231222312323124231252312623127231282312923130231312313223133231342313523136231372313823139231402314123142231432314423145231462314723148231492315023151231522315323154231552315623157231582315923160231612316223163231642316523166231672316823169231702317123172231732317423175231762317723178231792318023181231822318323184231852318623187231882318923190231912319223193231942319523196231972319823199232002320123202232032320423205232062320723208232092321023211232122321323214232152321623217232182321923220232212322223223232242322523226232272322823229232302323123232232332323423235232362323723238232392324023241232422324323244232452324623247232482324923250232512325223253232542325523256232572325823259232602326123262232632326423265232662326723268232692327023271232722327323274232752327623277232782327923280232812328223283232842328523286232872328823289232902329123292232932329423295232962329723298232992330023301233022330323304233052330623307233082330923310233112331223313233142331523316233172331823319233202332123322233232332423325233262332723328233292333023331233322333323334233352333623337233382333923340233412334223343233442334523346233472334823349233502335123352233532335423355233562335723358233592336023361233622336323364233652336623367233682336923370233712337223373233742337523376233772337823379233802338123382233832338423385233862338723388233892339023391233922339323394233952339623397233982339923400234012340223403234042340523406234072340823409234102341123412234132341423415234162341723418234192342023421234222342323424234252342623427234282342923430234312343223433234342343523436234372343823439234402344123442234432344423445234462344723448234492345023451234522345323454234552345623457234582345923460234612346223463234642346523466234672346823469234702347123472234732347423475234762347723478234792348023481234822348323484234852348623487234882348923490234912349223493234942349523496234972349823499235002350123502235032350423505235062350723508235092351023511235122351323514235152351623517235182351923520235212352223523235242352523526235272352823529235302353123532235332353423535235362353723538235392354023541235422354323544235452354623547235482354923550235512355223553235542355523556235572355823559235602356123562235632356423565235662356723568235692357023571235722357323574235752357623577235782357923580235812358223583235842358523586235872358823589235902359123592235932359423595235962359723598235992360023601236022360323604236052360623607236082360923610236112361223613236142361523616236172361823619236202362123622236232362423625236262362723628236292363023631236322363323634236352363623637236382363923640236412364223643236442364523646236472364823649236502365123652236532365423655236562365723658236592366023661236622366323664236652366623667236682366923670236712367223673236742367523676236772367823679236802368123682236832368423685236862368723688236892369023691236922369323694236952369623697236982369923700237012370223703237042370523706237072370823709237102371123712237132371423715237162371723718237192372023721237222372323724237252372623727237282372923730237312373223733237342373523736237372373823739237402374123742237432374423745237462374723748237492375023751237522375323754237552375623757237582375923760237612376223763237642376523766237672376823769237702377123772237732377423775237762377723778237792378023781237822378323784237852378623787237882378923790237912379223793237942379523796237972379823799238002380123802238032380423805238062380723808238092381023811238122381323814238152381623817238182381923820238212382223823238242382523826238272382823829238302383123832238332383423835238362383723838238392384023841238422384323844238452384623847238482384923850238512385223853238542385523856238572385823859238602386123862238632386423865238662386723868238692387023871238722387323874238752387623877238782387923880238812388223883238842388523886238872388823889238902389123892238932389423895238962389723898238992390023901239022390323904239052390623907239082390923910239112391223913239142391523916239172391823919239202392123922239232392423925239262392723928239292393023931239322393323934239352393623937239382393923940239412394223943239442394523946239472394823949239502395123952239532395423955239562395723958239592396023961239622396323964239652396623967239682396923970239712397223973239742397523976239772397823979239802398123982239832398423985239862398723988239892399023991239922399323994239952399623997239982399924000240012400224003240042400524006240072400824009240102401124012240132401424015240162401724018240192402024021240222402324024240252402624027240282402924030240312403224033240342403524036240372403824039240402404124042240432404424045240462404724048240492405024051240522405324054240552405624057240582405924060240612406224063240642406524066240672406824069240702407124072240732407424075240762407724078240792408024081240822408324084240852408624087240882408924090240912409224093240942409524096240972409824099241002410124102241032410424105241062410724108241092411024111241122411324114241152411624117241182411924120241212412224123241242412524126241272412824129241302413124132241332413424135241362413724138241392414024141241422414324144241452414624147241482414924150241512415224153241542415524156241572415824159241602416124162241632416424165241662416724168241692417024171241722417324174241752417624177241782417924180241812418224183241842418524186241872418824189241902419124192241932419424195241962419724198241992420024201242022420324204242052420624207242082420924210242112421224213242142421524216242172421824219242202422124222242232422424225242262422724228242292423024231242322423324234242352423624237242382423924240242412424224243242442424524246242472424824249242502425124252242532425424255242562425724258242592426024261242622426324264242652426624267242682426924270242712427224273242742427524276242772427824279242802428124282242832428424285242862428724288242892429024291242922429324294242952429624297242982429924300243012430224303243042430524306243072430824309243102431124312243132431424315243162431724318243192432024321243222432324324243252432624327243282432924330243312433224333243342433524336243372433824339243402434124342243432434424345243462434724348243492435024351243522435324354243552435624357243582435924360243612436224363243642436524366243672436824369243702437124372243732437424375243762437724378243792438024381243822438324384243852438624387243882438924390243912439224393243942439524396243972439824399244002440124402244032440424405244062440724408244092441024411244122441324414244152441624417244182441924420244212442224423244242442524426244272442824429244302443124432244332443424435244362443724438244392444024441244422444324444244452444624447244482444924450244512445224453244542445524456244572445824459244602446124462244632446424465244662446724468244692447024471244722447324474244752447624477244782447924480244812448224483244842448524486244872448824489244902449124492244932449424495244962449724498244992450024501245022450324504245052450624507245082450924510245112451224513245142451524516245172451824519245202452124522245232452424525245262452724528245292453024531245322453324534245352453624537245382453924540245412454224543245442454524546245472454824549245502455124552245532455424555245562455724558245592456024561245622456324564245652456624567245682456924570245712457224573245742457524576245772457824579245802458124582245832458424585245862458724588245892459024591245922459324594245952459624597245982459924600246012460224603246042460524606246072460824609246102461124612246132461424615246162461724618246192462024621246222462324624246252462624627246282462924630246312463224633246342463524636246372463824639246402464124642246432464424645246462464724648246492465024651246522465324654246552465624657246582465924660246612466224663246642466524666246672466824669246702467124672246732467424675246762467724678246792468024681246822468324684246852468624687246882468924690246912469224693246942469524696246972469824699247002470124702247032470424705247062470724708247092471024711247122471324714247152471624717247182471924720247212472224723247242472524726247272472824729247302473124732247332473424735247362473724738247392474024741247422474324744247452474624747247482474924750247512475224753247542475524756247572475824759247602476124762247632476424765247662476724768247692477024771247722477324774247752477624777247782477924780247812478224783247842478524786247872478824789247902479124792247932479424795247962479724798247992480024801248022480324804248052480624807248082480924810248112481224813248142481524816248172481824819248202482124822248232482424825248262482724828248292483024831248322483324834248352483624837248382483924840248412484224843248442484524846248472484824849248502485124852248532485424855248562485724858248592486024861248622486324864248652486624867248682486924870248712487224873248742487524876248772487824879248802488124882248832488424885248862488724888248892489024891248922489324894248952489624897248982489924900249012490224903249042490524906249072490824909249102491124912249132491424915249162491724918249192492024921249222492324924249252492624927249282492924930249312493224933249342493524936249372493824939249402494124942249432494424945249462494724948249492495024951249522495324954249552495624957249582495924960249612496224963249642496524966249672496824969249702497124972249732497424975249762497724978249792498024981249822498324984249852498624987249882498924990249912499224993249942499524996249972499824999250002500125002250032500425005250062500725008250092501025011250122501325014250152501625017250182501925020250212502225023250242502525026250272502825029250302503125032250332503425035250362503725038250392504025041250422504325044250452504625047250482504925050250512505225053250542505525056250572505825059250602506125062250632506425065250662506725068250692507025071250722507325074250752507625077250782507925080250812508225083250842508525086250872508825089250902509125092250932509425095250962509725098250992510025101251022510325104251052510625107251082510925110251112511225113251142511525116251172511825119251202512125122251232512425125251262512725128251292513025131251322513325134251352513625137251382513925140251412514225143251442514525146251472514825149251502515125152251532515425155251562515725158251592516025161251622516325164251652516625167251682516925170251712517225173251742517525176251772517825179251802518125182251832518425185251862518725188251892519025191251922519325194251952519625197251982519925200252012520225203252042520525206252072520825209252102521125212252132521425215252162521725218252192522025221252222522325224252252522625227252282522925230252312523225233252342523525236252372523825239252402524125242252432524425245252462524725248252492525025251252522525325254252552525625257252582525925260252612526225263252642526525266252672526825269252702527125272252732527425275252762527725278252792528025281252822528325284252852528625287252882528925290252912529225293252942529525296252972529825299253002530125302253032530425305253062530725308253092531025311253122531325314253152531625317253182531925320253212532225323253242532525326253272532825329253302533125332253332533425335253362533725338253392534025341253422534325344253452534625347253482534925350253512535225353253542535525356253572535825359253602536125362253632536425365253662536725368253692537025371253722537325374253752537625377253782537925380253812538225383253842538525386253872538825389253902539125392253932539425395253962539725398253992540025401254022540325404254052540625407254082540925410254112541225413254142541525416254172541825419254202542125422254232542425425254262542725428254292543025431254322543325434254352543625437254382543925440254412544225443254442544525446254472544825449254502545125452254532545425455254562545725458254592546025461254622546325464254652546625467254682546925470254712547225473254742547525476254772547825479254802548125482254832548425485254862548725488254892549025491254922549325494254952549625497254982549925500255012550225503255042550525506255072550825509255102551125512255132551425515255162551725518255192552025521255222552325524255252552625527255282552925530255312553225533255342553525536255372553825539255402554125542255432554425545255462554725548255492555025551255522555325554255552555625557255582555925560255612556225563255642556525566255672556825569255702557125572255732557425575255762557725578255792558025581255822558325584255852558625587255882558925590255912559225593255942559525596255972559825599256002560125602256032560425605256062560725608256092561025611256122561325614256152561625617256182561925620256212562225623256242562525626256272562825629256302563125632256332563425635256362563725638256392564025641256422564325644256452564625647256482564925650256512565225653256542565525656256572565825659256602566125662256632566425665256662566725668256692567025671256722567325674256752567625677256782567925680256812568225683256842568525686256872568825689256902569125692256932569425695256962569725698256992570025701257022570325704257052570625707257082570925710257112571225713257142571525716257172571825719257202572125722257232572425725257262572725728257292573025731257322573325734257352573625737257382573925740257412574225743257442574525746257472574825749257502575125752257532575425755257562575725758257592576025761257622576325764257652576625767257682576925770257712577225773257742577525776257772577825779257802578125782257832578425785257862578725788257892579025791257922579325794257952579625797257982579925800258012580225803258042580525806258072580825809258102581125812258132581425815258162581725818258192582025821258222582325824258252582625827258282582925830258312583225833258342583525836258372583825839258402584125842258432584425845258462584725848258492585025851258522585325854258552585625857258582585925860258612586225863258642586525866258672586825869258702587125872258732587425875258762587725878258792588025881258822588325884258852588625887258882588925890258912589225893258942589525896258972589825899259002590125902259032590425905259062590725908259092591025911259122591325914259152591625917259182591925920259212592225923259242592525926259272592825929259302593125932259332593425935259362593725938259392594025941259422594325944259452594625947259482594925950259512595225953259542595525956259572595825959259602596125962259632596425965259662596725968259692597025971259722597325974259752597625977259782597925980259812598225983259842598525986259872598825989259902599125992259932599425995259962599725998259992600026001260022600326004260052600626007260082600926010260112601226013260142601526016260172601826019260202602126022260232602426025260262602726028260292603026031260322603326034260352603626037260382603926040260412604226043260442604526046260472604826049260502605126052260532605426055260562605726058260592606026061260622606326064260652606626067260682606926070260712607226073260742607526076260772607826079260802608126082260832608426085260862608726088260892609026091260922609326094260952609626097260982609926100261012610226103261042610526106261072610826109261102611126112261132611426115261162611726118261192612026121261222612326124261252612626127261282612926130261312613226133261342613526136261372613826139261402614126142261432614426145261462614726148261492615026151261522615326154261552615626157261582615926160261612616226163261642616526166261672616826169261702617126172261732617426175261762617726178261792618026181261822618326184261852618626187261882618926190261912619226193261942619526196261972619826199262002620126202262032620426205262062620726208262092621026211262122621326214262152621626217262182621926220262212622226223262242622526226262272622826229262302623126232262332623426235262362623726238262392624026241262422624326244262452624626247262482624926250262512625226253262542625526256262572625826259262602626126262262632626426265262662626726268262692627026271262722627326274262752627626277262782627926280262812628226283262842628526286262872628826289262902629126292262932629426295262962629726298262992630026301263022630326304263052630626307263082630926310263112631226313263142631526316263172631826319263202632126322263232632426325263262632726328263292633026331263322633326334263352633626337263382633926340263412634226343263442634526346263472634826349263502635126352263532635426355263562635726358263592636026361263622636326364263652636626367263682636926370263712637226373263742637526376263772637826379263802638126382263832638426385263862638726388263892639026391263922639326394263952639626397263982639926400264012640226403264042640526406264072640826409264102641126412264132641426415264162641726418264192642026421264222642326424264252642626427264282642926430264312643226433264342643526436264372643826439264402644126442264432644426445264462644726448264492645026451264522645326454264552645626457264582645926460264612646226463264642646526466264672646826469264702647126472264732647426475264762647726478264792648026481264822648326484264852648626487264882648926490264912649226493264942649526496264972649826499265002650126502265032650426505265062650726508265092651026511265122651326514265152651626517265182651926520265212652226523265242652526526265272652826529265302653126532265332653426535265362653726538265392654026541265422654326544265452654626547265482654926550265512655226553265542655526556265572655826559265602656126562265632656426565265662656726568265692657026571265722657326574265752657626577265782657926580265812658226583265842658526586265872658826589265902659126592265932659426595265962659726598265992660026601266022660326604266052660626607266082660926610266112661226613266142661526616266172661826619266202662126622266232662426625266262662726628266292663026631266322663326634266352663626637266382663926640266412664226643266442664526646266472664826649266502665126652266532665426655266562665726658266592666026661266622666326664266652666626667266682666926670266712667226673266742667526676266772667826679266802668126682266832668426685266862668726688266892669026691266922669326694266952669626697266982669926700267012670226703267042670526706267072670826709267102671126712267132671426715267162671726718267192672026721267222672326724267252672626727267282672926730267312673226733267342673526736267372673826739267402674126742267432674426745 |
- /*##############################################################################
- HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- ############################################################################## */
- #include "jmisc.hpp"
- #include "jdebug.hpp"
- #include "jptree.hpp"
- #include "rtlkey.hpp"
- #include "jsort.hpp"
- #include "jhtree.hpp"
- #include "jqueue.tpp"
- #include "jisem.hpp"
- #include "thorxmlread.hpp"
- #include "thorrparse.ipp"
- #include "thorxmlwrite.hpp"
- #include "thorsoapcall.hpp"
- #include "thorcommon.ipp"
- #include "jlzw.hpp"
- #include "javahash.hpp"
- #include "javahash.tpp"
- #include "thorstep.ipp"
- #include "thorpipe.hpp"
- #include "thorfile.hpp"
- #include "eclhelper.hpp"
- #include "eclrtl_imp.hpp"
- #include "rtlfield_imp.hpp"
- #include "rtlds_imp.hpp"
- #include "rtlread_imp.hpp"
- #include "dafdesc.hpp"
- #include "dautils.hpp"
- namespace ccdserver_hqlhelper
- {
- #include "eclhelper_base.hpp"
- }
- #include "ccd.hpp"
- #include "ccdserver.hpp"
- #include "ccdcontext.hpp"
- #include "ccdactivities.hpp"
- #include "ccdquery.hpp"
- #include "ccdstate.hpp"
- #include "ccdqueue.ipp"
- #include "ccdsnmp.hpp"
- #include "ccddali.hpp"
- #include "jsmartsock.hpp"
- #include "dllserver.hpp"
- #include "workflow.hpp"
- #include "roxiemem.hpp"
- #include "roxierowbuff.hpp"
- #include "roxiehelper.hpp"
- #include "roxielmj.hpp"
- #include "roxierow.hpp"
- #include "thorplugin.hpp"
- #include "keybuild.hpp"
- #define MAX_HTTP_HEADERSIZE 8000
- #define MIN_PAYLOAD_SIZE 800
- #pragma warning(disable : 4355)
- #define DEFAULT_PARALLEL_LOOP_THREADS 1
- #define PROBE
- #ifdef _DEBUG
- //#define FAKE_EXCEPTIONS
- //#define TRACE_JOINGROUPS
- //#define TRACE_SPLIT
- //#define _CHECK_HEAPSORT
- //#undef PARALLEL_EXECUTE
- //#define TRACE_SEEK_REQUESTS
- #endif
- using roxiemem::OwnedRoxieRow;
- using roxiemem::OwnedRoxieString;
- using roxiemem::OwnedConstRoxieRow;
- using roxiemem::IRowManager;
- // 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...
- #if _MSC_VER==1200
- #define protected public
- #endif
- #define TRACE_STARTSTOP // This determines if it is available - it is enabled/disabled by a configuration option
-
- static const SmartStepExtra dummySmartStepExtra(SSEFreadAhead, NULL);
- inline void ReleaseRoxieRowSet(ConstPointerArray &data)
- {
- ForEachItemIn(idx, data)
- ReleaseRoxieRow(data.item(idx));
- data.kill();
- }
- //=================================================================================
- class RestartableThread : public CInterface
- {
- class MyThread : public Thread
- {
- Linked<RestartableThread> owner;
- public:
- MyThread(RestartableThread *_owner, const char *name) : Thread(name), owner(_owner)
- {
- }
- virtual int run()
- {
- owner->started.signal();
- return owner->run();
- }
- };
- friend class MyThread;
- Semaphore started;
- Owned<MyThread> thread;
- CriticalSection crit;
- StringAttr name;
- public:
- RestartableThread(const char *_name) : name(_name)
- {
- }
- virtual void start(const char *namePrefix)
- {
- StringBuffer s(namePrefix);
- s.append(name);
- {
- CriticalBlock b(crit);
- assertex(!thread);
- thread.setown(new MyThread(this, s));
- thread->start();
- }
- started.wait();
- }
- virtual void join()
- {
- {
- Owned<Thread> tthread;
- {
- CriticalBlock b(crit);
- tthread.setown(thread.getClear());
- }
- if (tthread)
- tthread->join();
- }
- }
- virtual int run() = 0;
- };
- //================================================================================
- // default implementation - can be overridden for efficiency...
- bool IRoxieInput::nextGroup(ConstPointerArray & group)
- {
- // MORE - this should be replaced with a version that reads to a builder
- const void * next;
- while ((next = nextInGroup()) != NULL)
- group.append(next);
- if (group.ordinality())
- return true;
- return false;
- }
- void IRoxieInput::readAll(RtlLinkedDatasetBuilder &builder)
- {
- loop
- {
- const void *nextrec = nextInGroup();
- if (!nextrec)
- {
- nextrec = nextInGroup();
- if (!nextrec)
- break;
- builder.appendEOG();
- }
- builder.appendOwn(nextrec);
- }
- }
- inline const void * nextUngrouped(IRoxieInput * input)
- {
- const void * ret = input->nextInGroup();
- if (!ret)
- ret = input->nextInGroup();
- return ret;
- };
- //=================================================================================
- //The following don't link their arguments because that creates a circular reference
- //But I wish there was a better way
- class IndirectSlaveContext : public CInterface, implements IRoxieSlaveContext
- {
- public:
- IndirectSlaveContext(IRoxieSlaveContext * _ctx = NULL) : ctx(_ctx) {}
- IMPLEMENT_IINTERFACE
- void set(IRoxieSlaveContext * _ctx) { ctx = _ctx; }
- virtual ICodeContext *queryCodeContext()
- {
- return ctx->queryCodeContext();
- }
- virtual void checkAbort()
- {
- ctx->checkAbort();
- }
- virtual void notifyAbort(IException *E)
- {
- ctx->notifyAbort(E);
- }
- virtual IActivityGraph * queryChildGraph(unsigned id)
- {
- return ctx->queryChildGraph(id);
- }
- virtual void noteChildGraph(unsigned id, IActivityGraph *childGraph)
- {
- ctx->noteChildGraph(id, childGraph) ;
- }
- virtual IRowManager &queryRowManager()
- {
- return ctx->queryRowManager();
- }
- virtual void noteStatistic(unsigned statCode, unsigned __int64 value, unsigned count) const
- {
- ctx->noteStatistic(statCode, value, count);
- }
- virtual void CTXLOG(const char *format, ...) const
- {
- va_list args;
- va_start(args, format);
- ctx->CTXLOGva(format, args);
- va_end(args);
- }
- virtual void CTXLOGva(const char *format, va_list args) const
- {
- ctx->CTXLOGva(format, args);
- }
- virtual void CTXLOGa(TracingCategory category, const char *prefix, const char *text) const
- {
- ctx->CTXLOGa(category, prefix, text);
- }
- virtual void logOperatorException(IException *E, const char *file, unsigned line, const char *format, ...) const
- {
- va_list args;
- va_start(args, format);
- ctx->logOperatorExceptionVA(E, file, line, format, args);
- va_end(args);
- }
- virtual void logOperatorExceptionVA(IException *E, const char *file, unsigned line, const char *format, va_list args) const
- {
- ctx->logOperatorExceptionVA(E, file, line, format, args);
- }
- virtual void CTXLOGae(IException *E, const char *file, unsigned line, const char *prefix, const char *format, ...) const
- {
- va_list args;
- va_start(args, format);
- ctx->CTXLOGaeva(E, file, line, prefix, format, args);
- va_end(args);
- }
- virtual void CTXLOGaeva(IException *E, const char *file, unsigned line, const char *prefix, const char *format, va_list args) const
- {
- ctx->CTXLOGaeva(E, file, line, prefix, format, args);
- }
- virtual void CTXLOGl(LogItem *log) const
- {
- ctx->CTXLOGl(log);
- }
- virtual StringBuffer &getLogPrefix(StringBuffer &ret) const
- {
- return ctx->getLogPrefix(ret);
- }
- virtual unsigned queryTraceLevel() const
- {
- return ctx->queryTraceLevel();
- }
- virtual bool isIntercepted() const
- {
- return ctx->isIntercepted();
- }
- virtual bool isBlind() const
- {
- return ctx->isBlind();
- }
- virtual unsigned parallelJoinPreload()
- {
- return ctx->parallelJoinPreload();
- }
- virtual unsigned concatPreload()
- {
- return ctx->concatPreload();
- }
- virtual unsigned fetchPreload()
- {
- return ctx->fetchPreload();
- }
- virtual unsigned fullKeyedJoinPreload()
- {
- return ctx->fullKeyedJoinPreload();
- }
- virtual unsigned keyedJoinPreload()
- {
- return ctx->keyedJoinPreload();
- }
- virtual unsigned prefetchProjectPreload()
- {
- return ctx->prefetchProjectPreload();
- }
- virtual void addSlavesReplyLen(unsigned len)
- {
- ctx->addSlavesReplyLen(len);
- }
- virtual const char *queryAuthToken()
- {
- return ctx->queryAuthToken();
- }
- virtual const IResolvedFile *resolveLFN(const char *filename, bool isOpt)
- {
- return ctx->resolveLFN(filename, isOpt);
- }
- virtual IRoxieWriteHandler *createLFN(const char *filename, bool overwrite, bool extend, const StringArray &clusters)
- {
- return ctx->createLFN(filename, overwrite, extend, clusters);
- }
- virtual void onFileCallback(const RoxiePacketHeader &header, const char *lfn, bool isOpt, bool isLocal)
- {
- ctx->onFileCallback(header, lfn, isOpt, isLocal);
- }
- virtual IActivityGraph *getLibraryGraph(const LibraryCallFactoryExtra &extra, IRoxieServerActivity *parentActivity)
- {
- return ctx->getLibraryGraph(extra, parentActivity);
- }
- virtual void noteProcessed(const IRoxieContextLogger &_activityContext, const IRoxieServerActivity *_activity, unsigned _idx, unsigned _processed, unsigned __int64 _totalCycles, unsigned __int64 _localCycles) const
- {
- ctx->noteProcessed(_activityContext, _activity, _idx, _processed, _totalCycles, _localCycles);
- }
- virtual IProbeManager *queryProbeManager() const
- {
- return ctx->queryProbeManager();
- }
- virtual IDebuggableContext *queryDebugContext() const
- {
- return ctx->queryDebugContext();
- }
- virtual bool queryTraceActivityTimes() const
- {
- return ctx->queryTraceActivityTimes();
- }
- virtual bool queryCheckingHeap() const
- {
- return ctx->queryCheckingHeap();
- }
- virtual bool queryTimeActivities() const
- {
- return ctx->queryTimeActivities();
- }
- virtual void printResults(IXmlWriter *output, const char *name, unsigned sequence)
- {
- ctx->printResults(output, name, sequence);
- }
- virtual void setWUState(WUState state)
- {
- ctx->setWUState(state);
- }
- virtual bool checkWuAborted()
- {
- return ctx->checkWuAborted();
- }
- virtual IWorkUnit *updateWorkUnit() const
- {
- return ctx->updateWorkUnit();
- }
- virtual IConstWorkUnit *queryWorkUnit() const
- {
- return ctx->queryWorkUnit();
- }
- virtual IRoxieServerContext *queryServerContext()
- {
- return ctx->queryServerContext();
- }
- virtual IWorkUnitRowReader *getWorkunitRowReader(const char *wuid, const char * name, unsigned sequence, IXmlToRowTransformer * xmlTransformer, IEngineRowAllocator *rowAllocator, bool isGrouped)
- {
- return ctx->getWorkunitRowReader(wuid, name, sequence, xmlTransformer, rowAllocator, isGrouped);
- }
- protected:
- IRoxieSlaveContext * ctx;
- };
- //=================================================================================
- #define RESULT_FLUSH_THRESHOLD 10000u
- #ifdef _DEBUG
- #define SOAP_SPLIT_THRESHOLD 100u
- #define SOAP_SPLIT_RESERVE 200u
- #else
- #define SOAP_SPLIT_THRESHOLD 64000u
- #define SOAP_SPLIT_RESERVE 65535u
- #endif
- //=================================================================================
- class CRoxieServerActivityFactoryBase : public CActivityFactory, implements IRoxieServerActivityFactory
- {
- protected:
- IntArray dependencies; // things I am dependent on
- IntArray dependencyIndexes; // things I am dependent on
- IntArray dependencyControlIds; // things I am dependent on
- StringArray dependencyEdgeIds; // How to describe them to the debugger
- unsigned dependentCount; // things dependent on me
- mutable CriticalSection statsCrit;
- mutable __int64 processed;
- mutable __int64 started;
- mutable __int64 totalCycles;
- mutable __int64 localCycles;
- public:
- IMPLEMENT_IINTERFACE;
- CRoxieServerActivityFactoryBase(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- processed = 0;
- started = 0;
- totalCycles = 0;
- localCycles = 0;
- dependentCount = 0;
- }
-
- ~CRoxieServerActivityFactoryBase()
- {
- }
- StringBuffer &toString(StringBuffer &ret) const
- {
- return ret.appendf("%p", this);
- }
- virtual void addDependency(unsigned _source, ThorActivityKind _kind, unsigned _sourceIdx, int controlId, const char *edgeId)
- {
- dependencies.append(_source);
- dependencyIndexes.append(_sourceIdx);
- dependencyControlIds.append(controlId);
- dependencyEdgeIds.append(edgeId);
- }
- virtual void noteDependent(unsigned target)
- {
- dependentCount++;
- }
- virtual IntArray &queryDependencies() { return dependencies; }
- virtual IntArray &queryDependencyIndexes() { return dependencyIndexes; }
- virtual IntArray &queryDependencyControlIds() { return dependencyControlIds; }
- virtual StringArray &queryDependencyEdgeIds() { return dependencyEdgeIds; }
- virtual unsigned queryId() const { return id; }
- virtual unsigned querySubgraphId() const { return subgraphId; }
- virtual ThorActivityKind getKind() const { return kind; }
- virtual IOutputMetaData * queryOutputMeta() const
- {
- return meta;
- }
- virtual bool isSink() const
- {
- return false;
- }
- virtual bool isFunction() const
- {
- return false;
- }
- virtual bool isGraphInvariant() const
- {
- return false;
- }
- virtual IHThorArg &getHelper() const
- {
- return *helperFactory();
- }
- virtual IRoxieServerActivity *createFunction(IHThorArg &arg, IProbeManager *_probeManager) const
- {
- arg.Release();
- throwUnexpected();
- }
- virtual void noteProcessed(unsigned idx, unsigned _processed, unsigned __int64 _totalCycles, unsigned __int64 _localCycles) const
- {
- if (_processed || _totalCycles || _localCycles)
- {
- CriticalBlock b(statsCrit);
- #ifdef _DEBUG
- assertex(_totalCycles >= _localCycles);
- #endif
- processed += _processed;
- totalCycles += _totalCycles;
- localCycles += _localCycles;
- }
- }
- virtual void noteStarted() const
- {
- CriticalBlock b(statsCrit);
- started ++;
- }
- virtual void noteStarted(unsigned idx) const
- {
- throwUnexpected(); // should be implemented/required by multiOutput cases only
- }
- virtual void getEdgeProgressInfo(unsigned output, IPropertyTree &edge) const
- {
- CriticalBlock b(statsCrit);
- if (output == 0)
- {
- putStatsValue(&edge, "count", "sum", processed);
- if (started)
- putStatsValue(&edge, "started", "sum", started);
- }
- else
- ERRLOG("unexpected call to getEdgeProcessInfo for output %d in activity %d", output, queryId());
- }
- virtual void getNodeProgressInfo(IPropertyTree &node) const
- {
- CActivityFactory::getNodeProgressInfo(node);
- CriticalBlock b(statsCrit);
- if (started)
- putStatsValue(&node, "_roxieStarted", "sum", started);
- if (totalCycles)
- putStatsValue(&node, "totalTime", "sum", (unsigned) (cycle_to_nanosec(totalCycles)/1000));
- if (localCycles)
- putStatsValue(&node, "localTime", "sum", (unsigned) (cycle_to_nanosec(localCycles)/1000));
- }
- virtual void resetNodeProgressInfo()
- {
- CActivityFactory::resetNodeProgressInfo();
- CriticalBlock b(statsCrit);
- started = 0;
- totalCycles = 0;
- localCycles = 0;
- }
- virtual void getActivityMetrics(StringBuffer &reply) const
- {
- CActivityFactory::getActivityMetrics(reply);
- CriticalBlock b(statsCrit);
- putStatsValue(reply, "_roxieStarted", "sum", started);
- putStatsValue(reply, "totalTime", "sum", (unsigned) (cycle_to_nanosec(totalCycles)/1000));
- putStatsValue(reply, "localTime", "sum", (unsigned) (cycle_to_nanosec(localCycles)/1000));
- }
- virtual unsigned __int64 queryLocalCycles() const
- {
- return localCycles;
- }
- virtual IQueryFactory &queryQueryFactory() const
- {
- return CActivityFactory::queryQueryFactory();
- }
- virtual ActivityArray *queryChildQuery(unsigned idx, unsigned &id)
- {
- return CActivityFactory::queryChildQuery(idx, id);
- }
- virtual void addChildQuery(unsigned id, ActivityArray *childQuery)
- {
- CActivityFactory::addChildQuery(id, childQuery);
- }
- virtual void createChildQueries(IArrayOf<IActivityGraph> &childGraphs, IRoxieServerActivity *parentActivity, IProbeManager *_probeManager, const IRoxieContextLogger &_logctx) const
- {
- ForEachItemIn(idx, childQueries)
- {
- childGraphs.append(*createActivityGraph(NULL, childQueryIndexes.item(idx), childQueries.item(idx), parentActivity, _probeManager, _logctx));
- }
- }
- virtual void onCreateChildQueries(IRoxieSlaveContext *ctx, IHThorArg *colocalArg, IArrayOf<IActivityGraph> &childGraphs) const
- {
- ForEachItemIn(idx, childGraphs)
- {
- ctx->noteChildGraph(childQueryIndexes.item(idx), &childGraphs.item(idx));
- childGraphs.item(idx).onCreate(ctx, colocalArg);
- }
- }
- IActivityGraph * createChildGraph(IRoxieSlaveContext * ctx, IHThorArg *colocalArg, unsigned childId, IRoxieServerActivity *parentActivity, IProbeManager * _probeManager, const IRoxieContextLogger &_logctx) const
- {
- unsigned match = childQueryIndexes.find(childId);
- assertex(match != NotFound);
- Owned<IActivityGraph> graph = createActivityGraph(NULL, childQueryIndexes.item(match), childQueries.item(match), parentActivity, _probeManager, _logctx);
- graph->onCreate(ctx, colocalArg);
- return graph.getClear();
- }
- virtual IRoxieServerSideCache *queryServerSideCache() const
- {
- return NULL; // Activities that wish to support server-side caching will need to do better....
- }
- virtual bool getEnableFieldTranslation() const
- {
- throwUnexpected(); // only implemented by index-related subclasses
- }
- virtual IDefRecordMeta *queryActivityMeta() const
- {
- throwUnexpected(); // only implemented by index-related subclasses
- }
- virtual void noteStatistic(unsigned statCode, unsigned __int64 value, unsigned count) const
- {
- mystats.noteStatistic(statCode, value, count);
- }
- virtual void getXrefInfo(IPropertyTree &reply, const IRoxieContextLogger &logctx) const
- {
- // Most activities have nothing to say...
- }
- };
- class CRoxieServerMultiInputInfo
- {
- private:
- UnsignedArray inputs;
- UnsignedArray inputIndexes;
- public:
- void set(unsigned idx, unsigned source, unsigned sourceidx)
- {
- if (idx==inputs.length())
- {
- inputs.append(source);
- inputIndexes.append(sourceidx);
- }
- else
- {
- while (!inputs.isItem(idx))
- {
- inputs.append(0);
- inputIndexes.append(0);
- }
- inputs.replace(source, idx);
- inputIndexes.replace(sourceidx, idx);
- }
- }
- unsigned get(unsigned idx, unsigned &sourceidx) const
- {
- if (inputs.isItem(idx))
- {
- sourceidx = inputIndexes.item(idx);
- return inputs.item(idx);
- }
- else
- return (unsigned) -1;
- }
- inline unsigned ordinality() const { return inputs.ordinality(); }
- };
- class CRoxieServerMultiInputFactory : public CRoxieServerActivityFactoryBase
- {
- private:
- CRoxieServerMultiInputInfo inputs;
- public:
- IMPLEMENT_IINTERFACE;
- CRoxieServerMultiInputFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactoryBase(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
- {
- inputs.set(idx, source, sourceidx);
- }
- virtual unsigned getInput(unsigned idx, unsigned &sourceidx) const
- {
- return inputs.get(idx, sourceidx);
- }
- virtual unsigned numInputs() const { return inputs.ordinality(); }
- };
- class CWrappedException : public CInterface, implements IException
- {
- Owned<IException> wrapped;
- ThorActivityKind kind;
- unsigned queryId;
- public:
- IMPLEMENT_IINTERFACE;
- CWrappedException(IException *_wrapped, ThorActivityKind _kind, unsigned _queryId)
- : wrapped(_wrapped), kind(_kind), queryId(_queryId)
- {
- }
- virtual int errorCode() const { return wrapped->errorCode(); }
- virtual StringBuffer & errorMessage(StringBuffer &msg) const { return wrapped->errorMessage(msg).appendf(" (in %s %d)", getActivityText(kind), queryId); }
- virtual MessageAudience errorAudience() const { return wrapped->errorAudience(); }
- };
- class CRoxieServerActivityFactory : public CRoxieServerActivityFactoryBase
- {
- protected:
- unsigned input;
- unsigned inputidx;
- public:
- IMPLEMENT_IINTERFACE;
- CRoxieServerActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactoryBase(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- input = (unsigned) -1;
- inputidx = 0;
- }
- inline void setInput(unsigned idx, unsigned source, unsigned sourceidx)
- {
- if (idx != 0)
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: id = %d : setInput() parameter out of bounds idx = %d at %s(%d)", id, idx, __FILE__, __LINE__);
- if (input != -1)
- 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__);
- input = source;
- inputidx = sourceidx;
- }
- virtual unsigned getInput(unsigned idx, unsigned &sourceidx) const
- {
- if (!idx)
- {
- sourceidx = inputidx;
- return input;
- }
- return (unsigned) -1;
- }
- virtual unsigned numInputs() const { return (input == (unsigned)-1) ? 0 : 1; }
- };
- class CRoxieServerMultiOutputFactory : public CRoxieServerActivityFactory
- {
- protected:
- unsigned numOutputs;
- unsigned __int64 *processedArray;
- bool *startedArray;
- CRoxieServerMultiOutputFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- numOutputs = 0;
- processedArray = NULL;
- startedArray = NULL;
- }
- ~CRoxieServerMultiOutputFactory()
- {
- delete [] processedArray;
- delete [] startedArray;
- }
- void setNumOutputs(unsigned num)
- {
- numOutputs = num;
- if (!num)
- num = 1; // Even sink activities like to track how many records they process
- processedArray = new unsigned __int64[num];
- startedArray = new bool[num];
- for (unsigned i = 0; i < num; i++)
- {
- processedArray[i] = 0;
- startedArray[i] = 0;
- }
- }
- virtual void getEdgeProgressInfo(unsigned idx, IPropertyTree &edge) const
- {
- assertex(numOutputs ? idx < numOutputs : idx==0);
- CriticalBlock b(statsCrit);
- putStatsValue(&edge, "count", "sum", processedArray[idx]);
- putStatsValue(&edge, "started", "sum", startedArray[idx]);
- }
- virtual void noteProcessed(unsigned idx, unsigned _processed, unsigned __int64 _totalCycles, unsigned __int64 _localCycles) const
- {
- assertex(numOutputs ? idx < numOutputs : idx==0);
- CriticalBlock b(statsCrit);
- processedArray[idx] += _processed;
- totalCycles += _totalCycles;
- localCycles += _localCycles;
- }
- virtual void noteStarted(unsigned idx) const
- {
- assertex(numOutputs ? idx < numOutputs : idx==0);
- CriticalBlock b(statsCrit);
- startedArray[idx] = true;
- }
- };
- class CRoxieServerInternalSinkFactory : public CRoxieServerActivityFactory
- {
- protected:
- bool isInternal;
- bool isRoot;
- unsigned usageCount;
- public:
- CRoxieServerInternalSinkFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- usageCount = _usageCount;
- isRoot = _isRoot;
- isInternal = false; // filled in by derived class constructor
- }
- virtual bool isSink() const
- {
- //only a sink if a root activity
- 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?
- }
- virtual void getEdgeProgressInfo(unsigned idx, IPropertyTree &edge) const
- {
- // 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
- // Just leave it blank is safest.
- }
- };
- typedef enum { STATEreset, STATEstarted, STATEstopped, STATEstarting } activityState;
- const char *queryStateText(activityState state)
- {
- switch (state)
- {
- case STATEreset: return "reset";
- case STATEstarted: return "started";
- case STATEstopped: return "stopped";
- case STATEstarting: return "starting";
- default: return "unknown";
- }
- }
- typedef ICopyArrayOf<IRoxieServerActivity> IRoxieServerActivityCopyArray;
- class CParallelActivityExecutor : public CAsyncFor
- {
- public:
- unsigned parentExtractSize;
- const byte * parentExtract;
- CParallelActivityExecutor(IRoxieServerActivityCopyArray & _activities, unsigned _parentExtractSize, const byte * _parentExtract) :
- activities(_activities), parentExtractSize(_parentExtractSize), parentExtract(_parentExtract) { }
- void Do(unsigned i)
- {
- activities.item(i).execute(parentExtractSize, parentExtract);
- }
- private:
- IRoxieServerActivityCopyArray & activities;
- };
- class CRoxieServerActivity : public CInterface, implements IRoxieServerActivity, implements IRoxieInput, implements IRoxieContextLogger
- {
- protected:
- IRoxieInput *input;
- IHThorArg &basehelper;
- IRoxieSlaveContext *ctx;
- const IRoxieServerActivityFactory *factory;
- IRoxieServerActivityCopyArray dependencies;
- IntArray dependencyIndexes;
- IntArray dependencyControlIds;
- IArrayOf<IActivityGraph> childGraphs;
- CachedOutputMetaData meta;
- IHThorArg *colocalParent;
- IEngineRowAllocator *rowAllocator;
- CriticalSection statecrit;
- mutable StatsCollector stats;
- unsigned processed;
- unsigned __int64 totalCycles;
- unsigned activityId;
- activityState state;
- bool createPending;
- bool debugging;
- bool timeActivities;
- public:
- IMPLEMENT_IINTERFACE;
- CRoxieServerActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : factory(_factory),
- basehelper(_factory->getHelper()),
- activityId(_factory->queryId())
- {
- input = NULL;
- ctx = NULL;
- meta.set(basehelper.queryOutputMeta());
- processed = 0;
- totalCycles = 0;
- if (factory)
- factory->createChildQueries(childGraphs, this, _probeManager, *this);
- state=STATEreset;
- rowAllocator = NULL;
- debugging = _probeManager != NULL; // Don't want to collect timing stats from debug sessions
- colocalParent = NULL;
- createPending = true;
- timeActivities = defaultTimeActivities;
- }
-
- CRoxieServerActivity(IHThorArg & _helper) : factory(NULL), basehelper(_helper)
- {
- activityId = 0;
- input = NULL;
- ctx = NULL;
- meta.set(basehelper.queryOutputMeta());
- processed = 0;
- totalCycles = 0;
- state=STATEreset;
- rowAllocator = NULL;
- debugging = false;
- colocalParent = NULL;
- createPending = true;
- timeActivities = defaultTimeActivities;
- }
- inline ~CRoxieServerActivity()
- {
- CriticalBlock cb(statecrit);
- if (traceStartStop)
- {
- DBGLOG("%p destroy %d state=%s", this, activityId, queryStateText(state)); // Note- CTXLOG may not be safe
- if (watchActivityId && watchActivityId==activityId)
- {
- DBGLOG("WATCH: %p destroy %d state=%s", this, activityId, queryStateText(state)); // Note- CTXLOG may not be safe
- }
- }
- if (state!=STATEreset)
- {
- DBGLOG("STATE: Activity %d destroyed but not reset", activityId);
- state = STATEreset; // bit pointless but there you go...
- }
- basehelper.Release();
- ::Release(rowAllocator);
- }
- virtual const IRoxieContextLogger &queryLogCtx()const
- {
- return *this;
- }
- inline void createRowAllocator()
- {
- if (!rowAllocator)
- rowAllocator = ctx->queryCodeContext()->getRowAllocator(meta.queryOriginal(), activityId);
- }
- // MORE - most of this is copied from ccd.hpp - can't we refactor?
- virtual void CTXLOG(const char *format, ...) const
- {
- va_list args;
- va_start(args, format);
- CTXLOGva(format, args);
- va_end(args);
- }
- virtual void CTXLOGva(const char *format, va_list args) const
- {
- StringBuffer text, prefix;
- getLogPrefix(prefix);
- text.valist_appendf(format, args);
- CTXLOGa(LOG_TRACING, prefix.str(), text.str());
- }
- virtual void CTXLOGa(TracingCategory category, const char *prefix, const char *text) const
- {
- if (ctx)
- ctx->CTXLOGa(category, prefix, text);
- else
- DBGLOG("[%s] %s", prefix, text);
- }
- virtual void logOperatorException(IException *E, const char *file, unsigned line, const char *format, ...) const
- {
- va_list args;
- va_start(args, format);
- StringBuffer prefix;
- getLogPrefix(prefix);
- CTXLOGaeva(E, file, line, prefix.str(), format, args);
- va_end(args);
- }
- virtual void logOperatorExceptionVA(IException *E, const char *file, unsigned line, const char *format, va_list args) const
- {
- StringBuffer prefix;
- getLogPrefix(prefix);
- CTXLOGaeva(E, file, line, prefix.str(), format, args);
- }
- virtual void CTXLOGae(IException *E, const char *file, unsigned line, const char *prefix, const char *format, ...) const
- {
- va_list args;
- va_start(args, format);
- CTXLOGaeva(E, file, line, prefix, format, args);
- va_end(args);
- }
- virtual void CTXLOGaeva(IException *E, const char *file, unsigned line, const char *prefix, const char *format, va_list args) const
- {
- if (ctx)
- ctx->CTXLOGaeva(E, file, line, prefix, format, args);
- else
- {
- StringBuffer ss;
- ss.appendf("[%s] ERROR", prefix);
- if (E)
- ss.append(": ").append(E->errorCode());
- if (file)
- ss.appendf(": %s(%d) ", file, line);
- if (E)
- E->errorMessage(ss.append(": "));
- if (format)
- {
- ss.append(": ").valist_appendf(format, args);
- }
- LOG(MCoperatorProgress, unknownJob, "%s", ss.str());
- }
- }
- virtual void CTXLOGl(LogItem *log) const
- {
- if (ctx)
- ctx->CTXLOGl(log);
- else
- {
- assert(ctx);
- log->Release(); // Should never happen
- }
- }
- virtual void noteStatistic(unsigned statCode, unsigned __int64 value, unsigned count) const
- {
- if (factory)
- factory->noteStatistic(statCode, value, count);
- if (ctx)
- ctx->noteStatistic(statCode, value, count);
- stats.noteStatistic(statCode, value, count);
- }
- virtual StringBuffer &getLogPrefix(StringBuffer &ret) const
- {
- if (ctx)
- ctx->getLogPrefix(ret);
- return ret.append('@').append(activityId);
- }
- virtual bool isIntercepted() const
- {
- return ctx ? ctx->isIntercepted() : false;
- }
- virtual bool isBlind() const
- {
- return ctx ? ctx->isBlind() : blindLogging;
- }
- virtual unsigned queryTraceLevel() const
- {
- if (ctx)
- return ctx->queryTraceLevel();
- else
- return traceLevel;
- }
- virtual bool isPassThrough()
- {
- return false;
- }
- virtual const IResolvedFile *resolveLFN(const char *filename, bool isOpt)
- {
- return ctx->resolveLFN(filename, isOpt);
- }
- virtual const IResolvedFile *queryVarFileInfo() const
- {
- throwUnexpected(); // should be implemented in more derived class by anyone that has a remote adaptor
- return NULL;
- }
- virtual void serializeSkipInfo(MemoryBuffer &out, unsigned seekLen, const void *rawSeek, unsigned numFields, const void * seek, const SmartStepExtra &stepExtra) const
- {
- throwUnexpected(); // should be implemented in more derived class wherever needed
- }
- virtual IRoxieSlaveContext *queryContext()
- {
- return ctx;
- }
- virtual IRoxieServerActivity *queryActivity() { return this; }
- virtual IIndexReadActivityInfo *queryIndexReadActivity() { return NULL; }
- virtual bool needsAllocator() const { return false; }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- ctx = _ctx;
- colocalParent = _colocalParent;
- createPending = true;
- if (needsAllocator())
- createRowAllocator();
- processed = 0;
- totalCycles = 0;
- if (factory)
- factory->onCreateChildQueries(_ctx, &basehelper, childGraphs);
- if (ctx)
- timeActivities = ctx->queryTimeActivities();
- }
- virtual void serializeCreateStartContext(MemoryBuffer &out)
- {
- //This should only be called after onStart has been called on the helper
- assertex(!createPending);
- assertex(state==STATEstarted);
- unsigned startlen = out.length();
- basehelper.serializeCreateContext(out);
- basehelper.serializeStartContext(out);
- if (queryTraceLevel() > 10)
- CTXLOG("serializeCreateStartContext for %d added %d bytes", activityId, out.length()-startlen);
- }
- virtual void serializeExtra(MemoryBuffer &out) {}
- inline void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CriticalBlock cb(statecrit);
- if (state != STATEreset && state != STATEstarting)
- {
- CTXLOG("STATE: Expected state to be reset, but was %s, in activity %d", queryStateText(state), activityId);
- }
- state=STATEstarted;
- #ifdef TRACE_STARTSTOP
- if (traceStartStop)
- {
- CTXLOG("start %p %d", this, activityId);
- if (watchActivityId && watchActivityId==activityId)
- {
- CTXLOG("WATCH: start %p %d", this, activityId);
- }
- }
- #endif
- executeDependencies(parentExtractSize, parentExtract, 0);
- if (input)
- input->start(parentExtractSize, parentExtract, paused);
- ensureCreated();
- basehelper.onStart(parentExtract, NULL);
- if (factory)
- factory->noteStarted();
- }
- void executeDependencies(unsigned parentExtractSize, const byte *parentExtract, unsigned controlId)
- {
- //MORE: Create a filtered list and then use asyncfor
- ForEachItemIn(idx, dependencies)
- {
- if (dependencyControlIds.item(idx) == controlId)
- dependencies.item(idx).execute(parentExtractSize, parentExtract);
- }
- }
- void stopDependencies(unsigned parentExtractSize, const byte *parentExtract, unsigned controlId)
- {
- ForEachItemIn(idx, dependencies)
- {
- if (dependencyControlIds.item(idx) == controlId)
- dependencies.item(idx).stop(false);
- }
- }
- virtual unsigned __int64 queryTotalCycles() const
- {
- return totalCycles;
- }
- virtual unsigned __int64 queryLocalCycles() const
- {
- __int64 ret = totalCycles;
- if (input) ret -= input->queryTotalCycles();
- if (ret < 0)
- ret = 0;
- return ret;
- }
- virtual IRoxieInput *queryInput(unsigned idx) const
- {
- if (idx==0)
- return input;
- else
- return NULL;
- }
- void noteProcessed(unsigned _idx, unsigned _processed, unsigned __int64 _totalCycles, unsigned __int64 _localCycles) const
- {
- if (factory)
- {
- if (!debugging)
- factory->noteProcessed(_idx, _processed, _totalCycles, _localCycles);
- if (ctx)
- ctx->noteProcessed(*this, this, _idx, _processed, _totalCycles, _localCycles);
- }
- }
- inline void ensureCreated()
- {
- if (createPending)
- {
- createPending = false;
- basehelper.onCreate(ctx->queryCodeContext(), colocalParent, NULL);
- }
- }
- inline void stop(bool aborting)
- {
- // NOTE - don't be tempted to skip the stop for activities that are reset - splitters need to see the stops
- if (state != STATEstopped)
- {
- CriticalBlock cb(statecrit);
- if (state != STATEstopped)
- {
- #ifdef TRACE_STARTSTOP
- if (traceStartStop)
- {
- CTXLOG("stop %p %d (state currently %s)", this, activityId, queryStateText(state));
- if (watchActivityId && watchActivityId==activityId)
- {
- CTXLOG("WATCH: stop %p %d", this, activityId);
- }
- }
- #endif
- state=STATEstopped;
- // NOTE - this is needed to ensure that dependencies which were not used are properly stopped
- ForEachItemIn(idx, dependencies)
- {
- if (dependencyControlIds.item(idx) == 0)
- dependencies.item(idx).stopSink(dependencyIndexes.item(idx));
- }
- if (input)
- input->stop(aborting);
- }
- }
- }
- inline void reset()
- {
- if (state != STATEreset)
- {
- CriticalBlock cb(statecrit);
- if (state != STATEreset)
- {
- if (state==STATEstarted || state==STATEstarting)
- {
- if (traceStartStop || traceLevel > 2)
- CTXLOG("STATE: activity %d reset without stop", activityId);
- stop(false);
- }
- if (ctx->queryTraceActivityTimes())
- {
- stats.dumpStats(*this);
- StringBuffer prefix, text;
- getLogPrefix(prefix);
- text.appendf("records processed - %d", processed);
- CTXLOGa(LOG_STATISTICS, prefix.str(), text.str());
- text.clear().appendf("total time - %d us", (unsigned) (cycle_to_nanosec(totalCycles)/1000));
- CTXLOGa(LOG_STATISTICS, prefix.str(), text.str());
- text.clear().appendf("local time - %d us", (unsigned) (cycle_to_nanosec(queryLocalCycles())/1000));
- CTXLOGa(LOG_STATISTICS, prefix.str(), text.str());
- }
- state = STATEreset;
- #ifdef TRACE_STARTSTOP
- if (traceStartStop)
- {
- CTXLOG("reset %p %d", this, activityId);
- if (watchActivityId && watchActivityId==activityId)
- {
- CTXLOG("WATCH: reset %p %d", this, activityId);
- }
- }
- #endif
- ForEachItemIn(idx, dependencies)
- dependencies.item(idx).reset();
- noteProcessed(0, processed, totalCycles, queryLocalCycles());
- if (input)
- input->reset();
- processed = 0;
- totalCycles = 0;
- }
- }
- }
- virtual void addDependency(IRoxieServerActivity &source, unsigned sourceIdx, int controlId)
- {
- dependencies.append(source);
- dependencyIndexes.append(sourceIdx);
- dependencyControlIds.append(controlId);
- }
- virtual void resetEOF()
- {
- //would make more sense if the default implementation (and eof member) were in the base class
- }
- // Sink activities should override this....
- virtual void execute(unsigned parentExtractSize, const byte * parentExtract)
- {
- throw MakeStringException(ROXIE_SINK, "Internal error: execute() requires a sink");
- }
- virtual void executeChild(size32_t & retSize, void * & ret, unsigned parentExtractSize, const byte * parentExtract)
- {
- throw MakeStringException(ROXIE_SINK, "Internal error: executeChild() requires a suitable sink");
- }
- virtual void stopSink(unsigned idx)
- {
- throw MakeStringException(ROXIE_SINK, "Internal error: stopSink() requires a suitable sink");
- }
- virtual __int64 evaluate()
- {
- throw MakeStringException(ROXIE_SINK, "Internal error: evaluate() requires a function");
- }
- virtual IRoxieInput * querySelectOutput(unsigned id)
- {
- return NULL;
- }
- virtual bool querySetStreamInput(unsigned id, IRoxieInput * _input)
- {
- return false;
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- assertex(!idx);
- input = _in;
- }
- virtual IRoxieInput *queryOutput(unsigned idx)
- {
- if (idx == (unsigned) -1)
- idx = 0;
- return idx ? NULL : this;
- }
- virtual IOutputMetaData *queryOutputMeta() const
- {
- return meta.queryOriginal();
- }
- virtual unsigned queryId() const
- {
- return activityId;
- }
- virtual unsigned querySubgraphId() const
- {
- return factory->querySubgraphId();
- }
- virtual void checkAbort()
- {
- ctx->checkAbort();
- }
- IException *makeWrappedException(IException *e)
- {
- StringBuffer msg;
- ThorActivityKind activityKind = factory ? factory->getKind() : TAKnone;
- CTXLOG("makeWrappedException - %s (in %s %d)", e->errorMessage(msg).str(), getActivityText(activityKind), activityId);
- if (QUERYINTERFACE(e, CWrappedException) || QUERYINTERFACE(e, IUserException))
- return e;
- else
- return new CWrappedException(e, activityKind, activityId);
- }
- virtual void gatherIterationUsage(IRoxieServerLoopResultProcessor & processor, unsigned parentExtractSize, const byte * parentExtract)
- {
- }
- virtual void associateIterationOutputs(IRoxieServerLoopResultProcessor & processor, unsigned parentExtractSize, const byte * parentExtract, IProbeManager *probeManager, IArrayOf<IRoxieInput> &probes)
- {
- }
- virtual void resetOutputsUsed()
- {
- }
- virtual void noteOutputUsed()
- {
- }
- virtual IRoxieServerSideCache *queryServerSideCache() const
- {
- return factory->queryServerSideCache();
- }
- virtual const IRoxieServerActivityFactory *queryFactory() const
- {
- return factory;
- }
- inline ThorActivityKind getKind() const
- {
- return factory->getKind();
- }
- inline bool isSink() const
- {
- return (factory != NULL) && factory->isSink();
- }
- };
- //=====================================================================================================
- class CRoxieServerLateStartActivity : public CRoxieServerActivity
- {
- protected:
- IRoxieInput *input; // Don't use base class input field as we want to delay starts
- bool prefiltered;
- bool eof;
- void lateStart(unsigned parentExtractSize, const byte *parentExtract, bool any)
- {
- prefiltered = !any;
- eof = prefiltered;
- if (!prefiltered)
- input->start(parentExtractSize, parentExtract, false);
- else
- {
- if (traceStartStop)
- CTXLOG("lateStart activity stopping input early as prefiltered");
- input->stop(false);
- }
- }
- public:
- CRoxieServerLateStartActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager)
- {
- input = NULL;
- prefiltered = false;
- eof = false;
- }
- virtual void stop(bool aborting)
- {
- if (!prefiltered)
- {
- input->stop(aborting);
- }
- else if (traceStartStop)
- CTXLOG("lateStart activity NOT stopping input late as prefiltered");
- CRoxieServerActivity::stop(aborting);
- }
- virtual unsigned __int64 queryLocalCycles() const
- {
- __int64 localCycles = totalCycles - input->queryTotalCycles();
- if (localCycles < 0)
- localCycles = 0;
- return localCycles;
- }
- virtual IRoxieInput *queryInput(unsigned idx) const
- {
- if (idx==0)
- return input;
- else
- return NULL;
- }
- virtual void reset()
- {
- CRoxieServerActivity::reset();
- input->reset();
- prefiltered = false;
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- assertex(!idx);
- input = _in;
- }
- };
- //=====================================================================================================
- atomic_t nextInstanceId;
- extern unsigned getNextInstanceId()
- {
- return atomic_add_exchange(&nextInstanceId, 1)+1;
- }
- atomic_t nextRuid;
- ruid_t getNextRuid()
- {
- ruid_t ret = atomic_add_exchange(&nextRuid, 1)+1;
- while (ret < RUID_FIRST)
- ret = atomic_add_exchange(&nextRuid, 1)+1; // ruids 0 and 1 are reserved for pings/unwanted discarder.
- return ret;
- }
- void setStartRuid(unsigned restarts)
- {
- atomic_set(&nextRuid, restarts * 0x10000);
- atomic_set(&nextInstanceId, restarts * 10000);
- }
- enum { LimitSkipErrorCode = 0, KeyedLimitSkipErrorCode = 1 };
- class LimitSkipException : public CInterface, public IException
- {
- int code;
- public:
- LimitSkipException(int _code) { code = _code; }
- IMPLEMENT_IINTERFACE;
- virtual int errorCode() const { return code; }
- virtual StringBuffer & errorMessage(StringBuffer &msg) const { return msg.append("LimitSkipException"); }
- virtual MessageAudience errorAudience() const { return MSGAUD_internal; }
- };
- IException *makeLimitSkipException(bool isKeyed)
- {
- // We need to make sure what we throw is IException not something derived from it....
- return new LimitSkipException(isKeyed ? KeyedLimitSkipErrorCode : LimitSkipErrorCode);
- }
- //=================================================================================
- interface IRecordPullerCallback : extends IExceptionHandler
- {
- virtual void processRow(const void *row) = 0;
- virtual void processEOG() = 0;
- virtual void processGroup(const ConstPointerArray &rows) = 0;
- virtual void processDone() = 0;
- };
- class RecordPullerThread : public RestartableThread
- {
- protected:
- IRoxieInput *input;
- IRecordPullerCallback *helper;
- Semaphore started; // MORE: GH->RKC I'm pretty sure this can be deleted, since handled by RestartableThread
- bool groupAtOnce, eof, eog;
- CriticalSection crit;
- public:
- RecordPullerThread(bool _groupAtOnce)
- : RestartableThread("RecordPullerThread"), groupAtOnce(_groupAtOnce)
- {
- input = NULL;
- helper = NULL;
- eof = eog = FALSE;
- }
- inline unsigned __int64 queryTotalCycles() const
- {
- return input->queryTotalCycles();
- }
- void setInput(IRecordPullerCallback *_helper, IRoxieInput *_input)
- {
- helper = _helper;
- input = _input;
- }
- IRoxieInput *queryInput() const
- {
- return input;
- }
- void start(unsigned parentExtractSize, const byte *parentExtract, bool paused, unsigned preload, bool noThread, IRoxieSlaveContext *ctx)
- {
- eof = false;
- eog = false;
- input->start(parentExtractSize, parentExtract, paused);
- try
- {
- if (preload && !paused)
- {
- if (traceLevel > 4)
- DBGLOG("Preload fetching first %d records", preload);
- if (groupAtOnce)
- pullGroups(preload);
- else
- pullRecords(preload);
- }
- if (eof)
- {
- if (traceLevel > 4)
- DBGLOG("No need to start puller after preload");
- helper->processDone();
- }
- else
- {
- if (!noThread)
- {
- StringBuffer logPrefix("[");
- if (ctx) ctx->getLogPrefix(logPrefix);
- logPrefix.append("] ");
- RestartableThread::start(logPrefix);
- started.wait();
- }
- }
- }
- catch (IException *e)
- {
- helper->fireException(e);
- }
- catch (...)
- {
- helper->fireException(MakeStringException(ROXIE_INTERNAL_ERROR, "Unexpected exception caught in RecordPullerThread::start"));
- }
- }
- void stop(bool aborting)
- {
- if (traceStartStop)
- DBGLOG("RecordPullerThread::stop");
- {
- 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.
- input->stop(aborting);
- }
- RestartableThread::join();
- }
- void reset()
- {
- input->reset();
- }
- virtual int run()
- {
- started.signal();
- try
- {
- if (groupAtOnce)
- pullGroups((unsigned) -1);
- else
- pullRecords((unsigned) -1);
- helper->processDone();
- }
- catch (IException *e)
- {
- helper->fireException(e);
- }
- catch (...)
- {
- helper->fireException(MakeStringException(ROXIE_INTERNAL_ERROR, "Unexpected exception caught in RecordPullerThread::run"));
- }
- return 0;
- }
- void done()
- {
- helper->processDone();
- }
- bool pullRecords(unsigned preload)
- {
- if (eof)
- return false;
- while (preload)
- {
- const void * row;
- {
- CriticalBlock c(crit); // See comments in stop for why this is needed
- row = input->nextInGroup();
- }
- if (row)
- {
- eog = false;
- helper->processRow(row);
- }
- else if (!eog)
- {
- helper->processEOG();
- eog = true;
- }
- else
- {
- eof = true;
- return false;
- }
- if (preload != (unsigned) -1)
- preload--;
- }
- return true;
- }
- void pullGroups(unsigned preload)
- {
- ConstPointerArray thisGroup;
- unsigned rowsDone = 0;
- while (preload && !eof)
- {
- const void *row;
- {
- CriticalBlock c(crit);
- row = input->nextInGroup();
- }
- if (row)
- {
- thisGroup.append(row);
- rowsDone++;
- }
- else if (thisGroup.length())
- {
- helper->processGroup(thisGroup);
- thisGroup.kill();
- if (preload != (unsigned) -1)
- {
- if (preload > rowsDone)
- preload -= rowsDone;
- else
- break;
- }
- rowsDone = 0;
- }
- else
- {
- eof = true;
- break;
- }
- }
- }
- };
- //=================================================================================
- #define READAHEAD_SIZE 1000
- // MORE - this code copied from ThreadedConcat code - may be able to common up some.
- class CRoxieServerReadAheadInput : public CInterface, implements IRoxieInput, implements IRecordPullerCallback
- {
- QueueOf<const void, true> buffer;
- InterruptableSemaphore ready;
- InterruptableSemaphore space;
- CriticalSection crit;
- bool eof;
- bool disabled;
- RecordPullerThread puller;
- unsigned preload;
- unsigned __int64 totalCycles;
- IRoxieSlaveContext *ctx;
- bool timeActivities;
- public:
- IMPLEMENT_IINTERFACE;
- CRoxieServerReadAheadInput(unsigned _preload) : puller(true), preload(_preload)
- {
- eof = false;
- disabled = false;
- totalCycles = 0;
- ctx = NULL;
- timeActivities = defaultTimeActivities;
- }
- void onCreate(IRoxieSlaveContext *_ctx)
- {
- ctx = _ctx;
- disabled = (ctx->queryDebugContext() != NULL);
- if (ctx)
- timeActivities = ctx->queryTimeActivities();
- }
- virtual IRoxieServerActivity *queryActivity()
- {
- return puller.queryInput()->queryActivity();
- }
- virtual IIndexReadActivityInfo *queryIndexReadActivity()
- {
- return puller.queryInput()->queryIndexReadActivity();
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- eof = false;
- totalCycles = 0;
- if (disabled)
- puller.queryInput()->start(parentExtractSize, parentExtract, paused);
- else
- {
- space.reinit(READAHEAD_SIZE);
- ready.reinit();
- puller.start(parentExtractSize, parentExtract, paused, preload, false, ctx);
- }
- }
- virtual void stop(bool aborting)
- {
- if (disabled)
- puller.queryInput()->stop(aborting);
- else
- {
- space.interrupt();
- ready.interrupt();
- puller.stop(aborting);
- }
- }
- virtual void reset()
- {
- if (disabled)
- puller.queryInput()->reset();
- else
- {
- puller.reset();
- ForEachItemIn(idx1, buffer)
- ReleaseRoxieRow(buffer.item(idx1));
- buffer.clear();
- }
- }
- virtual void resetEOF()
- {
- throwUnexpected();
- }
- virtual IOutputMetaData * queryOutputMeta() const
- {
- return puller.queryInput()->queryOutputMeta();
- }
- virtual void checkAbort()
- {
- puller.queryInput()->checkAbort();
- }
- void setInput(unsigned idx, IRoxieInput *_in)
- {
- assertex(!idx);
- puller.setInput(this, _in);
- }
- virtual unsigned __int64 queryTotalCycles() const
- {
- return totalCycles;
- }
- virtual unsigned __int64 queryLocalCycles() const
- {
- __int64 ret = totalCycles - puller.queryInput()->queryTotalCycles();
- if (ret < 0) ret = 0;
- return ret;
- }
- virtual IRoxieInput *queryInput(unsigned idx) const
- {
- return puller.queryInput()->queryInput(idx);
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (disabled)
- return puller.queryInput()->nextInGroup();
- else
- {
- loop
- {
- {
- CriticalBlock b(crit);
- if (eof && !buffer.ordinality())
- return NULL; // eof
- }
- ready.wait();
- const void *ret;
- {
- CriticalBlock b(crit);
- ret = buffer.dequeue();
- }
- space.signal();
- return ret;
- }
- }
- }
- virtual unsigned queryId() const { throwUnexpected(); }
- virtual bool fireException(IException *e)
- {
- // called from puller thread on failure
- ready.interrupt(LINK(e));
- space.interrupt(e);
- return true;
- }
- virtual void processRow(const void *row)
- {
- {
- CriticalBlock b(crit);
- buffer.enqueue(row);
- }
- ready.signal();
- space.wait();
- }
- virtual void processGroup(const ConstPointerArray &rows)
- {
- // NOTE - a bit bizarre in that it waits for the space AFTER using it.
- // But the space semaphore is only there to stop infinite readahead. And otherwise it would deadlock
- // if group was larger than max(space)
- {
- CriticalBlock b(crit);
- ForEachItemIn(idx, rows)
- buffer.enqueue(rows.item(idx));
- buffer.enqueue(NULL);
- }
- for (unsigned i2 = 0; i2 <= rows.length(); i2++) // note - does 1 extra for the null
- {
- ready.signal();
- space.wait();
- }
- }
- virtual void processEOG()
- {
- // Used when output is not grouped - just ignore
- }
- virtual void processDone()
- {
- CriticalBlock b(crit);
- eof = true;
- ready.signal();
- }
- };
- //=================================================================================
- class CRoxieServerTwoInputActivity : public CRoxieServerActivity
- {
- protected:
- IRoxieInput *input1;
- Owned<CRoxieServerReadAheadInput> puller;
- public:
- CRoxieServerTwoInputActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager)
- {
- input1 = NULL;
- }
- ~CRoxieServerTwoInputActivity()
- {
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- input1->start(parentExtractSize, parentExtract, paused);
- }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- if (puller)
- puller->onCreate(_ctx);
- CRoxieServerActivity::onCreate(_ctx, _colocalParent);
- }
- virtual void stop(bool aborting)
- {
- input1->stop(aborting);
- CRoxieServerActivity::stop(aborting);
- }
- virtual unsigned __int64 queryLocalCycles() const
- {
- __int64 ret;
- __int64 inputCycles = input->queryTotalCycles();
- __int64 input1Cycles = input1->queryTotalCycles();
- if (puller)
- ret = totalCycles - (inputCycles > input1Cycles ? inputCycles : input1Cycles);
- else
- ret = totalCycles - (inputCycles + input1Cycles);
- if (ret < 0)
- ret = 0;
- return ret;
- }
- virtual IRoxieInput *queryInput(unsigned idx) const
- {
- switch (idx)
- {
- case 0:
- return input;
- case 1:
- return input1;
- default:
- return NULL;
- }
- }
- virtual void reset()
- {
- CRoxieServerActivity::reset();
- if (input1)
- input1->reset();
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- switch(idx)
- {
- case 0:
- input = _in;
- break;
- case 1:
- input1 = _in;
- break;
- default:
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
- }
- }
- };
- //=================================================================================
- class CRoxieServerMultiInputBaseActivity : public CRoxieServerActivity
- {
- protected:
- unsigned numInputs;
- IRoxieInput **inputArray;
- public:
- CRoxieServerMultiInputBaseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
- : CRoxieServerActivity(_factory, _probeManager), numInputs(_numInputs)
- {
- inputArray = new IRoxieInput*[numInputs];
- for (unsigned i = 0; i < numInputs; i++)
- inputArray[i] = NULL;
- }
- ~CRoxieServerMultiInputBaseActivity()
- {
- delete [] inputArray;
- }
- virtual unsigned __int64 queryLocalCycles() const
- {
- __int64 localCycles = totalCycles;
- for (unsigned i = 0; i < numInputs; i++)
- localCycles -= inputArray[i]->queryTotalCycles();
- if (localCycles < 0)
- localCycles = 0;
- return localCycles;
- }
- virtual IRoxieInput *queryInput(unsigned idx) const
- {
- if (idx < numInputs)
- return inputArray[idx];
- else
- return NULL;
- }
- virtual void reset()
- {
- for (unsigned i = 0; i < numInputs; i++)
- inputArray[i]->reset();
- CRoxieServerActivity::reset();
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- inputArray[idx] = _in;
- }
- };
- //=================================================================================
- class CRoxieServerMultiInputActivity : public CRoxieServerMultiInputBaseActivity
- {
- public:
- CRoxieServerMultiInputActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
- : CRoxieServerMultiInputBaseActivity(_factory, _probeManager, _numInputs)
- {
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerMultiInputBaseActivity::start(parentExtractSize, parentExtract, paused);
- for (unsigned i = 0; i < numInputs; i++)
- {
- inputArray[i]->start(parentExtractSize, parentExtract, paused);
- }
- }
- virtual void stop(bool aborting)
- {
- for (unsigned i = 0; i < numInputs; i++)
- {
- inputArray[i]->stop(aborting);
- }
- CRoxieServerMultiInputBaseActivity::stop(aborting);
- }
- };
- //=====================================================================================================
- class CRoxieServerInternalSinkActivity : public CRoxieServerActivity
- {
- protected:
- unsigned numOutputs;
- bool executed;
- bool *stopped;
- CriticalSection ecrit;
- Owned<IException> exception;
- public:
- CRoxieServerInternalSinkActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numOutputs)
- : CRoxieServerActivity(_factory, _probeManager), numOutputs(_numOutputs)
- {
- executed = false;
- stopped = new bool[numOutputs];
- for (unsigned s = 0; s < numOutputs; s++)
- stopped[s] = false;
- }
- ~CRoxieServerInternalSinkActivity()
- {
- delete [] stopped;
- }
- virtual void reset()
- {
- for (unsigned s = 0; s < numOutputs; s++)
- stopped[s] = false;
- executed = false;
- exception.clear();
- CRoxieServerActivity::reset();
- }
- virtual IRoxieInput *queryOutput(unsigned idx)
- {
- return NULL;
- }
- virtual void stopSink(unsigned outputIdx)
- {
- if (!stopped[outputIdx])
- {
- stopped[outputIdx] = true;
- for (unsigned s = 0; s < numOutputs; s++)
- if (!stopped[s])
- return;
- stop(false); // all outputs stopped - stop parent.
- }
- }
- virtual const void *nextInGroup()
- {
- throwUnexpected(); // I am nobody's input
- }
- virtual void onExecute() = 0;
- virtual void execute(unsigned parentExtractSize, const byte * parentExtract)
- {
- CriticalBlock b(ecrit);
- if (exception)
- throw exception.getLink();
- if (!executed)
- {
- try
- {
- start(parentExtractSize, parentExtract, false);
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext()); // unfortunately this is not really best place for seeing in debugger.
- onExecute();
- }
- stop(false);
- executed = true;
- }
- catch (IException *E)
- {
- exception.set(E); // (or maybe makeWrappedException?)
- stop(true);
- throw;
- }
- catch (...)
- {
- exception.set(MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught at %s:%d", __FILE__, __LINE__));
- stop(true);
- throw;
- }
- }
- }
- };
- //=================================================================================
- class CRoxieServerQueryPacket : public CInterface, implements IRoxieServerQueryPacket
- {
- protected:
- Owned<IMessageResult> result;
- Owned<IRoxieQueryPacket> packet;
- Linked<IRoxieServerQueryPacket> continuation;
- unsigned hash;
- unsigned seq;
- unsigned lastDebugSequence;
- Owned<IRoxieQueryPacket> lastDebugResponse;
- ILRUChain *prev;
- ILRUChain *next;
- bool delayed;
- public:
- IMPLEMENT_IINTERFACE;
- CRoxieServerQueryPacket(IRoxieQueryPacket *p) : packet(p)
- {
- hash = 0;
- seq = 0;
- prev = NULL;
- next = NULL;
- delayed = false;
- lastDebugSequence = 0;
- }
- virtual IRoxieQueryPacket *queryPacket() const
- {
- return packet;
- }
- virtual bool isContinuation() const
- {
- return packet && (packet->queryHeader().continueSequence & ~CONTINUE_SEQUENCE_SKIPTO) != 0;
- }
- virtual bool isDelayed() const
- {
- return delayed;
- }
- virtual bool isEnd() const
- {
- return false;
- }
- virtual bool isLimit(unsigned __int64 &_rowLimit, unsigned __int64 &_keyedLimit, unsigned __int64 &_stopAfter) const
- {
- return false;
- }
- virtual bool hasResult() const
- {
- return result != NULL;
- }
- virtual bool hasContinuation() const
- {
- return continuation != NULL;
- }
- virtual void setDelayed(bool _delayed)
- {
- delayed = _delayed;
- }
- virtual void setPacket(IRoxieQueryPacket *_packet)
- {
- packet.setown(_packet);
- }
- virtual void setSequence(unsigned _seq)
- {
- assertex(!IsShared());
- seq = _seq;
- }
- virtual unsigned getSequence() const
- {
- return seq;
- }
- IMessageResult *getResult()
- {
- return result.getLink();
- }
- IMessageResult *queryResult()
- {
- return result;
- }
- void setResult(IMessageResult *r)
- {
- result.setown(r);
- }
- IRoxieServerQueryPacket *queryContinuation()
- {
- return continuation;
- }
- void setContinuation(IRoxieServerQueryPacket *c)
- {
- continuation.setown(c);
- }
- virtual unsigned queryHash() const
- {
- return hash;
- }
- virtual void setHash(unsigned _hash)
- {
- hash = _hash;
- }
- virtual ILRUChain *queryPrev() const { return prev; }
- virtual ILRUChain *queryNext() const { return next; }
- virtual void setPrev(ILRUChain *p) { prev = p; }
- virtual void setNext(ILRUChain *n) { next = n; }
- virtual void unchain()
- {
- if (prev && next)
- {
- prev->setNext(next);
- next->setPrev(prev);
- }
- next = NULL;
- prev = NULL;
- }
- virtual IRoxieQueryPacket *getDebugResponse(unsigned sequence)
- {
- if (sequence == lastDebugSequence)
- return lastDebugResponse.getLink();
- else if (sequence > lastDebugSequence)
- {
- lastDebugResponse.clear();
- return NULL;
- }
- else
- throwUnexpected();
- }
- virtual void setDebugResponse(unsigned sequence, IRoxieQueryPacket *response)
- {
- lastDebugSequence = sequence;
- lastDebugResponse.set(response);
- }
- };
- class CRoxieServerQueryPacketEndMarker : public CRoxieServerQueryPacket
- {
- public:
- CRoxieServerQueryPacketEndMarker() : CRoxieServerQueryPacket(NULL)
- {
- }
- virtual bool isEnd() const
- {
- return true;
- }
- };
- class CRoxieServerQueryPacketLimitMarker : public CRoxieServerQueryPacket
- {
- unsigned __int64 rowLimit;
- unsigned __int64 keyedLimit;
- unsigned __int64 stopAfter;
- public:
- CRoxieServerQueryPacketLimitMarker(unsigned __int64 _rowLimit, unsigned __int64 _keyedLimit, unsigned __int64 _stopAfter) : CRoxieServerQueryPacket(NULL)
- {
- rowLimit = _rowLimit;
- keyedLimit = _keyedLimit;
- stopAfter = _stopAfter;
- }
- virtual bool isLimit(unsigned __int64 &_rowLimit, unsigned __int64 &_keyedLimit, unsigned __int64 &_stopAfter) const
- {
- _rowLimit = rowLimit;
- _keyedLimit = keyedLimit;
- _stopAfter = stopAfter;
- return true;
- }
- };
- class CRoxieServerSideCache : implements IRoxieServerSideCache, implements ILRUChain
- {
- protected:
- unsigned cacheTableSize;
- unsigned cacheTableSpace;
- IRoxieServerQueryPacket **cacheTable;
- mutable ILRUChain *prev;
- mutable ILRUChain *next;
- mutable CriticalSection crit;
- virtual ILRUChain *queryPrev() const { return prev; }
- virtual ILRUChain *queryNext() const { return next; }
- virtual void setPrev(ILRUChain *p) { prev = p; }
- virtual void setNext(ILRUChain *n) { next = n; }
- virtual void unchain()
- {
- prev->setNext(next);
- next->setPrev(prev);
- next = NULL;
- prev = NULL;
- }
- void moveToHead(IRoxieServerQueryPacket *mru)
- {
- mru->unchain();
- mru->setNext(next);
- next->setPrev(mru);
- mru->setPrev(this);
- next = mru;
- }
- IRoxieServerQueryPacket *removeLRU()
- {
- if (next==this)
- assertex(next != this);
- IRoxieServerQueryPacket *goer = (IRoxieServerQueryPacket *) next;
- goer->unchain(); // NOTE - this will modify the value of next
- return goer;
- }
- void removeEntry(IRoxieServerQueryPacket *goer)
- {
- unsigned v = goer->queryHash() % cacheTableSize;
- loop
- {
- IRoxieServerQueryPacket *found = cacheTable[v];
- assertex(found);
- if (found == goer)
- {
- cacheTable[v] = NULL;
- unsigned vn = v;
- loop
- {
- vn++;
- if (vn==cacheTableSize) vn = 0;
- IRoxieServerQueryPacket *found2 = cacheTable[vn];
- if (!found2)
- break;
- unsigned vm = found2->queryHash() % cacheTableSize;
- if (((vn+cacheTableSize-vm) % cacheTableSize)>=((vn+cacheTableSize-v) % cacheTableSize)) // diff(vn,vm)>=diff(vn,v)
- {
- cacheTable[v] = found2;
- v = vn;
- cacheTable[v] = NULL;
- }
- }
- cacheTableSpace++;
- break;
- }
- v++;
- if (v==cacheTableSize)
- v = 0;
- }
- goer->Release();
- }
- public:
- CRoxieServerSideCache(unsigned _cacheSize)
- {
- cacheTableSize = (_cacheSize*4)/3;
- cacheTable = new IRoxieServerQueryPacket *[cacheTableSize];
- memset(cacheTable, 0, cacheTableSize * sizeof(IRoxieServerQueryPacket *));
- cacheTableSpace = _cacheSize;
- prev = this;
- next = this;
- }
- ~CRoxieServerSideCache()
- {
- for (unsigned i = 0; i < cacheTableSize; i++)
- {
- ::Release(cacheTable[i]);
- }
- delete [] cacheTable;
- }
- virtual IRoxieServerQueryPacket *findCachedResult(const IRoxieContextLogger &logctx, IRoxieQueryPacket *p) const
- {
- unsigned hash = p->hash();
- unsigned et = hash % cacheTableSize;
- if (traceServerSideCache)
- {
- StringBuffer s;
- logctx.CTXLOG("CRoxieServerSideCache::findCachedResult hash %x slot %d %s", hash, et, p->queryHeader().toString(s).str());
- }
- CriticalBlock b(crit);
- loop
- {
- IRoxieServerQueryPacket *found = cacheTable[et];
- if (!found)
- return NULL;
- if (found->queryHash() == hash && found->queryPacket()->cacheMatch(p))
- {
- const_cast<CRoxieServerSideCache *>(this)->moveToHead(found);
- if (traceServerSideCache)
- logctx.CTXLOG("CRoxieServerSideCache::findCachedResult cache hit");
- logctx.noteStatistic(STATS_SERVERCACHEHIT, 1, 1);
- return NULL;
- // 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....
- //IRoxieServerQueryPacket *ret = new CRoxieServerQueryPacket(p);
- //ret->setResult(found->getResult());
- //return ret;
- }
- et++;
- if (et == cacheTableSize)
- et = 0;
- }
- }
- virtual void noteCachedResult(IRoxieServerQueryPacket *out, IMessageResult *in)
- {
- if (true) //!in->getLength()) // MORE - separate caches for hits and nohits
- {
- unsigned hash = out->queryPacket()->hash();
- out->setHash(hash);
- unsigned et = hash % cacheTableSize;
- if (traceServerSideCache)
- {
- StringBuffer s;
- DBGLOG("CRoxieServerSideCache::noteCachedResult hash %x slot %d %s", hash, et, out->queryPacket()->queryHeader().toString(s).str());
- }
- CriticalBlock b(crit);
- loop
- {
- IRoxieServerQueryPacket *found = cacheTable[et];
- if (!found)
- {
- if (cacheTableSpace)
- {
- out->setResult(LINK(in));
- cacheTable[et] = LINK(out);
- cacheTableSpace--;
- moveToHead(out);
- break;
- }
- else
- {
- IRoxieServerQueryPacket *goer = removeLRU();
- removeEntry(goer);
- et = hash % cacheTableSize;
- continue;
- }
- }
- else if (found->queryHash()==hash && found->queryPacket()->cacheMatch(out->queryPacket()))
- {
- moveToHead(found);
- return; // already in the cache. Because we don't cache until we have result, this can happen where
- // multiple copies of a slave query are in-flight at once.
- }
- et++;
- if (et == cacheTableSize)
- et = 0;
- }
- }
- // MORE - do we need to worry about the attachment between the MessageUnpacker and the current row manager. May all fall out ok...
- // Can I easily spot a null result? Do I want to cache null results separately? only?
- }
- // Note that this caching mechanism (unlike the old keyed-join specific one) does not common up cases where multiple
- // identical queries are in-flight at the same time. But if we can make it persistant between queries that will
- // more than make up for it
- };
- class CRowArrayMessageUnpackCursor : public CInterface, implements IMessageUnpackCursor
- {
- ConstPointerArray &data;
- Linked<IMessageResult> result;
- public:
- IMPLEMENT_IINTERFACE;
- CRowArrayMessageUnpackCursor(ConstPointerArray &_data, IMessageResult *_result)
- : data(_data), result(_result)
- {
- }
- virtual bool atEOF() const
- {
- return data.length()==0;
- }
- virtual bool isSerialized() const
- {
- return false;
- }
- virtual const void * getNext(int length)
- {
- if (!data.length())
- return NULL;
- const void *ret = data.item(0);
- data.remove(0);
- return ret;
- }
- };
- // MORE - should possibly move more over to the lazy version used in indexread?
- class CRowArrayMessageResult : public CInterface, implements IMessageResult
- {
- ConstPointerArray data;
- IRowManager &rowManager;
- bool variableSize;
- public:
- IMPLEMENT_IINTERFACE;
- CRowArrayMessageResult(IRowManager &_rowManager, bool _variableSize) : rowManager(_rowManager), variableSize(_variableSize)
- {
- }
- ~CRowArrayMessageResult()
- {
- ReleaseRoxieRowSet(data);
- }
- virtual IMessageUnpackCursor *getCursor(IRowManager *rowMgr) const
- {
- CRowArrayMessageResult *_this = (CRowArrayMessageResult *) this;
- return new CRowArrayMessageUnpackCursor(_this->data, _this);
- }
- virtual const void *getMessageHeader(unsigned &length) const
- {
- throwUnexpected(); // should never get called - I don't have a header available
- length = 0;
- return NULL;
- }
- virtual const void *getMessageMetadata(unsigned &length) const
- {
- length = 0;
- return NULL;
- }
- virtual void discard() const
- {
- throwUnexpected();
- }
- void append(const void *row)
- {
- data.append(row);
- }
- };
- void throwRemoteException(IMessageUnpackCursor *extra)
- {
- RecordLengthType *rowlen = (RecordLengthType *) extra->getNext(sizeof(RecordLengthType));
- if (rowlen)
- {
- char *xml = (char *) extra->getNext(*rowlen);
- ReleaseRoxieRow(rowlen);
- Owned<IPropertyTree> p = createPTreeFromXMLString(xml);
- ReleaseRoxieRow(xml);
- unsigned code = p->getPropInt("Code", 0);
- const char *msg = p->queryProp("Message");
- if (!msg)
- msg = xml;
- throw MakeStringException(code, "%s", msg);
- }
- throwUnexpected();
- }
- class CRemoteResultAdaptor :public CInterface, implements IRoxieInput, implements IExceptionHandler
- {
- friend class CRemoteResultMerger;
- class CRemoteResultMerger
- {
- class HeapEntry : public CInterface
- {
- private:
- CRemoteResultAdaptor &adaptor;
- IMessageUnpackCursor *cursor;
- public:
- const void *current;
- bool isLast;
- bool lastIsComplete;
- IRoxieServerQueryPacket *packet;
- unsigned seq;
- public:
- inline const void *noteResult(IMessageUnpackCursor *_cursor, bool _lastIsComplete)
- {
- cursor = _cursor;
- lastIsComplete = _lastIsComplete;
- return next();
- }
- public:
- HeapEntry(CRemoteResultAdaptor &_adaptor, IRoxieServerQueryPacket *_packet, unsigned _seq) : adaptor(_adaptor), packet(_packet), seq(_seq)
- {
- cursor = NULL;
- current = NULL;
- isLast = false;
- lastIsComplete = true;
- }
- ~HeapEntry()
- {
- ::Release(packet);
- ::Release(cursor);
- ReleaseRoxieRow(current);
- }
- bool isCompleteMatch() const
- {
- if (!isLast || lastIsComplete)
- return true;
- else
- return false;
- }
- const void *next()
- {
- if (cursor)
- {
- ReleaseClearRoxieRow(current);
- current = adaptor.getRow(cursor);
- isLast = cursor->atEOF();
- if (!current)
- {
- cursor->Release();
- cursor = NULL;
- }
- }
- return current;
- }
- unsigned skipTo(IRangeCompare *compare, const void *seek, unsigned numFields, bool requireExactMatch)
- {
- // MORE - This loop should possibly be a binchop... though it's not absolutely clear that is true (depends on term frequencies)
- unsigned skipped = 0;
- loop
- {
- int c = compare->docompare(current, seek, numFields);
- //If larger than the seek values, then we may be allowed to return an inexact match,
- //if equal then it is required to be an exact match,
- if (c > 0)
- {
- if (!requireExactMatch || isCompleteMatch())
- break;
- }
- else if ((c == 0) && isCompleteMatch())
- break;
- skipped++;
- if (!next())
- break;
- }
- return skipped;
- }
- };
- CRemoteResultAdaptor &adaptor;
- CIArrayOf<HeapEntry> heapEntries;
- UnsignedArray heap;
- IRowManager *rowManager;
- unsigned numPending;
- unsigned numFields;
- bool endSeen;
- bool remakePending;
- IRangeCompare *compare;
- bool deferredContinuation;
- inline int doCompare(unsigned l, unsigned r)
- {
- int ret = compare->docompare(heapEntries.item(l).current, heapEntries.item(r).current, numFields);
- if (!ret) ret = heapEntries.item(l).seq - heapEntries.item(r).seq;
- return ret;
- }
- void makeHeap()
- {
- /* Permute blocks to establish the heap property
- For each element p, the children are p*2+1 and p*2+2 (provided these are in range)
- The children of p must both be greater than or equal to p
- The parent of a child c is given by p = (c-1)/2
- */
- unsigned i;
- unsigned n = heap.length();
- unsigned *s = heap.getArray();
- for (i=1; i<n; i++)
- {
- unsigned r = s[i];
- int c = i; /* child */
- while (c > 0)
- {
- int p = (c-1)/2; /* parent */
- if ( doCompare( s[c], s[p] ) >= 0 )
- break;
- s[c] = s[p];
- s[p] = r;
- c = p;
- }
- }
- remakePending = false;
- }
- void remakeHeap()
- {
- /* The row associated with block[0] will have changed
- This code restores the heap property
- */
- unsigned p = 0; /* parent */
- unsigned n = heap.length();
- unsigned *s = heap.getArray();
- while (1)
- {
- unsigned c = p*2 + 1; /* child */
- if ( c >= n )
- break;
- /* Select smaller child */
- if ( c+1 < n && doCompare( s[c+1], s[c] ) < 0 ) c += 1;
- /* If child is greater or equal than parent then we are done */
- if ( doCompare( s[c], s[p] ) >= 0 )
- break;
- /* Swap parent and child */
- unsigned r = s[c];
- s[c] = s[p];
- s[p] = r;
- /* child becomes parent */
- p = c;
- }
- remakePending = false;
- }
- void append(IRoxieServerQueryPacket *p, unsigned seq)
- {
- HeapEntry &h = *new HeapEntry(adaptor, LINK(p), seq);
- IMessageResult *result = p->queryResult();
- assertex(result);
- if (h.noteResult(result->getCursor(rowManager), isCompleteMatchFlag(result)))
- {
- heapEntries.append(h);
- heap.append(heap.ordinality());
- }
- else
- h.Release();
- }
- void removeHeap(unsigned idx)
- {
- heapEntries.remove(idx);
- ForEachItemIn(i, heap)
- {
- unsigned v = heap.item(i);
- assertex(v != idx);
- if (v > idx)
- heap.replace(v-1, i);
- }
- }
- bool isCompleteMatchFlag(IMessageResult *result)
- {
- unsigned metaLen;
- const byte *metaInfo = (const byte *) result->getMessageMetadata(metaLen);
- if (metaLen)
- {
- unsigned short continuationLen = *(unsigned short *) metaInfo;
- if (continuationLen >= sizeof(bool))
- {
- metaInfo += sizeof(unsigned short);
- return *(bool *) metaInfo;
- }
- }
- return true; // if no continuation info, last row was complete.
- }
- public:
- CRemoteResultMerger(CRemoteResultAdaptor &_adaptor) : adaptor(_adaptor)
- {
- init(NULL, NULL);
- }
- void init(ISteppingMeta *meta, IRowManager *_rowManager)
- {
- if (meta)
- {
- numFields = meta->getNumFields();
- compare = meta->queryCompare();
- }
- else
- {
- numFields = 0;
- compare = NULL;
- }
- rowManager = _rowManager;
- numPending = 0;
- endSeen = false;
- remakePending = false;
- deferredContinuation = false;
- }
- void reset()
- {
- heapEntries.kill();
- heap.kill();
- numPending = 0;
- endSeen = false;
- remakePending = false;
- deferredContinuation = false;
- }
- inline bool noteEndSeen()
- {
- bool hadSeen = endSeen;
- if (!endSeen)
- makeHeap();
- endSeen = true;
- return !hadSeen;
- }
- void noteResult(IRoxieServerQueryPacket *p, unsigned seq)
- {
- if (!p->isContinuation())
- append(p, seq);
- else
- {
- ForEachItemIn(idx, heapEntries)
- {
- HeapEntry &h = heapEntries.item(idx);
- if (h.packet == p)
- {
- IMessageResult *result = p->queryResult();
- if (!h.noteResult(result->getCursor(rowManager), isCompleteMatchFlag(result)))
- {
- heap.zap(idx);
- removeHeap(idx);
- }
- numPending--;
- if (!numPending)
- makeHeap();
- return;
- }
- }
- }
- // If we get here it must be a continuation for one that I have not yet consumed... we don't need to do anything.
- return;
- }
- unsigned skipRows(unsigned &idx, const void *seek, const void *rawSeek, unsigned numFields, unsigned seekLen, const SmartStepExtra & stepExtra)
- {
- HeapEntry &entry = heapEntries.item(idx);
- unsigned skipped = entry.current ? entry.skipTo(compare, seek, numFields, !stepExtra.returnMismatches()) : 0;
- if (!entry.current)
- {
- IRoxieServerQueryPacket *continuation = entry.packet->queryContinuation();
- if (continuation)
- {
- continuation->Link();
- entry.packet->Release();
- entry.packet = continuation;
- if (continuation->hasResult())
- {
- IMessageResult *result = continuation->queryResult();
- bool lastIsCompleteMatch = isCompleteMatchFlag(result);
- entry.noteResult(result->getCursor(rowManager), lastIsCompleteMatch);
- }
- else
- {
- if (continuation->isDelayed())
- {
- continuation->setDelayed(false);
- MemoryBuffer serializedSkip;
- adaptor.activity.serializeSkipInfo(serializedSkip, seekLen, rawSeek, numFields, seek, stepExtra);
- continuation->setPacket(continuation->queryPacket()->insertSkipData(serializedSkip.length(), serializedSkip.toByteArray()));
- ROQ->sendPacket(continuation->queryPacket(), adaptor.activity.queryLogCtx());
- adaptor.sentsome.signal();
- }
- numPending++;
- }
- }
- else
- {
- heap.zap(idx);
- removeHeap(idx);
- idx--;
- }
- }
- return skipped;
- }
- const void * nextSteppedGE(const void * seek, const void *rawSeek, unsigned numFields, unsigned seeklen, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
- {
- // We discard all rows < seekval from all entries in heap
- // If this results in additional slave requests, we return NULL so that we can wait for them
- // If not, we rebuild the heap (if any were skipped) and return the first row
- deferredContinuation = false;
- if (heap.length())
- {
- unsigned skipped = 0;
- unsigned idx = 0;
- while(heapEntries.isItem(idx))
- {
- skipped += skipRows(idx, seek, rawSeek, numFields, seeklen, stepExtra);
- idx++;
- }
- if (numPending)
- return NULL; // can't answer yet, need more results from slaves
- else
- {
- if (skipped)
- makeHeap();
- return next(wasCompleteMatch, stepExtra);
- }
- }
- else
- return NULL;
- }
- bool doContinuation(HeapEntry &topEntry, bool canDefer)
- {
- IRoxieServerQueryPacket *continuation = topEntry.packet->queryContinuation();
- if (continuation)
- {
- if (continuation->isDelayed() && canDefer)
- {
- if (adaptor.activity.queryLogCtx().queryTraceLevel() > 10)
- adaptor.activity.queryLogCtx().CTXLOG("Deferring continuation");
- deferredContinuation = true;
- }
- else
- {
- deferredContinuation = false;
- continuation->Link();
- topEntry.packet->Release();
- topEntry.packet = continuation;
- if (continuation->hasResult())
- {
- IMessageResult *result = continuation->queryResult();
- bool lastIsCompleteMatch = isCompleteMatchFlag(result);
- topEntry.noteResult(result->getCursor(rowManager), lastIsCompleteMatch);
- }
- else
- {
- if (continuation->isDelayed()) // has the continuation been requested yet?
- {
- continuation->Link();
- topEntry.packet->Release();
- topEntry.packet = continuation;
- continuation->setDelayed(false);
- if (adaptor.activity.queryLogCtx().queryTraceLevel() > 10)
- adaptor.activity.queryLogCtx().CTXLOG("About to send continuation, from doContinuation");
- ROQ->sendPacket(continuation->queryPacket(), adaptor.activity.queryLogCtx());
- adaptor.sentsome.signal();
- }
- numPending++; // we are waiting for one that is already in flight
- }
- }
- return true; // next not known yet
- }
- else
- return false;
- }
- const void *next(bool & wasCompleteMatch, const SmartStepExtra & stepExtra)
- {
- OwnedConstRoxieRow ret;
- if (heap.length())
- {
- if (deferredContinuation)
- {
- unsigned top = heap.item(0);
- HeapEntry &topEntry = heapEntries.item(top);
- doContinuation(topEntry, false);
- return NULL;
- }
- if (remakePending)
- remakeHeap();
- unsigned top = heap.item(0);
- HeapEntry &topEntry = heapEntries.item(top);
- ret.set(topEntry.current);
- wasCompleteMatch = topEntry.isCompleteMatch();
- const void *next = topEntry.next();
- if (!next)
- {
- if (!doContinuation(topEntry, stepExtra.returnMismatches()))
- {
- unsigned last = heap.pop();
- if (heap.length())
- heap.replace(last, 0);
- removeHeap(top);
- }
- }
- remakePending = true;
- }
- return ret.getClear();
- }
- bool ready()
- {
- return endSeen && numPending == 0;
- }
- };
- IRoxieServerQueryPacket *createRoxieServerQueryPacket(IRoxieQueryPacket *p, bool &cached)
- {
- if (serverSideCache && !debugContext)
- {
- IRoxieServerQueryPacket *ret = serverSideCache->findCachedResult(activity.queryLogCtx(), p);
- if (ret)
- {
- p->Release();
- cached = true;
- return ret;
- }
- }
- cached = false;
- return new CRoxieServerQueryPacket(p);
- }
- #ifdef _DEBUG
- void dumpPending()
- {
- CriticalBlock b(pendingCrit);
- ForEachItemIn(idx, pending)
- {
- IRoxieServerQueryPacket &p = pending.item(idx);
- StringBuffer s;
- unsigned __int64 dummy;
- if (p.isEnd())
- s.append("END");
- else if (p.isLimit(dummy, dummy, dummy))
- s.append("LIMIT");
- else
- {
- IRoxieQueryPacket *i = p.queryPacket();
- s.appendf("%s", p.hasResult() ? "COMPLETE " : "PENDING ");
- if (i)
- {
- RoxiePacketHeader &header = i->queryHeader();
- header.toString(s);
- }
- }
- DBGLOG("Pending %d %s", idx, s.str());
- }
- }
- #endif
- void abortPending()
- {
- CriticalBlock b(pendingCrit);
- ForEachItemIn(idx, pending)
- {
- IRoxieServerQueryPacket &p = pending.item(idx);
- if (!p.hasResult())
- {
- IRoxieQueryPacket *i = p.queryPacket();
- if (i)
- {
- RoxiePacketHeader &header = i->queryHeader();
- ROQ->sendAbort(header, activity.queryLogCtx());
- }
- }
- }
- pending.kill();
- }
- void checkDelayed()
- {
- if (ctx->queryDebugContext() && ctx->queryDebugContext()->getExecuteSequentially())
- {
- bool allDelayed = true;
- CriticalBlock b(pendingCrit);
- unsigned sendIdx = (unsigned) -1;
- ForEachItemIn(idx, pending)
- {
- IRoxieServerQueryPacket &p = pending.item(idx);
- if (p.queryPacket())
- {
- if (p.isDelayed())
- {
- if (sendIdx == (unsigned) -1)
- sendIdx = idx;
- }
- else if (!p.hasResult())
- {
- allDelayed = false;
- break;
- }
- }
- }
- if (allDelayed && sendIdx != (unsigned) -1)
- {
- if (activity.queryLogCtx().queryTraceLevel() > 10)
- activity.queryLogCtx().CTXLOG("About to send debug-deferred from next");
- pending.item(sendIdx).setDelayed(false);
- ROQ->sendPacket(pending.item(sendIdx).queryPacket(), activity.queryLogCtx());
- sentsome.signal();
- }
- }
- else if (deferredStart)
- {
- CriticalBlock b(pendingCrit);
- ForEachItemIn(idx, pending)
- {
- IRoxieServerQueryPacket &p = pending.item(idx);
- if (p.isDelayed())
- {
- if (activity.queryLogCtx().queryTraceLevel() > 10)
- activity.queryLogCtx().CTXLOG("About to send deferred start from next");
- p.setDelayed(false);
- ROQ->sendPacket(p.queryPacket(), activity.queryLogCtx());
- sentsome.signal();
- }
- }
- deferredStart = false;
- }
- }
- void retryPending()
- {
- CriticalBlock b(pendingCrit);
- checkDelayed();
- ForEachItemIn(idx, pending)
- {
- IRoxieServerQueryPacket &p = pending.item(idx);
- if (!p.hasResult() && !p.isDelayed())
- {
- IRoxieQueryPacket *i = p.queryPacket();
- if (i)
- {
- if (!i->queryHeader().retry())
- {
- StringBuffer s;
- IException *E = MakeStringException(ROXIE_MULTICAST_ERROR, "Failed to get response from slave(s) for %s in activity %d", i->queryHeader().toString(s).str(), queryId());
- activity.queryLogCtx().logOperatorException(E, __FILE__, __LINE__, "CRemoteResultAdaptor::retry");
- throw E;
- }
- if (!localSlave)
- {
- ROQ->sendPacket(i, activity.queryLogCtx());
- atomic_inc(&retriesSent);
- }
- }
- }
- }
- }
- class ChannelBuffer
- {
- protected:
- unsigned bufferLeft;
- MemoryBuffer buffer;
- char *nextBuf;
- unsigned overflowSequence;
- unsigned channel; // == bonded channel
- bool needsFlush;
- InterruptableSemaphore flowController;
- const CRemoteResultAdaptor &owner;
- CriticalSection crit;
- public:
- ChannelBuffer(const CRemoteResultAdaptor &_owner, unsigned _channel) : owner(_owner), channel(_channel), flowController(perChannelFlowLimit)
- {
- overflowSequence = 0;
- needsFlush = false;
- bufferLeft = 0;
- nextBuf = NULL;
- }
- void init(unsigned minSize)
- {
- assertex(!buffer.length());
- if (minSize < MIN_PAYLOAD_SIZE)
- minSize = MIN_PAYLOAD_SIZE;
- unsigned headerSize = sizeof(RoxiePacketHeader)+owner.headerLength();
- unsigned bufferSize = headerSize+minSize;
- if (bufferSize < mtu_size)
- bufferSize = mtu_size;
- buffer.reserveTruncate(bufferSize);
- bufferLeft = bufferSize - headerSize;
- assertex(buffer.toByteArray());
- nextBuf = (char *) buffer.toByteArray() + headerSize;
- needsFlush = false;
- }
- inline IRoxieQueryPacket *flush()
- {
- CriticalBlock cb(crit);
- Owned<IRoxieQueryPacket> ret;
- if (needsFlush)
- {
- buffer.setLength(nextBuf - buffer.toByteArray());
- RoxiePacketHeader *h = (RoxiePacketHeader *) buffer.toByteArray();
- h->init(owner.remoteId, owner.ruid, channel, overflowSequence);
- //patch logPrefix, cachedContext and parent extract into the place reserved in the message buffer
- byte * tgt = (byte*)(h+1);
- owner.copyHeader(tgt, channel);
- ret.setown(createRoxiePacket(buffer));
- if (overflowSequence == OVERFLOWSEQUENCE_MAX)
- overflowSequence = 1; // don't wrap to 0 - that is a bit special
- else
- overflowSequence++;
- needsFlush = false;
- bufferLeft = 0;
- if (owner.flowControlled)
- {
- CriticalUnblock cub(crit);
- while (!flowController.wait(1000))
- {
- StringBuffer s;
- owner.activity.queryLogCtx().CTXLOG("Channel %d blocked by flow control: %s", channel, h->toString(s).str());
- }
- }
- }
- return ret.getClear();
- }
- inline void signal()
- {
- if (owner.flowControlled)
- flowController.signal();
- }
- inline void interrupt(IException *e)
- {
- flowController.interrupt(e);
- }
- inline void *getBuffer(unsigned size)
- {
- CriticalBlock cb(crit);
- if (bufferLeft >= size)
- {
- needsFlush = true;
- void * ret = nextBuf;
- nextBuf += size;
- bufferLeft -= size;
- return ret;
- }
- else if (!needsFlush)
- {
- init(size);
- return getBuffer(size);
- }
- else if (owner.mergeOrder)
- {
- return buffer.reserve(size); // whole query needs to go as single packet if we are to merge
- }
- else
- return NULL; // will force it to flush and start a new packet
- }
- };
- private:
- friend class CRemoteResultMerger;
- bool allread;
- bool contextCached;
- bool preserveOrder;
- InterruptableSemaphore sentsome;
- Owned <IMessageCollator> mc;
- Owned<IMessageUnpackCursor> mu;
- Owned<IMessageResult> mr;
- ChannelBuffer **buffers;
- IHThorArg &helper;
- unsigned __int64 stopAfter;
- unsigned resendSequence;
- IHThorArg *colocalArg;
- IArrayOf<IRoxieServerQueryPacket> pending;
- CriticalSection pendingCrit;
- IRoxieServerSideCache *serverSideCache;
- unsigned sentSequence;
- Owned<IOutputRowDeserializer> deserializer;
- Owned<IEngineRowAllocator> rowAllocator;
- CRemoteResultMerger merger;
- // this is only used to avoid recreating a bufferStream for each row. A better solution may be needed
- MemoryBuffer tempRowBuffer;
- Owned<ISerialStream> bufferStream;
- CThorStreamDeserializerSource rowSource;
- protected:
- IRowManager *rowManager;
- IRoxieInput *owner;
- unsigned __int64 rowLimit;
- unsigned __int64 keyedLimit;
- IRoxieServerErrorHandler *errorHandler;
- CachedOutputMetaData meta;
- public:
- ISteppingMeta *mergeOrder;
- IRoxieSlaveContext *ctx;
- IDebuggableContext *debugContext;
- IRoxieServerActivity &activity;
- unsigned parentExtractSize;
- const byte * parentExtract;
- bool flowControlled;
- bool deferredStart;
- MemoryBuffer logInfo;
- MemoryBuffer cachedContext;
- const RemoteActivityId &remoteId;
- ruid_t ruid;
- mutable CriticalSection buffersCrit;
- unsigned processed;
- unsigned __int64 totalCycles;
- bool timeActivities;
- //private: //vc6 doesn't like this being private yet accessed by nested class...
- const void *getRow(IMessageUnpackCursor *mu)
- {
- if (!mu->isSerialized() || (meta.isFixedSize() && !deserializer))
- return mu->getNext(meta.getFixedSize());
- else
- {
- RecordLengthType *rowlen = (RecordLengthType *) mu->getNext(sizeof(RecordLengthType));
- if (rowlen)
- {
- RecordLengthType len = *rowlen;
- ReleaseRoxieRow(rowlen);
- const void *slaveRec = mu->getNext(len);
- if (deserializer && mu->isSerialized())
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- tempRowBuffer.setBuffer(len, const_cast<void *>(slaveRec), false);
- size_t outsize = deserializer->deserialize(rowBuilder, rowSource);
- ReleaseRoxieRow(slaveRec);
- return rowBuilder.finalizeRowClear(outsize);
- }
- else
- return slaveRec;
- }
- else
- return NULL;
- }
- }
- private:
- ChannelBuffer *queryChannelBuffer(unsigned channel, bool force=false)
- {
- CriticalBlock cb(buffersCrit);
- ChannelBuffer *b = buffers[channel];
- if (!b && force)
- {
- if (!contextCached)
- {
- logInfo.clear();
- unsigned char loggingFlags = LOGGING_FLAGSPRESENT | LOGGING_TRACELEVELSET;
- unsigned char ctxTraceLevel = activity.queryLogCtx().queryTraceLevel() + 1; // Avoid passing a 0
- if (activity.queryLogCtx().isIntercepted())
- loggingFlags |= LOGGING_INTERCEPTED;
- if (ctx->queryTraceActivityTimes())
- loggingFlags |= LOGGING_TIMEACTIVITIES;
- if (activity.queryLogCtx().isBlind())
- loggingFlags |= LOGGING_BLIND;
- if (ctx->queryCheckingHeap())
- loggingFlags |= LOGGING_CHECKINGHEAP;
- if (ctx->queryWorkUnit())
- loggingFlags |= LOGGING_WUID;
- if (debugContext)
- {
- loggingFlags |= LOGGING_DEBUGGERACTIVE;
- logInfo.append(loggingFlags).append(ctxTraceLevel);
- MemoryBuffer bpInfo;
- debugContext->serialize(bpInfo);
- bpInfo.append((__uint64)(memsize_t) &activity);
- logInfo.append((unsigned short) bpInfo.length());
- logInfo.append(bpInfo.length(), bpInfo.toByteArray());
- }
- else
- logInfo.append(loggingFlags).append(ctxTraceLevel);
- StringBuffer logPrefix;
- activity.queryLogCtx().getLogPrefix(logPrefix);
- logInfo.append(logPrefix);
- activity.serializeCreateStartContext(cachedContext.clear());
- activity.serializeExtra(cachedContext);
- if (activity.queryVarFileInfo())
- {
- activity.queryVarFileInfo()->queryTimeStamp().serialize(cachedContext);
- cachedContext.append(activity.queryVarFileInfo()->queryCheckSum());
- }
- contextCached = true;
- }
- b = buffers[channel] = new ChannelBuffer(*this, channel);
- }
- return b;
- }
- void processRow(const void *got)
- {
- processed++;
- if (processed > rowLimit)
- {
- ReleaseRoxieRow(got);
- errorHandler->onLimitExceeded(false); // NOTE - should throw exception
- throwUnexpected();
- }
- else if (processed > keyedLimit)
- {
- ReleaseRoxieRow(got);
- errorHandler->onLimitExceeded(true); // NOTE - should throw exception
- throwUnexpected();
- }
- }
- public:
- IMPLEMENT_IINTERFACE;
- CRemoteResultAdaptor(const RemoteActivityId &_remoteId, IOutputMetaData *_meta, IHThorArg &_helper, IRoxieServerActivity &_activity, bool _preserveOrder, bool _flowControlled)
- : remoteId(_remoteId), meta(_meta), activity(_activity), helper(_helper), preserveOrder(_preserveOrder), flowControlled(_flowControlled), merger(*this)
- {
- rowLimit = (unsigned __int64) -1;
- keyedLimit = (unsigned __int64) -1;
- contextCached = false;
- stopAfter = I64C(0x7FFFFFFFFFFFFFFF);
- buffers = new ChannelBuffer*[numChannels+1];
- memset(buffers, 0, (numChannels+1)*sizeof(ChannelBuffer *));
- parentExtractSize = 0;
- parentExtract = NULL;
- owner = NULL;
- mergeOrder = NULL;
- deferredStart = false;
- processed = 0;
- totalCycles = 0;
- sentSequence = 0;
- resendSequence = 0;
- serverSideCache = activity.queryServerSideCache();
- bufferStream.setown(createMemoryBufferSerialStream(tempRowBuffer));
- rowSource.setStream(bufferStream);
- timeActivities = defaultTimeActivities;
- }
- ~CRemoteResultAdaptor()
- {
- if (mc)
- {
- ROQ->queryReceiveManager()->detachCollator(mc);
- mc.clear();
- }
- for (unsigned channel = 0; channel <= numChannels; channel++)
- {
- delete(buffers[channel]);
- }
- delete [] buffers;
- }
- void setMeta(IOutputMetaData *newmeta)
- {
- meta.set(newmeta);
- }
- virtual IRoxieServerActivity *queryActivity()
- {
- return &activity;
- }
- virtual IIndexReadActivityInfo *queryIndexReadActivity()
- {
- return NULL;
- }
- void setMergeInfo(ISteppingMeta *_mergeOrder)
- {
- mergeOrder = _mergeOrder;
- deferredStart = true;
- }
- void send(IRoxieQueryPacket *p)
- {
- if (p)
- {
- Linked<IRoxieQueryPacket> saver(p); // avoids a race with abortPending, without keeping pendingCrit locked over the send which we might prefer not to
- assertex(p->queryHeader().uid==ruid);
- // MORE: Maybe we should base the fastlane flag on some other
- // criteria !! (i.e A Roxie server prediction based on the
- // activity type/activity behaviour/expected reply size .. etc).
- //
- // Currently (code below) based on high priority, seq=0, and none-child activity.
- // But this could still cause too many reply packets on the fatlane
- // (higher priority output Q), which may cause the activities on the
- // low priority output Q to not get service on time.
- if ((colocalArg == 0) && // not a child query activity??
- (p->queryHeader().activityId & (ROXIE_SLA_PRIORITY | ROXIE_HIGH_PRIORITY)) &&
- (p->queryHeader().overflowSequence == 0) &&
- (p->queryHeader().continueSequence & ~CONTINUE_SEQUENCE_SKIPTO)==0)
- p->queryHeader().retries |= ROXIE_FASTLANE;
- if (p->queryHeader().channel)
- {
- bool cached = false;
- IRoxieServerQueryPacket *rsqp = createRoxieServerQueryPacket(p, cached);
- if (deferredStart)
- rsqp->setDelayed(true);
- rsqp->setSequence(sentSequence++);
- {
- CriticalBlock b(pendingCrit);
- pending.append(*rsqp);
- }
- if (!deferredStart)
- {
- if (!cached)
- ROQ->sendPacket(p, activity.queryLogCtx());
- sentsome.signal();
- }
- }
- else
- {
- // 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
- // Need to add first, then send
- unsigned i;
- bool allCached = true;
- for (i = 1; i <= numChannels; i++)
- {
- IRoxieQueryPacket *q = p->clonePacket(i);
- bool thisChannelCached;
- IRoxieServerQueryPacket *rsqp = createRoxieServerQueryPacket(q, thisChannelCached);
- if (!thisChannelCached)
- allCached = false;
- rsqp->setSequence(sentSequence++);
- if (deferredStart)
- {
- rsqp->setDelayed(true);
- }
- {
- CriticalBlock b(pendingCrit);
- pending.append(*rsqp);
- }
- if (!deferredStart)
- sentsome.signal();
- }
- if (!allCached && !deferredStart)
- ROQ->sendPacket(p, activity.queryLogCtx());
- buffers[0]->signal(); // since replies won't come back on that channel...
- p->Release();
- }
- }
- }
- void *getMem(unsigned partNo, unsigned fileNo, unsigned size)
- {
- unsigned channel = partNo ? getBondedChannel(partNo) : 0;
- size += sizeof(PartNoType);
- ChannelBuffer *b = queryChannelBuffer(channel, true);
- char *buffer = (char *) b->getBuffer(size);
- if (!buffer)
- {
- send(b->flush());
- buffer = (char *) b->getBuffer(size);
- }
- PartNoType sp;
- sp.partNo = partNo;
- sp.fileNo = fileNo;
- memcpy(buffer, &sp, sizeof(sp));
- buffer += sizeof(sp);
- return buffer;
- }
- void injectResult(IMessageResult *result)
- {
- IRoxieServerQueryPacket *f = new CRoxieServerQueryPacket(NULL);
- f->setSequence(sentSequence++);
- f->setResult(result);
- CriticalBlock b(pendingCrit);
- pending.append(*f);
- sentsome.signal(); // MORE - arguably should only send if there is any point waking up the listener thread, to save context swicth
- }
- void flush()
- {
- for (unsigned channel = 0; channel <= numChannels; channel++)
- {
- ChannelBuffer *b = queryChannelBuffer(channel, false);
- if (b)
- send(b->flush());
- }
- }
- void interruptBuffers(IException *e)
- {
- for (unsigned channel = 0; channel <= numChannels; channel++)
- {
- ChannelBuffer *b = queryChannelBuffer(channel, false);
- if (b)
- b->interrupt(LINK(e));
- }
- }
- void senddone()
- {
- CriticalBlock b(pendingCrit);
- pending.append(*new CRoxieServerQueryPacketEndMarker);
- sentsome.signal();
- }
- bool fireException(IException *e)
- {
- {
- CriticalBlock b(pendingCrit);
- pending.append(*new CRoxieServerQueryPacketEndMarker);
- }
- interruptBuffers(e);
- if (mc)
- mc->interrupt(LINK(e));
- sentsome.interrupt(e);
- return true;
- }
- virtual void onCreate(IRoxieInput *_owner, IRoxieServerErrorHandler *_errorHandler, IRoxieSlaveContext *_ctx, IHThorArg *_colocalArg)
- {
- owner = _owner;
- errorHandler = _errorHandler;
- ctx = _ctx;
- debugContext = ctx->queryDebugContext();
- colocalArg = _colocalArg;
- if (meta.needsSerializeDisk())
- {
- deserializer.setown(meta.createDiskDeserializer(_ctx->queryCodeContext(), activity.queryId()));
- rowAllocator.setown(ctx->queryCodeContext()->getRowAllocator(meta.queryOriginal(), activity.queryId()));
- }
- if (ctx->queryDebugContext() && ctx->queryDebugContext()->getExecuteSequentially())
- deferredStart = true;
- if (ctx)
- timeActivities = ctx->queryTimeActivities();
- }
- virtual unsigned queryId() const
- {
- return owner->queryId();
- }
- virtual void onStart(unsigned _parentExtractSize, const byte * _parentExtract)
- {
- #ifdef TRACE_STARTSTOP
- if (traceStartStop)
- activity.queryLogCtx().CTXLOG("RRAonstart");
- #endif
- sentsome.reinit();
- ruid = getNextRuid();
- rowManager = &ctx->queryRowManager();
- if (mergeOrder)
- merger.init(mergeOrder, rowManager);
- if (mc)
- {
- ROQ->queryReceiveManager()->detachCollator(mc); // Should never happen - implies someone forgot to call onReset!
- }
- mc.setown(ROQ->queryReceiveManager()->createMessageCollator(rowManager, ruid));
- allread = false;
- mu.clear();
- contextCached = false;
- processed = 0;
- totalCycles = 0;
- resendSequence = 0;
- sentSequence = 0;
- for (unsigned channel = 0; channel <= numChannels; channel++)
- {
- delete(buffers[channel]);
- buffers[channel] = NULL;
- }
- flush();
- parentExtractSize = _parentExtractSize;
- parentExtract = _parentExtract;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- #ifdef TRACE_STARTSTOP
- if (traceStartStop)
- activity.queryLogCtx().CTXLOG("RRAstart");
- #endif
- owner->start(parentExtractSize, parentExtract, paused);
- totalCycles = 0;
- }
- void checkAbort()
- {
- owner->checkAbort();
- }
- void setLimits(unsigned __int64 _rowLimit, unsigned __int64 _keyedLimit, unsigned __int64 _stopAfter)
- {
- if (ctx->queryProbeManager())
- {
- if (_rowLimit != (unsigned __int64) -1) ctx->queryProbeManager()->setNodePropertyInt(&activity, "rowLimit", _rowLimit);
- if (_keyedLimit != (unsigned __int64) -1) ctx->queryProbeManager()->setNodePropertyInt(&activity, "keyedLimit", _keyedLimit);
- if (_stopAfter != I64C(0x7FFFFFFFFFFFFFFF)) ctx->queryProbeManager()->setNodePropertyInt(&activity, "choosenLimit", _stopAfter);
- }
- {
- CriticalBlock b(pendingCrit);
- if (pending.length())
- {
- #ifdef _DEBUG
- dumpPending(); // MORE - only defined in debug build - could have put the ifdef inside the dumpPending method
- #endif
- assertex(pending.length()==0);
- }
- pending.append(*new CRoxieServerQueryPacketLimitMarker(_rowLimit, _keyedLimit, _stopAfter));
- }
- sentsome.signal();
- rowLimit = _rowLimit;
- keyedLimit = _keyedLimit;
- stopAfter = _stopAfter;
- }
- virtual void stop(bool aborting)
- {
- #ifdef TRACE_STARTSTOP
- if (traceStartStop)
- activity.queryLogCtx().CTXLOG("RRAstop");
- #endif
- onStop(aborting);
- owner->stop(aborting);
- }
- void onStop(bool aborting)
- {
- #ifdef TRACE_STARTSTOP
- if (traceStartStop)
- activity.queryLogCtx().CTXLOG("RRAonstop");
- #endif
- abortPending();
- interruptBuffers(NULL);
- sentsome.interrupt();
- if (mc) // May not be set if start() chain threw exception
- mc->interrupt();
- }
- virtual void reset()
- {
- #ifdef TRACE_STARTSTOP
- if (traceStartStop)
- activity.queryLogCtx().CTXLOG("RRAreset");
- #endif
- owner->reset();
- onReset();
- }
- virtual void resetEOF()
- {
- throwUnexpected();
- }
- virtual void onReset()
- {
- #ifdef TRACE_STARTSTOP
- if (traceStartStop)
- activity.queryLogCtx().CTXLOG("RRAonreset");
- #endif
- if (mc)
- ROQ->queryReceiveManager()->detachCollator(mc);
- merger.reset();
- pending.kill();
- if (mc && ctx)
- ctx->addSlavesReplyLen(mc->queryBytesReceived());
- mc.clear(); // Or we won't free memory for graphs that get recreated
- mu.clear(); //ditto
- deferredStart = false;
- // NOTE: do NOT clear mergeOrder - this is set at create time not per child query
- }
- virtual IOutputMetaData * queryOutputMeta() const
- {
- return helper.queryOutputMeta();
- }
- virtual unsigned __int64 queryTotalCycles() const
- {
- return totalCycles;
- }
- virtual unsigned __int64 queryLocalCycles() const
- {
- return owner->queryLocalCycles();
- }
- virtual IRoxieInput *queryInput(unsigned idx) const
- {
- return owner->queryInput(idx);
- }
- const void * nextSteppedGE(const void *seek, const void *rawSeek, unsigned numFields, unsigned seekLen, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
- {
- if (activity.queryLogCtx().queryTraceLevel() > 20)
- {
- StringBuffer recstr;
- unsigned i;
- for (i = 0; i < seekLen; i++)
- {
- recstr.appendf("%02x ", ((unsigned char *) rawSeek)[i]);
- }
- activity.queryLogCtx().CTXLOG("CRemoteResultAdaptor::nextSteppedGE(rawSeek=%s numFields=%d, seeklen=%d, returnMismatches=%d)", recstr.str(), numFields, seekLen, stepExtra.returnMismatches());
- }
- assertex(mergeOrder);
- if (deferredStart)
- {
- CriticalBlock b(pendingCrit);
- ForEachItemIn(idx, pending)
- {
- IRoxieServerQueryPacket &p = pending.item(idx);
- if (p.isDelayed())
- {
- p.setDelayed(false);
- if (activity.queryLogCtx().queryTraceLevel() > 10)
- activity.queryLogCtx().CTXLOG("About to send deferred start from nextSteppedGE, setting requireExact to %d", !stepExtra.returnMismatches());
- MemoryBuffer serializedSkip;
- activity.serializeSkipInfo(serializedSkip, seekLen, rawSeek, numFields, seek, stepExtra);
- p.setPacket(p.queryPacket()->insertSkipData(serializedSkip.length(), serializedSkip.toByteArray()));
- ROQ->sendPacket(p.queryPacket(), activity.queryLogCtx());
- sentsome.signal();
- }
- }
- deferredStart = false;
- }
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (processed==stopAfter)
- return NULL;
- if (allread)
- return NULL;
- loop
- {
- if (merger.ready())
- {
- const void *got = merger.nextSteppedGE(seek, rawSeek, numFields, seekLen, wasCompleteMatch, stepExtra);
- if (got)
- {
- processRow(got);
- return got;
- }
- }
- if (!reload()) // MORE - should pass the seek info here...
- return NULL;
- }
- }
- virtual const void *nextInGroup()
- {
- // If we are merging then we need to do a heapsort on all
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (activity.queryLogCtx().queryTraceLevel() > 10)
- {
- activity.queryLogCtx().CTXLOG("CRemoteResultAdaptor::nextInGroup()");
- }
- loop
- {
- checkDelayed();
- if (processed==stopAfter)
- return NULL;
- if (allread)
- return NULL;
- // If we can still consume from the merger or the most recently retrieved mu, do so.
- const void *got = NULL;
- if (mergeOrder && merger.ready())
- {
- bool matched = true;
- got = merger.next(matched, dummySmartStepExtra);
- }
- else if (mu)
- got = getRow(mu);
- if (got)
- {
- processRow(got);
- return got;
- }
- if (!reload())
- return NULL;
- }
- }
- bool reload()
- {
- // Wait for something to be returned from a slave....
- mu.clear();
- sentsome.wait();
- // must be at least an endMarker on the queue since sentsome was signalled
- {
- CriticalBlock b(pendingCrit);
- IRoxieServerQueryPacket &top = pending.item(0);
- if (top.isLimit(rowLimit, keyedLimit, stopAfter)) // This is really a start marker...
- {
- pending.remove(0);
- return true;
- }
- else if (top.isEnd())
- {
- pending.remove(0);
- allread = true;
- if (activity.queryLogCtx().queryTraceLevel() > 5)
- activity.queryLogCtx().CTXLOG("All read on ruid %x", ruid);
- return false;
- }
- else if (mergeOrder)
- {
- unsigned idx = 0;
- bool added = false;
- while (pending.isItem(idx))
- {
- IRoxieServerQueryPacket &item = pending.item(idx);
- if (item.isEnd())
- {
- if (merger.noteEndSeen())
- {
- sentsome.signal(); // Because we waited, yet didn't actually consume anything
- added = true;
- }
- break;
- }
- else if (item.hasResult())
- {
- merger.noteResult(&item, item.getSequence());
- pending.remove(idx);
- added = true;
- }
- else if (item.isContinuation())
- idx++;
- else
- break;
- }
- if (added)
- return true;
- }
- else if (top.hasResult())
- {
- mr.setown(pending.item(0).getResult());
- mu.setown(mr->getCursor(rowManager));
- pending.remove(0);
- return true;
- }
- }
- getNextUnpacker();
- return true;
- }
- void getNextUnpacker()
- {
- mu.clear();
- unsigned ctxTraceLevel = activity.queryLogCtx().queryTraceLevel();
- loop
- {
- checkDelayed();
- unsigned timeout = remoteId.isSLAPriority() ? slaTimeout : (remoteId.isHighPriority() ? highTimeout : lowTimeout);
- owner->checkAbort();
- bool anyActivity;
- if (ctxTraceLevel > 5)
- activity.queryLogCtx().CTXLOG("Calling getNextUnpacker(%d)", timeout);
- mr.setown(mc->getNextResult(timeout, anyActivity));
- if (ctxTraceLevel > 6)
- activity.queryLogCtx().CTXLOG("Called getNextUnpacker(%d), activity=%d", timeout, anyActivity);
- owner->checkAbort();
- if (mr)
- {
- unsigned roxieHeaderLen;
- const RoxiePacketHeader &header = *(const RoxiePacketHeader *) mr->getMessageHeader(roxieHeaderLen);
- #ifdef _DEBUG
- assertex(roxieHeaderLen == sizeof(RoxiePacketHeader));
- #endif
- if (ctxTraceLevel > 5)
- {
- StringBuffer s;
- activity.queryLogCtx().CTXLOG("getNextUnpacker got packet %s", header.toString(s).str());
- }
- CriticalBlock b(pendingCrit);
- unsigned idx = 0;
- IRoxieServerQueryPacket *original = NULL;
- IRoxieQueryPacket *op;
- while (pending.isItem(idx))
- {
- original = &pending.item(idx);
- op = original->queryPacket();
- if (op && header.matchPacket(op->queryHeader()))
- break;
- original = NULL;
- idx++;
- }
- if (!original || original->hasResult())
- {
- switch (header.activityId)
- {
- case ROXIE_FILECALLBACK:
- {
- // tell slave to abort
- //if (ctxTraceLevel > 5)
- {
- StringBuffer s;
- activity.queryLogCtx().CTXLOG("Redundant callback on query %s", header.toString(s).str());
- }
- Owned<IMessageUnpackCursor> callbackData = mr->getCursor(rowManager);
- OwnedConstRoxieRow len = callbackData->getNext(sizeof(RecordLengthType));
- if (len)
- {
- RecordLengthType *rowlen = (RecordLengthType *) len.get();
- OwnedConstRoxieRow row = callbackData->getNext(*rowlen);
- const char *rowdata = (const char *) row.get();
- // bool isOpt = * (bool *) rowdata;
- // bool isLocal = * (bool *) (rowdata+1);
- ROQ->sendAbortCallback(header, rowdata+2, activity.queryLogCtx());
- }
- else
- throwUnexpected();
- break;
- }
- // MORE - ROXIE_ALIVE perhaps should go here too
- case ROXIE_TRACEINFO:
- {
- Owned<IMessageUnpackCursor> extra = mr->getCursor(rowManager);
- loop
- {
- RecordLengthType *rowlen = (RecordLengthType *) extra->getNext(sizeof(RecordLengthType));
- if (rowlen)
- {
- char *logInfo = (char *) extra->getNext(*rowlen);
- MemoryBuffer buf;
- buf.setBuffer(*rowlen, logInfo, false);
- activity.queryLogCtx().CTXLOGl(new LogItem(buf));
- ReleaseRoxieRow(rowlen);
- ReleaseRoxieRow(logInfo);
- }
- else
- break;
- }
- break;
- }
- default:
- if (ctxTraceLevel > 3)
- activity.queryLogCtx().CTXLOG("Discarding packet %p - original %p is NULL or has result already", mr.get(), original);
- mr->discard();
- break;
- }
- mr.clear();
- }
- else
- {
- atomic_inc(&resultsReceived);
- switch (header.activityId)
- {
- case ROXIE_DEBUGCALLBACK:
- {
- Owned<IMessageUnpackCursor> callbackData = mr->getCursor(rowManager);
- OwnedConstRoxieRow len = callbackData->getNext(sizeof(RecordLengthType));
- if (len)
- {
- RecordLengthType *rowlen = (RecordLengthType *) len.get();
- OwnedConstRoxieRow row = callbackData->getNext(*rowlen);
- char *rowdata = (char *) row.get();
- if (ctxTraceLevel > 5)
- {
- StringBuffer s;
- activity.queryLogCtx().CTXLOG("Callback on query %s for debug", header.toString(s).str());
- }
- MemoryBuffer slaveInfo;
- slaveInfo.setBuffer(*rowlen, rowdata, false);
- unsigned debugSequence;
- slaveInfo.read(debugSequence);
- Owned<IRoxieQueryPacket> reply = original->getDebugResponse(debugSequence);
- if (!reply)
- reply.setown(activity.queryContext()->queryDebugContext()->onDebugCallback(header, *rowlen, rowdata));
- if (reply)
- {
- original->setDebugResponse(debugSequence, reply);
- ROQ->sendPacket(reply, activity.queryLogCtx());
- }
- }
- else
- throwUnexpected();
- // MORE - somehow we need to make sure slave gets a reply even if I'm not waiting (in udp layer)
- // Leave original message on pending queue in original location - this is not a reply to it.
- break;
- }
- case ROXIE_FILECALLBACK:
- {
- // we need to send back to the slave a message containing the file info requested.
- Owned<IMessageUnpackCursor> callbackData = mr->getCursor(rowManager);
- OwnedConstRoxieRow len = callbackData->getNext(sizeof(RecordLengthType));
- if (len)
- {
- RecordLengthType *rowlen = (RecordLengthType *) len.get();
- OwnedConstRoxieRow row = callbackData->getNext(*rowlen);
- const char *rowdata = (const char *) row.get();
- bool isOpt = * (bool *) rowdata;
- bool isLocal = * (bool *) (rowdata+1);
- const char *lfn = rowdata+2;
- if (ctxTraceLevel > 5)
- {
- StringBuffer s;
- activity.queryLogCtx().CTXLOG("Callback on query %s file %s", header.toString(s).str(),(const char *) lfn);
- }
- activity.queryContext()->onFileCallback(header, lfn, isOpt, isLocal);
- }
- else
- throwUnexpected();
- // MORE - somehow we need to make sure slave gets a reply even if I'm not waiting (in udp layer)
- // Leave original message on pending queue in original location - this is not a reply to it.
- break;
- }
- case ROXIE_KEYEDLIMIT_EXCEEDED:
- activity.queryLogCtx().CTXLOG("ROXIE_KEYEDLIMIT_EXCEEDED");
- errorHandler->onLimitExceeded(true); // NOTE - should throw exception!
- throwUnexpected();
- case ROXIE_LIMIT_EXCEEDED:
- activity.queryLogCtx().CTXLOG("ROXIE_LIMIT_EXCEEDED");
- errorHandler->onLimitExceeded(false); // NOTE - should throw exception!
- throwUnexpected();
- case ROXIE_TRACEINFO:
- {
- Owned<IMessageUnpackCursor> extra = mr->getCursor(rowManager);
- loop
- {
- RecordLengthType *rowlen = (RecordLengthType *) extra->getNext(sizeof(RecordLengthType));
- if (rowlen)
- {
- char *logInfo = (char *) extra->getNext(*rowlen);
- MemoryBuffer buf;
- buf.setBuffer(*rowlen, logInfo, false);
- activity.queryLogCtx().CTXLOGl(new LogItem(buf));
- ReleaseRoxieRow(rowlen);
- ReleaseRoxieRow(logInfo);
- }
- else
- break;
- }
- break;
- }
- case ROXIE_EXCEPTION:
- if (ctxTraceLevel > 1)
- {
- StringBuffer s;
- activity.queryLogCtx().CTXLOG("Exception on query %s", header.toString(s).str());
- }
- op->queryHeader().noteException(header.retries);
- if (op->queryHeader().allChannelsFailed())
- {
- activity.queryLogCtx().CTXLOG("Multiple exceptions on query - aborting");
- Owned<IMessageUnpackCursor> exceptionData = mr->getCursor(rowManager);
- throwRemoteException(exceptionData);
- }
- // Leave it on pending queue in original location
- break;
- case ROXIE_ALIVE:
- if (ctxTraceLevel > 4)
- {
- StringBuffer s;
- activity.queryLogCtx().CTXLOG("ROXIE_ALIVE: %s", header.toString(s).str());
- }
- op->queryHeader().noteAlive(header.retries & ROXIE_RETRIES_MASK);
- // Leave it on pending queue in original location
- break;
- default:
- if (header.retries & ROXIE_RETRIES_MASK)
- atomic_inc(&retriesNeeded);
- unsigned metaLen;
- const void *metaData = mr->getMessageMetadata(metaLen);
- if (metaLen)
- {
- // We got back first chunk but there is more.
- // resend the packet, with the cursor info provided.
- // MORE - if smart-stepping, we don't want to send the continuation immediately. Other cases it's not clear that we do.
- if (ctxTraceLevel > 1)
- {
- StringBuffer s;
- activity.queryLogCtx().CTXLOG("Additional data size %d on query %s mergeOrder %p", metaLen, header.toString(s).str(), mergeOrder);
- }
- if (*((unsigned short *) metaData) + sizeof(unsigned short) != metaLen)
- {
- StringBuffer s;
- activity.queryLogCtx().CTXLOG("Additional data size %d on query %s mergeOrder %p", metaLen, header.toString(s).str(), mergeOrder);
- activity.queryLogCtx().CTXLOG("Additional data is corrupt");
- throwUnexpected();
- }
- MemoryBuffer nextQuery;
- nextQuery.append(sizeof(RoxiePacketHeader), &header);
- nextQuery.append(metaLen, metaData);
- nextQuery.append(op->getTraceLength(), op->queryTraceInfo());
- nextQuery.append(op->getContextLength(), op->queryContextData());
- if (resendSequence == CONTINUESEQUENCE_MAX)
- {
- activity.queryLogCtx().CTXLOG("ERROR: Continuation sequence wrapped"); // shouldn't actually matter.... but suggests a very iffy query!
- resendSequence = 1;
- }
- else
- resendSequence++;
- RoxiePacketHeader *newHeader = (RoxiePacketHeader *) nextQuery.toByteArray();
- newHeader->continueSequence = resendSequence; // NOTE - we clear the skipTo flag since continuation of a skip is NOT a skip...
- newHeader->retries &= ~ROXIE_RETRIES_MASK;
- IRoxieQueryPacket *resend = createRoxiePacket(nextQuery);
- CRoxieServerQueryPacket *fqp = new CRoxieServerQueryPacket(resend);
- fqp->setSequence(original->getSequence());
- pending.add(*fqp, idx+1); // note that pending takes ownership. sendPacket does not release.
- original->setContinuation(LINK(fqp));
- if (mergeOrder)
- fqp->setDelayed(true);
- else
- {
- ROQ->sendPacket(resend, activity.queryLogCtx());
- sentsome.signal();
- }
- // Note that we don't attempt to cache results that have continuation records - too tricky !
- }
- else
- {
- if (serverSideCache)
- serverSideCache->noteCachedResult(original, mr);
- }
- unsigned channel = header.channel;
- {
- ChannelBuffer *b = queryChannelBuffer(channel); // If not something is wrong, or we sent out on channel 0?
- if (b)
- b->signal();
- }
- original->setResult(mr.getClear());
- sentsome.signal();
- return;
- }
- }
- }
- else
- {
- if (!anyActivity)
- {
- activity.queryLogCtx().CTXLOG("Input has stalled - retry required?");
- retryPending();
- }
- }
- }
- }
- inline unsigned headerLength() const
- {
- return logInfo.length() + cachedContext.length() + sizeof(unsigned) + parentExtractSize;
- }
- void copyHeader(byte *tgt, unsigned channel) const
- {
- unsigned len = logInfo.length();
- memcpy(tgt, logInfo.toByteArray(), len);
- tgt += len;
- *(unsigned *) tgt = parentExtractSize;
- tgt += sizeof(unsigned);
- memcpy(tgt, parentExtract, parentExtractSize);
- tgt += parentExtractSize;
- memcpy(tgt, cachedContext.toByteArray(), cachedContext.length());
- tgt += cachedContext.length();
- }
- };
- class CSkippableRemoteResultAdaptor : public CRemoteResultAdaptor
- {
- Owned <IException> exception;
- bool skipping;
- ConstPointerArray buff;
- unsigned index;
- bool pulled;
- void pullInput()
- {
- try
- {
- if (exception)
- throw exception.getClear();
- unsigned __int64 count = 0;
- loop
- {
- const void * next = CRemoteResultAdaptor::nextInGroup();
- if (next == NULL)
- {
- next = CRemoteResultAdaptor::nextInGroup();
- if(next == NULL)
- break;
- buff.append(NULL);
- }
- count++;
- if (count > rowLimit)
- {
- ReleaseRoxieRow(next);
- ReleaseRoxieRowSet(buff);
- errorHandler->onLimitExceeded(false); // throws an exception - user or LimitSkipException
- throwUnexpected();
- }
- else if (count > keyedLimit)
- {
- ReleaseRoxieRow(next);
- ReleaseRoxieRowSet(buff);
- errorHandler->onLimitExceeded(true); // throws an exception - user or LimitSkipException
- throwUnexpected();
- }
- buff.append(next);
- }
- }
- catch (IException *E)
- {
- if (QUERYINTERFACE(E, LimitSkipException))
- {
- Owned<IException> cleanup = E;
- ReleaseRoxieRowSet(buff);
- const void *onfail = errorHandler->createLimitFailRow(E->errorCode() == KeyedLimitSkipErrorCode);
- if (onfail)
- buff.append(onfail);
- }
- else
- throw;
- }
- pulled = true;
- }
- public:
- CSkippableRemoteResultAdaptor(const RemoteActivityId &_remoteId, IOutputMetaData *_meta, IHThorArg &_helper, IRoxieServerActivity &_activity, bool _preserveOrder, bool _flowControlled, bool _skipping) :
- CRemoteResultAdaptor(_remoteId, _meta, _helper, _activity, _preserveOrder, _flowControlled)
- {
- skipping = _skipping;
- index = 0;
- pulled = false;
- }
- void setException(IException *E)
- {
- exception.setown(E);
- }
- virtual void onReset()
- {
- while (buff.isItem(index))
- ReleaseRoxieRow(buff.item(index++));
- buff.kill();
- pulled = false;
- exception.clear();
- CRemoteResultAdaptor::onReset();
- }
- void onStart(unsigned _parentExtractSize, const byte * _parentExtract)
- {
- index = 0;
- pulled = false;
- CRemoteResultAdaptor::onStart(_parentExtractSize, _parentExtract);
- }
- virtual const void * nextSteppedGE(const void *seek, const void *rawSeek, unsigned numFields, unsigned seeklen, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
- {
- // 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
- if (exception)
- throw exception.getClear();
- return CRemoteResultAdaptor::nextSteppedGE(seek, rawSeek, numFields, seeklen, wasCompleteMatch, stepExtra);
- }
- virtual const void *nextInGroup()
- {
- if (skipping)
- {
- if(!pulled)
- pullInput();
- if(buff.isItem(index))
- {
- const void * next = buff.item(index++);
- if(next)
- processed++;
- return next;
- }
- return NULL;
- }
- else
- {
- if (exception)
- throw exception.getClear();
- return CRemoteResultAdaptor::nextInGroup();
- }
- }
- };
- //=================================================================================
- class CRoxieServerApplyActivity : public CRoxieServerInternalSinkActivity
- {
- IHThorApplyArg &helper;
- public:
- CRoxieServerApplyActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerInternalSinkActivity(_factory, _probeManager, 0), helper((IHThorApplyArg &) basehelper)
- {
- }
- virtual void onExecute()
- {
- helper.start();
- loop
- {
- const void * next = input->nextInGroup();
- if (!next)
- {
- next = input->nextInGroup();
- if (!next)
- break;
- }
- helper.apply(next);
- ReleaseRoxieRow(next);
- }
- helper.end();
- }
- };
- class CRoxieServerApplyActivityFactory : public CRoxieServerActivityFactory
- {
- bool isRoot;
- public:
- CRoxieServerApplyActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerApplyActivity(this, _probeManager);
- }
- virtual bool isSink() const
- {
- return isRoot;
- }
- };
- IRoxieServerActivityFactory *createRoxieServerApplyActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
- {
- return new CRoxieServerApplyActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
- }
- //=================================================================================
- class CRoxieServerNullActivity : public CRoxieServerActivity
- {
- public:
- CRoxieServerNullActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager)
- {
- }
- virtual const void *nextInGroup()
- {
- return NULL;
- }
- };
- IRoxieServerActivity * createRoxieServerNullActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- {
- return new CRoxieServerNullActivity(_factory, _probeManager);
- }
- class CRoxieServerNullActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerNullActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerNullActivity(this, _probeManager);
- }
- virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
- {
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for null activity");
- }
- };
- IRoxieServerActivityFactory *createRoxieServerNullActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerNullActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerPassThroughActivity : public CRoxieServerActivity
- {
- public:
- CRoxieServerPassThroughActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager)
- {
- }
- virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
- {
- return input->gatherConjunctions(collector);
- }
- virtual void resetEOF()
- {
- input->resetEOF();
- }
- virtual const void *nextInGroup()
- {
- const void * next = input->nextInGroup();
- if (next)
- processed++;
- return next;
- }
- virtual bool isPassThrough()
- {
- return true;
- }
- virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- const void * next = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
- if (next)
- processed++;
- return next;
- }
- IInputSteppingMeta * querySteppingMeta()
- {
- return input->querySteppingMeta();
- }
- };
- IRoxieServerActivity * createRoxieServerPassThroughActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- {
- return new CRoxieServerPassThroughActivity(_factory, _probeManager);
- }
- //=================================================================================
- class CRoxieServerChildBaseActivity : public CRoxieServerActivity
- {
- protected:
- bool eof;
- bool first;
- public:
- CRoxieServerChildBaseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager)
- {
- eof = false;
- first = true;
- }
- ~CRoxieServerChildBaseActivity()
- {
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- eof = false;
- first = true;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- }
- };
- class CRoxieServerChildBaseActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerChildBaseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
- {
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for %s activity", getActivityText(kind));
- }
- };
- //=================================================================================
- class CRoxieServerChildIteratorActivity : public CRoxieServerChildBaseActivity
- {
- IHThorChildIteratorArg &helper;
- public:
- CRoxieServerChildIteratorActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerChildBaseActivity(_factory, _probeManager), helper((IHThorChildIteratorArg &) basehelper)
- {
- }
- virtual bool needsAllocator() const { return true; }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (eof)
- return NULL;
- bool ok;
- if (first)
- {
- ok = helper.first();
- first = false;
- }
- else
- ok = helper.next();
- try
- {
- while (ok)
- {
- processed++;
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- unsigned outSize = helper.transform(rowBuilder);
- if (outSize)
- return rowBuilder.finalizeRowClear(outSize);
- ok = helper.next();
- }
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- eof = true;
- return NULL;
- }
- };
- class CRoxieServerChildIteratorActivityFactory : public CRoxieServerChildBaseActivityFactory
- {
- public:
- CRoxieServerChildIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerChildBaseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerChildIteratorActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerChildIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerChildIteratorActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerChildNormalizeActivity : public CRoxieServerChildBaseActivity
- {
- IHThorChildNormalizeArg &helper;
- public:
- CRoxieServerChildNormalizeActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerChildBaseActivity(_factory, _probeManager), helper((IHThorChildNormalizeArg &) basehelper)
- {
- }
- virtual bool needsAllocator() const { return true; }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (eof)
- return NULL;
- bool ok;
- if (first)
- {
- ok = helper.first();
- first = false;
- }
- else
- ok = helper.next();
- if (ok)
- {
- try
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- do {
- unsigned outSize = helper.transform(rowBuilder);
- if (outSize)
- {
- processed++;
- return rowBuilder.finalizeRowClear(outSize);
- }
- ok = helper.next();
- }
- while (ok);
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- eof = true;
- return NULL;
- }
- };
- class CRoxieServerChildNormalizeActivityFactory : public CRoxieServerChildBaseActivityFactory
- {
- public:
- CRoxieServerChildNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerChildBaseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerChildNormalizeActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerNewChildNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerChildNormalizeActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerChildAggregateActivity : public CRoxieServerChildBaseActivity
- {
- IHThorChildAggregateArg &helper;
- public:
- CRoxieServerChildAggregateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerChildBaseActivity(_factory, _probeManager), helper((IHThorChildAggregateArg &) basehelper)
- {
- }
- virtual bool needsAllocator() const { return true; }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (eof)
- return NULL;
- eof = true;
- processed++;
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- helper.clearAggregate(rowBuilder);
- helper.processRows(rowBuilder);
- size32_t finalSize = meta.getRecordSize(rowBuilder.getSelf());
- return rowBuilder.finalizeRowClear(finalSize);
- }
- };
- class CRoxieServerChildAggregateActivityFactory : public CRoxieServerChildBaseActivityFactory
- {
- public:
- CRoxieServerChildAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerChildBaseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerChildAggregateActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerNewChildAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerChildAggregateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerChildGroupAggregateActivity : public CRoxieServerChildBaseActivity, public IHThorGroupAggregateCallback
- {
- IHThorChildGroupAggregateArg &helper;
- RowAggregator aggregated;
- public:
- IMPLEMENT_IINTERFACE
- CRoxieServerChildGroupAggregateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerChildBaseActivity(_factory, _probeManager), helper((IHThorChildGroupAggregateArg &) basehelper),
- aggregated(helper, helper)
- {
- }
- void processRow(const void * next)
- {
- aggregated.addRow(next);
- }
-
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerChildBaseActivity::start(parentExtractSize, parentExtract, paused);
- aggregated.start(rowAllocator);
- }
- virtual void reset()
- {
- aggregated.reset();
- CRoxieServerChildBaseActivity::reset();
- }
- virtual bool needsAllocator() const { return true; }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (eof)
- return NULL;
- if (first)
- {
- helper.processRows(this);
- first = false;
- }
- Owned<AggregateRowBuilder> next = aggregated.nextResult();
- if (next)
- {
- processed++;
- return next->finalizeRowClear();
- }
- eof = true;
- return NULL;
- }
- };
- class CRoxieServerChildGroupAggregateActivityFactory : public CRoxieServerChildBaseActivityFactory
- {
- public:
- CRoxieServerChildGroupAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerChildBaseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerChildGroupAggregateActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerNewChildGroupAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerChildGroupAggregateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerChildThroughNormalizeActivity : public CRoxieServerChildBaseActivity
- {
- IHThorChildThroughNormalizeArg &helper;
- const void * lastInput;
- unsigned numProcessedLastGroup;
- bool ok;
- public:
- CRoxieServerChildThroughNormalizeActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerChildBaseActivity(_factory, _probeManager), helper((IHThorChildThroughNormalizeArg &) basehelper)
- {
- lastInput = NULL;
- numProcessedLastGroup = 0;
- ok = false;
- }
- virtual void stop(bool aborting)
- {
- CRoxieServerChildBaseActivity::stop(aborting);
- ReleaseRoxieRow(lastInput);
- lastInput = NULL;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerChildBaseActivity::start(parentExtractSize, parentExtract, paused);
- numProcessedLastGroup = processed;
- ok = false;
- }
- virtual bool needsAllocator() const { return true; }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- loop
- {
- if (ok)
- ok = helper.next();
- while (!ok)
- {
- ReleaseRoxieRow(lastInput);
- lastInput = input->nextInGroup();
- if (!lastInput)
- {
- if (numProcessedLastGroup != processed)
- {
- numProcessedLastGroup = processed;
- return NULL;
- }
- lastInput = input->nextInGroup();
- if (!lastInput)
- return NULL;
- }
- ok = helper.first(lastInput);
- }
- try
- {
- do
- {
- unsigned outSize = helper.transform(rowBuilder);
- if (outSize)
- {
- processed++;
- return rowBuilder.finalizeRowClear(outSize);
- }
- ok = helper.next();
- } while (ok);
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- }
- };
- class CRoxieServerChildThroughNormalizeActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerChildThroughNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerChildThroughNormalizeActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerNewChildThroughNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerChildThroughNormalizeActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerDistributionActivity : public CRoxieServerInternalSinkActivity
- {
- IHThorDistributionArg &helper;
- public:
- CRoxieServerDistributionActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerInternalSinkActivity(_factory, _probeManager, 0), helper((IHThorDistributionArg &)basehelper)
- {
- }
- virtual void onExecute()
- {
- MemoryAttr ma;
- IDistributionTable * * accumulator = (IDistributionTable * *)ma.allocate(helper.queryInternalRecordSize()->getMinRecordSize());
- helper.clearAggregate(accumulator);
- OwnedConstRoxieRow nextrec(input->nextInGroup());
- loop
- {
- if (!nextrec)
- {
- nextrec.setown(input->nextInGroup());
- if (!nextrec)
- break;
- }
- helper.process(accumulator, nextrec);
- nextrec.setown(input->nextInGroup());
- }
- StringBuffer result;
- result.append("<XML>");
- helper.gatherResult(accumulator, result);
- result.append("</XML>");
- helper.sendResult(result.length(), result.str());
- helper.destruct(accumulator);
- }
- };
- class CRoxieServerDistributionActivityFactory : public CRoxieServerActivityFactory
- {
- bool isRoot;
- public:
- CRoxieServerDistributionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerDistributionActivity(this, _probeManager);
- }
- virtual bool isSink() const
- {
- return isRoot;
- }
- };
- IRoxieServerActivityFactory *createRoxieServerDistributionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
- {
- return new CRoxieServerDistributionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
- }
- //=================================================================================
- class CRoxieServerLinkedRawIteratorActivity : public CRoxieServerActivity
- {
- IHThorLinkedRawIteratorArg &helper;
- public:
- CRoxieServerLinkedRawIteratorActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorLinkedRawIteratorArg &) basehelper)
- {
- }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- const void *ret =helper.next();
- if (ret)
- {
- LinkRoxieRow(ret);
- processed++;
- }
- return ret;
- }
- };
- class CRoxieServerLinkedRawIteratorActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerLinkedRawIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerLinkedRawIteratorActivity(this, _probeManager);
- }
- virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
- {
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for %s activity", getActivityText(kind));
- }
- };
- IRoxieServerActivityFactory *createRoxieServerLinkedRawIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerLinkedRawIteratorActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerDatasetResultActivity : public CRoxieServerActivity
- {
- public:
- CRoxieServerDatasetResultActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager)
- {
- }
- virtual const void *nextInGroup()
- {
- throwUnexpected();
- }
- virtual void executeChild(size32_t & retSize, void * & ret, unsigned parentExtractSize, const byte * parentExtract)
- {
- try
- {
- start(parentExtractSize, parentExtract, false);
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- MemoryBuffer result;
- IRecordSize * inputMeta = input->queryOutputMeta();
- loop
- {
- const void *nextrec = input->nextInGroup();
- if (!nextrec)
- {
- nextrec = input->nextInGroup();
- if (!nextrec)
- break;
- }
- result.append(inputMeta->getRecordSize(nextrec), nextrec);
- ReleaseRoxieRow(nextrec);
- }
- retSize = result.length();
- ret = result.detach();
- }
- stop(false);
- reset();
- }
- catch(IException *E)
- {
- ctx->notifyAbort(E);
- stop(true);
- reset();
- throw;
- }
- catch(...)
- {
- Owned<IException> E = MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught at %s:%d", __FILE__, __LINE__);
- ctx->notifyAbort(E);
- stop(true);
- reset();
- throw;
- }
- }
- };
- class CRoxieServerDatasetResultActivityFactory : public CRoxieServerActivityFactory
- {
- bool isRoot;
- public:
- CRoxieServerDatasetResultActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerDatasetResultActivity(this, _probeManager);
- }
- virtual bool isSink() const
- {
- return isRoot;
- }
- };
- IRoxieServerActivityFactory *createRoxieServerDatasetResultActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
- {
- return new CRoxieServerDatasetResultActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
- }
- //=================================================================================
- class CRoxieServerInlineTableActivity : public CRoxieServerActivity
- {
- IHThorInlineTableArg &helper;
- __uint64 curRow;
- __uint64 numRows;
- public:
- CRoxieServerInlineTableActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorInlineTableArg &) basehelper)
- {
- curRow = 0;
- numRows = 0;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- curRow = 0;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- numRows = helper.numRows();
- }
- virtual bool needsAllocator() const { return true; }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- // Filtering empty rows, returns the next valid row
- while (curRow < numRows)
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- unsigned outSize = helper.getRow(rowBuilder, curRow++);
- if (outSize)
- {
- processed++;
- return rowBuilder.finalizeRowClear(outSize);
- }
- }
- return NULL;
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
- }
- };
- class CRoxieServerInlineTableActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerInlineTableActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerInlineTableActivity(this, _probeManager);
- }
- virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
- {
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for InlineTable activity");
- }
- };
- IRoxieServerActivityFactory *createRoxieServerInlineTableActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerInlineTableActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerWorkUnitReadActivity : public CRoxieServerActivity
- {
- IHThorWorkunitReadArg &helper;
- Owned<IWorkUnitRowReader> wuReader; // MORE - can we use IRoxieInput instead?
- public:
- CRoxieServerWorkUnitReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorWorkunitReadArg &)basehelper)
- {
- }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerActivity::onCreate(_ctx, _colocalParent);
- if (!ctx->queryServerContext())
- {
- throw MakeStringException(ROXIE_INTERNAL_ERROR, "Workunit read activity cannot be executed in slave context");
- }
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- IXmlToRowTransformer * xmlTransformer = helper.queryXmlTransformer();
- OwnedRoxieString fromWuid(helper.getWUID());
- wuReader.setown(ctx->getWorkunitRowReader(fromWuid, helper.queryName(), helper.querySequence(), xmlTransformer, rowAllocator, meta.isGrouped()));
- // MORE _ should that be in onCreate?
- }
- virtual void reset()
- {
- wuReader.clear();
- CRoxieServerActivity::reset();
- };
- virtual bool needsAllocator() const { return true; }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- const void *ret = wuReader->nextInGroup();
- if (ret)
- processed++;
- return ret;
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
- }
- };
- class CRoxieServerWorkUnitReadActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerWorkUnitReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerWorkUnitReadActivity(this, _probeManager);
- }
- virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
- {
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for WorkUnitRead activity");
- }
- };
- IRoxieServerActivityFactory *createRoxieServerWorkUnitReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerWorkUnitReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- interface ILocalGraphEx : public IEclGraphResults
- {
- public:
- virtual void setResult(unsigned id, IGraphResult * result) = 0;
- virtual IRoxieInput * createResultIterator(unsigned id) = 0;
- virtual void setGraphLoopResult(IGraphResult * result) = 0;
- virtual IRoxieInput * createGraphLoopResultIterator(unsigned id) = 0;
- };
- class CSafeRoxieInput : public CInterface, implements IRoxieInput
- {
- public:
- CSafeRoxieInput(IRoxieInput * _input) : input(_input) {}
- IMPLEMENT_IINTERFACE
- virtual IOutputMetaData * queryOutputMeta() const
- {
- return input->queryOutputMeta();
- }
- virtual unsigned queryId() const
- {
- return input->queryId();
- }
- virtual unsigned __int64 queryTotalCycles() const
- {
- return input->queryTotalCycles();
- }
- virtual unsigned __int64 queryLocalCycles() const
- {
- return input->queryLocalCycles();
- }
- virtual IRoxieInput *queryInput(unsigned idx) const
- {
- return input->queryInput(idx);
- }
- virtual IRoxieServerActivity *queryActivity()
- {
- return input->queryActivity();
- }
- virtual IIndexReadActivityInfo *queryIndexReadActivity()
- {
- return input->queryIndexReadActivity();
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CriticalBlock procedure(cs);
- input->start(parentExtractSize, parentExtract, paused);
- }
- virtual void stop(bool aborting)
- {
- CriticalBlock procedure(cs);
- input->stop(aborting);
- }
- virtual void reset()
- {
- CriticalBlock procedure(cs);
- input->reset();
- }
- virtual void resetEOF()
- {
- CriticalBlock procedure(cs);
- input->resetEOF();
- }
- virtual void checkAbort()
- {
- CriticalBlock procedure(cs);
- input->checkAbort();
- }
- virtual const void *nextInGroup()
- {
- CriticalBlock procedure(cs);
- return input->nextInGroup();
- }
- virtual bool nextGroup(ConstPointerArray & group)
- {
- CriticalBlock procedure(cs);
- return input->nextGroup(group);
- }
- private:
- CriticalSection cs;
- Linked<IRoxieInput> input;
- };
- //=================================================================================
- class CPseudoRoxieInput : public CInterface, implements IRoxieInput
- {
- protected:
- unsigned __int64 totalCycles;
- public:
- IMPLEMENT_IINTERFACE;
-
- CPseudoRoxieInput()
- {
- totalCycles = 0;
- }
- virtual unsigned __int64 queryTotalCycles() const
- {
- return totalCycles;
- }
- virtual unsigned __int64 queryLocalCycles() const
- {
- return totalCycles;
- }
- virtual IRoxieInput *queryInput(unsigned idx) const
- {
- return NULL;
- }
- virtual IRoxieServerActivity *queryActivity()
- {
- throwUnexpected();
- }
- virtual IIndexReadActivityInfo *queryIndexReadActivity()
- {
- throwUnexpected();
- }
- virtual IOutputMetaData * queryOutputMeta() const { throwUnexpected(); }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused) { }
- virtual void stop(bool aborting) { }
- virtual void reset() { totalCycles = 0; }
- virtual void checkAbort() { }
- virtual unsigned queryId() const { throwUnexpected(); }
- virtual void resetEOF() { }
- };
- class CIndirectRoxieInput : public CPseudoRoxieInput
- {
- public:
- CIndirectRoxieInput(IRoxieInput * _input = NULL) : input(_input)
- {
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- input->start(parentExtractSize, parentExtract, paused);
- }
- virtual void stop(bool aborting)
- {
- input->stop(aborting);
- }
- virtual void reset()
- {
- input->reset();
- totalCycles = 0;
- }
- virtual void checkAbort()
- {
- input->checkAbort();
- }
- virtual const void * nextInGroup()
- {
- return input->nextInGroup();
- }
- virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
- {
- return input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
- }
- virtual unsigned __int64 queryLocalCycles() const
- {
- __int64 ret = totalCycles - input->queryTotalCycles();
- if (ret < 0)
- ret = 0;
- return ret;
- }
- virtual IRoxieInput *queryInput(unsigned idx) const
- {
- return input->queryInput(idx);
- }
- virtual unsigned queryId() const
- {
- return input->queryId();
- }
- virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
- {
- return input->gatherConjunctions(collector);
- }
- virtual void resetEOF()
- {
- input->resetEOF();
- }
- virtual unsigned numConcreteOutputs() const
- {
- return input->numConcreteOutputs();
- }
-
- virtual IRoxieInput * queryConcreteInput(unsigned idx)
- {
- return input->queryConcreteInput(idx);
- }
- virtual IOutputMetaData * queryOutputMeta() const
- {
- return input->queryOutputMeta();
- }
- virtual IRoxieServerActivity *queryActivity()
- {
- return input->queryActivity();
- }
- void setInput(IRoxieInput * _input)
- {
- input = _input;
- }
- protected:
- IRoxieInput * input;
- };
- class CExtractMapperInput : public CIndirectRoxieInput
- {
- unsigned savedParentExtractSize;
- const byte * savedParentExtract;
- public:
- CExtractMapperInput(IRoxieInput * _input = NULL) : CIndirectRoxieInput(_input)
- {
- savedParentExtractSize = 0;
- savedParentExtract = NULL;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- input->start(savedParentExtractSize, savedParentExtract, paused);
- }
- void setParentExtract(unsigned _savedParentExtractSize, const byte * _savedParentExtract)
- {
- savedParentExtractSize = _savedParentExtractSize;
- savedParentExtract = _savedParentExtract;
- }
- };
- class CGraphResult : public CInterface, implements IGraphResult
- {
- CriticalSection cs;
- byte **rowset;
- size32_t count;
- bool complete;
- void clear()
- {
- CriticalBlock func(cs);
- rtlReleaseRowset(count, rowset);
- rowset = NULL;
- count = 0;
- complete = false;
- }
- public:
- IMPLEMENT_IINTERFACE
- CGraphResult()
- {
- complete = false; // dummy result is not supposed to be used...
- rowset = NULL;
- count = 0;
- }
- CGraphResult(size32_t _count, byte **_rowset)
- : count(_count), rowset(_rowset)
- {
- complete = true;
- }
- ~CGraphResult()
- {
- clear();
- }
- // interface IGraphResult
- virtual IRoxieInput * createIterator()
- {
- if (!complete)
- throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Internal Error: Reading uninitialised graph result");
- return new CGraphResultIterator(this);
- }
- virtual void getLinkedResult(unsigned & countResult, byte * * & result)
- {
- if (!complete)
- throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Internal Error: Reading uninitialised graph result");
- result = rtlLinkRowset(rowset);
- countResult = count;
- }
- virtual const void * getLinkedRowResult()
- {
- if (!complete)
- throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Internal Error: Reading uninitialised graph result");
- if (count != 1)
- throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Internal Error: Expected a single row result");
- const void * ret = rowset[0];
- LinkRoxieRow(ret);
- return ret;
- }
- //other
- const void * getRow(unsigned i)
- {
- CriticalBlock func(cs);
- if (i >= count)
- return NULL;
- const void * ret = rowset[i];
- if (ret) LinkRoxieRow(ret);
- return ret;
- }
- protected:
- class CGraphResultIterator : public CPseudoRoxieInput
- {
- unsigned i;
- Linked<CGraphResult> result;
- public:
- CGraphResultIterator(CGraphResult * _result) : result(_result) { i = 0; }
- IMPLEMENT_IINTERFACE
- public:
- virtual const void * nextInGroup()
- {
- return result->getRow(i++);
- }
- };
- };
- //=================================================================================
- class CRoxieServerLocalResultReadActivity : public CRoxieServerActivity
- {
- IHThorLocalResultReadArg &helper;
- Owned<IRoxieInput> iter;
- ILocalGraphEx * graph;
- unsigned graphId;
- unsigned sequence;
- public:
- CRoxieServerLocalResultReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _graphId)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorLocalResultReadArg &)basehelper), graphId(_graphId)
- {
- graph = NULL;
- sequence = 0;
- }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerActivity::onCreate(_ctx, _colocalParent);
- graph = static_cast<ILocalGraphEx *>(_ctx->queryCodeContext()->resolveLocalQuery(graphId));
- sequence = helper.querySequence();
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- iter.setown(graph->createResultIterator(sequence));
- }
- virtual void reset()
- {
- iter.clear();
- CRoxieServerActivity::reset();
- };
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- const void * next = iter->nextInGroup();
- if (next)
- {
- processed++;
- atomic_inc(&rowsIn);
- }
- return next;
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
- }
- };
- class CRoxieServerLocalResultReadActivityFactory : public CRoxieServerActivityFactory
- {
- unsigned graphId;
- public:
- CRoxieServerLocalResultReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _graphId)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), graphId(_graphId)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerLocalResultReadActivity(this, _probeManager, graphId);
- }
- virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
- {
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for LocalResultRead activity");
- }
- };
- IRoxieServerActivityFactory *createRoxieServerLocalResultReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned graphId)
- {
- return new CRoxieServerLocalResultReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, graphId);
- }
- //=================================================================================
- class CRoxieServerLocalResultStreamReadActivity : public CRoxieServerActivity
- {
- IHThorLocalResultReadArg &helper;
- Owned<IRoxieInput> streamInput;
- unsigned sequence;
- public:
- CRoxieServerLocalResultStreamReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorLocalResultReadArg &)basehelper)
- {
- sequence = 0;
- }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerActivity::onCreate(_ctx, _colocalParent);
- sequence = helper.querySequence();
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- assertex(streamInput != NULL);
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- streamInput->start(parentExtractSize, parentExtract, paused);
- }
- virtual void stop(bool aborting)
- {
- CRoxieServerActivity::stop(aborting);
- streamInput->stop(aborting);
- }
- virtual void reset()
- {
- streamInput->reset();
- CRoxieServerActivity::reset();
- };
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- const void * next = streamInput->nextInGroup();
- if (next)
- {
- processed++;
- atomic_inc(&rowsIn);
- }
- return next;
- }
- virtual bool querySetStreamInput(unsigned id, IRoxieInput * _input)
- {
- if (id == sequence)
- {
- streamInput.set(_input);
- return true;
- }
- return false;
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
- }
- };
- class CRoxieServerLocalResultStreamReadActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerLocalResultStreamReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerLocalResultStreamReadActivity(this, _probeManager);
- }
- virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
- {
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for LocalResultRead activity");
- }
- };
- IRoxieServerActivityFactory *createRoxieServerLocalResultStreamReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerLocalResultStreamReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=====================================================================================================
- class CRoxieServerLocalResultWriteActivity : public CRoxieServerInternalSinkActivity
- {
- IHThorLocalResultWriteArg &helper;
- ILocalGraphEx * graph;
- unsigned graphId;
- public:
- CRoxieServerLocalResultWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _graphId, unsigned _numOutputs)
- : CRoxieServerInternalSinkActivity(_factory, _probeManager, _numOutputs), helper((IHThorLocalResultWriteArg &)basehelper), graphId(_graphId)
- {
- graph = NULL;
- }
- virtual bool needsAllocator() const { return true; }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerInternalSinkActivity::onCreate(_ctx, _colocalParent);
- graph = static_cast<ILocalGraphEx *>(_ctx->queryCodeContext()->resolveLocalQuery(graphId));
- }
- virtual void onExecute()
- {
- RtlLinkedDatasetBuilder builder(rowAllocator);
- input->readAll(builder);
- Owned<CGraphResult> result = new CGraphResult(builder.getcount(), builder.linkrows());
- graph->setResult(helper.querySequence(), result);
- }
- virtual const void *nextInGroup()
- {
- return input->nextInGroup(); // I can act as a passthrough input
- }
- IRoxieInput * querySelectOutput(unsigned id)
- {
- if (id == helper.querySequence())
- {
- executed = true; // Ensure that we don't try to pull as a sink as well as via the passthrough
- return LINK(this);
- }
- return NULL;
- }
- };
- class CRoxieServerLocalResultWriteActivityFactory : public CRoxieServerInternalSinkFactory
- {
- unsigned graphId;
- public:
- CRoxieServerLocalResultWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, unsigned _graphId, bool _isRoot)
- : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot), graphId(_graphId)
- {
- isInternal = true;
- Owned<IHThorLocalResultWriteArg> helper = (IHThorLocalResultWriteArg *) helperFactory();
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerLocalResultWriteActivity(this, _probeManager, graphId, usageCount);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerLocalResultWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, unsigned _graphId, bool _isRoot)
- {
- return new CRoxieServerLocalResultWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _graphId, _isRoot);
- }
- //=====================================================================================================
- class CRoxieServerDictionaryResultWriteActivity : public CRoxieServerInternalSinkActivity
- {
- IHThorDictionaryResultWriteArg &helper;
- ILocalGraphEx * graph;
- unsigned graphId;
- public:
- CRoxieServerDictionaryResultWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _usageCount, unsigned _graphId)
- : CRoxieServerInternalSinkActivity(_factory, _probeManager, _usageCount), helper((IHThorDictionaryResultWriteArg &)basehelper), graphId(_graphId)
- {
- graph = NULL;
- }
- virtual bool needsAllocator() const { return true; }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerInternalSinkActivity::onCreate(_ctx, _colocalParent);
- graph = static_cast<ILocalGraphEx *>(_ctx->queryCodeContext()->resolveLocalQuery(graphId));
- }
- virtual void onExecute()
- {
- unsigned sequence = helper.querySequence();
- RtlLinkedDictionaryBuilder builder(rowAllocator, helper.queryHashLookupInfo());
- loop
- {
- const void *row = input->nextInGroup();
- if (!row)
- {
- row = input->nextInGroup();
- if (!row)
- break;
- }
- builder.appendOwn(row);
- processed++;
- }
- Owned<CGraphResult> result = new CGraphResult(builder.getcount(), builder.linkrows());
- graph->setResult(helper.querySequence(), result);
- }
- virtual const void *nextInGroup()
- {
- return input->nextInGroup(); // I can act as a passthrough input
- }
- IRoxieInput * querySelectOutput(unsigned id)
- {
- if (id == helper.querySequence())
- {
- executed = true; // Ensure that we don't try to pull as a sink as well as via the passthrough
- return LINK(this);
- }
- return NULL;
- }
- };
- class CRoxieServerDictionaryResultWriteActivityFactory : public CRoxieServerInternalSinkFactory
- {
- unsigned graphId;
- public:
- CRoxieServerDictionaryResultWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, unsigned _graphId, bool _isRoot)
- : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot), graphId(_graphId)
- {
- isInternal = true;
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerDictionaryResultWriteActivity(this, _probeManager, usageCount, graphId);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerDictionaryResultWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, unsigned _graphId, bool _isRoot)
- {
- return new CRoxieServerDictionaryResultWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _graphId, _isRoot);
- }
- //=================================================================================
- class CRoxieServerGraphLoopResultReadActivity : public CRoxieServerActivity
- {
- protected:
- IHThorGraphLoopResultReadArg &helper;
- Owned<IRoxieInput> iter;
- ILocalGraphEx * graph;
- unsigned graphId;
- unsigned sequence;
- public:
- CRoxieServerGraphLoopResultReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _graphId)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorGraphLoopResultReadArg &)basehelper), graphId(_graphId)
- {
- graph = NULL;
- sequence = 0;
- }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerActivity::onCreate(_ctx, _colocalParent);
- graph = static_cast<ILocalGraphEx *>(_ctx->queryCodeContext()->resolveLocalQuery(graphId));
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- if (iter)
- iter->start(parentExtractSize, parentExtract, paused);
- else
- {
- sequence = helper.querySequence();
- if ((int)sequence >= 0)
- {
- try
- {
- iter.setown(graph->createGraphLoopResultIterator(sequence));
- }
- catch (IException * E)
- {
- throw makeWrappedException(E);
- }
- }
- }
- }
- virtual void stop(bool aborting)
- {
- if (iter)
- iter->stop(aborting);
- CRoxieServerActivity::stop(aborting);
- }
- virtual void reset()
- {
- if (iter)
- iter->reset();
- iter.clear();
- CRoxieServerActivity::reset();
- };
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- const void * next = iter ? iter->nextInGroup() : NULL;
- if (next)
- {
- processed++;
- atomic_inc(&rowsIn);
- }
- return next;
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
- }
- virtual void gatherIterationUsage(IRoxieServerLoopResultProcessor & processor, unsigned parentExtractSize, const byte * parentExtract)
- {
- ensureCreated();
- basehelper.onStart(parentExtract, NULL);
- processor.noteUseIteration(helper.querySequence());
- }
- virtual void associateIterationOutputs(IRoxieServerLoopResultProcessor & processor, unsigned parentExtractSize, const byte * parentExtract, IProbeManager *probeManager, IArrayOf<IRoxieInput> &probes)
- {
- //helper already initialised from the gratherIterationUsage() call.
- iter.set(processor.connectIterationOutput(helper.querySequence(), probeManager, probes, this, 0));
- }
- virtual IInputSteppingMeta * querySteppingMeta()
- {
- assertex(iter);
- return iter->querySteppingMeta();
- }
- virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
- {
- assertex(iter);
- return iter->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
- }
- };
- //variety of CRoxieServerGraphLoopResultReadActivity created internally with a predefined sequence number
- class CRoxieServerInternalGraphLoopResultReadActivity : public CRoxieServerGraphLoopResultReadActivity
- {
- public:
- CRoxieServerInternalGraphLoopResultReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _graphId, unsigned _sequence)
- : CRoxieServerGraphLoopResultReadActivity(_factory, _probeManager, _graphId)
- {
- sequence = _sequence;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- if ((int)sequence >= 0)
- {
- try
- {
- iter.setown(graph->createGraphLoopResultIterator(sequence));
- }
- catch (IException * E)
- {
- throw makeWrappedException(E);
- }
- }
- }
- };
- class CRoxieServerGraphLoopResultReadActivityFactory : public CRoxieServerActivityFactory
- {
- unsigned graphId;
- public:
- CRoxieServerGraphLoopResultReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _graphId)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), graphId(_graphId)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerGraphLoopResultReadActivity(this, _probeManager, graphId);
- }
- virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
- {
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for GraphLoopResultRead activity");
- }
- };
- IRoxieServerActivityFactory *createRoxieServerGraphLoopResultReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned graphId)
- {
- return new CRoxieServerGraphLoopResultReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, graphId);
- }
- //=====================================================================================================
- class CRoxieServerGraphLoopResultWriteActivity : public CRoxieServerInternalSinkActivity
- {
- IHThorGraphLoopResultWriteArg &helper;
- ILocalGraphEx * graph;
- unsigned graphId;
- public:
- CRoxieServerGraphLoopResultWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _graphId, unsigned _numOutputs)
- : CRoxieServerInternalSinkActivity(_factory, _probeManager, _numOutputs), helper((IHThorGraphLoopResultWriteArg &)basehelper), graphId(_graphId)
- {
- graph = NULL;
- }
- virtual bool needsAllocator() const { return true; }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerInternalSinkActivity::onCreate(_ctx, _colocalParent);
- graph = static_cast<ILocalGraphEx *>(_ctx->queryCodeContext()->resolveLocalQuery(graphId));
- }
- virtual void onExecute()
- {
- RtlLinkedDatasetBuilder builder(rowAllocator);
- input->readAll(builder);
- Owned<CGraphResult> result = new CGraphResult(builder.getcount(), builder.linkrows());
- graph->setGraphLoopResult(result);
- }
- virtual IRoxieInput *queryOutput(unsigned idx)
- {
- if (idx==0)
- return this;
- else
- return NULL;
- }
- virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
- {
- return input->gatherConjunctions(collector);
- }
- virtual void resetEOF()
- {
- input->resetEOF();
- }
- virtual const void *nextInGroup()
- {
- const void * next = input->nextInGroup();
- if (next)
- processed++;
- return next;
- }
- virtual bool isPassThrough()
- {
- return true;
- }
- virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- const void * next = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
- if (next)
- processed++;
- return next;
- }
- IInputSteppingMeta * querySteppingMeta()
- {
- return input->querySteppingMeta();
- }
- virtual IOutputMetaData * queryOutputMeta() const
- {
- return input->queryOutputMeta();
- }
- };
- class CRoxieServerGraphLoopResultWriteActivityFactory : public CRoxieServerInternalSinkFactory
- {
- unsigned graphId;
- public:
- CRoxieServerGraphLoopResultWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, unsigned _graphId)
- : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, true), graphId(_graphId)
- {
- isInternal = true;
- Owned<IHThorGraphLoopResultWriteArg> helper = (IHThorGraphLoopResultWriteArg *) helperFactory();
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerGraphLoopResultWriteActivity(this, _probeManager, graphId, usageCount);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerGraphLoopResultWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, unsigned _graphId)
- {
- return new CRoxieServerGraphLoopResultWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _graphId);
- }
- #if 0
- //=====================================================================================================
- CHThorLocalResultSpillActivity::CHThorLocalResultSpillActivity(IAgentContext &_agent, ActivityId const & _id, IHThorLocalResultSpillArg &_arg)
- : CHThorSimpleActivityBase(_agent, _id, _arg), helper(_arg)
- {
- next = NULL;
- }
- void CHThorLocalResultSpillActivity::ready()
- {
- CHThorSimpleActivityBase::ready();
- next = input->nextInGroup();
- grouped = input->isGrouped();
- rowdata.clear();
- }
- const void * CHThorLocalResultSpillActivity::nextInGroup()
- {
- const void * ret = next;
- next = input->nextInGroup();
- if (!ret && !next)
- return NULL;
- if (ret)
- {
- size32_t thisSize = outputMeta->getRecordSize(ret);
- rowdata.append(thisSize, ret);
- if (grouped)
- rowdata.append(next == NULL);
- }
- return ret;
- }
- void CHThorLocalResultSpillActivity::done()
- {
- loop
- {
- const void * ret = nextInGroup();
- if (!ret)
- {
- ret = nextInGroup();
- if (!ret)
- break;
- }
- ReleaseRoxieRow(ret);
- }
- agent.setLocalResult(helper.querySequence(), rowdata.length(), rowdata.toByteArray());
- CHThorSimpleActivityBase::done();
- }
- #endif
- //=================================================================================
- class CRoxieServerDedupActivity : public CRoxieServerActivity
- {
- protected:
- IHThorDedupArg &helper;
- unsigned numKept;
- unsigned numToKeep;
- public:
- CRoxieServerDedupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorDedupArg &)basehelper)
- {
- numKept = 0;
- numToKeep = 0;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- numKept = 0;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- numToKeep = helper.numToKeep();
- }
- };
- class CRoxieServerDedupKeepLeftActivity : public CRoxieServerDedupActivity
- {
- IRangeCompare * stepCompare;
- const void *prev;
- public:
- CRoxieServerDedupKeepLeftActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerDedupActivity(_factory, _probeManager)
- {
- prev = NULL;
- stepCompare = NULL;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- prev = NULL;
- CRoxieServerDedupActivity::start(parentExtractSize, parentExtract, paused);
- IInputSteppingMeta * stepMeta = input->querySteppingMeta();
- stepCompare = NULL;
- if (stepMeta)
- stepCompare = stepMeta->queryCompare();
- }
- virtual void reset()
- {
- ReleaseClearRoxieRow(prev);
- CRoxieServerDedupActivity::reset();
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- const void * next;
- loop
- {
- next = input->nextInGroup();
- if (!prev || !next || !helper.matches(prev,next))
- {
- numKept = 0;
- break;
- }
- if (numKept < numToKeep-1)
- {
- numKept++;
- break;
- }
- ReleaseRoxieRow(next);
- }
- ReleaseRoxieRow(prev);
- prev = next;
- if (next)
- {
- LinkRoxieRow(next);
- processed++;
- }
- return next;
- }
- virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- const void * next;
- loop
- {
- next = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
- //If the record was an in-exact match from the index then return it immediately
- //and don't cause it to dedup following legal records.
- if (!wasCompleteMatch)
- {
- assertex(stepExtra.returnMismatches());
- return next;
- }
- if (!prev || !next || !helper.matches(prev,next))
- {
- numKept = 0;
- break;
- }
- if (numKept < numToKeep-1)
- {
- numKept++;
- break;
- }
- //Unusual - deduping by x,y stepped on x,y,z - still want any record back as soon as possible.
- if (stepExtra.returnMismatches())
- {
- //If asked to return mismatches we are only interested in mismatches that will force the stepped
- //condition to advance
- if (stepCompare->docompare(next, seek, numFields) != 0)
- {
- wasCompleteMatch = false;
- break;
- }
- }
- ReleaseRoxieRow(next);
- }
- ReleaseRoxieRow(prev);
- prev = next;
- if (next)
- {
- LinkRoxieRow(next);
- processed++;
- }
- return next;
- }
- virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
- {
- return input->gatherConjunctions(collector);
- }
- virtual void resetEOF()
- {
- input->resetEOF();
- }
- IInputSteppingMeta * querySteppingMeta()
- {
- return input->querySteppingMeta();
- }
- };
- //=================================================================================
- class CRoxieServerDedupKeepRightActivity : public CRoxieServerDedupActivity
- {
- const void *kept;
- bool first;
- public:
- CRoxieServerDedupKeepRightActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerDedupActivity(_factory, _probeManager)
- {
- kept = NULL;
- first = true;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- first = true;
- kept = NULL;
- CRoxieServerDedupActivity::start(parentExtractSize, parentExtract, paused);
- }
- virtual void reset()
- {
- ReleaseClearRoxieRow(kept);
- CRoxieServerActivity::reset();
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (first)
- {
- kept = input->nextInGroup();
- first = false;
- }
- const void * next;
- loop
- {
- next = input->nextInGroup();
- if (!kept || !next || !helper.matches(kept,next))
- {
- numKept = 0;
- break;
- }
- if (numKept < numToKeep-1)
- {
- numKept++;
- break;
- }
- ReleaseRoxieRow(kept);
- kept = next;
- }
- const void * ret = kept;
- kept = next;
- // CTXLOG("dedup returns %p", ret);
- if (ret) processed++;
- return ret;
- }
- };
- class CRoxieServerDedupAllActivity : public CRoxieServerActivity
- {
- IHThorDedupArg &helper;
- unsigned survivorIndex;
- ConstPointerArray survivors;
- bool keepLeft;
- bool eof;
- bool first;
- ICompare *primaryCompare;
- public:
- CRoxieServerDedupAllActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _keepLeft)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorDedupArg &)basehelper)
- {
- keepLeft = _keepLeft;
- primaryCompare = helper.queryComparePrimary();
- eof = false;
- first = true;
- survivorIndex = 0;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- eof = false;
- first = true;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- }
- virtual void reset()
- {
- #ifdef _DEBUG
- while (survivors.isItem(survivorIndex))
- {
- ReleaseRoxieRow(survivors.item(survivorIndex++));
- }
- #endif
- survivors.kill();
- eof = false;
- first = true;
- CRoxieServerActivity::reset();
- }
- void dedupRange(unsigned first, unsigned last, ConstPointerArray & group)
- {
- for (unsigned idxL = first; idxL < last; idxL++)
- {
- const void * left = group.item(idxL);
- if (left)
- {
- for (unsigned idxR = first; idxR < last; idxR++)
- {
- const void * right = group.item(idxR);
- if ((idxL != idxR) && right)
- {
- if (helper.matches(left, right))
- {
- if (keepLeft)
- {
- group.replace(NULL, idxR);
- ReleaseRoxieRow(right);
- }
- else
- {
- group.replace(NULL, idxL);
- ReleaseRoxieRow(left);
- break;
- }
- }
- }
- }
- }
- }
- }
- void dedupRangeIndirect(unsigned first, unsigned last, void *** index)
- {
- for (unsigned idxL = first; idxL < last; idxL++)
- {
- void * left = *(index[idxL]);
- if (left)
- {
- for (unsigned idxR = first; idxR < last; idxR++)
- {
- void * right = *(index[idxR]);
- if ((idxL != idxR) && right)
- {
- if (helper.matches(left, right))
- {
- if (keepLeft)
- {
- *(index[idxR]) = NULL;
- ReleaseRoxieRow(right);
- }
- else
- {
- *(index[idxL]) = NULL;
- ReleaseRoxieRow(left);
- break;
- }
- }
- }
- }
- }
- }
- }
- bool calcNextDedupAll()
- {
- survivors.kill();
- survivorIndex = 0;
- ConstPointerArray group;
- if (eof || !input->nextGroup(group))
- {
- eof = true;
- return false;
- }
- unsigned max = group.ordinality();
- if (primaryCompare)
- {
- //hard, if not impossible, to hit this code once optimisations in place
- MemoryAttr indexbuff(max*sizeof(void **));
- void *** index = (void ***)indexbuff.bufferBase();
- qsortvecstable(const_cast<void * *>(group.getArray()), max, *primaryCompare, index);
- unsigned first = 0;
- for (unsigned idx = 1; idx < max; idx++)
- {
- if (primaryCompare->docompare(*(index[first]), *(index[idx])) != 0)
- {
- dedupRangeIndirect(first, idx, index);
- first = idx;
- }
- }
- dedupRangeIndirect(first, max, index);
- for(unsigned idx2=0; idx2<max; ++idx2)
- {
- void * cur = *(index[idx2]);
- if(cur)
- survivors.append(cur);
- }
- }
- else
- {
- dedupRange(0, max, group);
- for(unsigned idx=0; idx<max; ++idx)
- {
- const void * cur = group.item(idx);
- if(cur)
- survivors.append(cur);
- }
- }
- return true;
- }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (first)
- {
- calcNextDedupAll();
- first = false;
- }
- while (survivors.isItem(survivorIndex))
- {
- const void *ret = survivors.item(survivorIndex++);
- if (ret)
- {
- processed++;
- return ret;
- }
- }
- calcNextDedupAll();
- return NULL;
- }
- };
- class CRoxieServerDedupActivityFactory : public CRoxieServerActivityFactory
- {
- bool compareAll;
- bool keepLeft;
- public:
- CRoxieServerDedupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- Owned<IHThorDedupArg> helper = (IHThorDedupArg *) helperFactory();
- compareAll = helper->compareAll();
- keepLeft = helper->keepLeft();
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- if (compareAll)
- return new CRoxieServerDedupAllActivity(this, _probeManager, keepLeft);
- else if (keepLeft)
- return new CRoxieServerDedupKeepLeftActivity(this, _probeManager);
- else
- return new CRoxieServerDedupKeepRightActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerDedupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerDedupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerHashDedupActivity : public CRoxieServerActivity
- {
- bool eof;
- IHThorHashDedupArg &helper;
- class HashDedupElement
- {
- public:
- HashDedupElement(unsigned _hash, const void *_keyRow)
- : hash(_hash), keyRow(_keyRow)
- {
- }
- ~HashDedupElement()
- {
- ReleaseRoxieRow(keyRow);
- }
- inline unsigned queryHash() const
- {
- return hash;
- }
- inline const void *queryRow() const
- {
- return keyRow;
- }
- private:
- unsigned hash;
- const void *keyRow;
- };
- class HashDedupTable : public SuperHashTable
- {
- public:
- HashDedupTable(IHThorHashDedupArg & _helper, unsigned _activityId)
- : helper(_helper),
- activityId(_activityId),
- keySize(helper.queryKeySize())
- {
- }
- virtual ~HashDedupTable() { releaseAll(); }
- virtual unsigned getHashFromElement(const void *et) const
- {
- const HashDedupElement *element = reinterpret_cast<const HashDedupElement *>(et);
- return element->queryHash();
- }
- virtual unsigned getHashFromFindParam(const void *fp) const { throwUnexpected(); }
- virtual const void * getFindParam(const void *et) const { throwUnexpected(); }
- virtual bool matchesElement(const void *et, const void *searchET) const { throwUnexpected(); }
- virtual bool matchesFindParam(const void *et, const void *key, unsigned fphash) const
- {
- const HashDedupElement *element = reinterpret_cast<const HashDedupElement *>(et);
- if (fphash != element->queryHash())
- return false;
- return (helper.queryKeyCompare()->docompare(element->queryRow(), key) == 0);
- }
- virtual void onAdd(void *et) {}
- virtual void onRemove(void *et)
- {
- const HashDedupElement *element = reinterpret_cast<const HashDedupElement *>(et);
- delete element;
- }
- void onCreate(IRoxieSlaveContext *ctx)
- {
- keyRowAllocator.setown(ctx->queryCodeContext()->getRowAllocator(keySize.queryOriginal(), activityId));
- }
- void reset()
- {
- kill();
- }
- bool insert(const void * row)
- {
- unsigned hash = helper.queryHash()->hash(row);
- RtlDynamicRowBuilder keyRowBuilder(keyRowAllocator, true);
- size32_t thisKeySize = helper.recordToKey(keyRowBuilder, row);
- OwnedConstRoxieRow keyRow = keyRowBuilder.finalizeRowClear(thisKeySize);
- if (find(hash, keyRow.get()))
- return false;
- addNew(new HashDedupElement(hash, keyRow.getClear()), hash);
- return true;
- }
- private:
- IHThorHashDedupArg & helper;
- CachedOutputMetaData keySize;
- Owned<IEngineRowAllocator> keyRowAllocator;
- unsigned activityId;
- } table;
- public:
- CRoxieServerHashDedupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorHashDedupArg &)basehelper), table(helper, activityId)
- {
- eof = false;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- eof = false;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- }
- virtual void onCreate(IRoxieSlaveContext *ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerActivity::onCreate(ctx, colocalParent);
- table.onCreate(ctx);
- }
- virtual void reset()
- {
- table.reset();
- eof = false;
- CRoxieServerActivity::reset();
- }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- while(!eof)
- {
- const void * next = input->nextInGroup();
- if(!next)
- {
- if (table.count() == 0)
- eof = true;
- table.reset();
- return NULL;
- }
- if(table.insert(next))
- return next;
- else
- ReleaseRoxieRow(next);
- }
- return NULL;
- }
- };
- class CRoxieServerHashDedupActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerHashDedupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerHashDedupActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerHashDedupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerHashDedupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerRollupActivity : public CRoxieServerActivity
- {
- IHThorRollupArg &helper;
- OwnedConstRoxieRow left;
- OwnedConstRoxieRow prev;
- OwnedConstRoxieRow right;
- bool readFirstRow;
- public:
- CRoxieServerRollupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorRollupArg &)basehelper)
- {
- readFirstRow = false;
- }
- ~CRoxieServerRollupActivity()
- {
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- readFirstRow = false;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- }
- virtual void reset()
- {
- left.clear();
- prev.clear();
- right.clear();
- CRoxieServerActivity::reset();
- }
- virtual bool needsAllocator() const { return true; }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (!readFirstRow)
- {
- left.setown(input->nextInGroup());
- prev.set(left);
- readFirstRow = true;
- }
- loop
- {
- right.setown(input->nextInGroup());
- if(!prev || !right || !helper.matches(prev,right))
- {
- const void * ret = left.getClear();
- if(ret)
- processed++;
- left.setown(right.getClear());
- prev.set(left);
- return ret;
- }
- try
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- unsigned outSize = helper.transform(rowBuilder, left, right);
- if (outSize)
- left.setown(rowBuilder.finalizeRowClear(outSize));
- if (helper.getFlags() & RFrolledismatchleft)
- prev.set(left);
- else
- prev.set(right);
- }
- catch(IException * E)
- {
- throw makeWrappedException(E);
- }
- }
- }
- };
- class CRoxieServerRollupActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerRollupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerRollupActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerRollupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerRollupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerNormalizeActivity : public CRoxieServerActivity
- {
- IHThorNormalizeArg &helper;
- unsigned numThisRow;
- unsigned curRow;
- const void *buffer;
- unsigned numProcessedLastGroup;
- public:
- CRoxieServerNormalizeActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorNormalizeArg &)basehelper)
- {
- buffer = NULL;
- numThisRow = 0;
- curRow = 0;
- numProcessedLastGroup = 0;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- numThisRow = 0;
- curRow = 0;
- numProcessedLastGroup = 0;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- }
- virtual void reset()
- {
- ReleaseClearRoxieRow(buffer);
- CRoxieServerActivity::reset();
- }
- virtual bool needsAllocator() const { return true; }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- loop
- {
- while (curRow == numThisRow)
- {
- if (buffer)
- ReleaseClearRoxieRow(buffer);
- buffer = input->nextInGroup();
- if (!buffer && (processed == numProcessedLastGroup))
- buffer = input->nextInGroup();
- if (!buffer)
- {
- numProcessedLastGroup = processed;
- return NULL;
- }
- curRow = 0;
- numThisRow = helper.numExpandedRows(buffer);
- }
- try
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- unsigned actualSize = helper.transform(rowBuilder, buffer, ++curRow);
- if (actualSize != 0)
- {
- processed++;
- return rowBuilder.finalizeRowClear(actualSize);
- }
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- }
- };
- class CRoxieServerNormalizeActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerNormalizeActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerNormalizeActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerNormalizeChildActivity : public CRoxieServerActivity
- {
- IHThorNormalizeChildArg &helper;
- unsigned numThisRow;
- unsigned curRow;
- const void *buffer;
- unsigned numProcessedLastGroup;
- INormalizeChildIterator * cursor;
- const void * curChildRow;
- bool advanceInput()
- {
- loop
- {
- ReleaseClearRoxieRow(buffer);
- buffer = input->nextInGroup();
- if (!buffer && (processed == numProcessedLastGroup))
- buffer = input->nextInGroup();
- if (!buffer)
- {
- numProcessedLastGroup = processed;
- return false;
- }
- curChildRow = cursor->first(buffer);
- if (curChildRow)
- {
- curRow = 0;
- return true;
- }
- }
- }
- public:
- CRoxieServerNormalizeChildActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorNormalizeChildArg &)basehelper)
- {
- buffer = NULL;
- cursor = NULL;
- numThisRow = 0;
- curRow = 0;
- numProcessedLastGroup = 0;
- curChildRow = NULL;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- numThisRow = 0;
- curRow = 0;
- numProcessedLastGroup = 0;
- curChildRow = NULL;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- cursor = helper.queryIterator();
- }
- virtual void stop(bool aborting)
- {
- CRoxieServerActivity::stop(aborting);
- }
- virtual void reset()
- {
- cursor = NULL;
- ReleaseClearRoxieRow(buffer);
- CRoxieServerActivity::reset();
- }
- virtual bool needsAllocator() const { return true; }
- const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- loop
- {
- if (!buffer)
- {
- if (!advanceInput())
- return NULL;
- }
- try
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- size32_t outSize = helper.transform(rowBuilder, buffer, curChildRow, ++curRow);
- curChildRow = cursor->next();
- if (!curChildRow)
- ReleaseClearRoxieRow(buffer);
- if (outSize != 0)
- {
- processed++;
- return rowBuilder.finalizeRowClear(outSize);
- }
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- }
- };
- class CRoxieServerNormalizeChildActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerNormalizeChildActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerNormalizeChildActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerNormalizeChildActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerNormalizeChildActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerNormalizeLinkedChildActivity : public CRoxieServerActivity
- {
- IHThorNormalizeLinkedChildArg &helper;
- OwnedConstRoxieRow curParent;
- OwnedConstRoxieRow curChild;
- unsigned numProcessedLastGroup;
- bool advanceInput()
- {
- loop
- {
- curParent.setown(input->nextInGroup());
- if (!curParent && (processed == numProcessedLastGroup))
- curParent.setown(input->nextInGroup());
- if (!curParent)
- {
- numProcessedLastGroup = processed;
- return false;
- }
- curChild.set(helper.first(curParent));
- if (curChild)
- return true;
- }
- }
- public:
- CRoxieServerNormalizeLinkedChildActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorNormalizeLinkedChildArg &)basehelper)
- {
- numProcessedLastGroup = 0;
- }
- ~CRoxieServerNormalizeLinkedChildActivity()
- {
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- numProcessedLastGroup = 0;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- }
- virtual void reset()
- {
- curParent.clear();
- curChild.clear();
- CRoxieServerActivity::reset();
- }
- const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- loop
- {
- if (!curParent)
- {
- if (!advanceInput())
- return NULL;
- }
- try
- {
- const void *ret = curChild.getClear();
- curChild.set(helper.next());
- if (!curChild)
- curParent.clear();
- if (ret)
- {
- processed++;
- return ret;
- }
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- }
- };
- class CRoxieServerNormalizeLinkedChildActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerNormalizeLinkedChildActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerNormalizeLinkedChildActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerNormalizeLinkedChildActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerNormalizeLinkedChildActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- interface ISortAlgorithm : extends IInterface
- {
- virtual void prepare(IRoxieInput *input) = 0;
- virtual const void *next() = 0;
- virtual void reset() = 0;
- };
- class CQuickSortAlgorithm : implements CInterfaceOf<ISortAlgorithm>
- {
- unsigned curIndex;
- ConstPointerArray sorted;
- ICompare *compare;
- public:
- CQuickSortAlgorithm(ICompare *_compare) : compare(_compare)
- {
- curIndex = 0;
- }
- virtual void prepare(IRoxieInput *input)
- {
- curIndex = 0;
- if (input->nextGroup(sorted))
- qsortvec(const_cast<void * *>(sorted.getArray()), sorted.ordinality(), *compare);
- }
- virtual const void *next()
- {
- if (sorted.isItem(curIndex))
- return sorted.item(curIndex++);
- return NULL;
- }
- virtual void reset()
- {
- while (sorted.isItem(curIndex))
- ReleaseRoxieRow(sorted.item(curIndex++));
- curIndex = 0;
- sorted.kill();
- }
- };
- class CSpillingQuickSortAlgorithm : implements CInterfaceOf<ISortAlgorithm>, implements roxiemem::IBufferedRowCallback
- {
- enum {
- InitialSortElements = 0,
- //The number of rows that can be added without entering a critical section, and therefore also the number
- //of rows that might not get freed when memory gets tight.
- CommitStep=32
- };
- roxiemem::DynamicRoxieOutputRowArray rowsToSort;
- roxiemem::RoxieSimpleInputRowArray sorted;
- ICompare *compare;
- IRoxieSlaveContext * ctx;
- Owned<IDiskMerger> diskMerger;
- Owned<IRowStream> diskReader;
- Owned<IOutputMetaData> rowMeta;
- unsigned activityId;
- public:
- CSpillingQuickSortAlgorithm(ICompare *_compare, IRoxieSlaveContext * _ctx, IOutputMetaData * _rowMeta, unsigned _activityId)
- : rowsToSort(&_ctx->queryRowManager(), InitialSortElements, CommitStep, _activityId), ctx(_ctx), compare(_compare), rowMeta(_rowMeta), activityId(_activityId)
- {
- ctx->queryRowManager().addRowBuffer(this);
- }
- ~CSpillingQuickSortAlgorithm()
- {
- ctx->queryRowManager().removeRowBuffer(this);
- diskReader.clear();
- }
- virtual void prepare(IRoxieInput *input)
- {
- loop
- {
- const void * next = input->nextInGroup();
- if (!next)
- break;
- if (!rowsToSort.append(next))
- {
- {
- roxiemem::RoxieOutputRowArrayLock block(rowsToSort);
- //We should have been called back to free any committed rows, but occasionally it may not (e.g., if
- //the problem is global memory is exhausted) - in which case force a spill here (but add any pending
- //rows first).
- if (rowsToSort.numCommitted() != 0)
- {
- rowsToSort.flush();
- spillRows();
- }
- //Ensure new rows are written to the head of the array. It needs to be a separate call because
- //spillRows() cannot shift active row pointer since it can be called from any thread
- rowsToSort.flush();
- }
- if (!rowsToSort.append(next))
- {
- ReleaseRoxieRow(next);
- throw MakeStringException(ROXIEMM_MEMORY_LIMIT_EXCEEDED, "Insufficient memory to append sort row");
- }
- }
- }
- rowsToSort.flush();
- roxiemem::RoxieOutputRowArrayLock block(rowsToSort);
- if (diskMerger)
- {
- spillRows();
- rowsToSort.kill();
- diskReader.setown(diskMerger->merge(compare));
- }
- else
- {
- unsigned numRows = rowsToSort.numCommitted();
- if (numRows)
- {
- const void * * rows = rowsToSort.getBlock(numRows);
- //MORE: Should this be parallel? Should that be dependent on whether it is grouped? Should be a hint.
- qsortvec(const_cast<void * *>(rows), numRows, *compare);
- }
- sorted.transferFrom(rowsToSort);
- }
- }
- virtual const void *next()
- {
- if(diskReader)
- return diskReader->nextRow();
- return sorted.dequeue();
- }
- virtual void reset()
- {
- //MORE: This could transfer any row pointer from sorted back to rowsToSort. It would trade
- //fewer heap allocations with not freeing up the memory from large group sorts.
- rowsToSort.clearRows();
- sorted.kill();
- //Disk reader must be cleared before the merger - or the files may still be locked.
- diskReader.clear();
- diskMerger.clear();
- }
- //interface roxiemem::IBufferedRowCallback
- virtual unsigned getSpillCost() const
- {
- //Spill global sorts before grouped sorts
- if (rowMeta->isGrouped())
- return 20;
- return 10;
- }
- virtual bool freeBufferedRows(bool critical)
- {
- roxiemem::RoxieOutputRowArrayLock block(rowsToSort);
- return spillRows();
- }
- protected:
- bool spillRows()
- {
- unsigned numRows = rowsToSort.numCommitted();
- if (numRows == 0)
- return false;
- const void * * rows = rowsToSort.getBlock(numRows);
- qsortvec(const_cast<void * *>(rows), numRows, *compare);
- Owned<IRowWriter> out = queryMerger()->createWriteBlock();
- for (unsigned i= 0; i < numRows; i++)
- {
- out->putRow(rows[i]);
- }
- rowsToSort.noteSpilled(numRows);
- return true;
- }
- IDiskMerger * queryMerger()
- {
- if (!diskMerger)
- {
- unsigned __int64 seq = (memsize_t)this ^ get_cycles_now();
- StringBuffer spillBasename;
- spillBasename.append(tempDirectory).append(PATHSEPCHAR).appendf("spill_sort_%"I64F"u", seq);
- Owned<IRowLinkCounter> linker = new RoxieRowLinkCounter();
- Owned<IRowInterfaces> rowInterfaces = createRowInterfaces(rowMeta, activityId, ctx->queryCodeContext());
- diskMerger.setown(createDiskMerger(rowInterfaces, linker, spillBasename));
- }
- return diskMerger;
- }
- };
- #define INSERTION_SORT_BLOCKSIZE 1024
- class SortedBlock : public CInterface, implements IInterface
- {
- unsigned sequence;
- const void **rows;
- unsigned length;
- unsigned pos;
- SortedBlock(const SortedBlock &);
- public:
- IMPLEMENT_IINTERFACE;
- SortedBlock(unsigned _sequence, IRowManager *rowManager, unsigned activityId) : sequence(_sequence)
- {
- rows = (const void **) rowManager->allocate(INSERTION_SORT_BLOCKSIZE * sizeof(void *), activityId);
- length = 0;
- pos = 0;
- }
- ~SortedBlock()
- {
- while (pos < length)
- ReleaseRoxieRow(rows[pos++]);
- ReleaseRoxieRow(rows);
- }
- int compareTo(SortedBlock *r, ICompare *compare)
- {
- int rc = compare->docompare(rows[pos], r->rows[r->pos]);
- if (!rc)
- rc = sequence - r->sequence;
- return rc;
- }
- const void *next()
- {
- if (pos < length)
- return rows[pos++];
- else
- return NULL;
- }
- inline bool eof()
- {
- return pos==length;
- }
- bool insert(const void *next, ICompare *_compare )
- {
- unsigned b = length;
- if (b == INSERTION_SORT_BLOCKSIZE)
- return false;
- else if (b < 7)
- {
- while (b)
- {
- if (_compare->docompare(next, rows[b-1]) >= 0)
- break;
- b--;
- }
- if (b != length)
- memmove(&rows[b+1], &rows[b], (length - b) * sizeof(void *));
- rows[b] = next;
- length++;
- return true;
- }
- else
- {
- unsigned int a = 0;
- while ((int)a<b)
- {
- int i = (a+b)/2;
- int rc = _compare->docompare(next, rows[i]);
- if (rc>=0)
- a = i+1;
- else
- b = i;
- }
- if (a != length)
- memmove(&rows[a+1], &rows[a], (length - a) * sizeof(void *));
- rows[a] = next;
- length++;
- return true;
- }
- }
- };
- class CInsertionSortAlgorithm : implements CInterfaceOf<ISortAlgorithm>
- {
- SortedBlock *curBlock;
- unsigned blockNo;
- IArrayOf<SortedBlock> blocks;
- unsigned activityId;
- IRowManager *rowManager;
- ICompare *compare;
- void newBlock()
- {
- blocks.append(*curBlock);
- curBlock = new SortedBlock(blockNo++, rowManager, activityId);
- }
- inline static int doCompare(SortedBlock &l, SortedBlock &r, ICompare *compare)
- {
- return l.compareTo(&r, compare);
- }
- void makeHeap()
- {
- /* Permute blocks to establish the heap property
- For each element p, the children are p*2+1 and p*2+2 (provided these are in range)
- The children of p must both be greater than or equal to p
- The parent of a child c is given by p = (c-1)/2
- */
- unsigned i;
- unsigned n = blocks.length();
- SortedBlock **s = blocks.getArray();
- for (i=1; i<n; i++)
- {
- SortedBlock * r = s[i];
- int c = i; /* child */
- while (c > 0)
- {
- int p = (c-1)/2; /* parent */
- if ( doCompare( blocks.item(c), blocks.item(p), compare ) >= 0 )
- break;
- s[c] = s[p];
- s[p] = r;
- c = p;
- }
- }
- }
- void remakeHeap()
- {
- /* The row associated with block[0] will have changed
- This code restores the heap property
- */
- unsigned p = 0; /* parent */
- unsigned n = blocks.length();
- SortedBlock **s = blocks.getArray();
- while (1)
- {
- unsigned c = p*2 + 1; /* child */
- if ( c >= n )
- break;
- /* Select smaller child */
- if ( c+1 < n && doCompare( blocks.item(c+1), blocks.item(c), compare ) < 0 ) c += 1;
- /* If child is greater or equal than parent then we are done */
- if ( doCompare( blocks.item(c), blocks.item(p), compare ) >= 0 )
- break;
- /* Swap parent and child */
- SortedBlock *r = s[c];
- s[c] = s[p];
- s[p] = r;
- /* child becomes parent */
- p = c;
- }
- }
- public:
- CInsertionSortAlgorithm(ICompare *_compare, IRowManager *_rowManager, unsigned _activityId)
- : compare(_compare)
- {
- rowManager = _rowManager;
- activityId = _activityId;
- curBlock = NULL;
- blockNo = 0;
- }
- virtual void reset()
- {
- blocks.kill();
- delete curBlock;
- curBlock = NULL;
- blockNo = 0;
- }
- virtual void prepare(IRoxieInput *input)
- {
- blockNo = 0;
- curBlock = new SortedBlock(blockNo++, rowManager, activityId);
- loop
- {
- const void *next = input->nextInGroup();
- if (!next)
- break;
- if (!curBlock->insert(next, compare))
- {
- newBlock();
- curBlock->insert(next, compare);
- }
- }
- if (blockNo > 1)
- {
- blocks.append(*curBlock);
- curBlock = NULL;
- makeHeap();
- }
- }
- virtual const void * next()
- {
- const void *ret;
- if (blockNo==1) // single block case..
- {
- ret = curBlock->next();
- }
- else if (blocks.length())
- {
- SortedBlock &top = blocks.item(0);
- ret = top.next();
- if (top.eof())
- blocks.replace(blocks.popGet(), 0);
- remakeHeap();
- }
- else
- ret = NULL;
- return ret;
- }
- };
- class CHeapSortAlgorithm : implements CInterfaceOf<ISortAlgorithm>
- {
- unsigned curIndex;
- ConstPointerArray sorted;
- bool inputAlreadySorted;
- IntArray sequences;
- bool eof;
- ICompare *compare;
- #ifdef _CHECK_HEAPSORT
- void checkHeap() const
- {
- unsigned n = sorted.ordinality();
- if (n)
- {
- ICompare *_compare = compare;
- void **s = sorted.getArray();
- int *sq = sequences.getArray();
- unsigned p;
- #if 0
- CTXLOG("------------------------%d entries-----------------", n);
- for (p = 0; p < n; p++)
- {
- CTXLOG("HEAP %d: %d %.10s", p, sq[p], s[p] ? s[p] : "..");
- }
- #endif
- for (p = 0; p < n; p++)
- {
- unsigned c = p*2+1;
- if (c<n)
- assertex(!s[c] || (docompare(p, c, _compare, s, sq) <= 0));
- c++;
- if (c<n)
- assertex(!s[c] || (docompare(p, c, _compare, s, sq) <= 0));
- }
- }
- }
- #else
- inline void checkHeap() const {}
- #endif
- const void *removeHeap()
- {
- unsigned n = sorted.ordinality();
- if (n)
- {
- const void *ret = sorted.item(0);
- if (n > 1 && ret)
- {
- ICompare *_compare = compare;
- const void **s = sorted.getArray();
- int *sq = sequences.getArray();
- unsigned v = 0; // vacancy
- loop
- {
- unsigned c = 2*v + 1;
- if (c < n)
- {
- unsigned f = c; // favourite to fill it
- c++;
- if (c < n && s[c] && (!s[f] || (docompare(f, c, _compare, s, sq) > 0))) // is the smaller of the children
- f = c;
- sq[v] = sq[f];
- if ((s[v] = s[f]) != NULL)
- v = f;
- else
- break;
- }
- else
- {
- s[v] = NULL;
- break;
- }
- }
- }
- checkHeap();
- return ret;
- }
- else
- return NULL;
- }
- static inline int docompare(unsigned l, unsigned r, ICompare *_compare, const void **s, int *sq)
- {
- int rc = _compare->docompare(s[l], s[r]);
- if (!rc)
- rc = sq[l] - sq[r];
- return rc;
- }
- void insertHeap(const void *next)
- {
- // Upside-down heap sort
- // Maintain a heap where every parent is lower than each of its children
- // Root (at node 0) is lowest record seen, nodes 2n+1, 2n+2 are the children
- // To insert a row, add it at end then keep swapping with parent as long as parent is greater
- // To remove a row, take row 0, then recreate heap by replacing it with smaller of two children and so on down the tree
- // Nice features:
- // 1. Deterministic
- // 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
- // 3. Already sorted case can be spotted at zero cost while reading.
- // 4. If you don't read all the results, you don't have to complete the sort
- // BUT it is NOT stable, so we have to use a parallel array of sequence numbers
- unsigned n = sorted.ordinality();
- sorted.append(next);
- sequences.append(n);
- if (!n)
- return;
- ICompare *_compare = compare;
- const void **s = sorted.getArray();
- if (inputAlreadySorted)
- {
- if (_compare->docompare(next, s[n-1]) >= 0)
- return;
- else
- {
- // MORE - could delay creating sequences until now...
- inputAlreadySorted = false;
- }
- }
- int *sq = sequences.getArray();
- unsigned q = n;
- while (n)
- {
- unsigned parent = (n-1) / 2;
- const void *p = s[parent];
- if (_compare->docompare(p, next) <= 0)
- break;
- s[n] = p;
- sq[n] = sq[parent];
- s[parent] = next;
- sq[parent] = q;
- n = parent;
- }
- }
- public:
- CHeapSortAlgorithm(ICompare *_compare) : compare(_compare)
- {
- inputAlreadySorted = true;
- curIndex = 0;
- eof = false;
- }
- virtual void reset()
- {
- eof = false;
- if (inputAlreadySorted)
- {
- while (sorted.isItem(curIndex))
- ReleaseRoxieRow(sorted.item(curIndex++));
- sorted.kill();
- }
- else
- {
- ReleaseRoxieRowSet(sorted);
- }
- inputAlreadySorted = true;
- sequences.kill();
- }
- virtual void prepare(IRoxieInput *input)
- {
- inputAlreadySorted = true;
- curIndex = 0;
- eof = false;
- assertex(sorted.ordinality()==0);
- const void *next = input->nextInGroup();
- if (!next)
- {
- eof = true;
- return;
- }
- loop
- {
- insertHeap(next);
- next = input->nextInGroup();
- if (!next)
- break;
- }
- checkHeap();
- }
- virtual const void * next()
- {
- if (inputAlreadySorted)
- {
- if (sorted.isItem(curIndex))
- {
- return sorted.item(curIndex++);
- }
- else
- return NULL;
- }
- else
- return removeHeap();
- }
- };
- typedef enum {heapSort, insertionSort, quickSort, spillingQuickSort, unknownSort } RoxieSortAlgorithm;
- class CRoxieServerSortActivity : public CRoxieServerActivity
- {
- protected:
- IHThorSortArg &helper;
- ICompare *compare;
- Owned<ISortAlgorithm> sorter;
- bool readInput;
- RoxieSortAlgorithm sortAlgorithm;
- unsigned sortFlags;
- public:
- CRoxieServerSortActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, RoxieSortAlgorithm _sortAlgorithm, unsigned _sortFlags)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorSortArg &)basehelper), sortAlgorithm(_sortAlgorithm), sortFlags(_sortFlags)
- {
- compare = helper.queryCompare();
- readInput = false;
- }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerActivity::onCreate(_ctx, _colocalParent);
- switch (sortAlgorithm)
- {
- case heapSort:
- sorter.setown(new CHeapSortAlgorithm(compare));
- break;
- case insertionSort:
- sorter.setown(new CInsertionSortAlgorithm(compare, &ctx->queryRowManager(), activityId));
- break;
- case quickSort:
- sorter.setown(new CQuickSortAlgorithm(compare));
- break;
- case spillingQuickSort:
- sorter.setown(new CSpillingQuickSortAlgorithm(compare, ctx, meta, activityId));
- break;
- case unknownSort:
- sorter.clear(); // create it later....
- break;
- default:
- throwUnexpected();
- break;
- }
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- assertex(!readInput);
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- }
- virtual void reset()
- {
- if (sorter)
- sorter->reset();
- readInput = false;
- CRoxieServerActivity::reset();
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (!readInput)
- {
- if (sortAlgorithm == unknownSort)
- {
- sorter.clear();
- IHThorAlgorithm *sortMethod = static_cast<IHThorAlgorithm *>(helper.selectInterface(TAIalgorithm_1));
- OwnedRoxieString useAlgorithm(sortMethod->getAlgorithm());
- if (useAlgorithm)
- {
- if (stricmp(useAlgorithm, "quicksort")==0)
- {
- if (sortFlags & TAFstable)
- throw MakeStringException(ROXIE_UNKNOWN_ALGORITHM, "Invalid stable sort algorithm %s requested", useAlgorithm.get());
- sorter.setown(new CQuickSortAlgorithm(compare));
- }
- else if (stricmp(useAlgorithm, "heapsort")==0)
- sorter.setown(new CHeapSortAlgorithm(compare));
- else if (stricmp(useAlgorithm, "insertionsort")==0)
- sorter.setown(new CInsertionSortAlgorithm(compare, &ctx->queryRowManager(), activityId));
- else
- {
- WARNLOG(ROXIE_UNKNOWN_ALGORITHM, "Ignoring unsupported sort order algorithm '%s', using default", useAlgorithm.get());
- if (sortFlags & TAFunstable)
- sorter.setown(new CQuickSortAlgorithm(compare));
- else
- sorter.setown(new CHeapSortAlgorithm(compare));
- }
- }
- else
- 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...
- }
- sorter->prepare(input);
- readInput = true;
- }
- const void *ret = sorter->next();
- if (ret)
- processed++;
- else
- {
- sorter->reset();
- readInput = false; // ready for next group
- }
- return ret;
- }
- };
- class CRoxieServerSortActivityFactory : public CRoxieServerActivityFactory
- {
- RoxieSortAlgorithm sortAlgorithm;
- unsigned sortFlags;
- public:
- CRoxieServerSortActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- sortAlgorithm = heapSort;
- sortFlags = TAFstable;
- Owned<IHThorSortArg> sortHelper = (IHThorSortArg *) helperFactory();
- IHThorAlgorithm *sortMethod = static_cast<IHThorAlgorithm *>(sortHelper->selectInterface(TAIalgorithm_1));
- if (sortMethod)
- {
- sortFlags = sortMethod->getAlgorithmFlags();
- if (sortFlags & TAFunstable)
- sortAlgorithm = quickSort;
- if (!(sortFlags & TAFconstant))
- sortAlgorithm = unknownSort;
- else
- {
- OwnedRoxieString useAlgorithm(sortMethod->getAlgorithm());
- if (useAlgorithm)
- {
- if (stricmp(useAlgorithm, "quicksort")==0)
- {
- if (sortFlags & TAFstable)
- throw MakeStringException(ROXIE_UNKNOWN_ALGORITHM, "Invalid stable sort algorithm %s requested", useAlgorithm.get());
- sortAlgorithm = quickSort;
- }
- else if (stricmp(useAlgorithm, "spillingquicksort")==0)
- {
- if (sortFlags & TAFstable)
- throw MakeStringException(ROXIE_UNKNOWN_ALGORITHM, "Invalid stable sort algorithm %s requested", useAlgorithm.get());
- sortAlgorithm = spillingQuickSort;
- }
- else if (stricmp(useAlgorithm, "heapsort")==0)
- sortAlgorithm = heapSort; // NOTE - we do allow UNSTABLE('heapsort') in order to facilitate runtime selection
- else if (stricmp(useAlgorithm, "insertionsort")==0)
- sortAlgorithm = insertionSort;
- else
- {
- WARNLOG(ROXIE_UNKNOWN_ALGORITHM, "Ignoring unsupported sort order algorithm '%s', using default", useAlgorithm.get());
- if (sortFlags & TAFunstable)
- sortAlgorithm = quickSort;
- else
- sortAlgorithm = heapSort;
- }
- }
- }
- }
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerSortActivity(this, _probeManager, sortAlgorithm, sortFlags);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerSortActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerSortActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=====================================================================================================
- class CRoxieServerSortedActivity : public CRoxieServerActivity
- {
- IHThorSortedArg &helper;
- ICompare * compare;
- const void *prev;
- IRangeCompare * stepCompare;
- public:
- CRoxieServerSortedActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorSortedArg &)basehelper)
- {
- prev = NULL;
- compare = helper.queryCompare();
- stepCompare = NULL;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- IInputSteppingMeta * stepMeta = input->querySteppingMeta();
- if (stepMeta)
- stepCompare = stepMeta->queryCompare();
- prev = NULL;
- }
- virtual void reset()
- {
- ReleaseClearRoxieRow(prev);
- CRoxieServerActivity::reset();
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- const void *ret = input->nextInGroup();
- if (ret && prev && compare->docompare(prev, ret) > 0)
- {
- // MORE - better to give mismatching rows that indexes?
- throw MakeStringException(ROXIE_NOT_SORTED, "SORTED(%u) detected incorrectly sorted rows (row %d, %d))", activityId, processed, processed+1);
- }
- ReleaseRoxieRow(prev);
- prev = ret;
- if (ret)
- {
- LinkRoxieRow(prev);
- processed++;
- }
- return ret;
- }
- virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- const void *ret = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
- if (ret && prev && compare->docompare(prev, ret) > 0)
- {
- // MORE - better to give mismatching rows that indexes?
- throw MakeStringException(ROXIE_NOT_SORTED, "SORTED(%u) detected incorrectly sorted rows (row %d, %d))", activityId, processed, processed+1);
- }
- ReleaseRoxieRow(prev);
- prev = ret;
- if (ret)
- {
- LinkRoxieRow(prev);
- processed++;
- }
- return ret;
- }
- IInputSteppingMeta * querySteppingMeta()
- {
- return input->querySteppingMeta();
- }
- virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
- {
- return input->gatherConjunctions(collector);
- }
- virtual void resetEOF()
- {
- input->resetEOF();
- }
- };
- class CRoxieServerSortedActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerSortedActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerSortedActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerSortedActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerSortedActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=====================================================================================================
- class CRoxieServerThroughSpillActivity : public CRoxieServerActivity
- {
- /*
- BE VERY CAREFUL - this code is tricky.
- Note that starts and stops (and resets) can occur in strange orders
- The FIRST start OR stop must initialize the activity but only the first START should call the upstream start.
- The last stop should call the upstream stop.
- The first reset should call the upstream reset.
- 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
- not yet had start or stop called - for this to happen init() is called on all outputs on the first start or stop.
- Some outputs may be completely pruned away when used in a GRAPH - these outputs should not receive any start/stop/reset and should be
- ignored in the minIndex calculation
- */
- public:
- IHThorArg &helper;
- unsigned activeOutputs;
- unsigned numOutputs;
- unsigned numOriginalOutputs;
- QueueOf<const void, true> buffer;
- CriticalSection crit;
- CriticalSection crit2;
- unsigned tailIdx;
- unsigned headIdx;
- Owned<IException> error;
- class OutputAdaptor : public CInterface, implements IRoxieInput
- {
- bool eof, eofpending, stopped;
- public:
- CRoxieServerThroughSpillActivity *parent;
- unsigned idx;
- unsigned oid;
- unsigned processed;
- unsigned __int64 totalCycles;
- public:
- IMPLEMENT_IINTERFACE;
- OutputAdaptor()
- {
- parent = NULL;
- oid = 0;
- idx = 0;
- processed = 0;
- totalCycles = 0;
- eofpending = false;
- eof = false;
- stopped = false;
- }
- ~OutputAdaptor()
- {
- if (traceStartStop)
- DBGLOG("%p ~OutputAdaptor %d", this, oid);
- }
- void init()
- {
- if (traceStartStop)
- DBGLOG("%p init Input adaptor %d", this, oid);
- idx = 0;
- processed = 0;
- totalCycles = 0;
- eofpending = false;
- eof = false;
- stopped = false;
- }
- virtual unsigned queryId() const
- {
- return parent->queryId();
- }
- virtual IRoxieServerActivity *queryActivity()
- {
- return parent;
- }
- virtual IIndexReadActivityInfo *queryIndexReadActivity()
- {
- return parent->queryIndexReadActivity();
- }
-
- virtual unsigned __int64 queryTotalCycles() const
- {
- return totalCycles;
- }
- virtual unsigned __int64 queryLocalCycles() const
- {
- return 0;
- }
- virtual IRoxieInput *queryInput(unsigned idx) const
- {
- return parent->queryInput(idx);
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, parent->timeActivities, parent->ctx->queryDebugContext());
- if (eof)
- return NULL;
- const void *ret = parent->readBuffered(idx, oid);
- #ifdef TRACE_SPLIT
- parent->CTXLOG("Adaptor %d got back %p for record %d", oid, ret, idx);
- #endif
- idx++;
- if (ret)
- {
- processed++;
- eofpending = false;
- }
- else if (eofpending)
- eof = true;
- else
- eofpending = true;
- return ret;
- }
- virtual IOutputMetaData * queryOutputMeta() const
- {
- return parent->queryOutputMeta();
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- // NOTE: it is tempting to move the init() of all output adaptors here. However that is not a good idea,
- // since adaptors that have not yet started or stopped (but are going to) still need to have been init()'ed
- // for minIndex to give the correct answers
- // therefore, we call init() on all adaptors on receipt of the first start() or stop()
- if (traceStartStop)
- parent->CTXLOG("%p start Input adaptor %d stopped = %d", this, oid, stopped);
- parent->start(oid, parentExtractSize, parentExtract, paused);
- }
- virtual void stop(bool aborting)
- {
- if (traceStartStop)
- parent->CTXLOG("%p stop Input adaptor %d stopped = %d", this, oid, stopped);
- if (!stopped)
- {
- parent->stop(oid, idx, aborting); // NOTE - may call init()
- stopped = true; // parent code relies on stop being called exactly once per adaptor, so make sure it is!
- idx = (unsigned) -1; // causes minIndex not to save rows for me...
- }
- };
- virtual void reset()
- {
- if (traceStartStop)
- parent->CTXLOG("%p reset Input adaptor %d stopped = %d", this, oid, stopped);
- parent->reset(oid);
- parent->noteProcessed(oid, processed, 0, 0);
- processed = 0;
- idx = 0; // value should not be relevant really but this is the safest...
- stopped = false;
- };
- virtual void resetEOF()
- {
- parent->resetEOF();
- }
- virtual void checkAbort()
- {
- parent->checkAbort();
- }
- } *adaptors;
- bool *used;
- unsigned nextFreeOutput()
- {
- unsigned i = numOutputs;
- while (i)
- {
- i--;
- if (!used[i])
- return i;
- }
- throwUnexpected();
- }
- unsigned minIndex(unsigned exceptOid)
- {
- // MORE - yukky code (and slow). Could keep them heapsorted by idx or something
- // this is trying to determine whethwe any of the adaptors will in the future read a given record
- unsigned minIdx = (unsigned) -1;
- for (unsigned i = 0; i < numOutputs; i++)
- {
- if (i != exceptOid && used[i] && adaptors[i].idx < minIdx)
- minIdx = adaptors[i].idx;
- }
- return minIdx;
- }
- void initOutputs()
- {
- activeOutputs = numOutputs;
- for (unsigned i = 0; i < numOriginalOutputs; i++)
- if (used[i])
- adaptors[i].init();
- state = STATEstarting;
- }
- public:
- CRoxieServerThroughSpillActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numOutputs)
- : CRoxieServerActivity(_factory, _probeManager), helper(basehelper), numOutputs(_numOutputs)
- {
- numOriginalOutputs = numOutputs;
- adaptors = new OutputAdaptor[numOutputs];
- used = new bool[numOutputs];
- for (unsigned i = 0; i < numOutputs; i++)
- {
- adaptors[i].parent = this;
- adaptors[i].oid = i;
- used[i] = false;
- }
- tailIdx = 0;
- headIdx = 0;
- activeOutputs = numOutputs;
- }
- ~CRoxieServerThroughSpillActivity()
- {
- delete [] adaptors;
- delete [] used;
- }
- const void *readBuffered(unsigned idx, unsigned oid)
- {
- CriticalBlock b(crit);
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext()); // NOTE - time spent waiting for crit not included here. Is that right?
- if (idx == headIdx) // test once without getting the crit2 sec
- {
- CriticalUnblock b1(crit);
- CriticalBlock b2(crit2);
- if (error)
- {
- throw error.getLink();
- }
- if (idx == headIdx) // test again now that we have it
- {
- try
- {
- const void *row = input->nextInGroup();
- CriticalBlock b3(crit);
- headIdx++;
- if (activeOutputs==1)
- {
- #ifdef TRACE_SPLIT
- CTXLOG("spill %d optimised return of %p", activityId, row);
- #endif
- return row; // optimization for the case where only one output still active.
- }
- buffer.enqueue(row);
- }
- catch (IException *E)
- {
- #ifdef TRACE_SPLIT
- CTXLOG("spill %d caught exception", activityId);
- #endif
- error.set(E);
- throw;
- }
- catch (...)
- {
- IException *E = MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught in CRoxieServerThroughSpillActivity::readBuffered");
- error.set(E);
- throw E;
- }
- }
- }
- idx -= tailIdx;
- if (!idx)
- {
- unsigned min = minIndex(oid);
- if (min > tailIdx)
- {
- tailIdx++;
- const void *ret = buffer.dequeue(); // no need to link - last puller
- #ifdef TRACE_SPLIT
- CTXLOG("last puller return of %p", ret);
- #endif
- return ret;
- }
- }
- const void *ret = buffer.item(idx);
- if (ret) LinkRoxieRow(ret);
- #ifdef TRACE_SPLIT
- CTXLOG("standard return of %p", ret);
- #endif
- return ret;
- }
- virtual void start(unsigned oid, unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CriticalBlock b(crit);
- if (error)
- throw error.getLink();
- if (factory)
- factory->noteStarted(oid);
- if (traceStartStop)
- CTXLOG("SPLIT %p: start %d child %d activeOutputs %d numOutputs %d numOriginalOutputs %d state %s", this, activityId, oid, activeOutputs, numOutputs, numOriginalOutputs, queryStateText(state));
- if (state != STATEstarted)
- {
- if (state != STATEstarting)
- initOutputs();
- tailIdx = 0;
- headIdx = 0;
- error.clear();
- try
- {
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- }
- catch (IException *E)
- {
- #ifdef TRACE_SPLIT
- CTXLOG("spill %d caught exception in start", activityId);
- #endif
- error.set(E);
- throw;
- }
- catch (...)
- {
- IException *E = MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught in CRoxieServerThroughSpillActivity::start");
- error.set(E);
- throw E;
- }
- }
- }
- void stop(unsigned oid, unsigned idx, bool aborting)
- {
- // Note that OutputAdaptor code ensures that stop is not called more than once per adaptor
- CriticalBlock b(crit);
- #ifdef TRACE_STARTSTOP
- if (traceStartStop)
- {
- CTXLOG("SPLIT %p: stop %d child %d activeOutputs %d numOutputs %d numOriginalOutputs %d state %s", this, activityId, oid, activeOutputs, numOutputs, numOriginalOutputs, queryStateText(state));
- if (watchActivityId && watchActivityId==activityId)
- {
- CTXLOG("WATCH: stop %d", activityId);
- }
- }
- #endif
- if (state != STATEstarting && state != STATEstarted)
- initOutputs();
- if (activeOutputs > 1)
- {
- if (tailIdx==idx)
- {
- // Discard all buffered rows that are there purely for this adaptor to read them
- unsigned min = minIndex(oid);
- if (min != (unsigned) -1)
- // what does -1 signify?? No-one wants anything? In which case can't we kill all rows??
- // Should never happen though if there are still some active.
- // there may be a small window where adaptors are blocked on the semaphore...
- {
- #ifdef TRACE_SPLIT
- CTXLOG("%p: Discarding buffered rows from %d to %d for oid %x (%d outputs active)", this, idx, min, oid, activeOutputs);
- #endif
- while (tailIdx < min)
- {
- ReleaseRoxieRow(buffer.dequeue());
- tailIdx++;
- }
- }
- }
- activeOutputs--;
- return;
- }
- #ifdef TRACE_SPLIT
- CTXLOG("%p: All outputs done", this);
- #endif
- activeOutputs = numOutputs;
- CRoxieServerActivity::stop(aborting);
- };
- void reset(unsigned oid)
- {
- if (traceStartStop)
- CTXLOG("SPLIT %p: reset %d child %d activeOutputs %d numOutputs %d numOriginalOutputs %d state %s", this, activityId, oid, activeOutputs, numOutputs, numOriginalOutputs, queryStateText(state));
- activeOutputs = numOutputs;
- while (buffer.ordinality())
- ReleaseRoxieRow(buffer.dequeue());
- error.clear();
- if (state != STATEreset) // make sure input is only reset once
- CRoxieServerActivity::reset();
- };
- virtual unsigned __int64 queryLocalCycles() const
- {
- return 0;
- }
- virtual const void *nextInGroup()
- {
- throwUnexpected(); // Internal logic error - we are not anybody's input
- }
- virtual IOutputMetaData * queryOutputMeta() const
- {
- // if (outputMeta)
- // return outputMeta;
- // else
- return input->queryOutputMeta(); // not always known (e.g. disk write - though Gavin _could_ fill it in)
- }
- virtual IRoxieInput *queryOutput(unsigned idx)
- {
- if (idx==(unsigned)-1)
- idx = nextFreeOutput(); // MORE - what is this used for?
- assertex(idx < numOriginalOutputs);
- assertex(!used[idx]);
- used[idx] = true;
- return &adaptors[idx];
- }
- virtual void resetOutputsUsed()
- {
- numOutputs = 1;
- activeOutputs = 1;
- // MORE RKC->GH should we be clearing the used array here? anywhere?
- }
- virtual void noteOutputUsed()
- {
- assertex(numOutputs < numOriginalOutputs);
- numOutputs++;
- activeOutputs = numOutputs;
- }
- virtual bool isPassThrough()
- {
- return numOutputs==1;
- }
- };
- class CRoxieServerThroughSpillActivityFactory : public CRoxieServerMultiOutputFactory
- {
- public:
- CRoxieServerThroughSpillActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerMultiOutputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- Owned<IHThorSpillArg> helper = (IHThorSpillArg *) helperFactory();
- setNumOutputs(helper->getTempUsageCount() + 1);
- }
- CRoxieServerThroughSpillActivityFactory(IQueryFactory &_queryFactory, HelperFactory *_helperFactory, unsigned _numOutputs)
- : CRoxieServerMultiOutputFactory(0, 0, _queryFactory, _helperFactory, TAKsplit)
- {
- setNumOutputs(_numOutputs);
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerThroughSpillActivity(this, _probeManager, numOutputs);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerThroughSpillActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerThroughSpillActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- IRoxieServerActivityFactory *createRoxieServerThroughSpillActivityFactory(IQueryFactory &_queryFactory, HelperFactory *_factory, unsigned _numOutputs)
- {
- return new CRoxieServerThroughSpillActivityFactory(_queryFactory, _factory, _numOutputs);
- }
- //----------------------------------------------------------------------------------------------
- class CRoxieServerSplitActivityFactory : public CRoxieServerMultiOutputFactory
- {
- public:
- CRoxieServerSplitActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerMultiOutputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- Owned<IHThorSplitArg> helper = (IHThorSplitArg *) helperFactory();
- setNumOutputs(helper->numBranches());
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerThroughSpillActivity(this, _probeManager, numOutputs);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerSplitActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerSplitActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=====================================================================================================
- #define PIPE_BUFSIZE 0x8000
- static IException *createPipeFailureException(const char *cmd, unsigned retcode, IPipeProcess *pipe)
- {
- StringBuffer msg;
- if(pipe->hasError())
- {
- try
- {
- char error[512];
- size32_t sz = pipe->readError(sizeof(error), error);
- if(sz && sz!=(size32_t)-1)
- msg.append(", stderr: '").append(sz, error).append("'");
- }
- catch (IException *e)
- {
- EXCLOG(e, "Error reading pipe stderr");
- e->Release();
- }
- }
- return MakeStringException(ROXIE_PIPE_ERROR, "Pipe process %s returned error %u%s", cmd, retcode, msg.str());
- }
- class CRoxieServerPipeReadActivity : public CRoxieServerActivity
- {
- IHThorPipeReadArg &helper;
- Owned<IPipeProcess> pipe;
- StringAttr pipeCommand;
- Owned<IOutputRowDeserializer> rowDeserializer;
- Owned<IReadRowStream> readTransformer;
- bool groupSignalled;
- public:
- CRoxieServerPipeReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorPipeReadArg &)basehelper)
- {
- groupSignalled = true;
- }
- virtual bool needsAllocator() const { return true; }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerActivity::onCreate(_ctx, _colocalParent);
- rowDeserializer.setown(rowAllocator->createDiskDeserializer(ctx->queryCodeContext()));
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- groupSignalled = true; // i.e. don't start with a NULL row
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- if (!readTransformer)
- {
- OwnedRoxieString xmlIteratorPath(helper.getXmlIteratorPath());
- readTransformer.setown(createReadRowStream(rowAllocator, rowDeserializer, helper.queryXmlTransformer(), helper.queryCsvTransformer(), xmlIteratorPath, helper.getPipeFlags()));
- }
- OwnedRoxieString pipeProgram(helper.getPipeProgram());
- openPipe(pipeProgram);
- }
- virtual void stop(bool aborting)
- {
- CRoxieServerActivity::stop(aborting);
- pipe.clear();
- readTransformer->setStream(NULL);
- }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- while (!waitForPipe())
- {
- if (!pipe)
- return NULL;
- if (helper.getPipeFlags() & TPFgroupeachrow)
- {
- if (!groupSignalled)
- {
- groupSignalled = true;
- return NULL;
- }
- }
- }
- const void *ret = readTransformer->next();
- assertex(ret != NULL); // if ret can ever be NULL then we need to recode this logic
- processed++;
- groupSignalled = false;
- return ret;
- }
- protected:
- bool waitForPipe()
- {
- if (!pipe)
- return false; // done
- if (!readTransformer->eos())
- return true;
- verifyPipe();
- return false;
- }
- void openPipe(char const * cmd)
- {
- pipeCommand.setown(cmd);
- pipe.setown(createPipeProcess());
- if(!pipe->run(NULL, cmd, ".", false, true, true, 0x10000))
- throw MakeStringException(ROXIE_PIPE_ERROR, "Could not run pipe process %s", cmd);
- Owned<ISimpleReadStream> pipeReader = pipe->getOutputStream();
- readTransformer->setStream(pipeReader.get());
- }
- void verifyPipe()
- {
- if (pipe)
- {
- unsigned err = pipe->wait();
- if(err && !(helper.getPipeFlags() & TPFnofail))
- {
- throw createPipeFailureException(pipeCommand.get(), err, pipe);
- }
- pipe.clear();
- }
- }
- };
- class CRoxieServerPipeThroughActivity : public CRoxieServerActivity, implements IRecordPullerCallback
- {
- IHThorPipeThroughArg &helper;
- RecordPullerThread puller;
- Owned<IPipeProcess> pipe;
- StringAttr pipeCommand;
- InterruptableSemaphore pipeVerified;
- InterruptableSemaphore pipeOpened;
- CachedOutputMetaData inputMeta;
- Owned<IOutputRowSerializer> rowSerializer;
- Owned<IOutputRowDeserializer> rowDeserializer;
- Owned<IPipeWriteXformHelper> writeTransformer;
- Owned<IReadRowStream> readTransformer;
- bool firstRead;
- bool recreate;
- bool inputExhausted;
- bool groupSignalled;
- public:
- CRoxieServerPipeThroughActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorPipeThroughArg &)basehelper), puller(false)
- {
- recreate = helper.recreateEachRow();
- groupSignalled = true;
- firstRead = false;
- inputExhausted = false;
- }
- virtual bool needsAllocator() const { return true; }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerActivity::onCreate(_ctx, _colocalParent);
- rowSerializer.setown(inputMeta.createDiskSerializer(ctx->queryCodeContext(), activityId));
- rowDeserializer.setown(rowAllocator->createDiskDeserializer(ctx->queryCodeContext()));
- writeTransformer.setown(createPipeWriteXformHelper(helper.getPipeFlags(), helper.queryXmlOutput(), helper.queryCsvOutput(), rowSerializer));
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- firstRead = true;
- inputExhausted = false;
- groupSignalled = true; // i.e. don't start with a NULL row
- pipeVerified.reinit();
- pipeOpened.reinit();
- writeTransformer->ready();
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- if (!readTransformer)
- {
- OwnedRoxieString xmlIterator(helper.getXmlIteratorPath());
- readTransformer.setown(createReadRowStream(rowAllocator, rowDeserializer, helper.queryXmlTransformer(), helper.queryCsvTransformer(), xmlIterator, helper.getPipeFlags()));
- }
- if(!recreate)
- {
- OwnedRoxieString pipeProgram(helper.getPipeProgram());
- openPipe(pipeProgram);
- }
- puller.start(parentExtractSize, parentExtract, paused, 0, false, ctx); // Pipe does not support preload presently - locks up
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- if (idx)
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
- puller.setInput(this, _in);
- inputMeta.set(_in->queryOutputMeta());
- }
- virtual void stop(bool aborting)
- {
- pipeVerified.interrupt(NULL);
- pipeOpened.interrupt(NULL);
- puller.stop(aborting);
- CRoxieServerActivity::stop(aborting);
- pipe.clear();
- readTransformer->setStream(NULL);
- }
- virtual void reset()
- {
- puller.reset();
- CRoxieServerActivity::reset();
- }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- while (!waitForPipe())
- {
- if (!pipe)
- return NULL;
- if (helper.getPipeFlags() & TPFgroupeachrow)
- {
- if (!groupSignalled)
- {
- groupSignalled = true;
- return NULL;
- }
- }
- }
- const void *ret = readTransformer->next();
- assertex(ret != NULL); // if ret can ever be NULL then we need to recode this logic
- processed++;
- groupSignalled = false;
- return ret;
- }
- virtual void processRow(const void *row)
- {
- // called from puller thread
- if(recreate)
- openPipe(helper.getNameFromRow(row));
- writeTransformer->writeTranslatedText(row, pipe);
- ReleaseRoxieRow(row);
- if(recreate)
- {
- closePipe();
- pipeVerified.wait();
- }
- }
- virtual void processDone()
- {
- // called from puller thread
- if(recreate)
- {
- inputExhausted = true;
- pipeOpened.signal();
- }
- else
- {
- closePipe();
- pipeVerified.wait();
- }
- }
- virtual void processEOG()
- {
- }
- void processGroup(const ConstPointerArray &)
- {
- throwUnexpected();
- }
- virtual bool fireException(IException *e)
- {
- pipeOpened.interrupt(LINK(e));
- pipeVerified.interrupt(e);
- return true;
- }
- private:
- bool waitForPipe()
- {
- if (firstRead)
- {
- pipeOpened.wait();
- firstRead = false;
- }
- if (!pipe)
- return false; // done
- if (!readTransformer->eos())
- return true;
- verifyPipe();
- if (recreate && !inputExhausted)
- pipeOpened.wait();
- return false;
- }
- void openPipe(char const * cmd)
- {
- pipeCommand.setown(cmd);
- pipe.setown(createPipeProcess());
- if(!pipe->run(NULL, cmd, ".", true, true, true, 0x10000))
- throw MakeStringException(ROXIE_PIPE_ERROR, "Could not run pipe process %s", cmd);
- writeTransformer->writeHeader(pipe);
- Owned<ISimpleReadStream> pipeReader = pipe->getOutputStream();
- readTransformer->setStream(pipeReader.get());
- pipeOpened.signal();
- }
- void closePipe()
- {
- writeTransformer->writeFooter(pipe);
- pipe->closeInput();
- }
- void verifyPipe()
- {
- if (pipe)
- {
- unsigned err = pipe->wait();
- if(err && !(helper.getPipeFlags() & TPFnofail))
- {
- throw createPipeFailureException(pipeCommand.get(), err, pipe);
- }
- pipe.clear();
- pipeVerified.signal();
- }
- }
- };
- class CRoxieServerPipeWriteActivity : public CRoxieServerInternalSinkActivity
- {
- IHThorPipeWriteArg &helper;
- Owned<IPipeProcess> pipe;
- StringAttr pipeCommand;
- CachedOutputMetaData inputMeta;
- Owned<IOutputRowSerializer> rowSerializer;
- Owned<IPipeWriteXformHelper> writeTransformer;
- bool firstRead;
- bool recreate;
- bool inputExhausted;
- public:
- CRoxieServerPipeWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numOutputs)
- : CRoxieServerInternalSinkActivity(_factory, _probeManager, _numOutputs), helper((IHThorPipeWriteArg &)basehelper)
- {
- recreate = helper.recreateEachRow();
- firstRead = false;
- inputExhausted = false;
- }
- virtual bool needsAllocator() const { return true; }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerActivity::onCreate(_ctx, _colocalParent);
- inputMeta.set(input->queryOutputMeta());
- rowSerializer.setown(inputMeta.createDiskSerializer(ctx->queryCodeContext(), activityId));
- writeTransformer.setown(createPipeWriteXformHelper(helper.getPipeFlags(), helper.queryXmlOutput(), helper.queryCsvOutput(), rowSerializer));
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- firstRead = true;
- inputExhausted = false;
- writeTransformer->ready();
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- if(!recreate)
- {
- OwnedRoxieString pipeProgram(helper.getPipeProgram());
- openPipe(pipeProgram);
- }
- }
- virtual void stop(bool aborting)
- {
- CRoxieServerActivity::stop(aborting);
- pipe.clear();
- }
- virtual void onExecute()
- {
- loop
- {
- const void *row = input->nextInGroup();
- if (!row)
- {
- row = input->nextInGroup();
- if (!row)
- break;
- }
- processed++;
- if(recreate)
- openPipe(helper.getNameFromRow(row));
- writeTransformer->writeTranslatedText(row, pipe);
- ReleaseRoxieRow(row);
- if(recreate)
- closePipe();
- }
- closePipe();
- }
- private:
- void openPipe(char const * cmd)
- {
- pipeCommand.setown(cmd);
- pipe.setown(createPipeProcess());
- if(!pipe->run(NULL, cmd, ".", true, false, true, 0x10000))
- throw MakeStringException(ROXIE_PIPE_ERROR, "Could not run pipe process %s", cmd);
- writeTransformer->writeHeader(pipe);
- }
- void closePipe()
- {
- writeTransformer->writeFooter(pipe);
- pipe->closeInput();
- unsigned err = pipe->wait();
- if(err && !(helper.getPipeFlags() & TPFnofail))
- {
- throw createPipeFailureException(pipeCommand.get(), err, pipe);
- }
- pipe.clear();
- }
- };
- class CRoxieServerPipeReadActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerPipeReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerPipeReadActivity(this, _probeManager);
- }
- };
- class CRoxieServerPipeThroughActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerPipeThroughActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerPipeThroughActivity(this, _probeManager);
- }
- };
- class CRoxieServerPipeWriteActivityFactory : public CRoxieServerInternalSinkFactory
- {
- public:
- CRoxieServerPipeWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
- : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerPipeWriteActivity(this, _probeManager, usageCount);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerPipeReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerPipeReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- IRoxieServerActivityFactory *createRoxieServerPipeThroughActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerPipeThroughActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- IRoxieServerActivityFactory *createRoxieServerPipeWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
- {
- return new CRoxieServerPipeWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot);
- }
- //=====================================================================================================
- class CRoxieServerStreamedIteratorActivity : public CRoxieServerActivity
- {
- IHThorStreamedIteratorArg &helper;
- Owned<IRowStream> rows;
- public:
- CRoxieServerStreamedIteratorActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorStreamedIteratorArg &)basehelper)
- {
- }
- ~CRoxieServerStreamedIteratorActivity()
- {
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- rows.setown(helper.createInput());
- }
- virtual void stop(bool aborting)
- {
- if (rows)
- {
- rows->stop();
- rows.clear();
- }
- CRoxieServerActivity::stop(aborting);
- }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- assertex(rows != NULL);
- const void * next = rows->nextRow();
- if (next)
- processed++;
- return next;
- }
- };
- class CRoxieServerStreamedIteratorActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerStreamedIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerStreamedIteratorActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerStreamedIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerStreamedIteratorActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=====================================================================================================
- class CRoxieServerFilterActivity : public CRoxieServerLateStartActivity
- {
- IHThorFilterArg &helper;
- bool anyThisGroup;
- IRangeCompare * stepCompare;
- public:
- CRoxieServerFilterActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerLateStartActivity(_factory, _probeManager), helper((IHThorFilterArg &)basehelper)
- {
- anyThisGroup = false;
- stepCompare = NULL;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- anyThisGroup = false;
- CRoxieServerLateStartActivity::start(parentExtractSize, parentExtract, paused);
- lateStart(parentExtractSize, parentExtract, helper.canMatchAny());
- stepCompare = NULL;
- if (!eof)
- {
- IInputSteppingMeta * stepMeta = input->querySteppingMeta();
- if (stepMeta)
- stepCompare = stepMeta->queryCompare();
- }
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (eof)
- return NULL;
- loop
- {
- const void * ret = input->nextInGroup();
- if (!ret)
- {
- //stop returning two NULLs in a row.
- if (anyThisGroup)
- {
- anyThisGroup = false;
- return NULL;
- }
- ret = input->nextInGroup();
- if (!ret)
- {
- eof = true;
- return NULL; // eof...
- }
- }
- if (helper.isValid(ret))
- {
- anyThisGroup = true;
- processed++;
- return ret;
- }
- ReleaseRoxieRow(ret);
- }
- }
- virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
- {
- //Could assert that this isn't grouped
- // MORE - will need rethinking once we rethink the nextSteppedGE interface for global smart-stepping.
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (eof)
- return NULL;
- loop
- {
- const void * ret = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
- if (!ret)
- {
- eof = true;
- return NULL;
- }
- if (!wasCompleteMatch)
- {
- anyThisGroup = false; // RKC->GH - is this right??
- return ret;
- }
- if (helper.isValid(ret))
- {
- anyThisGroup = true;
- processed++;
- return ret;
- }
- if (!stepExtra.returnMismatches())
- {
- ReleaseRoxieRow(ret);
- return nextInGroup();
- }
- //If asked to return mismatches we are only interested in mismatches that will force the stepped
- //condition to advance
- if (stepCompare->docompare(ret, seek, numFields) != 0)
- {
- wasCompleteMatch = false;
- anyThisGroup = false; // WHY?
- return ret;
- }
- ReleaseRoxieRow(ret);
- }
- }
- virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
- {
- return input->gatherConjunctions(collector);
- }
- virtual void resetEOF()
- {
- eof = prefiltered;
- anyThisGroup = false;
- input->resetEOF();
- }
- IInputSteppingMeta * querySteppingMeta()
- {
- return input->querySteppingMeta();
- }
- };
- class CRoxieServerFilterActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerFilterActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerFilterActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerFilterActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerFilterActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=====================================================================================================
- class CRoxieServerFilterGroupActivity : public CRoxieServerLateStartActivity
- {
- IHThorFilterGroupArg &helper;
- unsigned curIndex;
- ConstPointerArray gathered;
- IRangeCompare * stepCompare;
- public:
- CRoxieServerFilterGroupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerLateStartActivity(_factory, _probeManager), helper((IHThorFilterGroupArg &)basehelper)
- {
- curIndex = 0;
- stepCompare = NULL;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerLateStartActivity::start(parentExtractSize, parentExtract, paused);
- lateStart(parentExtractSize, parentExtract, helper.canMatchAny());//sets eof
- assertex(eof == !helper.canMatchAny());
- curIndex = 0;
- stepCompare = NULL;
- if (!eof)
- {
- IInputSteppingMeta * inputStepping = input->querySteppingMeta();
- if (inputStepping)
- stepCompare = inputStepping->queryCompare();
- }
- }
- virtual void reset()
- {
- releaseGathered();
- CRoxieServerLateStartActivity::reset();
- }
- inline void releaseGathered()
- {
- while (gathered.isItem(curIndex))
- ReleaseRoxieRow(gathered.item(curIndex++));
- gathered.kill();
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- loop
- {
- if (eof)
- return NULL;
- if (gathered.ordinality())
- {
- if (gathered.isItem(curIndex))
- {
- const void * ret = gathered.item(curIndex++);
- processed++;
- return ret;
- }
- curIndex = 0;
- gathered.kill();
- return NULL;
- }
- const void * ret = input->nextInGroup();
- while (ret)
- {
- gathered.append(ret);
- ret = input->nextInGroup();
- }
- unsigned num = gathered.ordinality();
- if (num != 0)
- {
- if (!helper.isValid(num, (const void * *)gathered.getArray()))
- ReleaseRoxieRowSet(gathered); // read next group
- }
- else
- eof = true;
- }
- }
- virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (eof)
- return NULL;
- if (gathered.ordinality())
- {
- while (gathered.isItem(curIndex))
- {
- const void * ret = gathered.item(curIndex++);
- if (stepCompare->docompare(ret, seek, numFields) >= 0)
- {
- processed++;
- return ret;
- }
- ReleaseRoxieRow(ret);
- }
- curIndex = 0;
- gathered.kill();
- //nextSteppedGE never returns an end of group marker.
- }
- //Not completely sure about this - it could lead the the start of a group being skipped,
- //so the group filter could potentially work on a different group. If so, we'd need to check the
- //next fields were a subset of the grouping fields - more an issue for the group activity.
-
- //MORE: What do we do with wasCompleteMatch? something like the following????
- #if 0
- loop
- {
- const void * ret;
- if (stepExtra.returnMismatches())
- {
- bool matchedCompletely = true;
- ret = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
- if (!wasCompleteMatch)
- return ret;
- }
- else
- ret = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
- #endif
- const void * ret = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
- while (ret)
- {
- gathered.append(ret);
- ret = input->nextInGroup();
- }
- unsigned num = gathered.ordinality();
- if (num != 0)
- {
- if (!helper.isValid(num, (const void * *)gathered.getArray()))
- ReleaseRoxieRowSet(gathered); // read next group
- }
- else
- eof = true;
- return nextUngrouped(this);
- }
- virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
- {
- return input->gatherConjunctions(collector);
- }
- virtual void resetEOF()
- {
- eof = false;
- releaseGathered();
- input->resetEOF();
- }
- IInputSteppingMeta * querySteppingMeta()
- {
- return input->querySteppingMeta();
- }
- };
- class CRoxieServerFilterGroupActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerFilterGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerFilterGroupActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerFilterGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerFilterGroupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerSideEffectActivity : public CRoxieServerActivity
- {
- IHThorSideEffectArg &helper;
- CriticalSection ecrit;
- Owned<IException> exception;
- bool executed;
- public:
- CRoxieServerSideEffectActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorSideEffectArg &)basehelper)
- {
- executed = false;
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- CriticalBlock b(ecrit);
- if (exception)
- throw(exception.getLink());
- if (!executed)
- {
- try
- {
- executed = true;
- helper.action();
- }
- catch(IException *E)
- {
- exception.set(E);
- throw;
- }
- }
- return NULL;
- }
- virtual void execute(unsigned parentExtractSize, const byte * parentExtract)
- {
- CriticalBlock b(ecrit);
- if (exception)
- throw(exception.getLink());
- if (!executed)
- {
- try
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- executed = true;
- start(parentExtractSize, parentExtract, false);
- helper.action();
- stop(false);
- }
- catch(IException *E)
- {
- ctx->notifyAbort(E);
- stop(true);
- exception.set(E);
- throw;
- }
- }
- }
- virtual void reset()
- {
- executed = false;
- exception.clear();
- CRoxieServerActivity::reset();
- }
- };
- class CRoxieServerSideEffectActivityFactory : public CRoxieServerActivityFactory
- {
- bool isRoot;
- public:
- CRoxieServerSideEffectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerSideEffectActivity(this, _probeManager);
- }
- virtual bool isSink() const
- {
- return isRoot && !meta.queryOriginal();
- }
- };
- IRoxieServerActivityFactory *createRoxieServerSideEffectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
- {
- return new CRoxieServerSideEffectActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
- }
- //=================================================================================
- class CRoxieServerActionActivity : public CRoxieServerInternalSinkActivity
- {
- IHThorActionArg &helper;
- public:
- CRoxieServerActionActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numOutputs)
- : CRoxieServerInternalSinkActivity(_factory, _probeManager, _numOutputs), helper((IHThorActionArg &)basehelper)
- {
- }
- virtual void onExecute()
- {
- helper.action();
- }
- };
- class CRoxieServerActionActivityFactory : public CRoxieServerInternalSinkFactory
- {
- public:
- CRoxieServerActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
- : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerActionActivity(this, _probeManager, usageCount);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
- {
- return new CRoxieServerActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot);
- }
- //=================================================================================
- class CRoxieServerSampleActivity : public CRoxieServerActivity
- {
- IHThorSampleArg &helper;
- unsigned numSamples;
- unsigned numToSkip;
- unsigned whichSample;
- bool anyThisGroup;
- bool eof;
- public:
- CRoxieServerSampleActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorSampleArg &)basehelper)
- {
- numSamples = 0;
- numToSkip = 0;
- whichSample = 0;
- anyThisGroup = false;
- eof = false;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- anyThisGroup = false;
- eof = false;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- numSamples = helper.getProportion();
- whichSample = helper.getSampleNumber();
- numToSkip = (whichSample ? whichSample-1 : 0);
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (eof)
- return NULL;
- loop
- {
- const void * ret = input->nextInGroup();
- if (!ret)
- {
- //this does work with groups - may or may not be useful...
- //reset the sample for each group.... probably best.
- numToSkip = (whichSample ? whichSample-1 : 0);
- if (anyThisGroup)
- {
- anyThisGroup = false;
- return NULL;
- }
- ret = input->nextInGroup();
- if (!ret)
- {
- eof = true;
- return NULL; // eof...
- }
- }
- if (numToSkip == 0)
- {
- anyThisGroup = true;
- numToSkip = numSamples-1;
- processed++;
- return ret;
- }
- numToSkip--;
- ReleaseRoxieRow(ret);
- }
- }
- };
- class CRoxieServerSampleActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerSampleActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerSampleActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerSampleActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerSampleActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerChooseSetsActivity : public CRoxieServerActivity
- {
- IHThorChooseSetsArg &helper;
- unsigned numSets;
- unsigned * setCounts;
- bool done;
- public:
- CRoxieServerChooseSetsActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorChooseSetsArg &)basehelper)
- {
- setCounts = NULL;
- numSets = 0;
- done = false;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- done = false;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- numSets = helper.getNumSets();
- setCounts = new unsigned[numSets];
- memset(setCounts, 0, sizeof(unsigned)*numSets);
- helper.setCounts(setCounts);
- }
- virtual void reset()
- {
- delete [] setCounts;
- setCounts = NULL;
- CRoxieServerActivity::reset();
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (done)
- return NULL;
- loop
- {
- const void * ret = input->nextInGroup();
- if (!ret)
- {
- ret = input->nextInGroup();
- if (!ret)
- {
- done = true;
- return NULL;
- }
- }
- processed++;
- switch (helper.getRecordAction(ret))
- {
- case 2:
- done = true;
- return ret;
- case 1:
- return ret;
- }
- ReleaseRoxieRow(ret);
- }
- }
- };
- class CRoxieServerChooseSetsActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerChooseSetsActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerChooseSetsActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerChooseSetsActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerChooseSetsActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerChooseSetsExActivity : public CRoxieServerActivity
- {
- protected:
- IHThorChooseSetsExArg &helper;
- unsigned numSets;
- unsigned curIndex;
- unsigned * setCounts;
- count_t * limits;
- bool done;
- ConstPointerArray gathered;
- virtual bool includeRow(const void * row) = 0;
- virtual void calculateSelection() = 0;
- public:
- CRoxieServerChooseSetsExActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorChooseSetsExArg &)basehelper)
- {
- setCounts = NULL;
- limits = NULL;
- done = false;
- curIndex = 0;
- numSets = 0;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- done = false;
- curIndex = 0;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- numSets = helper.getNumSets();
- setCounts = new unsigned[numSets];
- memset(setCounts, 0, sizeof(unsigned)*numSets);
- limits = (count_t *)calloc(sizeof(count_t), numSets);
- helper.getLimits(limits);
- }
- virtual void reset()
- {
- delete [] setCounts;
- setCounts = NULL;
- free(limits);
- limits = NULL;
- while (gathered.isItem(curIndex))
- ReleaseRoxieRow(gathered.item(curIndex++));
- gathered.kill();
- CRoxieServerActivity::reset();
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (gathered.ordinality() == 0)
- {
- curIndex = 0;
- if (!input->nextGroup(gathered))
- {
- done = true;
- return NULL;
- }
- ForEachItemIn(idx1, gathered)
- {
- unsigned category = helper.getCategory(gathered.item(idx1));
- if (category)
- setCounts[category-1]++;
- }
- calculateSelection();
- }
- while (gathered.isItem(curIndex))
- {
- const void * row = gathered.item(curIndex);
- gathered.replace(NULL, curIndex);
- curIndex++;
- if (includeRow(row))
- {
- processed++;
- return row;
- }
- ReleaseRoxieRow(row);
- }
- gathered.kill();
- return NULL;
- }
- };
- class CRoxieServerChooseSetsLastActivity : public CRoxieServerChooseSetsExActivity
- {
- unsigned * numToSkip;
- public:
- CRoxieServerChooseSetsLastActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager) : CRoxieServerChooseSetsExActivity(_factory, _probeManager)
- {
- numToSkip = NULL;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerChooseSetsExActivity::start(parentExtractSize, parentExtract, paused);
- numToSkip = (unsigned *)calloc(sizeof(unsigned), numSets);
- }
- virtual void reset()
- {
- free(numToSkip);
- numToSkip = NULL;
- CRoxieServerChooseSetsExActivity::reset();
- }
- protected:
- virtual void calculateSelection()
- {
- for (unsigned idx=0; idx < numSets; idx++)
- {
- if (setCounts[idx] < limits[idx])
- numToSkip[idx] = 0;
- else
- numToSkip[idx] = (unsigned)(setCounts[idx] - limits[idx]);
- }
- }
- virtual bool includeRow(const void * row)
- {
- unsigned category = helper.getCategory(row);
- if (category)
- {
- if (numToSkip[category-1] == 0)
- return true;
- numToSkip[category-1]--;
- }
- return false;
- }
- };
- class CRoxieServerChooseSetsEnthActivity : public CRoxieServerChooseSetsExActivity
- {
- count_t * counter;
- public:
- CRoxieServerChooseSetsEnthActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager) : CRoxieServerChooseSetsExActivity(_factory, _probeManager)
- {
- counter = NULL;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerChooseSetsExActivity::start(parentExtractSize, parentExtract, paused);
- counter = (count_t *)calloc(sizeof(count_t), numSets);
- }
- virtual void reset()
- {
- free(counter);
- counter = NULL;
- CRoxieServerChooseSetsExActivity::reset();
- }
- protected:
- virtual void calculateSelection()
- {
- }
- virtual bool includeRow(const void * row)
- {
- unsigned category = helper.getCategory(row);
- if (category)
- {
- assertex(category <= numSets);
- counter[category-1] += limits[category-1];
- if(counter[category-1] >= setCounts[category-1])
- {
- counter[category-1] -= setCounts[category-1];
- return true;
- }
- }
- return false;
- }
- };
- class CRoxieServerChooseSetsEnthActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerChooseSetsEnthActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerChooseSetsEnthActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerChooseSetsEnthActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerChooseSetsEnthActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- class CRoxieServerChooseSetsLastActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerChooseSetsLastActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerChooseSetsLastActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerChooseSetsLastActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerChooseSetsLastActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerEnthActivity : public CRoxieServerActivity
- {
- IHThorEnthArg &helper;
- unsigned __int64 numerator;
- unsigned __int64 denominator;
- unsigned __int64 counter;
- bool eof;
- public:
- CRoxieServerEnthActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorEnthArg &)basehelper)
- {
- eof = false;
- numerator = denominator = counter = 0;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- eof = false;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- numerator = helper.getProportionNumerator();
- denominator = helper.getProportionDenominator();
- if(denominator == 0) denominator = 1; //MORE: simplest way to avoid disaster in this case
- counter = (helper.getSampleNumber()-1) * greatestCommonDivisor(numerator, denominator);
- if (counter >= denominator)
- counter %= denominator;
- }
- inline bool wanted()
- {
- counter += numerator;
- if(counter >= denominator)
- {
- counter -= denominator;
- return true;
- }
- return false;
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (eof)
- return NULL;
- const void * ret;
- loop
- {
- ret = input->nextInGroup();
- if(!ret) //end of group
- ret = input->nextInGroup();
- if(!ret) //eof
- {
- eof = true;
- return ret;
- }
- if (wanted())
- return ret;
- ReleaseRoxieRow(ret);
- }
- }
- };
- class CRoxieServerEnthActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerEnthActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerEnthActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerEnthActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerEnthActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerAggregateActivity : public CRoxieServerActivity
- {
- IHThorAggregateArg &helper;
- bool eof;
- bool isInputGrouped;
- bool abortEarly;
- public:
- CRoxieServerAggregateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorAggregateArg &)basehelper)
- {
- eof = false;
- isInputGrouped = false;
- abortEarly = false;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- eof = false;
- isInputGrouped = input->queryOutputMeta()->isGrouped(); // could be done earlier, in setInput?
- abortEarly = !isInputGrouped && (factory->getKind() == TAKexistsaggregate); // ditto
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- }
- virtual bool needsAllocator() const { return true; }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (eof)
- return NULL;
- const void * next = input->nextInGroup();
- if (!next && isInputGrouped)
- {
- eof = true;
- return NULL;
- }
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- size32_t finalSize = helper.clearAggregate(rowBuilder);
- if (next)
- {
- finalSize = helper.processFirst(rowBuilder, next);
- ReleaseRoxieRow(next);
- if (!abortEarly)
- {
- loop
- {
- next = input->nextInGroup();
- if (!next)
- break;
- finalSize = helper.processNext(rowBuilder, next);
- ReleaseRoxieRow(next);
- }
- }
- }
- if (!isInputGrouped) // either read all, or aborted early
- eof = true;
- processed++;
- return rowBuilder.finalizeRowClear(finalSize);
- }
- };
- class CRoxieServerAggregateActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerAggregateActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerAggregateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- typedef unsigned t_hashPrefix;
- class CRoxieServerHashAggregateActivity : public CRoxieServerActivity
- {
- IHThorHashAggregateArg &helper;
- RowAggregator aggregated;
- bool eof;
- bool gathered;
- bool isGroupedAggregate;
- public:
- CRoxieServerHashAggregateActivity(const IRoxieServerActivityFactory *_factory, bool _isGroupedAggregate, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorHashAggregateArg &)basehelper),
- isGroupedAggregate(_isGroupedAggregate),
- aggregated(helper, helper)
- {
- eof = false;
- gathered = false;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- eof = false;
- gathered = false;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- }
- virtual void reset()
- {
- aggregated.reset();
- CRoxieServerActivity::reset();
- }
- virtual bool needsAllocator() const { return true; }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (eof)
- return NULL;
- if (!gathered)
- {
- aggregated.start(rowAllocator);
- bool eog = true;
- loop
- {
- const void * next = input->nextInGroup();
- if (!next)
- {
- if (isGroupedAggregate)
- {
- if (eog)
- eof = true;
- break;
- }
- next = input->nextInGroup();
- if (!next)
- break;
- }
- eog = false;
- aggregated.addRow(next);
- ReleaseRoxieRow(next);
- }
- gathered = true;
- }
- Owned<AggregateRowBuilder> next = aggregated.nextResult();
- if (next)
- {
- processed++;
- return next->finalizeRowClear();
- }
- if (!isGroupedAggregate)
- eof = true;
- aggregated.reset();
- gathered = false;
- return NULL;
- }
- };
- class CRoxieServerHashAggregateActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerHashAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- isGroupedAggregate = _graphNode.getPropBool("att[@name='grouped']/@value");
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerHashAggregateActivity(this, isGroupedAggregate, _probeManager);
- }
- protected:
- bool isGroupedAggregate;
- };
- IRoxieServerActivityFactory *createRoxieServerHashAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
- {
- return new CRoxieServerHashAggregateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
- }
- //=================================================================================
- class CRoxieServerDegroupActivity : public CRoxieServerActivity
- {
- IHThorDegroupArg &helper;
- bool eof;
- public:
- CRoxieServerDegroupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorDegroupArg &)basehelper)
- {
- eof = false;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- eof = false;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (eof)
- return NULL;
- const void * ret = input->nextInGroup();
- if (!ret)
- ret = input->nextInGroup();
- if (ret)
- processed++;
- else
- eof = true;
- return ret;
- }
- virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (eof)
- return NULL;
- const void * ret = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
- if (ret)
- processed++;
- else
- eof = true;
- return ret;
- }
- virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
- {
- return input->gatherConjunctions(collector);
- }
- virtual void resetEOF()
- {
- eof = false;
- input->resetEOF();
- }
- IInputSteppingMeta * querySteppingMeta()
- {
- return input->querySteppingMeta();
- }
- };
- class CRoxieServerDegroupActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerDegroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerDegroupActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerDegroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerDegroupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerSpillReadActivity : public CRoxieServerActivity
- {
- IHThorDiskReadArg &helper;
- bool needTransform;
- bool eof;
- bool anyThisGroup;
- unsigned __int64 rowLimit;
- unsigned __int64 choosenLimit;
- public:
- CRoxieServerSpillReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorDiskReadArg &)basehelper)
- {
- needTransform = helper.needTransform();
- rowLimit = (unsigned __int64) -1;
- choosenLimit = 0;
- eof = false;
- anyThisGroup = false;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- anyThisGroup = false;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- if (helper.canMatchAny())
- eof = false;
- else
- eof = true;
- choosenLimit = helper.getChooseNLimit();
- rowLimit = helper.getRowLimit();
- helper.setCallback(NULL); // members should not be called - change if they are
- }
- virtual bool needsAllocator() const { return true; }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (eof)
- return NULL;
- if (processed==choosenLimit)
- {
- eof = true;
- return NULL;
- }
- if (needTransform)
- {
- loop
- {
- const void *in = input->nextInGroup();
- if (!in)
- {
- if (anyThisGroup)
- {
- anyThisGroup = false;
- return NULL;
- }
- in = input->nextInGroup();
- if (!in)
- {
- eof = true;
- return NULL; // eof...
- }
- }
- unsigned outSize;
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- try
- {
- outSize = helper.transform(rowBuilder, in);
- ReleaseRoxieRow(in);
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- if (outSize)
- {
- anyThisGroup = true;
- processed++;
- if (processed==rowLimit)
- {
- if (traceLevel > 4)
- DBGLOG("activityid = %d line = %d", activityId, __LINE__);
- helper.onLimitExceeded();
- }
- return rowBuilder.finalizeRowClear(outSize);
- }
- }
- }
- else
- {
- const void *ret = input->nextInGroup();
- if (ret)
- {
- processed++;
- if (processed==rowLimit)
- {
- if (traceLevel > 4)
- DBGLOG("activityid = %d line = %d", activityId, __LINE__);
- ReleaseClearRoxieRow(ret);
- helper.onLimitExceeded(); // should not return
- throwUnexpected();
- }
- }
- return ret;
- }
- }
- };
- class CRoxieServerSpillReadActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerSpillReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerSpillReadActivity(this, _probeManager);
- }
- virtual void addDependency(unsigned source, ThorActivityKind sourceKind, unsigned sourceIdx, int controlId, const char *edgeId)
- {
- if (sourceKind==TAKspill || sourceKind==TAKdiskwrite) // Bit of a hack - codegen probably should differentiate
- setInput(0, source, sourceIdx);
- else
- CRoxieServerActivityFactory::addDependency(source, kind, sourceIdx, controlId, edgeId);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerSpillReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerSpillReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerSpillWriteActivity : public CRoxieServerActivity
- {
- public:
- CRoxieServerSpillWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager)
- {
- }
- ~CRoxieServerSpillWriteActivity()
- {
- }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- return input->nextInGroup();
- }
- };
- //==================================================================================
- class CRoxieServerDiskWriteActivity : public CRoxieServerInternalSinkActivity, implements IRoxiePublishCallback
- {
- protected:
- Owned<IExtRowWriter> outSeq;
- Owned<IOutputRowSerializer> rowSerializer;
- Linked<IFileIOStream> diskout;
- bool blockcompressed;
- bool extend;
- bool overwrite;
- bool encrypted;
- bool grouped;
- IHThorDiskWriteArg &helper;
- StringBuffer lfn; // logical filename
- CachedOutputMetaData diskmeta;
- Owned<IRoxieWriteHandler> writer;
- bool tallycrc;
- unsigned __int64 uncompressedBytesWritten;
- CRC32 crc;
- void updateWorkUnitResult(unsigned __int64 reccount)
- {
- assertex(writer);
- // MORE - a lot of this is common with hthor
- 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
- {
- WorkunitUpdate wu = ctx->updateWorkUnit();
- if (wu)
- {
- unsigned flags = helper.getFlags();
- WUFileKind fileKind;
- if (TDXtemporary & flags)
- fileKind = WUFileTemporary;
- else if(TDXjobtemp & flags)
- fileKind = WUFileJobOwned;
- else if(TDWowned & flags)
- fileKind = WUFileOwned;
- else
- fileKind = WUFileStandard;
- StringArray clusters;
- writer->getClusters(clusters);
- wu->addFile(lfn.str(), &clusters, helper.getTempUsageCount(), fileKind, NULL);
- if (!(flags & TDXtemporary) && helper.getSequence() >= 0)
- {
- Owned<IWUResult> result = wu->updateResultBySequence(helper.getSequence());
- if (result)
- {
- result->setResultTotalRowCount(reccount);
- result->setResultStatus(ResultStatusCalculated);
- if (helper.getFlags() & TDWresult)
- result->setResultFilename(lfn.str());
- else
- result->setResultLogicalName(lfn.str());
- }
- }
- }
- }
- }
- void resolve()
- {
- OwnedRoxieString rawLogicalName = helper.getFileName();
- assertex(rawLogicalName);
- assertex((helper.getFlags() & TDXtemporary) == 0);
- StringArray clusters;
- unsigned clusterIdx = 0;
- while(true)
- {
- OwnedRoxieString cluster(helper.getCluster(clusterIdx));
- if(!cluster)
- break;
- clusters.append(cluster);
- clusterIdx++;
- }
- if (clusters.length())
- {
- if (extend)
- throw MakeStringException(0, "Cannot combine EXTEND and CLUSTER flags on disk write of file %s", rawLogicalName.get());
- }
- else
- {
- if (roxieName.length())
- clusters.append(roxieName.str());
- else
- clusters.append(".");
- }
- writer.setown(ctx->createLFN(rawLogicalName, overwrite, extend, clusters)); // MORE - if there's a workunit, use if for scope.
- // MORE - need to check somewhere that single part if it's an existing file or an external one...
- }
- public:
- CRoxieServerDiskWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerInternalSinkActivity(_factory, _probeManager, 0), helper((IHThorDiskWriteArg &)basehelper)
- {
- extend = ((helper.getFlags() & TDWextend) != 0);
- overwrite = ((helper.getFlags() & TDWoverwrite) != 0);
- grouped = false; // don't think we need to support it...
- diskmeta.set(helper.queryDiskRecordSize());
- blockcompressed = (((helper.getFlags() & TDWnewcompress) != 0) || (((helper.getFlags() & TDXcompress) != 0) && (diskmeta.getFixedSize() >= MIN_ROWCOMPRESS_RECSIZE))); //always use new compression
- encrypted = false; // set later
- tallycrc = true;
- uncompressedBytesWritten = 0;
- }
- ~CRoxieServerDiskWriteActivity()
- {
- }
- virtual bool needsAllocator() const
- {
- return true;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
-
- resolve();
- Owned<IFileIO> io;
- void *ekey;
- size32_t ekeylen;
- helper.getEncryptKey(ekeylen, ekey);
- Owned<ICompressor> ecomp;
- if (ekeylen!=0)
- {
- ecomp.setown(createAESCompressor256(ekeylen,ekey));
- memset(ekey,0,ekeylen);
- rtlFree(ekey);
- encrypted = true;
- blockcompressed = true;
- }
- if (blockcompressed)
- io.setown(createCompressedFileWriter(writer->queryFile(), (diskmeta.isFixedSize() ? diskmeta.getFixedSize() : 0), extend, true, ecomp));
- else
- io.setown(writer->queryFile()->open(extend ? IFOwrite : IFOcreate));
- if (!io)
- throw MakeStringException(errno, "Failed to create%s file %s for writing", (encrypted ? " encrypted" : (blockcompressed ? " compressed" : "")), writer->queryFile()->queryFilename());
- diskout.setown(createBufferedIOStream(io));
- if (extend)
- diskout->seek(0, IFSend);
- tallycrc = !factory->queryQueryFactory().getDebugValueBool("skipFileFormatCrcCheck", false) && !(helper.getFlags() & TDRnocrccheck) && !blockcompressed;
- Owned<IRowInterfaces> rowIf = createRowInterfaces(input->queryOutputMeta(), activityId, ctx->queryCodeContext());
- rowSerializer.set(rowIf->queryRowSerializer());
- unsigned rwFlags = rw_autoflush;
- if(grouped)
- rwFlags |= rw_grouped;
- if(tallycrc)
- rwFlags |= rw_crc;
- if(!factory->queryQueryFactory().getDebugValueBool("skipFileFormatCrcCheck", false) && !(helper.getFlags() & TDRnocrccheck))
- rwFlags |= rw_crc;
- outSeq.setown(createRowWriter(diskout, rowIf, rwFlags));
- }
- virtual void stop(bool aborting)
- {
- if (aborting)
- {
- if (writer)
- writer->finish(false, this);
- }
- else
- {
- if (outSeq)
- outSeq->flush(&crc);
- if (outSeq)
- uncompressedBytesWritten = outSeq->getPosition();
- if (writer)
- {
- updateWorkUnitResult(processed);
- writer->finish(true, this);
- }
- }
- writer.clear();
- CRoxieServerActivity::stop(aborting);
- }
- virtual void reset()
- {
- CRoxieServerActivity::reset();
- diskout.clear();
- outSeq.clear();
- writer.clear();
- uncompressedBytesWritten = 0;
- crc.reset();
- }
- virtual void onExecute()
- {
- loop
- {
- const void *nextrec = input->nextInGroup();
- if (!nextrec)
- {
- nextrec = input->nextInGroup();
- if (!nextrec)
- break;
- }
- processed++;
- outSeq->putRow(nextrec);
- }
- }
- virtual void setFileProperties(IFileDescriptor *desc) const
- {
- IPropertyTree &partProps = desc->queryPart(0)->queryProperties(); //properties of the first file part.
- IPropertyTree &fileProps = desc->queryProperties(); // properties of the logical file
- if (blockcompressed)
- {
- // caller has already set @size from file size...
- fileProps.setPropBool("@blockCompressed", true);
- fileProps.setPropInt64("@compressedSize", partProps.getPropInt64("@size", 0));
- partProps.setPropInt64("@compressedSize", partProps.getPropInt64("@size", 0));
- fileProps.setPropInt64("@size", uncompressedBytesWritten);
- partProps.setPropInt64("@size", uncompressedBytesWritten);
- }
- else if (tallycrc)
- partProps.setPropInt64("@fileCrc", crc.get());
- if (encrypted)
- fileProps.setPropBool("@encrypted", true);
- fileProps.setPropInt64("@recordCount", processed);
- unsigned flags = helper.getFlags();
- if (flags & TDWpersist)
- fileProps.setPropBool("@persistent", true);
- if (grouped)
- fileProps.setPropBool("@grouped", true);
- if (flags & (TDWowned|TDXjobtemp|TDXtemporary))
- fileProps.setPropBool("@owned", true);
- if (flags & TDWresult)
- fileProps.setPropBool("@result", true);
- IConstWorkUnit *workUnit = ctx->queryWorkUnit();
- if (workUnit)
- {
- SCMStringBuffer owner, wuid, job;
- fileProps.setProp("@owner", workUnit->getUser(owner).str());
- fileProps.setProp("@workunit", workUnit->getWuid(wuid).str());
- fileProps.setProp("@job", workUnit->getJobName(job).str());
- }
- if (flags & TDWexpires)
- setExpiryTime(fileProps, helper.getExpiryDays());
- if (flags & TDWupdate)
- {
- unsigned eclCRC;
- unsigned __int64 totalCRC;
- helper.getUpdateCRCs(eclCRC, totalCRC);
- fileProps.setPropInt("@eclCRC", eclCRC);
- fileProps.setPropInt64("@totalCRC", totalCRC);
- }
- fileProps.setPropInt("@formatCrc", helper.getFormatCrc());
- IRecordSize * inputMeta = input->queryOutputMeta();
- if ((inputMeta->isFixedSize()) && !isOutputTransformed())
- fileProps.setPropInt("@recordSize", inputMeta->getFixedSize() + (grouped ? 1 : 0));
- const char *recordECL = helper.queryRecordECL();
- if (recordECL && *recordECL)
- fileProps.setProp("ECL", recordECL);
- fileProps.setProp("@kind", "flat"); // default, derivitives may override
- }
- virtual IUserDescriptor *queryUserDescriptor() const
- {
- IConstWorkUnit *workUnit = ctx->queryWorkUnit();
- if (workUnit)
- return workUnit->queryUserDescriptor();
- else
- return NULL;
- }
- virtual bool isOutputTransformed() const { return false; }
- };
- //=================================================================================
- class CRoxieServerCsvWriteActivity : public CRoxieServerDiskWriteActivity
- {
- IHThorCsvWriteArg &csvHelper;
- CSVOutputStream csvOutput;
- public:
- CRoxieServerCsvWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerDiskWriteActivity(_factory, _probeManager), csvHelper(static_cast<IHThorCsvWriteArg &>(helper))
- {
- csvOutput.init(csvHelper.queryCsvParameters(), false);
- }
- virtual void onExecute()
- {
- OwnedRoxieString header(csvHelper.queryCsvParameters()->getHeader());
- if (header)
- {
- csvOutput.beginLine();
- csvOutput.writeHeaderLn(strlen(header), header);
- diskout->write(csvOutput.length(), csvOutput.str());
- }
- loop
- {
- const void *nextrec = input->nextInGroup();
- if (!nextrec)
- {
- nextrec = input->nextInGroup();
- if (!nextrec)
- break;
- }
- processed++;
- csvOutput.beginLine();
- csvHelper.writeRow((const byte *)nextrec, &csvOutput);
- csvOutput.endLine();
- diskout->write(csvOutput.length(), csvOutput.str());
- ReleaseRoxieRow(nextrec);
- }
- OwnedRoxieString footer(csvHelper.queryCsvParameters()->getFooter());
- if (footer)
- {
- csvOutput.beginLine();
- csvOutput.writeHeaderLn(strlen(footer), footer);
- diskout->write(csvOutput.length(), csvOutput.str());
- }
- }
- virtual void setFileProperties(IFileDescriptor *desc) const
- {
- CRoxieServerDiskWriteActivity::setFileProperties(desc);
- IPropertyTree &props = desc->queryProperties();
- props.setProp("@format","utf8n");
- ICsvParameters *csvParameters = csvHelper.queryCsvParameters();
- StringBuffer separator;
- OwnedRoxieString rs(csvParameters->getSeparator(0));
- const char *s = rs;
- while (s && *s)
- {
- if (',' == *s)
- separator.append("\\,");
- else
- separator.append(*s);
- ++s;
- }
- props.setProp("@csvSeparate", separator.str());
- props.setProp("@csvQuote", rs.setown(csvParameters->getQuote(0)));
- props.setProp("@csvTerminate", rs.setown(csvParameters->getTerminator(0)));
- props.setProp("@csvEscape", rs.setown(csvParameters->getEscape(0)));
- props.setProp("@kind", "csv");
- }
- virtual bool isOutputTransformed() const { return true; }
- };
- class CRoxieServerXmlWriteActivity : public CRoxieServerDiskWriteActivity
- {
- IHThorXmlWriteArg &xmlHelper;
- StringAttr rowTag;
- public:
- CRoxieServerXmlWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerDiskWriteActivity(_factory, _probeManager), xmlHelper(static_cast<IHThorXmlWriteArg &>(helper))
- {
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerDiskWriteActivity::start(parentExtractSize, parentExtract, paused);
- OwnedRoxieString xmlpath(xmlHelper.getXmlIteratorPath());
- if (!xmlpath)
- rowTag.set("Row");
- else
- {
- const char *path = xmlpath;
- if (*path == '/') path++;
- if (strchr(path, '/')) UNIMPLEMENTED; // more what do we do with /mydata/row
- rowTag.set(path);
- }
- }
- virtual void onExecute()
- {
- OwnedRoxieString suppliedHeader(xmlHelper.getHeader());
- const char *header = suppliedHeader;
- if (!header) header = "<Dataset>\n";
- diskout->write(strlen(header), header);
- CommonXmlWriter xmlOutput(xmlHelper.getXmlFlags());
- loop
- {
- OwnedConstRoxieRow nextrec = input->nextInGroup();
- if (!nextrec)
- {
- nextrec.setown(input->nextInGroup());
- if (!nextrec)
- break;
- }
- processed++;
- xmlOutput.clear().outputBeginNested(rowTag, false);
- xmlHelper.toXML((const byte *)nextrec.get(), xmlOutput);
- xmlOutput.outputEndNested(rowTag);
- diskout->write(xmlOutput.length(), xmlOutput.str());
- }
- OwnedRoxieString suppliedFooter(xmlHelper.getFooter());
- const char * footer = suppliedFooter;
- if (!footer) footer = "</Dataset>\n";
- diskout->write(strlen(footer), footer);
- }
- virtual void reset()
- {
- CRoxieServerDiskWriteActivity::reset();
- rowTag.clear();
- }
- virtual void setFileProperties(IFileDescriptor *desc) const
- {
- CRoxieServerDiskWriteActivity::setFileProperties(desc);
- desc->queryProperties().setProp("@format","utf8n");
- desc->queryProperties().setProp("@rowTag",rowTag.get());
- desc->queryProperties().setProp("@kind", "xml");
- }
- virtual bool isOutputTransformed() const { return true; }
- };
- class CRoxieServerDiskWriteActivityFactory : public CRoxieServerMultiOutputFactory
- {
- bool isRoot;
- bool isTemp;
- public:
- CRoxieServerDiskWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
- : CRoxieServerMultiOutputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
- {
- Owned<IHThorDiskWriteArg> helper = (IHThorDiskWriteArg *) helperFactory();
- isTemp = (helper->getFlags() & TDXtemporary) != 0;
- setNumOutputs(helper->getTempUsageCount());
- if (_kind!=TAKdiskwrite)
- assertex(numOutputs == 0);
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- switch (numOutputs)
- {
- case 0:
- switch (kind)
- {
- case TAKdiskwrite: return new CRoxieServerDiskWriteActivity(this, _probeManager);
- case TAKcsvwrite: return new CRoxieServerCsvWriteActivity(this, _probeManager);
- case TAKxmlwrite: return new CRoxieServerXmlWriteActivity(this, _probeManager);
- };
- throwUnexpected();
- case 1:
- return new CRoxieServerSpillWriteActivity(this, _probeManager);
- default:
- return new CRoxieServerThroughSpillActivity(this, _probeManager, numOutputs);
- }
- }
- virtual bool isSink() const
- {
- return numOutputs == 0 && !isTemp; // MORE - check with Gavin if this is right if not a temp but reread in same job...
- }
- };
- IRoxieServerActivityFactory *createRoxieServerDiskWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
- {
- return new CRoxieServerDiskWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
- }
- //=================================================================================
- class CRoxieServerIndexWriteActivity : public CRoxieServerInternalSinkActivity, implements IRoxiePublishCallback
- {
- IHThorIndexWriteArg &helper;
- bool overwrite;
- Owned<ClusterWriteHandler> clusterHandler;
- Owned<IRoxieWriteHandler> writer;
- unsigned __int64 reccount;
- unsigned int fileCrc;
- StringBuffer filename;
- void updateWorkUnitResult()
- {
- 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
- {
- WorkunitUpdate wu = ctx->updateWorkUnit();
- if (wu)
- {
- if (!(helper.getFlags() & TDXtemporary) && helper.getSequence() >= 0)
- {
- Owned<IWUResult> result = wu->updateResultBySequence(helper.getSequence());
- if (result)
- {
- result->setResultTotalRowCount(reccount);
- result->setResultStatus(ResultStatusCalculated);
- result->setResultLogicalName(filename.str());
- }
- }
- if(clusterHandler)
- clusterHandler->finish(writer->queryFile());
- }
- CTXLOG("Created roxie index file %s", filename.str());
- }
- }
- virtual void resolve()
- {
- StringArray clusters;
- unsigned clusterIdx = 0;
- while(true)
- {
- OwnedRoxieString cluster(helper.getCluster(clusterIdx));
- if(!cluster)
- break;
- clusters.append(cluster);
- clusterIdx++;
- }
- if (roxieName.length())
- clusters.append(roxieName.str());
- else
- clusters.append(".");
- OwnedRoxieString fname(helper.getFileName());
- writer.setown(ctx->createLFN(fname, overwrite, false, clusters)); // MORE - if there's a workunit, use if for scope.
- filename.set(writer->queryFile()->queryFilename());
- if (writer->queryFile()->exists())
- {
- if (overwrite)
- {
- CTXLOG("Removing existing %s from DFS",filename.str());
- writer->queryFile()->remove();
- }
- else
- throw MakeStringException(99, "Cannot write index file %s, file already exists (missing OVERWRITE attribute?)", filename.str());
- }
- }
- void buildUserMetadata(Owned<IPropertyTree> & metadata)
- {
- size32_t nameLen;
- char * nameBuff;
- size32_t valueLen;
- char * valueBuff;
- unsigned idx = 0;
- while(helper.getIndexMeta(nameLen, nameBuff, valueLen, valueBuff, idx++))
- {
- StringBuffer name(nameLen, nameBuff);
- StringBuffer value(valueLen, valueBuff);
- if(*nameBuff == '_' && strcmp(name, "_nodeSize") != 0)
- {
- OwnedRoxieString fname(helper.getFileName());
- throw MakeStringException(0, "Invalid name %s in user metadata for index %s (names beginning with underscore are reserved)", name.str(), fname.get());
- }
- if(!validateXMLTag(name.str()))
- {
- OwnedRoxieString fname(helper.getFileName());
- throw MakeStringException(0, "Invalid name %s in user metadata for index %s (not legal XML element name)", name.str(), fname.get());
- }
- if(!metadata)
- metadata.setown(createPTree("metadata"));
- metadata->setProp(name.str(), value.str());
- }
- }
- void buildLayoutMetadata(Owned<IPropertyTree> & metadata)
- {
- if(!metadata)
- metadata.setown(createPTree("metadata"));
- metadata->setProp("_record_ECL", helper.queryRecordECL());
- void * layoutMetaBuff;
- size32_t layoutMetaSize;
- if(helper.getIndexLayout(layoutMetaSize, layoutMetaBuff))
- {
- metadata->setPropBin("_record_layout", layoutMetaSize, layoutMetaBuff);
- rtlFree(layoutMetaBuff);
- }
- }
- public:
- CRoxieServerIndexWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerInternalSinkActivity(_factory, _probeManager, 0), helper(static_cast<IHThorIndexWriteArg &>(basehelper))
- {
- overwrite = ((helper.getFlags() & TIWoverwrite) != 0);
- reccount = 0;
- fileCrc = 0;
- }
- ~CRoxieServerIndexWriteActivity()
- {
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- resolve();
- }
- virtual void onExecute()
- {
- bool isVariable = helper.queryDiskRecordSize()->isVariableSize();
- size32_t maxDiskRecordSize;
- if (isVariable)
- {
- if (helper.getFlags() & TIWmaxlength)
- maxDiskRecordSize = helper.getMaxKeySize();
- else
- maxDiskRecordSize = KEYBUILD_MAXLENGTH; // Current default behaviour, could be improved in the future
- }
- else
- maxDiskRecordSize = helper.queryDiskRecordSize()->getFixedSize();
- if (maxDiskRecordSize > KEYBUILD_MAXLENGTH)
- throw MakeStringException(99, "Index maximum record length (%d) exceeds 32k internal limit", maxDiskRecordSize);
- OwnedMalloc<char> rowBuffer(maxDiskRecordSize, true);
- unsigned __int64 fileSize = 0;
- fileCrc = -1;
- OwnedRoxieString dsName(helper.getFileName());
- if (dsName.get())
- {
- Owned<const IResolvedFile> dsFileInfo = resolveLFN(dsName, false);
- if (dsFileInfo)
- {
- fileSize = dsFileInfo->getFileSize();
- }
- }
- {
- Owned<IFileIO> io;
- try
- {
- io.setown(writer->queryFile()->open(IFOcreate));
- }
- catch(IException * e)
- {
- e->Release();
- clearKeyStoreCache(false);
- io.setown(writer->queryFile()->open(IFOcreate));
- }
- if(!io)
- throw MakeStringException(errno, "Failed to create file %s for writing", filename.str());
- Owned<IFileIOStream> out = createIOStream(io);
- unsigned flags = COL_PREFIX | HTREE_FULLSORT_KEY;
- if (helper.getFlags() & TIWrowcompress)
- flags |= HTREE_COMPRESSED_KEY|HTREE_QUICK_COMPRESSED_KEY;
- else if (!(helper.getFlags() & TIWnolzwcompress))
- flags |= HTREE_COMPRESSED_KEY;
- if (isVariable)
- flags |= HTREE_VARSIZE;
- Owned<IPropertyTree> metadata;
- buildUserMetadata(metadata);
- buildLayoutMetadata(metadata);
- unsigned nodeSize = metadata ? metadata->getPropInt("_nodeSize", NODESIZE) : NODESIZE;
- Owned<IKeyBuilder> builder = createKeyBuilder(out, flags, maxDiskRecordSize, fileSize, nodeSize, helper.getKeyedSize(), 0);
- class BcWrapper : implements IBlobCreator
- {
- IKeyBuilder *builder;
- public:
- BcWrapper(IKeyBuilder *_builder) : builder(_builder) {}
- virtual unsigned __int64 createBlob(size32_t size, const void * ptr)
- {
- return builder->createBlob(size, (const char *) ptr);
- }
- } bc(builder);
- // Loop thru the results
- loop
- {
- OwnedConstRoxieRow nextrec(input->nextInGroup());
- if (!nextrec)
- {
- nextrec.setown(input->nextInGroup());
- if (!nextrec)
- break;
- }
- try
- {
- unsigned __int64 fpos;
- RtlStaticRowBuilder rowBuilder(rowBuffer, maxDiskRecordSize);
- size32_t thisSize = helper.transform(rowBuilder, nextrec, &bc, fpos);
- builder->processKeyData(rowBuffer, fpos, thisSize);
- }
- catch(IException * e)
- {
- throw makeWrappedException(e);
- }
- reccount++;
- }
- if(metadata)
- builder->finish(metadata,&fileCrc);
- else
- builder->finish(&fileCrc);
- }
- }
- virtual void stop(bool aborting)
- {
- if (writer)
- {
- if (!aborting)
- updateWorkUnitResult();
- writer->finish(!aborting, this);
- writer.clear();
- }
- CRoxieServerActivity::stop(aborting);
- }
- virtual void reset()
- {
- CRoxieServerActivity::reset();
- writer.clear();
- }
- //interface IRoxiePublishCallback
- virtual void setFileProperties(IFileDescriptor *desc) const
- {
- IPropertyTree &partProps = desc->queryPart(0)->queryProperties(); //properties of the first file part.
- IPropertyTree &fileProps = desc->queryProperties(); // properties of the logical file
- // Now publish to name services
- StringBuffer dir,base;
- offset_t indexFileSize = writer->queryFile()->size();
- if(clusterHandler)
- clusterHandler->splitPhysicalFilename(dir, base);
- else
- splitFilename(filename.str(), &dir, &dir, &base, &base);
- desc->setDefaultDir(dir.str());
- //properties of the first file part.
- Owned<IPropertyTree> attrs;
- if(clusterHandler)
- attrs.setown(createPTree("Part")); // clusterHandler is going to set attributes
- else
- {
- // add cluster
- StringBuffer mygroupname;
- desc->setNumParts(1);
- desc->setPartMask(base.str());
- attrs.set(&desc->queryPart(0)->queryProperties());
- }
- attrs->setPropInt64("@size", indexFileSize);
- CDateTime createTime, modifiedTime, accessedTime;
- writer->queryFile()->getTime(&createTime, &modifiedTime, &accessedTime);
- // round file time down to nearest sec. Nanosec accurancy is not preserved elsewhere and can lead to mismatch later.
- unsigned hour, min, sec, nanosec;
- modifiedTime.getTime(hour, min, sec, nanosec);
- modifiedTime.setTime(hour, min, sec, 0);
- StringBuffer timestr;
- modifiedTime.getString(timestr);
- if(timestr.length())
- attrs->setProp("@modified", timestr.str());
- if(clusterHandler)
- clusterHandler->setDescriptorParts(desc, base.str(), attrs);
- // properties of the logical file
- IPropertyTree & properties = desc->queryProperties();
- properties.setProp("@kind", "key");
- properties.setPropInt64("@size", indexFileSize);
- properties.setPropInt64("@recordCount", reccount);
- SCMStringBuffer info;
- WorkunitUpdate workUnit = ctx->updateWorkUnit();
- if (workUnit)
- {
- properties.setProp("@owner", workUnit->getUser(info).str());
- info.clear();
- properties.setProp("@workunit", workUnit->getWuid(info).str());
- info.clear();
- properties.setProp("@job", workUnit->getJobName(info).str());
- }
- char const * rececl = helper.queryRecordECL();
- if(rececl && *rececl)
- properties.setProp("ECL", rececl);
- if (helper.getFlags() & TIWexpires)
- setExpiryTime(properties, helper.getExpiryDays());
- if (helper.getFlags() & TIWupdate)
- {
- unsigned eclCRC;
- unsigned __int64 totalCRC;
- helper.getUpdateCRCs(eclCRC, totalCRC);
- properties.setPropInt("@eclCRC", eclCRC);
- properties.setPropInt64("@totalCRC", totalCRC);
- }
- properties.setPropInt("@fileCrc", fileCrc);
- properties.setPropInt("@formatCrc", helper.getFormatCrc());
- void * layoutMetaBuff;
- size32_t layoutMetaSize;
- if(helper.getIndexLayout(layoutMetaSize, layoutMetaBuff))
- {
- properties.setPropBin("_record_layout", layoutMetaSize, layoutMetaBuff);
- rtlFree(layoutMetaBuff);
- }
- }
- IUserDescriptor *queryUserDescriptor() const
- {
- IConstWorkUnit *workUnit = ctx->queryWorkUnit();
- if (workUnit)
- return workUnit->queryUserDescriptor();
- else
- return NULL;
- }
- };
- //=================================================================================
- class CRoxieServerIndexWriteActivityFactory : public CRoxieServerMultiOutputFactory
- {
- public:
- CRoxieServerIndexWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
- : CRoxieServerMultiOutputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- setNumOutputs(0);
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerIndexWriteActivity(this, _probeManager);
- }
- virtual bool isSink() const
- {
- return true;
- }
- };
- IRoxieServerActivityFactory *createRoxieServerIndexWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
- {
- return new CRoxieServerIndexWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
- }
- //=================================================================================
- static inline void getLimitType(unsigned flags, bool & limitFail, bool & limitOnFail)
- {
- if((flags & JFmatchAbortLimitSkips) != 0)
- {
- limitFail = false;
- limitOnFail = false;
- }
- else
- {
- limitOnFail = ((flags & JFonfail) != 0);
- limitFail = !limitOnFail;
- }
- }
- class CRoxieServerJoinActivity : public CRoxieServerTwoInputActivity
- {
- enum { JSfill, JSfillleft, JSfillright, JScollate, JScompare, JSleftonly, JSrightonly } state;
- IHThorJoinArg &helper;
- ICompare * collate;
- ICompare * collateupper;
- ThorActivityKind activityKind;
- bool leftOuterJoin;
- bool rightOuterJoin;
- bool exclude;
- bool limitFail;
- bool limitOnFail;
- unsigned keepLimit;
- unsigned joinLimit;
- unsigned atmostLimit;
- unsigned abortLimit;
- unsigned atmostsTriggered;
- bool betweenjoin;
- OwnedRowArray right;
- const void * left;
- const void * pendingRight;
- unsigned rightIndex;
- unsigned joinCounter;
- BoolArray matchedRight;
- bool matchedLeft;
- Owned<IException> failingLimit;
- ConstPointerArray filteredRight;
- Owned<IRHLimitedCompareHelper> limitedhelper;
- OwnedConstRoxieRow defaultLeft;
- OwnedConstRoxieRow defaultRight;
- Owned<IEngineRowAllocator> defaultLeftAllocator;
- Owned<IEngineRowAllocator> defaultRightAllocator;
- bool cloneLeft;
- void createDefaultLeft()
- {
- if (!defaultLeft)
- {
- if (!defaultLeftAllocator)
- defaultLeftAllocator.setown(ctx->queryCodeContext()->getRowAllocator(input->queryOutputMeta(), activityId));
- RtlDynamicRowBuilder rowBuilder(defaultLeftAllocator);
- size32_t thisSize = helper.createDefaultLeft(rowBuilder);
- defaultLeft.setown(rowBuilder.finalizeRowClear(thisSize));
- }
- }
- void createDefaultRight()
- {
- if (!defaultRight)
- {
- if (!defaultRightAllocator)
- defaultRightAllocator.setown(ctx->queryCodeContext()->getRowAllocator(input1->queryOutputMeta(), activityId));
- RtlDynamicRowBuilder rowBuilder(defaultRightAllocator);
- size32_t thisSize = helper.createDefaultRight(rowBuilder);
- defaultRight.setown(rowBuilder.finalizeRowClear(thisSize));
- }
- }
- public:
- CRoxieServerJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerTwoInputActivity(_factory, _probeManager), helper((IHThorJoinArg &)basehelper)
- {
- // MORE - some of this should be done in factory
- unsigned joinFlags = helper.getJoinFlags();
- leftOuterJoin = (joinFlags & JFleftouter) != 0;
- rightOuterJoin = (joinFlags & JFrightouter) != 0;
- exclude = (joinFlags & JFexclude) != 0;
- cloneLeft = (joinFlags & JFtransformmatchesleft) != 0;
- getLimitType(joinFlags, limitFail, limitOnFail);
- if (joinFlags & JFslidingmatch)
- {
- betweenjoin = true;
- collate = helper.queryCompareLeftRightLower();
- collateupper = helper.queryCompareLeftRightUpper();
- }
- else
- {
- betweenjoin = false;
- collate = collateupper = helper.queryCompareLeftRight();
- }
- rightIndex = 0;
- joinCounter = 0;
- state = JSfill;
- matchedLeft = false;
- joinLimit = 0;
- keepLimit = 0; // wait until ctx available
- atmostLimit = 0; // wait until ctx available
- abortLimit = 0; // wait until ctx available
- atmostsTriggered = 0;
- assertex((joinFlags & (JFfirst | JFfirstleft | JFfirstright)) == 0);
- left = NULL;
- pendingRight = NULL;
- activityKind = _factory->getKind();
- }
- virtual bool needsAllocator() const { return true; }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- left = NULL;
- rightIndex = 0;
- joinCounter = 0;
- state = JSfill;
- matchedLeft = false;
- CRoxieServerTwoInputActivity::start(parentExtractSize, parentExtract, paused);
- keepLimit = helper.getKeepLimit();
- if (keepLimit == 0)
- keepLimit = (unsigned)-1;
- atmostsTriggered = 0;
- atmostLimit = helper.getJoinLimit();
- if(atmostLimit == 0)
- atmostLimit = (unsigned)-1;
- else
- assertex(!rightOuterJoin && !betweenjoin);
- abortLimit = helper.getMatchAbortLimit();
- if (abortLimit == 0)
- abortLimit = (unsigned)-1;
- if (rightOuterJoin)
- createDefaultLeft();
- if ((leftOuterJoin && (activityKind==TAKjoin || activityKind==TAKjoinlight || activityKind==TAKdenormalizegroup)) || limitOnFail)
- createDefaultRight();
- if ((helper.getJoinFlags() & JFlimitedprefixjoin) && helper.getJoinLimit())
- { //limited match join (s[1..n])
- limitedhelper.setown(createRHLimitedCompareHelper());
- limitedhelper->init( helper.getJoinLimit(), input1, collate, helper.queryPrefixCompare() );
- }
- }
- virtual void reset()
- {
- if (atmostsTriggered)
- noteStatistic(STATS_ATMOST, atmostsTriggered, 1);
- right.clear();
- ReleaseClearRoxieRow(left);
- ReleaseClearRoxieRow(pendingRight);
- defaultRight.clear();
- defaultLeft.clear();
- CRoxieServerTwoInputActivity::reset();
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- switch(idx)
- {
- case 0:
- if ((helper.getJoinFlags() & JFparallel) != 0)
- {
- puller.setown(new CRoxieServerReadAheadInput(0)); // MORE - cant ask context for parallelJoinPreload as context is not yet set up.
- puller->setInput(0, _in);
- _in = puller;
- }
- input = _in;
- break;
- case 1:
- input1 = _in;
- break;
- default:
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
- }
- }
- virtual IRoxieInput *queryOutput(unsigned idx)
- {
- if (idx==(unsigned)-1)
- idx = 0;
- return idx ? NULL : this;
- }
- void fillLeft()
- {
- matchedLeft = false;
- left = input->nextInGroup();
- if (!left)
- left = input->nextInGroup();
- if(betweenjoin && left && pendingRight && (collate->docompare(left, pendingRight) >= 0))
- fillRight();
- if (limitedhelper && 0==rightIndex)
- {
- rightIndex = 0;
- joinCounter = 0;
- right.clear();
- matchedRight.kill();
- if (left)
- {
- limitedhelper->getGroup(right,left);
- ForEachItemIn(idx, right)
- matchedRight.append(false);
- }
- }
- }
- void fillRight()
- {
- if (limitedhelper)
- return;
- failingLimit.clear();
- if(betweenjoin && left)
- {
- aindex_t start = 0;
- while(right.isItem(start) && (collateupper->docompare(left, right.item(start)) > 0))
- start++;
- if(start>0)
- right.clearPart(0, start);
- }
- else
- right.clear();
- rightIndex = 0;
- joinCounter = 0;
- unsigned groupCount = 0;
- const void * next;
- while(true)
- {
- if(pendingRight)
- {
- next = pendingRight;
- pendingRight = NULL;
- }
- else
- {
- next = input1->nextInGroup();
- }
- if(!rightOuterJoin && next && (!left || (collateupper->docompare(left, next) > 0))) // if right is less than left, and not right outer, can skip group
- {
- while(next)
- {
- ReleaseClearRoxieRow(next);
- next = input1->nextInGroup();
- }
- continue;
- }
- while(next)
- {
- if(groupCount==abortLimit)
- {
- if(limitFail)
- failLimit();
- if (ctx->queryDebugContext())
- ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
- if(limitOnFail)
- {
- assertex(!failingLimit);
- try
- {
- failLimit();
- }
- catch(IException * except)
- {
- failingLimit.setown(except);
- }
- assertex(failingLimit != NULL);
- }
- right.append(next);
- do
- {
- next = input1->nextInGroup();
- ReleaseRoxieRow(next);
- } while(next);
- break;
- }
- else if(groupCount==atmostLimit)
- {
- atmostsTriggered++;
- right.clear();
- groupCount = 0;
- while(next)
- {
- ReleaseRoxieRow(next);
- next = input1->nextInGroup();
- }
- }
- else
- {
- right.append(next);
- groupCount++;
- }
- next = input1->nextInGroup();
- }
- // 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
- if(betweenjoin && left)
- {
- pendingRight = input1->nextInGroup();
- if(!pendingRight || (collate->docompare(left, pendingRight) < 0))
- break;
- }
- else
- break;
- }
- matchedRight.kill();
- ForEachItemIn(idx, right)
- matchedRight.append(false);
- }
- const void * joinRecords(const void * curLeft, const void * curRight, unsigned counter)
- {
- if (cloneLeft)
- {
- LinkRoxieRow(curLeft);
- return curLeft;
- }
- try
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- size32_t thisSize = helper.transform(rowBuilder, curLeft, curRight, counter);
- if (thisSize)
- return rowBuilder.finalizeRowClear(thisSize);
- else
- return NULL;
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- const void * denormalizeRecords(const void * curLeft, ConstPointerArray & rows)
- {
- try
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- unsigned numRows = rows.ordinality();
- const void * right = numRows ? rows.item(0) : defaultRight.get();
- size32_t thisSize = helper.transform(rowBuilder, curLeft, right, numRows, (const void * *)rows.getArray());
- if (thisSize)
- return rowBuilder.finalizeRowClear(thisSize);
- else
- return NULL;
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- const void * joinException(const void * curLeft, IException * except)
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- size32_t thisSize = helper.onFailTransform(rowBuilder, curLeft, defaultRight, except);
- return rowBuilder.finalizeRowClear(thisSize);
- }
- void failLimit()
- {
- helper.onMatchAbortLimitExceeded();
- CommonXmlWriter xmlwrite(0);
- if (input->queryOutputMeta() && input->queryOutputMeta()->hasXML())
- {
- input->queryOutputMeta()->toXML((byte *) left, xmlwrite);
- }
- throw MakeStringException(ROXIE_TOO_MANY_RESULTS, "More than %d match candidates in join %d for row %s", abortLimit, queryId(), xmlwrite.str());
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- loop
- {
- switch (state)
- {
- case JSfill:
- fillLeft();
- state = JSfillright;
- break;
- case JSfillright:
- fillRight();
- state = JScollate;
- break;
- case JSfillleft:
- fillLeft();
- state = JScollate;
- break;
- case JScollate:
- if (right.ordinality() == 0)
- {
- if (left == NULL)
- return NULL;
- state = JSleftonly;
- }
- else
- {
- if (!left)
- state = JSrightonly;
- else
- {
- int diff;
- if(betweenjoin)
- diff = ((collate->docompare(left, right.item(0)) < 0) ? -1 : ((collateupper->docompare(left, right.item(right.ordinality()-1)) > 0) ? +1 : 0));
- else
- diff = collate->docompare(left, right.item(0));
- bool limitExceeded = right.ordinality()>abortLimit;
- if (diff == 0)
- {
- if (limitExceeded)
- {
- const void * ret = NULL;
- if(failingLimit)
- ret = joinException(left, failingLimit);
- ReleaseRoxieRow(left);
- left = NULL;
- state = JSfillleft;
- ForEachItemIn(idx, right)
- matchedRight.replace(true, idx);
- if(ret)
- {
- processed++;
- return ret;
- }
- }
- else
- {
- state = JScompare;
- joinLimit = keepLimit;
- }
- }
- else if (diff < 0)
- state = JSleftonly;
- else if (limitExceeded)
- {
- // MORE - Roxie code seems to think there should be a destroyRowset(right) here....
- state = JSfillright;
- }
- else
- state = JSrightonly;
- }
- }
- break;
- case JSrightonly:
- if (rightOuterJoin)
- {
- switch (activityKind)
- {
- case TAKjoin:
- {
- while (right.isItem(rightIndex))
- {
- if (!matchedRight.item(rightIndex))
- {
- const void * rhs = right.item(rightIndex++);
- const void *ret = joinRecords(defaultLeft, rhs, 0);
- if (ret)
- {
- processed++;
- return ret;
- }
- }
- else
- rightIndex++;
- }
- break;
- }
- //Probably excessive to implement the following, but possibly useful
- case TAKdenormalize:
- {
- OwnedConstRoxieRow newLeft;
- newLeft.set(defaultLeft);
- unsigned rowSize = 0;
- unsigned leftCount = 0;
- while (right.isItem(rightIndex))
- {
- if (!matchedRight.item(rightIndex))
- {
- const void * rhs = right.item(rightIndex);
- try
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- unsigned thisSize = helper.transform(rowBuilder, newLeft, rhs, ++leftCount);
- if (thisSize)
- {
- rowSize = thisSize;
- newLeft.setown(rowBuilder.finalizeRowClear(rowSize));
- }
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- rightIndex++;
- }
- state = JSfillright;
- if (rowSize)
- {
- processed++;
- return newLeft.getClear();
- }
- break;
- }
- case TAKdenormalizegroup:
- {
- filteredRight.kill();
- while (right.isItem(rightIndex))
- {
- if (!matchedRight.item(rightIndex))
- filteredRight.append(right.item(rightIndex));
- rightIndex++;
- }
- state = JSfillright;
- if (filteredRight.ordinality())
- {
- const void * ret = denormalizeRecords(defaultLeft, filteredRight);
- filteredRight.kill();
- if (ret)
- {
- processed++;
- return ret;
- }
- }
- break;
- }
- }
- }
- state = JSfillright;
- break;
-
- case JSleftonly:
- {
- const void * ret = NULL;
- if (!matchedLeft && leftOuterJoin)
- {
- switch (activityKind)
- {
- case TAKjoin:
- ret = joinRecords(left, defaultRight, 0);
- break;
- case TAKdenormalize:
- ret = left;
- left = NULL;
- break;
- case TAKdenormalizegroup:
- filteredRight.kill();
- ret = denormalizeRecords(left, filteredRight);
- break;
- }
- }
- ReleaseRoxieRow(left);
- left = NULL;
- state = JSfillleft;
- if (ret)
- {
- processed++;
- return ret;
- }
- break;
- }
- case JScompare:
- if (joinLimit != 0)
- {
- switch (activityKind)
- {
- case TAKjoin:
- {
- while (right.isItem(rightIndex))
- {
- const void * rhs = right.item(rightIndex++);
- if (helper.match(left, rhs))
- {
- matchedRight.replace(true, rightIndex-1);
- matchedLeft = true;
- if (!exclude)
- {
- const void *ret = joinRecords(left, rhs, ++joinCounter);
- if (ret)
- {
- processed++;
- joinLimit--;
- return ret;
- }
- }
- }
- }
- break;
- }
- case TAKdenormalize:
- {
- OwnedConstRoxieRow newLeft;
- newLeft.set(left);
- unsigned rowSize = 0;
- unsigned leftCount = 0;
- while (right.isItem(rightIndex) && joinLimit)
- {
- try
- {
- const void * rhs = right.item(rightIndex++);
- if (helper.match(left, rhs))
- {
- matchedRight.replace(true, rightIndex-1);
- matchedLeft = true;
- if (!exclude)
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- unsigned thisSize = helper.transform(rowBuilder, newLeft, rhs, ++leftCount);
- if (thisSize)
- {
- rowSize = thisSize;
- newLeft.setown(rowBuilder.finalizeRowClear(rowSize));
- joinLimit--;
- }
- }
- }
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- state = JSleftonly;
- rightIndex = 0;
- if (rowSize)
- {
- processed++;
- return newLeft.getClear();
- }
- break;
- }
- case TAKdenormalizegroup:
- {
- filteredRight.kill();
- while (right.isItem(rightIndex))
- {
- const void * rhs = right.item(rightIndex++);
- if (helper.match(left, rhs))
- {
- matchedRight.replace(true, rightIndex-1);
- filteredRight.append(rhs);
- matchedLeft = true;
- if (filteredRight.ordinality()==joinLimit)
- break;
- }
- }
- state = JSleftonly;
- rightIndex = 0;
- if (!exclude && filteredRight.ordinality())
- {
- const void * ret = denormalizeRecords(left, filteredRight);
- filteredRight.kill();
- if (ret)
- {
- processed++;
- return ret;
- }
- }
- break;
- }
- }
- }
- state = JSleftonly;
- rightIndex = 0;
- joinCounter = 0;
- break;
- }
- }
- }
- };
- class CRoxieServerJoinActivityFactory : public CRoxieServerActivityFactory
- {
- unsigned input2;
- unsigned input2idx;
- public:
- CRoxieServerJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- input2 = 0;
- input2idx = 0;
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerJoinActivity(this, _probeManager);
- }
- virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
- {
- if (idx==1)
- {
- input2 = source;
- input2idx = sourceidx;
- }
- else
- CRoxieServerActivityFactory::setInput(idx, source, sourceidx);
- }
- virtual unsigned getInput(unsigned idx, unsigned &sourceidx) const
- {
- switch (idx)
- {
- case 1:
- sourceidx = input2idx;
- return input2;
- case 0:
- return CRoxieServerActivityFactory::getInput(idx, sourceidx);
- default:
- return (unsigned) -1;
- }
- }
- virtual unsigned numInputs() const { return 2; }
- };
- IRoxieServerActivityFactory *createRoxieServerJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- #define CONCAT_READAHEAD 1000
- class CRoxieThreadedConcatReader : public CInterface, implements IRecordPullerCallback
- {
- public:
- IMPLEMENT_IINTERFACE;
- CRoxieThreadedConcatReader(InterruptableSemaphore &_ready, bool _grouped)
- : puller(false), grouped(_grouped), atEog(true), ready(_ready), eof(false)
- {
- }
- void start(unsigned parentExtractSize, const byte *parentExtract, bool paused, IRoxieSlaveContext *ctx)
- {
- space.reinit(CONCAT_READAHEAD);
- puller.start(parentExtractSize, parentExtract, paused, ctx->concatPreload(), false, ctx);
- }
- void stop(bool aborting)
- {
- space.interrupt();
- puller.stop(aborting);
- }
- IRoxieInput *queryInput() const
- {
- return puller.queryInput();
- }
- void reset()
- {
- puller.reset();
- ForEachItemIn(idx, buffer)
- ReleaseRoxieRow(buffer.item(idx));
- buffer.clear();
- eof = false;
- atEog = true;
- }
- void setInput(IRoxieInput *_in)
- {
- puller.setInput(this, _in);
- }
- virtual void processRow(const void *row)
- {
- buffer.enqueue(row);
- ready.signal();
- space.wait();
- }
- virtual void processGroup(const ConstPointerArray &rows)
- {
- // We use record-by-record input mode of the puller thread even in grouped mode.
- throwUnexpected();
- }
- virtual void processEOG()
- {
- if (grouped)
- processRow(NULL);
- }
- virtual void processDone()
- {
- processRow(NULL);
- }
- virtual bool fireException(IException *e)
- {
- // called from puller thread on failure
- ready.interrupt(LINK(e));
- space.interrupt(e);
- return true;
- }
- bool peek(const void * &row, bool &anyActive)
- {
- if (!eof)
- {
- if (buffer.ordinality())
- {
- space.signal();
- row = buffer.dequeue();
- if (row==NULL)
- {
- if (atEog)
- {
- eof = true;
- return false;
- }
- else
- atEog = true;
- }
- else if (grouped)
- atEog = false;
- return true;
- }
- anyActive = true;
- }
- return false;
- }
- protected:
- RecordPullerThread puller;
- InterruptableSemaphore space;
- InterruptableSemaphore &ready;
- SafeQueueOf<const void, true> buffer;
- bool atEog;
- bool eof;
- bool grouped;
- };
- MAKEPointerArray(CRoxieThreadedConcatReader, ReaderArray);
- class CRoxieServerThreadedConcatActivity : public CRoxieServerActivity
- {
- InterruptableSemaphore ready;
- ReaderArray pullers;
- unsigned numInputs;
- unsigned nextPuller; // for round robin
- unsigned readyPending;
- bool eof;
- bool inGroup;
- bool grouped;
- public:
- CRoxieServerThreadedConcatActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _grouped, unsigned _numInputs)
- : CRoxieServerActivity(_factory, _probeManager), grouped(_grouped)
- {
- numInputs = _numInputs;
- eof = (numInputs==0);
- inGroup = false;
- nextPuller = 0;
- readyPending = 0;
- for (unsigned i = 0; i < numInputs; i++)
- pullers.append(*new CRoxieThreadedConcatReader(ready, _grouped));
- }
- ~CRoxieServerThreadedConcatActivity()
- {
- ForEachItemIn(idx, pullers)
- delete &pullers.item(idx);
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- eof = (numInputs==0);
- inGroup = false;
- nextPuller = 0;
- readyPending = 0;
- ready.reinit();
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- ForEachItemIn(idx, pullers)
- {
- pullers.item(idx).start(parentExtractSize, parentExtract, paused, ctx);
- // NOTE - it is ok to start the thread running while parts of the subgraph are still being started, since everything
- // in the part of the subgraph that the thread uses has been started.
- // Note that splitters are supposed to cope with being used when only some outputs have been started.
- }
- }
- virtual void stop(bool aborting)
- {
- ready.interrupt();
- ForEachItemIn(idx, pullers)
- pullers.item(idx).stop(aborting);
- CRoxieServerActivity::stop(aborting);
- }
- virtual unsigned __int64 queryLocalCycles() const
- {
- return 0;
- }
- virtual IRoxieInput *queryInput(unsigned idx) const
- {
- if (pullers.isItem(idx))
- return pullers.item(idx).queryInput();
- else
- return NULL;
- }
- virtual void reset()
- {
- CRoxieServerActivity::reset();
- ForEachItemIn(idx, pullers)
- pullers.item(idx).reset();
- eof = false;
- inGroup = false;
- nextPuller = 0;
- readyPending = 0;
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- if (pullers.isItem(idx))
- pullers.item(idx).setInput(_in);
- else
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (eof)
- return NULL;
- loop
- {
- if (readyPending && !inGroup)
- {
- if (readyPending > 1)
- ready.signal(readyPending-1);
- readyPending = 0;
- }
- else
- ready.wait();
- bool anyActive = false;
- ForEachItemIn(unused_index, pullers)
- {
- // NOTE - we round robin not just because it's more efficient, but because it ensures the preservation of grouping information
- const void *ret;
- bool fetched = pullers.item(nextPuller).peek(ret, anyActive);
- if (fetched)
- {
- inGroup = (ret != NULL);
- return ret;
- }
- if (inGroup && grouped)
- {
- // Some other puller has data, but we can't consume it until the group we are reading is complete.
- readyPending++;
- anyActive = true;
- break;
- }
- nextPuller++;
- if (nextPuller==pullers.ordinality())
- nextPuller = 0;
- }
- if (!anyActive)
- break;
- // A ready signal without anything being ready means someone reached end-of-file.
- }
- eof = true;
- return NULL;
- }
- };
- class CRoxieServerOrderedConcatActivity : public CRoxieServerActivity
- {
- IRoxieInput *curInput;
- bool eogSeen;
- bool anyThisGroup;
- bool grouped;
- unsigned numInputs;
- unsigned inputIdx;
- IRoxieInput **inputArray;
- public:
- CRoxieServerOrderedConcatActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _grouped, unsigned _numInputs)
- : CRoxieServerActivity(_factory, _probeManager)
- {
- eogSeen = false;
- anyThisGroup = false;
- grouped = _grouped;
- numInputs = _numInputs;
- inputIdx = 0;
- inputArray = new IRoxieInput*[numInputs];
- for (unsigned i = 0; i < numInputs; i++)
- inputArray[i] = NULL;
- curInput = NULL;
- }
- ~CRoxieServerOrderedConcatActivity()
- {
- delete [] inputArray;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- inputIdx = 0;
- curInput = inputArray[inputIdx];
- eogSeen = false;
- anyThisGroup = false;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- for (unsigned i = 0; i < numInputs; i++)
- inputArray[i]->start(parentExtractSize, parentExtract, paused);
- }
- virtual void stop(bool aborting)
- {
- for (unsigned i = 0; i < numInputs; i++)
- inputArray[i]->stop(aborting);
- CRoxieServerActivity::stop(aborting);
- }
- virtual unsigned __int64 queryLocalCycles() const
- {
- return 0;
- }
- virtual IRoxieInput *queryInput(unsigned idx) const
- {
- if (idx < numInputs)
- return inputArray[idx];
- else
- return NULL;
- }
- virtual void reset()
- {
- CRoxieServerActivity::reset();
- for (unsigned i = 0; i < numInputs; i++)
- inputArray[i]->reset();
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- inputArray[idx] = _in;
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (!curInput)
- return NULL; // eof
- const void * next = curInput->nextInGroup();
- if (next)
- {
- anyThisGroup = true;
- eogSeen = false;
- processed++;
- return next;
- }
- else if (!eogSeen)
- {
- eogSeen = true;
- if (grouped)
- {
- if (anyThisGroup)
- {
- anyThisGroup = false;
- return NULL;
- }
- else
- return nextInGroup();
- }
- else
- return nextInGroup();
- }
- else if (inputIdx < numInputs-1)
- {
- inputIdx++;
- curInput = inputArray[inputIdx];
- eogSeen = false;
- return nextInGroup();
- }
- else
- {
- curInput = NULL;
- return NULL;
- }
- }
- };
- class CRoxieServerConcatActivityFactory : public CRoxieServerMultiInputFactory
- {
- bool ordered;
- bool grouped;
- public:
- CRoxieServerConcatActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- Owned <IHThorFunnelArg> helper = (IHThorFunnelArg *) helperFactory();
- ordered = helper->isOrdered();
- grouped = helper->queryOutputMeta()->isGrouped();
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- if (ordered || (_probeManager && _probeManager->queryDebugManager()))
- return new CRoxieServerOrderedConcatActivity(this, _probeManager, grouped, numInputs());
- else
- return new CRoxieServerThreadedConcatActivity(this, _probeManager, grouped, numInputs());
- }
- };
- IRoxieServerActivityFactory *createRoxieServerConcatActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerConcatActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerNonEmptyActivity : public CRoxieServerMultiInputBaseActivity
- {
- IRoxieInput * selectedInput;
- unsigned savedParentExtractSize;
- const byte * savedParentExtract;
- bool foundInput;
- public:
- CRoxieServerNonEmptyActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
- : CRoxieServerMultiInputBaseActivity(_factory, _probeManager, _numInputs)
- {
- foundInput = false;
- selectedInput = NULL;
- savedParentExtractSize = 0;;
- savedParentExtract = NULL;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- //Don't start the inputs yet so we can short-circuit...
- CRoxieServerMultiInputBaseActivity::start(parentExtractSize, parentExtract, paused);
- savedParentExtractSize = parentExtractSize;
- savedParentExtract = parentExtract;
- }
- virtual void stop(bool aborting)
- {
- if (foundInput)
- {
- if (selectedInput)
- selectedInput->stop(aborting);
- }
- else
- {
- for (unsigned i = 0; i < numInputs; i++)
- inputArray[i]->stop(aborting);
- }
- CRoxieServerMultiInputBaseActivity::stop(aborting);
- }
- virtual void reset()
- {
- CRoxieServerMultiInputBaseActivity::reset();
- foundInput = false;
- selectedInput = NULL;
- }
- virtual unsigned __int64 queryLocalCycles() const
- {
- return 0; // Can't easily calcuate anything reliable but local processing is negligible
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (!foundInput)
- {
- foundInput = true;
- //If we get an exception in this loop then stop() will stop any started inputs
- for (unsigned i=0; i < numInputs; i++)
- {
- selectedInput = inputArray[i];
- selectedInput->start(savedParentExtractSize, savedParentExtract, false);
- const void * next = selectedInput->nextInGroup();
- if (next)
- {
- //Found a row so stop remaining
- for (unsigned j=i+1; j < numInputs; j++)
- inputArray[j]->stop(false);
- processed++;
- return next;
- }
- selectedInput->stop(false);
- }
- selectedInput = NULL;
- return NULL;
- }
- if (!selectedInput)
- return NULL;
- const void * next = selectedInput->nextInGroup();
- if (next)
- processed++;
- return next;
- }
- };
- class CRoxieServerNonEmptyActivityFactory : public CRoxieServerMultiInputFactory
- {
- public:
- CRoxieServerNonEmptyActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerNonEmptyActivity(this, _probeManager, numInputs());
- }
- };
- IRoxieServerActivityFactory *createRoxieServerNonEmptyActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerNonEmptyActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerMergeActivity : public CRoxieServerActivity
- {
- IHThorMergeArg &helper;
- unsigned *mergeheap;
- unsigned activeInputs;
- unsigned numInputs;
- IRoxieInput **inputArray;
- const void **pending;
- bool first;
- ICompare *compare;
- bool dedup;
- void permute()
- {
- assertex(activeInputs == 0);
- for(unsigned i = 0; i < numInputs; i++)
- if(pullInput(i))
- mergeheap[activeInputs++] = i;
- // the tree structure: element p has children p*2+1 and p*2+2, or element c has parent (unsigned)(c-1)/2
- // the heap property: no element should be smaller than its parent
- // the dedup variant: if(dedup), the top of the heap should also not be equal to either child
- // 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
- if (activeInputs >= 2)
- for(unsigned p = (activeInputs-2)/2; p > 0; --p)
- siftDown(p);
- if(dedup)
- siftDownDedupTop();
- else
- siftDown(0);
- }
- void readNext()
- {
- if(!pullInput(mergeheap[0]))
- if(!promote(0))
- return;
- // we have changed the element at the top of the heap, so need to sift it down to maintain the heap property
- if(dedup)
- siftDownDedupTop();
- else
- siftDown(0);
- }
- bool pullInput(unsigned i)
- {
- const void *next = inputArray[i]->nextInGroup();
- if (!next)
- next = inputArray[i]->nextInGroup();
- pending[i] = next;
- return (next != NULL);
- }
- bool promote(unsigned p)
- {
- activeInputs--;
- if(activeInputs == p)
- return false;
- mergeheap[p] = mergeheap[activeInputs];
- return true;
- }
- bool siftDown(unsigned p)
- {
- // assumimg that all descendents of p form a heap, sift p down to its correct position, and so include it in the heap
- bool nochange = true;
- while(1)
- {
- unsigned c = p*2 + 1;
- if(c >= activeInputs)
- return nochange;
- if(c+1 < activeInputs)
- {
- int childcmp = BuffCompare(c+1, c);
- if((childcmp < 0) || ((childcmp == 0) && (mergeheap[c+1] < mergeheap[c])))
- ++c;
- }
- int cmp = BuffCompare(c, p);
- if((cmp > 0) || ((cmp == 0) && (mergeheap[c] > mergeheap[p])))
- return nochange;
- nochange = false;
- unsigned r = mergeheap[c];
- mergeheap[c] = mergeheap[p];
- mergeheap[p] = r;
- p = c;
- }
- }
- void siftDownDedupTop()
- {
- // same as siftDown(0), except that it also ensures that the top of the heap is not equal to either of its children
- if(activeInputs < 2)
- return;
- unsigned c = 1;
- int childcmp = 1;
- if(activeInputs >= 3)
- {
- childcmp = BuffCompare(2, 1);
- if(childcmp < 0)
- c = 2;
- }
- int cmp = BuffCompare(c, 0);
- if(cmp > 0)
- return;
- // the following loop ensures the correct property holds on the smaller branch, and that childcmp==0 iff the top matches the other branch
- while(cmp <= 0)
- {
- if(cmp == 0)
- {
- if(mergeheap[c] < mergeheap[0])
- {
- unsigned r = mergeheap[c];
- mergeheap[c] = mergeheap[0];
- mergeheap[0] = r;
- }
- ReleaseClearRoxieRow(pending[mergeheap[c]]);
- if(!pullInput(mergeheap[c]))
- if(!promote(c))
- break;
- siftDown(c);
- }
- else
- {
- unsigned r = mergeheap[c];
- mergeheap[c] = mergeheap[0];
- mergeheap[0] = r;
- if(siftDown(c))
- break;
- }
- cmp = BuffCompare(c, 0);
- }
- // the following loop ensures the uniqueness property holds on the other branch too
- c = 3-c;
- if(activeInputs <= c)
- return;
- while(childcmp == 0)
- {
- if(mergeheap[c] < mergeheap[0])
- {
- unsigned r = mergeheap[c];
- mergeheap[c] = mergeheap[0];
- mergeheap[0] = r;
- }
- ReleaseClearRoxieRow(pending[mergeheap[c]]);
- if(!pullInput(mergeheap[c]))
- if(!promote(c))
- break;
- siftDown(c);
- childcmp = BuffCompare(c, 0);
- }
- }
- inline int BuffCompare(unsigned a, unsigned b)
- {
- return compare->docompare(pending[mergeheap[a]], pending[mergeheap[b]]);
- }
- public:
- CRoxieServerMergeActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorMergeArg &)basehelper), numInputs(_numInputs)
- {
- activeInputs = 0;
- first = true;
- mergeheap = new unsigned[numInputs];
- inputArray = new IRoxieInput*[numInputs];
- pending = new const void *[numInputs];
- compare = helper.queryCompare();
- dedup = helper.dedup();
- for (unsigned i = 0; i < numInputs; i++)
- {
- inputArray[i] = NULL;
- pending[i] = NULL;
- }
- }
- ~CRoxieServerMergeActivity()
- {
- delete [] mergeheap;
- delete [] inputArray;
- delete [] pending;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- activeInputs = 0;
- first = true;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- for (unsigned i = 0; i < numInputs; i++)
- {
- inputArray[i]->start(parentExtractSize, parentExtract, paused);
- }
- }
- virtual void stop(bool aborting)
- {
- for (unsigned i = 0; i < numInputs; i++)
- {
- inputArray[i]->stop(aborting);
- }
- CRoxieServerActivity::stop(aborting);
- }
- virtual void reset()
- {
- for (unsigned i = 0; i < numInputs; i++)
- {
- ReleaseClearRoxieRow(pending[i]);
- inputArray[i]->reset();
- }
- CRoxieServerActivity::reset();
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- inputArray[idx] = _in;
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (first)
- {
- permute();
- first = false;
- }
- if (activeInputs)
- {
- const void *next = pending[mergeheap[0]];
- readNext();
- if (next)
- processed++;
- return next;
- }
- else
- return NULL;
- }
- };
- class CRoxieServerMergeActivityFactory : public CRoxieServerMultiInputFactory
- {
- public:
- CRoxieServerMergeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerMergeActivity(this, _probeManager, numInputs());
- }
- };
- IRoxieServerActivityFactory *createRoxieServerMergeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerMergeActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerRegroupActivity : public CRoxieServerMultiInputActivity
- {
- IHThorRegroupArg &helper;
- unsigned inputIndex;
- bool eof;
- unsigned __int64 numProcessedLastGroup;
- public:
- CRoxieServerRegroupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
- : CRoxieServerMultiInputActivity(_factory, _probeManager, _numInputs), helper((IHThorRegroupArg &)basehelper)
- {
- inputIndex = 0;
- eof = false;
- numProcessedLastGroup = 0;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- inputIndex = 0;
- eof = false;
- numProcessedLastGroup = processed;
- CRoxieServerMultiInputActivity::start(parentExtractSize, parentExtract, paused);
- }
- const void * nextFromInputs()
- {
- unsigned initialInput = inputIndex;
- while (inputIndex < numInputs)
- {
- const void * next = inputArray[inputIndex]->nextInGroup();
- if (next)
- {
- if ((inputIndex != initialInput) && (inputIndex != initialInput+1))
- {
- ReleaseRoxieRow(next);
- throw MakeStringException(ROXIE_MISMATCH_GROUP_ERROR, "Mismatched groups supplied to Regroup (%d)", factory->queryId());
- }
- return next;
- }
- inputIndex++;
- }
- if ((initialInput != 0) && (initialInput+1 != numInputs))
- throw MakeStringException(ROXIE_MISMATCH_GROUP_ERROR, "Mismatched groups supplied to Regroup (%d)", factory->queryId());
- inputIndex = 0;
- return NULL;
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (eof)
- return NULL;
- const void * ret = nextFromInputs();
- if (ret)
- {
- processed++;
- return ret;
- }
- if (numProcessedLastGroup != processed)
- {
- numProcessedLastGroup = processed;
- return NULL;
- }
- eof = true;
- return NULL;
- }
- #if 0
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- //MORE: RKC: Do we want to do this i) always ii) conditionally iii) never
- if (idx)
- {
- puller.setown(new CRoxieServerReadAheadInput(0)); // MORE - cant ask context for parallelJoinPreload as context is not yet set up.
- puller->setInput(0, _in);
- CRoxieServerMultiInputActivity::setInput(idx, puller);
- }
- else
- CRoxieServerMultiInputActivity::setInput(idx, _in);
- }
- #endif
- };
- class CRoxieServerRegroupActivityFactory : public CRoxieServerMultiInputFactory
- {
- public:
- CRoxieServerRegroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerRegroupActivity(this, _probeManager, numInputs());
- }
- };
- IRoxieServerActivityFactory *createRoxieServerRegroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerRegroupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerCombineActivity : public CRoxieServerMultiInputActivity
- {
- IHThorCombineArg &helper;
- unsigned __int64 numProcessedLastGroup;
- public:
- CRoxieServerCombineActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
- : CRoxieServerMultiInputActivity(_factory, _probeManager, _numInputs), helper((IHThorCombineArg &)basehelper)
- {
- numProcessedLastGroup = 0;
- }
- ~CRoxieServerCombineActivity()
- {
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- numProcessedLastGroup = processed;
- CRoxieServerMultiInputActivity::start(parentExtractSize, parentExtract, paused);
- }
- void nextInputs(ConstPointerArray & out)
- {
- for (unsigned i=0; i < numInputs; i++)
- {
- const void * next = inputArray[i]->nextInGroup();
- if (next)
- out.append(next);
- }
- }
- virtual bool needsAllocator() const { return true; }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- loop
- {
- ConstPointerArray group;
- nextInputs(group);
- if ((group.ordinality() == 0) && (numProcessedLastGroup == processed))
- nextInputs(group);
- if (group.ordinality() == 0)
- {
- numProcessedLastGroup = processed;
- return NULL;
- }
- else if (group.ordinality() != numInputs)
- {
- ReleaseRoxieRowSet(group);
- throw MakeStringException(ROXIE_MISMATCH_GROUP_ERROR, "Mismatched group input for Combine Activity(%d)", factory->queryId());
- }
- try
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- size32_t outSize = helper.transform(rowBuilder, group.ordinality(), group.getArray());
- ReleaseRoxieRowSet(group);
- if (outSize)
- {
- processed++;
- return rowBuilder.finalizeRowClear(outSize);
- }
- }
- catch (IException *E)
- {
- ReleaseRoxieRowSet(group);
- throw makeWrappedException(E);
- }
- }
- }
- };
- class CRoxieServerCombineActivityFactory : public CRoxieServerMultiInputFactory
- {
- public:
- CRoxieServerCombineActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerCombineActivity(this, _probeManager, numInputs());
- }
- };
- IRoxieServerActivityFactory *createRoxieServerCombineActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerCombineActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerCombineGroupActivity : public CRoxieServerTwoInputActivity
- {
- IHThorCombineGroupArg &helper;
- unsigned __int64 numProcessedLastGroup;
- public:
- CRoxieServerCombineGroupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerTwoInputActivity(_factory, _probeManager), helper((IHThorCombineGroupArg &)basehelper)
- {
- numProcessedLastGroup = 0;
- }
- ~CRoxieServerCombineGroupActivity()
- {
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- numProcessedLastGroup = processed;
- CRoxieServerTwoInputActivity::start(parentExtractSize, parentExtract, paused);
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- switch(idx)
- {
- case 0:
- #if 0
- //MORE: RKC: Do we want to do this i) always ii) conditionally iii) never
- puller.setown(new CRoxieServerReadAheadInput(0)); // MORE - cant ask context for parallelJoinPreload as context is not yet set up.
- puller->setInput(0, _in);
- _in = puller;
- #endif
- input = _in;
- break;
- case 1:
- input1 = _in;
- break;
- default:
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
- }
- }
- virtual IRoxieInput *queryOutput(unsigned idx)
- {
- if (idx==(unsigned)-1)
- idx = 0;
- return idx ? NULL : this;
- }
- virtual bool needsAllocator() const { return true; }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- loop
- {
- const void * left = input->nextInGroup();
- if (!left && (numProcessedLastGroup == processed))
- left = input->nextInGroup();
- if (!left)
- {
- if (numProcessedLastGroup == processed)
- {
- const void * nextRight = input1->nextInGroup();
- if (nextRight)
- {
- ReleaseRoxieRow(nextRight);
- throw MakeStringException(ROXIE_MISSING_GROUP_ERROR, "Missing LEFT record for Combine Group (%d)", factory->queryId());
- }
- }
- else
- numProcessedLastGroup = processed;
- return NULL;
- }
- ConstPointerArray group;
- loop
- {
- const void * in = input1->nextInGroup();
- if (!in)
- break;
- group.append(in);
- }
- if (group.ordinality() == 0)
- {
- ReleaseRoxieRow(left);
- ReleaseRoxieRowSet(group);
- throw MakeStringException(ROXIE_MISSING_GROUP_ERROR, "Missing RIGHT group for Combine Group (%d)", factory->queryId());
- }
- try
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- size32_t outSize = helper.transform(rowBuilder, left, group.ordinality(), (const void * *)group.getArray());
- ReleaseRoxieRow(left);
- ReleaseRoxieRowSet(group);
- if (outSize)
- {
- processed++;
- return rowBuilder.finalizeRowClear(outSize);
- }
- }
- catch (IException *E)
- {
- ReleaseRoxieRow(left);
- ReleaseRoxieRowSet(group);
- throw makeWrappedException(E);
- }
- }
- }
- };
- class CRoxieServerCombineGroupActivityFactory : public CRoxieServerActivityFactory
- {
- unsigned input2;
- unsigned input2idx;
- public:
- CRoxieServerCombineGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- input2 = 0;
- input2idx = 0;
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerCombineGroupActivity(this, _probeManager);
- }
- virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
- {
- if (idx==1)
- {
- input2 = source;
- input2idx = sourceidx;
- }
- else
- CRoxieServerActivityFactory::setInput(idx, source, sourceidx);
- }
- virtual unsigned getInput(unsigned idx, unsigned &sourceidx) const
- {
- switch (idx)
- {
- case 1:
- sourceidx = input2idx;
- return input2;
- case 0:
- return CRoxieServerActivityFactory::getInput(idx, sourceidx);
- default:
- return (unsigned) -1;
- }
- }
- virtual unsigned numInputs() const { return 2; }
- };
- IRoxieServerActivityFactory *createRoxieServerCombineGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerCombineGroupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerRollupGroupActivity : public CRoxieServerActivity
- {
- IHThorRollupGroupArg &helper;
- bool eof;
- public:
- CRoxieServerRollupGroupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager),
- helper((IHThorRollupGroupArg &)basehelper)
- {
- eof = false;
- }
- ~CRoxieServerRollupGroupActivity()
- {
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- eof = false;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- }
- virtual bool needsAllocator() const { return true; }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (eof)
- return NULL;
- loop
- {
- ConstPointerArray group;
- loop
- {
- const void * in = input->nextInGroup();
- if (!in)
- break;
- group.append(in);
- }
- if (group.ordinality() == 0)
- {
- eof = true;
- return NULL;
- }
- try
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- size32_t outSize = helper.transform(rowBuilder, group.ordinality(), (const void * *)group.getArray());
- ReleaseRoxieRowSet(group);
- if (outSize)
- {
- processed++;
- return rowBuilder.finalizeRowClear(outSize);
- }
- }
- catch (IException * E)
- {
- ReleaseRoxieRowSet(group);
- throw makeWrappedException(E);
- }
- }
- }
- };
- class CRoxieServerRollupGroupActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerRollupGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerRollupGroupActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerRollupGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerRollupGroupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerFilterProjectActivity : public CRoxieServerLateStartActivity
- {
- IHThorFilterProjectArg &helper;
- unsigned numProcessedLastGroup;
- unsigned __int64 recordCount;
- public:
- CRoxieServerFilterProjectActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerLateStartActivity(_factory, _probeManager), helper((IHThorFilterProjectArg &)basehelper)
- {
- numProcessedLastGroup = 0;
- recordCount = 0;
- }
- ~CRoxieServerFilterProjectActivity()
- {
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- numProcessedLastGroup = 0;
- recordCount = 0;
- CRoxieServerLateStartActivity::start(parentExtractSize, parentExtract, paused);
- lateStart(parentExtractSize, parentExtract, helper.canMatchAny()); //sets eof
- }
- virtual bool needsAllocator() const { return true; }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (eof)
- return NULL;
- loop
- {
- const void * in = input->nextInGroup();
- if (!in)
- {
- recordCount = 0;
- if (numProcessedLastGroup == processed)
- in = input->nextInGroup();
- if (!in)
- {
- numProcessedLastGroup = processed;
- return NULL;
- }
- }
- try
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- size32_t outSize = helper.transform(rowBuilder, in, ++recordCount);
- ReleaseRoxieRow(in);
- if (outSize)
- {
- processed++;
- return rowBuilder.finalizeRowClear(outSize);
- }
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- }
- };
- class CRoxieServerFilterProjectActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerFilterProjectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerFilterProjectActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerFilterProjectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerFilterProjectActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerProjectActivity : public CRoxieServerActivity
- {
- unsigned numProcessedLastGroup;
- bool count;
- unsigned __int64 recordCount;
- public:
- CRoxieServerProjectActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _count)
- : CRoxieServerActivity(_factory, _probeManager),
- count(_count)
- {
- numProcessedLastGroup = 0;
- recordCount = 0;
- }
- ~CRoxieServerProjectActivity()
- {
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- numProcessedLastGroup = 0;
- recordCount = 0;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- }
- virtual bool needsAllocator() const { return true; }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- loop
- {
- OwnedConstRoxieRow in = input->nextInGroup();
- if (!in)
- {
- recordCount = 0;
- if (numProcessedLastGroup == processed)
- in.setown(input->nextInGroup());
- if (!in)
- {
- numProcessedLastGroup = processed;
- return NULL;
- }
- }
- try
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- size32_t outSize;
- if (count)
- outSize = ((IHThorCountProjectArg &) basehelper).transform(rowBuilder, in, ++recordCount);
- else
- outSize = ((IHThorProjectArg &) basehelper).transform(rowBuilder, in);
- if (outSize)
- {
- processed++;
- return rowBuilder.finalizeRowClear(outSize);
- }
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- }
- };
- class CRoxieServerProjectActivityFactory : public CRoxieServerActivityFactory
- {
- protected:
- bool count;
- public:
- CRoxieServerProjectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- count = (_kind==TAKcountproject || _kind==TAKprefetchcountproject);
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerProjectActivity(this, _probeManager, count);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerProjectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerProjectActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerPrefetchProjectActivity : public CRoxieServerActivity, implements IRecordPullerCallback
- {
- unsigned numProcessedLastGroup;
- bool count;
- bool eof;
- bool allPulled;
- bool isThreaded;
- unsigned preload;
- unsigned __int64 recordCount;
- IHThorPrefetchProjectArg &helper;
- RecordPullerThread puller;
- InterruptableSemaphore ready;
- InterruptableSemaphore space;
- class PrefetchInfo : public CInterface
- {
- public:
- inline PrefetchInfo(IHThorPrefetchProjectArg &helper, const void *_in, unsigned __int64 _recordCount)
- {
- if (helper.preTransform(extract, _in, _recordCount))
- {
- in.setown(_in);
- recordCount = _recordCount;
- }
- else
- ReleaseRoxieRow(_in);
- }
- OwnedConstRoxieRow in;
- unsigned __int64 recordCount;
- rtlRowBuilder extract;
- };
- QueueOf<PrefetchInfo, true> pulled;
- CriticalSection pulledCrit;
- public:
- CRoxieServerPrefetchProjectActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _count)
- : CRoxieServerActivity(_factory, _probeManager),
- helper((IHThorPrefetchProjectArg &) basehelper),
- puller(false),
- count(_count)
- {
- numProcessedLastGroup = 0;
- recordCount = 0;
- eof = false;
- allPulled = false;
- isThreaded = (helper.getFlags() & PPFparallel) != 0;
- preload = 0;
- }
- ~CRoxieServerPrefetchProjectActivity()
- {
- while (pulled.ordinality())
- ::Release(pulled.dequeue());
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- if (idx)
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
- puller.setInput(this, _in);
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- numProcessedLastGroup = 0;
- recordCount = 0;
- eof = false;
- allPulled = false;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- preload = helper.getLookahead();
- if (!preload)
- preload = ctx->prefetchProjectPreload();
- space.reinit(preload);
- ready.reinit();
- puller.start(parentExtractSize, parentExtract, paused, preload, !isThreaded, ctx);
- }
- virtual void stop(bool aborting)
- {
- space.interrupt();
- ready.interrupt();
- CRoxieServerActivity::stop(aborting);
- puller.stop(aborting);
- }
- virtual void reset()
- {
- CRoxieServerActivity::reset();
- puller.reset();
- allPulled = false;
- while (pulled.ordinality())
- ::Release(pulled.dequeue());
- }
- virtual PrefetchInfo *readNextRecord()
- {
- if (!isThreaded)
- {
- if (!allPulled) // This looks like it's thread unsafe but we are inside the if(!isThreaded) so should be ok
- puller.pullRecords(1);
- }
- else
- ready.wait();
- CriticalBlock b(pulledCrit);
- PrefetchInfo *ret = pulled.ordinality() ? pulled.dequeue() : NULL;
- space.signal();
- return ret;
- }
- virtual bool needsAllocator() const { return true; }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (eof)
- return NULL;
- loop
- {
- Owned<PrefetchInfo> in = readNextRecord();
- if (!in)
- {
- recordCount = 0;
- if (numProcessedLastGroup == processed)
- in.setown(readNextRecord());
- if (!in)
- {
- numProcessedLastGroup = processed;
- eof = true;
- return NULL;
- }
- }
- try
- {
- if (in->in)
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- size32_t outSize;
- IThorChildGraph *child = helper.queryChild();
- Owned<IEclGraphResults> results;
- if (child)
- results.setown(child->evaluate(in->extract.size(), in->extract.getbytes()));
- outSize = helper.transform(rowBuilder, in->in, results, in->recordCount);
- if (outSize)
- {
- processed++;
- return rowBuilder.finalizeRowClear(outSize);
- }
- }
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- }
- // interface IExceptionHandler
- virtual bool fireException(IException *e)
- {
- // called from puller thread on failure
- ready.interrupt(LINK(e));
- space.interrupt(e);
- return true;
- }
- // interface IRecordPullerCallback
- virtual void processRow(const void *row)
- {
- {
- CriticalBlock b(pulledCrit);
- pulled.enqueue(new PrefetchInfo(helper, row, ++recordCount));
- }
- if (isThreaded)
- {
- ready.signal();
- space.wait();
- }
- }
- virtual void processEOG()
- {
- {
- CriticalBlock b(pulledCrit);
- pulled.enqueue(NULL);
- }
- if (isThreaded)
- {
- ready.signal();
- space.wait();
- }
- }
- virtual void processGroup(const ConstPointerArray &rows)
- {
- throwUnexpected();
- }
- virtual void processDone()
- {
- CriticalBlock b(pulledCrit);
- allPulled = true;
- if (isThreaded)
- ready.signal();
- }
- };
- class CRoxieServerPrefetchProjectActivityFactory : public CRoxieServerProjectActivityFactory
- {
- public:
- CRoxieServerPrefetchProjectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerProjectActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerPrefetchProjectActivity(this, _probeManager, count);
- }
- };
- extern IRoxieServerActivityFactory *createRoxieServerPrefetchProjectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerPrefetchProjectActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CPointerArrayRoxieInput : public CPseudoRoxieInput
- {
- public:
- CPointerArrayRoxieInput()
- {
- rowset = NULL;
- rowcount = 0;
- curRow = 0;
- }
- void init(size32_t _rowcount, byte **_rowset)
- {
- rowset = _rowset;
- rowcount = _rowcount;
- curRow = 0;
- }
- virtual const void * nextInGroup()
- {
- if (curRow < rowcount)
- {
- const void * ret = rowset[curRow];
- if (ret)
- LinkRoxieRow(ret);
- curRow++;
- return ret;
- }
- return NULL;
- }
- protected:
- byte **rowset;
- size32_t rowcount;
- size32_t curRow;
- };
- class CRoxieServerLoopActivity : public CRoxieServerActivity
- {
- protected:
- IHThorLoopArg &helper;
- ThorActivityKind activityKind;
- unsigned maxIterations;
- bool finishedLooping;
- unsigned flags;
- bool eof;
- rtlRowBuilder loopExtractBuilder;
- unsigned loopGraphId;
- Linked<IOutputMetaData> counterMeta;
- public:
- CRoxieServerLoopActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _loopGraphId, IOutputMetaData * _counterMeta)
- : CRoxieServerActivity(_factory, _probeManager),
- helper((IHThorLoopArg &)basehelper), loopGraphId(_loopGraphId), counterMeta(_counterMeta)
- {
- eof = false;
- finishedLooping = false;
- activityKind = factory->getKind();
- flags = helper.getFlags();
- maxIterations = 0;
- }
- virtual bool needsAllocator() const { return true; }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- eof = false;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- int iterations = (int) helper.numIterations();
- maxIterations = (iterations >= 0) ? iterations : 0;
- finishedLooping = ((activityKind == TAKloopcount) && (maxIterations == 0));
- if ((flags & IHThorLoopArg::LFnewloopagain) && !helper.loopFirstTime())
- finishedLooping = true;
- loopExtractBuilder.clear();
- helper.createParentExtract(loopExtractBuilder); // could possibly delay this until execution actually happens
- }
- virtual void stop(bool aborting)
- {
- CRoxieServerActivity::stop(aborting);
- loopExtractBuilder.clear();
- }
- void createCounterResult(IRoxieServerChildGraph * graph, unsigned counter)
- {
- if (flags & IHThorLoopArg::LFcounter)
- {
- void * counterRow = ctx->queryRowManager().allocate(sizeof(thor_loop_counter_t), activityId);
- *((thor_loop_counter_t *)counterRow) = counter;
- RtlLinkedDatasetBuilder builder(rowAllocator);
- builder.appendOwn(counterRow);
- Owned<CGraphResult> counterResult = new CGraphResult(builder.getcount(), builder.linkrows());
- graph->setInputResult(2, counterResult);
- }
- }
- };
- //=================================================================================
- class CRoxieServerSequentialLoopActivity : public CRoxieServerLoopActivity
- {
- Owned<IActivityGraph> loopQuery;
- Owned<IRoxieServerChildGraph> loopGraph;
- IRoxieInput * curInput;
- RtlLinkedDatasetBuilder *loopInputBuilder;
- CPointerArrayRoxieInput arrayInput;
- Linked<IRoxieInput> resultInput;
- unsigned loopCounter;
- public:
- CRoxieServerSequentialLoopActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _loopGraphId, IOutputMetaData * _counterMeta)
- : CRoxieServerLoopActivity(_factory, _probeManager, _loopGraphId, _counterMeta)
- {
- curInput = NULL;
- loopCounter = 0;
- loopInputBuilder = NULL;
- }
- virtual bool needsAllocator() const { return true; }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerLoopActivity::onCreate(_ctx, _colocalParent);
- loopQuery.set(_ctx->queryChildGraph(loopGraphId));
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- curInput = input;
- loopCounter = 1;
- CRoxieServerLoopActivity::start(parentExtractSize, parentExtract, paused);
- //MORE: Not sure about this, should IRoxieServerChildGraph be combined with IActivityGraph?
- loopGraph.set(loopQuery->queryLoopGraph());
- loopInputBuilder = new RtlLinkedDatasetBuilder(rowAllocator);
- }
- virtual void stop(bool aborting)
- {
- delete loopInputBuilder;
- loopInputBuilder = NULL;
- CRoxieServerLoopActivity::stop(aborting);
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (eof)
- return NULL;
- unsigned emptyIterations = 0;
- loop
- {
- loop
- {
- const void * ret = curInput->nextInGroup();
- if (!ret)
- {
- ret = curInput->nextInGroup(); // more cope with groups somehow....
- if (!ret)
- {
- if (finishedLooping)
- {
- eof = true;
- return NULL;
- }
- break;
- }
- }
- if (finishedLooping ||
- ((flags & IHThorLoopArg::LFfiltered) && !helper.sendToLoop(loopCounter, ret)))
- {
- processed++;
- return ret;
- }
- loopInputBuilder->appendOwn(ret);
- }
- switch (activityKind)
- {
- case TAKloopdataset:
- {
- if (!(flags & IHThorLoopArg::LFnewloopagain))
- {
- if (!helper.loopAgain(loopCounter, loopInputBuilder->getcount(), (const void**) loopInputBuilder->queryrows()))
- {
- if (loopInputBuilder->getcount() == 0)
- {
- eof = true;
- return NULL;
- }
- arrayInput.init(loopInputBuilder->getcount(), loopInputBuilder->linkrows());
- // MORE - should builder be cleared here?
- curInput = &arrayInput;
- finishedLooping = true;
- continue; // back to the input loop again
- }
- }
- break;
- }
- case TAKlooprow:
- if (!loopInputBuilder->getcount())
- {
- finishedLooping = true;
- eof = true;
- return NULL;
- }
- break;
- }
- if (loopInputBuilder->getcount())
- emptyIterations = 0;
- else
- {
- //note: any outputs which didn't go around the loop again, would return the record, reinitializing emptyIterations
- emptyIterations++;
- if (emptyIterations > maxEmptyLoopIterations)
- throw MakeStringException(ROXIE_TOO_MANY_EMPTY_LOOP, "Executed LOOP with empty input and output %u times", emptyIterations);
- if (emptyIterations % 32 == 0)
- CTXLOG("Executing LOOP with empty input and output %u times", emptyIterations);
- }
- checkAbort();
- try
- {
- Owned<IRoxieGraphResults> results = executeIteration(loopExtractBuilder.size(), loopExtractBuilder.getbytes(), loopCounter);
- resultInput.setown(results->createIterator(0));
- if (flags & IHThorLoopArg::LFnewloopagain)
- {
- Owned<IRoxieInput> againResult = results->createIterator(helper.loopAgainResult());
- OwnedConstRoxieRow row = againResult->nextInGroup();
- assertex(row);
- //Result is a row which contains a single boolean field.
- if (!((const bool *)row.get())[0])
- finishedLooping = true;
- }
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- curInput = resultInput.get();
- loopCounter++;
- if ((activityKind == TAKloopcount) && (loopCounter > maxIterations))
- finishedLooping = true;
- }
- }
- IRoxieGraphResults * executeIteration(unsigned parentExtractSize, const byte *parentExtract, unsigned counter)
- {
- try
- {
- loopGraph->beforeExecute();
- Owned<IGraphResult> inputRowsResult = new CGraphResult(loopInputBuilder->getcount(), loopInputBuilder->linkrows());
- loopInputBuilder->clear();
- loopGraph->setInputResult(1, inputRowsResult);
- createCounterResult(loopGraph, counter);
- Owned<IRoxieGraphResults> ret = loopGraph->execute(parentExtractSize, parentExtract);
- loopGraph->afterExecute();
- return ret.getClear();
- }
- catch (...)
- {
- CTXLOG("Exception thrown in loop body - cleaning up");
- loopGraph->afterExecute();
- throw;
- }
- }
- };
- //=================================================================================
- typedef SafeQueueOf<const void, true> SafeRowQueue;
- class CRowQueuePseudoInput : public CPseudoRoxieInput
- {
- public:
- CRowQueuePseudoInput(SafeRowQueue & _input) :
- input(_input)
- {
- eof = false;
- }
- virtual const void * nextInGroup()
- {
- if (eof)
- return NULL;
- const void * ret = input.dequeue();
- if (!ret)
- eof = true;
- return ret;
- }
- protected:
- SafeRowQueue & input;
- bool eof;
- };
- class CRoxieServerParallelLoopActivity;
- class LoopFilterPseudoInput : public CIndirectRoxieInput
- {
- public:
- LoopFilterPseudoInput(CRoxieServerParallelLoopActivity * _activity, IRoxieInput * _input, unsigned _counter) :
- CIndirectRoxieInput(_input), activity(_activity), counter(_counter)
- {
- }
- virtual const void * nextInGroup();
- protected:
- CRoxieServerParallelLoopActivity * activity;
- unsigned counter;
- };
- class LoopExecutorThread : public RestartableThread
- {
- protected:
- Owned<IRoxieInput> safeInput;
- CRoxieServerParallelLoopActivity * activity;
- bool eof;
- CriticalSection crit;
- unsigned flags;
- SafeRowQueue tempResults[2];
- unsigned savedParentExtractSize;
- const byte * savedParentExtract;
- IArrayOf<IActivityGraph> cachedGraphs;
- IRoxieSlaveContext *ctx;
- public:
- LoopExecutorThread()
- : RestartableThread("LoopExecutorThread")
- {
- activity = NULL;
- eof = false;
- flags = 0;
- ctx = NULL;
- savedParentExtract = NULL;
- savedParentExtractSize = 0;
- }
- virtual IRoxieInput *queryInput(unsigned idx) const
- {
- return safeInput->queryInput(idx);
- }
- void setInput(CRoxieServerParallelLoopActivity * _activity, IRoxieInput *_input, unsigned _flags)
- {
- activity = _activity;
- flags = _flags;
- // 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.
- safeInput.setown(new CSafeRoxieInput(_input));
- }
- IRoxieInput *queryInput() const
- {
- return safeInput;
- }
- void onCreate(IRoxieSlaveContext * _ctx);
- void start(unsigned parentExtractSize, const byte *parentExtract, bool paused);
- void stop(bool aborting);
- void reset();
- virtual int run();
- protected:
- void executeLoop();
- void executeLoopInstance(unsigned counter, unsigned numIterations, IRoxieInput * input, SafeRowQueue * spillOutput);
- IRoxieInput * createLoopIterationGraph(unsigned i, IRoxieInput * input, unsigned counter);
- };
- class CRoxieServerParallelLoopActivity : public CRoxieServerLoopActivity
- {
- friend class LoopFilterPseudoInput;
- friend class LoopExecutorThread;
- QueueOf<const void, true> ready;
- CriticalSection helperCS;
- CriticalSection cs;
- size32_t sizeNumParallel;
- rtlDataAttr listNumParallel;
- unsigned defaultNumParallel;
- LoopExecutorThread executor;
- IProbeManager* probeManager;
- CriticalSection canAccess;
- CriticalSection scrit;
- InterruptableSemaphore readySpace;
- InterruptableSemaphore recordsReady;
- protected:
- bool includeInLoop(unsigned counter, const void * row)
- {
- CriticalBlock b(helperCS);
- return helper.sendToLoop(counter, row);
- }
- public:
- CRoxieServerParallelLoopActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _loopGraphId, IOutputMetaData * _counterMeta)
- : CRoxieServerLoopActivity(_factory, _probeManager, _loopGraphId, _counterMeta),
- readySpace(parallelLoopFlowLimit)
- {
- probeManager = _probeManager;
- defaultNumParallel = 0;
- sizeNumParallel = 0;
- }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerActivity::onCreate(_ctx, _colocalParent);
- executor.onCreate(_ctx);
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CriticalBlock b(scrit); // can stop while still starting, if unlucky...
- readySpace.reinit(parallelLoopFlowLimit);
- recordsReady.reinit();
- CRoxieServerLoopActivity::start(parentExtractSize, parentExtract, paused);
- defaultNumParallel = helper.defaultParallelIterations();
- if (!defaultNumParallel)
- defaultNumParallel = DEFAULT_PARALLEL_LOOP_THREADS;
- helper.numParallelIterations(sizeNumParallel, listNumParallel.refdata());
- //MORE: If numIterations <= number of parallel iterations[1],
- //then we don't need to create a separate thread to do the processing, and the results will also avoid
- //being transferred via a queue
- executor.start(parentExtractSize, parentExtract, paused);
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- if (idx)
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
- executor.setInput(this, _in, flags);
- }
- virtual void stop(bool aborting)
- {
- CriticalBlock b(scrit); // can stop while still starting, if unlucky...
- readySpace.interrupt();
- recordsReady.interrupt();
- executor.join(); // MORE - may not be needed given stop/reset split
- CRoxieServerLoopActivity::stop(aborting);
- }
- virtual void reset()
- {
- while (ready.ordinality())
- ReleaseRoxieRow(ready.dequeue());
- executor.reset();
- CRoxieServerActivity::reset();
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- loop
- {
- if (eof)
- return NULL;
- recordsReady.wait();
- CriticalBlock procedure(canAccess);
- if (ready.ordinality())
- {
- const void *result = ready.dequeue();
- readySpace.signal();
- if (result)
- processed++;
- return result;
- }
- else
- eof = true;
- }
- }
- unsigned getNumParallel(unsigned iter)
- {
- if (iter * sizeof(unsigned) >= sizeNumParallel)
- return defaultNumParallel;
- return ((unsigned *)listNumParallel.getdata())[iter];
- }
- inline void enqueueResult(const void * row)
- {
- try
- {
- while(!readySpace.wait(1000))
- {
- CTXLOG("Blocked waiting for space in loop %p activity id: %d output queue: %d records in queue", this, queryId(), ready.ordinality());
- }
- }
- catch (...)
- {
- ReleaseRoxieRow(row);
- throw;
- }
- CriticalBlock b2(canAccess);
- ready.enqueue(row);
- recordsReady.signal();
- }
- inline void finishResults()
- {
- recordsReady.signal();
- }
- virtual bool fireException(IException *e)
- {
- readySpace.interrupt(LINK(e));
- recordsReady.interrupt(e);
- return true;
- }
- IActivityGraph * createChildGraphInstance()
- {
- return factory->createChildGraph(ctx, &helper, loopGraphId, this, probeManager, *this);
- }
- IActivityGraph * queryChildGraph()
- {
- return ctx->queryChildGraph(loopGraphId);
- }
- };
- //=================================================================================
- const void * LoopFilterPseudoInput::nextInGroup()
- {
- loop
- {
- const void * next = input->nextInGroup();
- if (!next || activity->includeInLoop(counter, next))
- return next;
- activity->enqueueResult(next);
- }
- }
- void LoopExecutorThread::onCreate(IRoxieSlaveContext * _ctx)
- {
- //Initialise the cached graph list with the child instance that will always be created. Other iterations will be created on demand.
- ctx = _ctx;
- cachedGraphs.append(*LINK(activity->queryChildGraph()));
- }
- void LoopExecutorThread::start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- savedParentExtractSize = parentExtractSize;
- savedParentExtract = parentExtract;
- eof = false;
- StringBuffer logPrefix("[");
- ctx->getLogPrefix(logPrefix).append("] ");
- RestartableThread::start(logPrefix);
- }
- int LoopExecutorThread::run()
- {
- try
- {
- executeLoop();
- }
- catch (IException *e)
- {
- activity->fireException(e);
- }
- catch (...)
- {
- activity->fireException(MakeStringException(ROXIE_INTERNAL_ERROR, "Unexpected exception caught in LoopExecutorThread::run"));
- }
- return 0;
- }
- void LoopExecutorThread::stop(bool aborting)
- {
- safeInput->stop(aborting);
- RestartableThread::join();
- }
- void LoopExecutorThread::reset()
- {
- safeInput->reset();
- }
- void LoopExecutorThread::executeLoop()
- {
- unsigned iterations = 0;
- unsigned counter = 0;
- unsigned outputIndex = 0;
- //Note, activities don't link inputs, so need to be careful that special inputs remain linked while the activity is executing.
- loop
- {
- if (activity->activityKind == TAKloopcount)
- {
- if (counter == activity->maxIterations)
- break;
- }
- else
- {
- //This condition isn't quite right because it needs to be whether the filtered
- //input is empty. May be ok if we include that in the semantics,
- if (tempResults[1-outputIndex].ordinality() == 0)
- break;
- }
- unsigned numParallel = activity->getNumParallel(iterations);
- Linked<IRoxieInput> curInput;
- if (iterations == 0)
- curInput.set(safeInput);
- else
- {
- SafeRowQueue & inputQueue = tempResults[1-outputIndex];
- inputQueue.enqueue(NULL);
- curInput.setown(new CRowQueuePseudoInput(inputQueue));
- }
- SafeRowQueue * curOutput = NULL;
- if (counter+numParallel > activity->maxIterations)
- numParallel = activity->maxIterations - counter;
- else if (counter+numParallel < activity->maxIterations)
- curOutput = &tempResults[outputIndex];
- executeLoopInstance(counter, numParallel, curInput, curOutput);
- outputIndex = 1-outputIndex;
- counter += numParallel;
- iterations++;
- }
- //Check for TAKlooprow, where end of loop couldn't be determined ahead of time
- SafeRowQueue & inputQueue = tempResults[1-outputIndex];
- while (inputQueue.ordinality())
- {
- const void * next = inputQueue.dequeue();
- activity->enqueueResult(next);
- }
- activity->finishResults();
- }
- void LoopExecutorThread::executeLoopInstance(unsigned counter, unsigned numIterations, IRoxieInput * input, SafeRowQueue * spillOutput)
- {
- IArrayOf<IRoxieInput> savedInputs; // activities don't link their inputs, so this list keeps filters alive.
- Linked<IRoxieInput> curInput = input;
- unsigned i;
- for (i= 0; i != numIterations; i++)
- {
- unsigned thisCounter = counter+i+1;
- IRoxieInput * filtered = curInput;
- if (flags & IHThorLoopArg::LFfiltered)
- {
- filtered = new LoopFilterPseudoInput(activity, curInput, thisCounter);
- savedInputs.append(*filtered);
- }
- //graph is kept, so new curInput will be guaranteed to exist
- curInput.setown(createLoopIterationGraph(i, filtered, thisCounter));
- }
- try
- {
- curInput->start(savedParentExtractSize, savedParentExtract, false);
- if (spillOutput)
- {
- loop
- {
- const void * next = curInput->nextInGroup();
- if (!next)
- break;
- spillOutput->enqueue(next);
- }
- }
- else
- {
- loop
- {
- const void * next = curInput->nextInGroup();
- if (!next)
- break;
- activity->enqueueResult(next);
- }
- }
- }
- catch (IException *E)
- {
- ctx->notifyAbort(E);
- for (i= 0; i != numIterations; i++)
- {
- cachedGraphs.item(i).queryLoopGraph()->afterExecute();
- }
- curInput->stop(true);
- curInput->reset();
- throw;
- }
- for (i= 0; i != numIterations; i++)
- {
- cachedGraphs.item(i).queryLoopGraph()->afterExecute();
- }
- curInput->stop(false);
- curInput->reset();
- }
- IRoxieInput * LoopExecutorThread::createLoopIterationGraph(unsigned i, IRoxieInput * input, unsigned counter)
- {
- if (!cachedGraphs.isItem(i))
- cachedGraphs.append(*activity->createChildGraphInstance());
- Linked<IRoxieServerChildGraph> loopGraph = cachedGraphs.item(i).queryLoopGraph();
- loopGraph->beforeExecute();
- if (!loopGraph->querySetInputResult(1, input))
- throwUnexpected(); // a loop which doesn't use the value from the previous iteration. Should probably handle even if daft.
- activity->createCounterResult(loopGraph, counter);
- return loopGraph->selectOutput(0);
- }
- //=================================================================================
- class CCounterRowMetaData : public CInterface, implements IOutputMetaData
- {
- public:
- IMPLEMENT_IINTERFACE
- virtual size32_t getRecordSize(const void *) { return sizeof(thor_loop_counter_t); }
- virtual size32_t getMinRecordSize() const { return sizeof(thor_loop_counter_t); }
- virtual size32_t getFixedSize() const { return sizeof(thor_loop_counter_t); }
- virtual void toXML(const byte * self, IXmlWriter & out) { }
- virtual unsigned getVersion() const { return OUTPUTMETADATA_VERSION; }
- virtual unsigned getMetaFlags() { return 0; }
- virtual void destruct(byte * self) {}
- virtual IOutputRowSerializer * createDiskSerializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
- virtual IOutputRowDeserializer * createDiskDeserializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
- virtual ISourceRowPrefetcher * createDiskPrefetcher(ICodeContext * ctx, unsigned activityId) { return NULL; }
- virtual IOutputMetaData * querySerializedDiskMeta() { return this; }
- virtual IOutputRowSerializer * createInternalSerializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
- virtual IOutputRowDeserializer * createInternalDeserializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
- virtual void walkIndirectMembers(const byte * self, IIndirectMemberVisitor & visitor) {}
- virtual IOutputMetaData * queryChildMeta(unsigned i) { return NULL; }
- };
- class CRoxieServerLoopActivityFactory : public CRoxieServerActivityFactory
- {
- unsigned loopGraphId;
- unsigned flags;
- Linked<IOutputMetaData> counterMeta;
- public:
- CRoxieServerLoopActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _loopGraphId)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), loopGraphId(_loopGraphId)
- {
- Owned<IHThorLoopArg> helper = (IHThorLoopArg *) helperFactory();
- flags = helper->getFlags();
- counterMeta.setown(new CCounterRowMetaData);
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- if (flags & IHThorLoopArg::LFparallel)
- return new CRoxieServerParallelLoopActivity(this, _probeManager, loopGraphId, counterMeta);
- else
- return new CRoxieServerSequentialLoopActivity(this, _probeManager, loopGraphId, counterMeta);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerLoopActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _loopGraphId)
- {
- return new CRoxieServerLoopActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _loopGraphId);
- }
- //=================================================================================
- class CRoxieServerGraphLoopActivity : public CRoxieServerActivity
- {
- protected:
- IHThorGraphLoopArg &helper;
- unsigned maxIterations;
- unsigned flags;
- rtlRowBuilder GraphExtractBuilder;
- unsigned loopGraphId;
- Linked<IOutputMetaData> counterMeta;
- public:
- CRoxieServerGraphLoopActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _GraphGraphId, IOutputMetaData * _counterMeta)
- : CRoxieServerActivity(_factory, _probeManager),
- helper((IHThorGraphLoopArg &)basehelper), loopGraphId(_GraphGraphId), counterMeta(_counterMeta)
- {
- flags = helper.getFlags();
- maxIterations = 0;
- }
- virtual bool needsAllocator() const { return true; }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- int iterations = (int) helper.numIterations();
- maxIterations = (iterations >= 0) ? iterations : 0;
- if (maxIterations > maxGraphLoopIterations)
- throw MakeStringException(ROXIE_TOO_MANY_GRAPH_LOOP, "Attempt to execute graph %u times", maxIterations);
- if (maxIterations != 0)
- {
- GraphExtractBuilder.clear();
- helper.createParentExtract(GraphExtractBuilder);
- }
- }
- virtual void stop(bool aborting)
- {
- CRoxieServerActivity::stop(aborting);
- GraphExtractBuilder.clear();
- }
- void createCounterResult(IRoxieServerChildGraph * graph, unsigned counter)
- {
- if (flags & IHThorGraphLoopArg::GLFcounter)
- {
- void * counterRow = ctx->queryRowManager().allocate(sizeof(thor_loop_counter_t), activityId);
- *((thor_loop_counter_t *)counterRow) = counter;
- RtlLinkedDatasetBuilder builder(rowAllocator);
- builder.appendOwn(counterRow);
- Owned<CGraphResult> counterResult = new CGraphResult(builder.getcount(), builder.linkrows());
- graph->setInputResult(0, counterResult);
- }
- }
- };
- //=================================================================================
- class CRoxieServerSequentialGraphLoopActivity : public CRoxieServerGraphLoopActivity
- {
- Owned<IActivityGraph> GraphQuery;
- Owned<IRoxieServerChildGraph> loopGraph;
- Linked<IRoxieInput> resultInput;
- bool evaluated;
- public:
- CRoxieServerSequentialGraphLoopActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _GraphGraphId, IOutputMetaData * _counterMeta)
- : CRoxieServerGraphLoopActivity(_factory, _probeManager, _GraphGraphId, _counterMeta)
- {
- evaluated = false;
- }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerGraphLoopActivity::onCreate(_ctx, _colocalParent);
- GraphQuery.set(_ctx->queryChildGraph(loopGraphId));
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerGraphLoopActivity::start(parentExtractSize, parentExtract, paused);
- //MORE: Not sure about this, should IRoxieServerChildGraph be combined with IActivityGraph?
- loopGraph.set(GraphQuery->queryLoopGraph());
- evaluated = false;
- }
- virtual void stop(bool aborting)
- {
- if (loopGraph)
- loopGraph->clearGraphLoopResults();
- CRoxieServerGraphLoopActivity::stop(aborting);
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (!evaluated)
- {
- executeEntireGraph();
- evaluated = true;
- }
- const void * ret = resultInput->nextInGroup();
- if (ret)
- processed++;
- return ret;
- }
- void executeIteration(unsigned parentExtractSize, const byte *parentExtract, unsigned counter)
- {
- try
- {
- loopGraph->beforeExecute();
- createCounterResult(loopGraph, counter);
- loopGraph->executeGraphLoop(parentExtractSize, parentExtract);
- loopGraph->afterExecute();
- }
- catch (...)
- {
- CTXLOG("Exception thrown in graph body - cleaning up");
- loopGraph->afterExecute();
- throw;
- }
- }
- void createInitialGraphInput()
- {
- loopGraph->clearGraphLoopResults();
- RtlLinkedDatasetBuilder builder(rowAllocator);
- input->readAll(builder);
- Owned<CGraphResult> result = new CGraphResult(builder.getcount(), builder.linkrows());
- loopGraph->setGraphLoopResult(0, result);
- }
- void executeEntireGraph()
- {
- createInitialGraphInput();
- for (unsigned loopCounter=1; loopCounter <= maxIterations; loopCounter++)
- {
- executeIteration(GraphExtractBuilder.size(), GraphExtractBuilder.getbytes(), loopCounter);
- }
- resultInput.setown(loopGraph->getGraphLoopResult(maxIterations));
- }
- };
- //=================================================================================
- struct GraphOutputSplitterArg : public ccdserver_hqlhelper::CThorSplitArg
- {
- public:
- virtual unsigned numBranches()
- {
- return 0;
- }
- virtual IOutputMetaData * queryOutputMeta()
- {
- return NULL;// get it from the parent..
- }
- };
- extern "C" IHThorArg * createGraphOutputSplitter() { return new GraphOutputSplitterArg; }
- class CGraphIterationInfo : public CInterface
- {
- private:
- Owned<IRoxieServerActivityFactory> factory; // Note - before sourceAct, so destroyed last
- unsigned sourceIdx;
- Linked<IRoxieServerActivity> sourceAct;
- Linked<IRoxieInput> sourceInput;
- unsigned numUses;
- unsigned iteration;
- public:
- CGraphIterationInfo(IRoxieServerActivity * _sourceAct, IRoxieInput *_input, unsigned _sourceIdx, unsigned _iteration)
- : sourceAct(_sourceAct), sourceInput(_input), sourceIdx(_sourceIdx), iteration(_iteration)
- {
- numUses = 0;
- }
- inline void noteUsed()
- {
- numUses++;
- }
- void createSplitter(IRoxieSlaveContext *ctx, IProbeManager *probeManager)
- {
- if (numUses > 1)
- {
- factory.setown(createRoxieServerThroughSpillActivityFactory(sourceAct->queryFactory()->queryQueryFactory(), createGraphOutputSplitter, numUses));
- IRoxieServerActivity *splitter = factory->createActivity(NULL);
- splitter->onCreate(ctx, NULL);
- IRoxieInput *input = sourceAct->queryOutput(sourceIdx);
- if (probeManager)
- {
- IInputBase * inputBase = probeManager->createProbe(static_cast<IInputBase*>(input), sourceAct, splitter, sourceIdx, 0, iteration);
- input = static_cast<IRoxieInput*>(inputBase);
- // MORE - shouldn't this be added to probes?
- }
- sourceAct.setown(splitter);
- sourceAct->setInput(0, input);
- sourceIdx = 0;
- sourceInput.clear();
- }
- }
- IRoxieInput *connectOutput(IProbeManager *probeManager, IArrayOf<IRoxieInput> &probes, IRoxieServerActivity *targetAct, unsigned targetIdx)
- {
- // MORE - not really necessary to create splitters in separate pass, is it?
- if (factory) // we created a splitter....
- sourceInput.set(sourceAct->queryOutput(sourceIdx));
- IRoxieInput *ret = sourceInput;
- if (probeManager)
- {
- IInputBase *inputBase = probeManager->createProbe(ret, sourceAct, targetAct, sourceIdx, targetIdx, iteration);
- ret = static_cast<IRoxieInput *>(inputBase);
- probes.append(*LINK(ret));
- }
- if (factory) // we created a splitter....
- sourceIdx++;
- return ret;
- }
- };
- class CRoxieServerParallelGraphLoopActivity : public CRoxieServerGraphLoopActivity, implements IRoxieServerLoopResultProcessor
- {
- Owned<IActivityGraph> childGraph;
- IRoxieInput * resultInput;
- CIArrayOf<CGraphIterationInfo> outputs;
- IArrayOf<IRoxieServerChildGraph> iterationGraphs;
- Owned<CExtractMapperInput> inputExtractMapper;
- IProbeManager *probeManager;
- unsigned createLoopCounter;
- IArrayOf<IRoxieInput> probes;
- public:
- CRoxieServerParallelGraphLoopActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _GraphGraphId, IOutputMetaData * _counterMeta)
- : CRoxieServerGraphLoopActivity(_factory, _probeManager, _GraphGraphId, _counterMeta), probeManager(_probeManager)
- {
- inputExtractMapper.setown(new CExtractMapperInput);
- resultInput = NULL;
- createLoopCounter = 0;
- }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerGraphLoopActivity::onCreate(_ctx, _colocalParent);
- childGraph.set(_ctx->queryChildGraph(loopGraphId));
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- //Input needs to be handled very carefully.....
- //We don't want to call onStart on the input unless it is actually used, so don't use the base CRoxieServerActivity implementation.
- //This activity's input needs to be started with (parentExtractSize, parentExtract), but the elements in the graph need to be started with the
- //GraphExtractBuilder parent extract. So we need to wrap the input in a pseudo-input (inputExtractMapper) that passes through a different
- //parentExtract. Something very similar will be needed for query library calls with streaming inputs when they are implemented.
- assertex(idx == 0);
- inputExtractMapper->setInput(_in);
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerGraphLoopActivity::start(parentExtractSize, parentExtract, paused); // initialises GraphExtractBuilder
- inputExtractMapper->setParentExtract(parentExtractSize, parentExtract);
- createExpandedGraph(GraphExtractBuilder.size(), GraphExtractBuilder.getbytes(), probeManager);
- resultInput->start(GraphExtractBuilder.size(), GraphExtractBuilder.getbytes(), paused);
- }
- virtual void stop(bool aborting)
- {
- if (resultInput)
- resultInput->stop(aborting);
- CRoxieServerGraphLoopActivity::stop(aborting);
- }
- virtual void reset()
- {
- if (resultInput)
- resultInput->reset();
- resultInput = NULL;
- iterationGraphs.kill();
- outputs.kill();
- if (probeManager)
- {
- probeManager->deleteGraph(NULL, (IArrayOf<IInputBase>*)&probes);
- probes.kill();
- }
- CRoxieServerGraphLoopActivity::reset();
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- const void * ret = resultInput->nextInGroup();
- if (ret)
- processed++;
- return ret;
- }
- void createExpandedGraph(unsigned parentExtractSize, const byte *parentExtract, IProbeManager *probeManager)
- {
- //result(0) is the input to the graph.
- resultInput = inputExtractMapper;
- outputs.append(* new CGraphIterationInfo(resultInput->queryActivity(), resultInput, 0, 1));
- for (createLoopCounter=1; createLoopCounter <= maxIterations; createLoopCounter++)
- {
- IRoxieServerChildGraph * graph = childGraph->createGraphLoopInstance(createLoopCounter, parentExtractSize, parentExtract, *this);
- graph->beforeExecute();
- iterationGraphs.append(*graph);
- graph->gatherIterationUsage(*this);
- CGraphIterationInfo *iteration = graph->selectGraphLoopOutput();
- outputs.append(*iteration);
- }
- createLoopCounter = 0;
- createSplitters(probeManager);
- ForEachItemIn(i2, iterationGraphs)
- iterationGraphs.item(i2).associateIterationOutputs(*this);
- resultInput = outputs.tos().connectOutput(probeManager, probes, this, 0);
- }
- void createSplitters(IProbeManager *probeManager)
- {
- ForEachItemIn(i, outputs)
- {
- CGraphIterationInfo & next = outputs.item(i);
- next.createSplitter(ctx, probeManager);
- }
- }
- //IRoxieServerLoopResultProcessor
- virtual void noteUseIteration(unsigned _whichIteration)
- {
- int whichIteration = (int) _whichIteration; // May go negative - API is unsigned for historical reasons
- if (whichIteration >= 0)
- {
- if (!outputs.isItem(whichIteration))
- throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Error reading graph result %d from iteration %d", whichIteration, createLoopCounter);
- outputs.item(whichIteration).noteUsed();
- }
- }
- virtual IRoxieInput * connectIterationOutput(unsigned whichIteration, IProbeManager *probeManager, IArrayOf<IRoxieInput> &probes, IRoxieServerActivity *targetAct, unsigned targetIdx)
- {
- if (outputs.isItem(whichIteration))
- {
- CGraphIterationInfo & next = outputs.item(whichIteration);
- return next.connectOutput(probeManager, probes, targetAct, targetIdx);
- }
- return NULL;
- }
- };
- //=================================================================================
- class CRoxieServerGraphLoopActivityFactory : public CRoxieServerActivityFactory
- {
- unsigned loopGraphId;
- unsigned flags;
- Linked<IOutputMetaData> counterMeta;
- public:
- CRoxieServerGraphLoopActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _loopGraphId)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), loopGraphId(_loopGraphId)
- {
- Owned<IHThorGraphLoopArg> helper = (IHThorGraphLoopArg *) helperFactory();
- flags = helper->getFlags();
- counterMeta.setown(new CCounterRowMetaData);
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- if (kind == TAKparallelgraphloop)
- return new CRoxieServerParallelGraphLoopActivity(this, _probeManager, loopGraphId, counterMeta);
- else
- return new CRoxieServerSequentialGraphLoopActivity(this, _probeManager, loopGraphId, counterMeta);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerGraphLoopActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _loopGraphId)
- {
- return new CRoxieServerGraphLoopActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _loopGraphId);
- }
- //=====================================================================================================
- class CRoxieServerLibraryCallActivity : public CRoxieServerActivity
- {
- class OutputAdaptor : public CExtractMapperInput
- {
- bool stopped;
- public:
- CRoxieServerLibraryCallActivity *parent;
- unsigned oid;
- unsigned processed;
- public:
- IMPLEMENT_IINTERFACE;
- OutputAdaptor() : CExtractMapperInput(NULL)
- {
- parent = NULL;
- oid = 0;
- init();
- }
- void init()
- {
- processed = 0;
- stopped = false;
- }
- virtual unsigned queryId() const
- {
- return parent->queryId();
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- parent->start(oid, parentExtractSize, parentExtract, paused);
- CExtractMapperInput::start(parentExtractSize, parentExtract, paused);
- }
- virtual void stop(bool aborting)
- {
- if (!stopped)
- {
- stopped = true;
- parent->stop(oid, aborting); // parent code relies on stop being called exactly once per adaptor, so make sure it is!
- CExtractMapperInput::stop(aborting);
- }
- };
- virtual void reset()
- {
- parent->reset(oid, processed);
- CExtractMapperInput::reset();
- init();
- };
- virtual void checkAbort()
- {
- parent->checkAbort();
- }
- };
-
- IHThorLibraryCallArg &helper;
- unsigned numInputs;
- unsigned numOutputs;
- unsigned numActiveOutputs;
- bool started;
- OutputAdaptor* outputAdaptors;
- CExtractMapperInput * * inputAdaptors;
- bool * inputUsed;
- bool * outputUsed;
- Owned<IException> error;
- CriticalSection crit;
- rtlRowBuilder libraryExtractBuilder;
- Owned<IActivityGraph> libraryGraph;
- const LibraryCallFactoryExtra & extra;
- public:
- CRoxieServerLibraryCallActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs, unsigned _numOutputs, const LibraryCallFactoryExtra & _extra)
- : CRoxieServerActivity(_factory, _probeManager),
- helper((IHThorLibraryCallArg &)basehelper), extra(_extra)
- {
- numInputs = _numInputs;
- numOutputs = _numOutputs;
- numActiveOutputs = numOutputs;
- inputAdaptors = new CExtractMapperInput*[numInputs];
- inputUsed = new bool[numInputs];
- for (unsigned i1 = 0; i1 < numInputs; i1++)
- {
- inputAdaptors[i1] = new CExtractMapperInput;
- inputUsed[i1] = false;
- }
- outputAdaptors = new OutputAdaptor[numOutputs];
- outputUsed = new bool[numOutputs];
- for (unsigned i2 = 0; i2 < numOutputs; i2++)
- {
- outputAdaptors[i2].parent = this;
- outputAdaptors[i2].oid = i2;
- outputUsed[i2] = false;
- }
- started = false;
- }
- ~CRoxieServerLibraryCallActivity()
- {
- for (unsigned i1 = 0; i1 < numInputs; i1++)
- ::Release(inputAdaptors[i1]);
- delete [] inputAdaptors;
- delete [] inputUsed;
- delete [] outputAdaptors;
- delete [] outputUsed;
- }
-
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerActivity::onCreate(_ctx, _colocalParent);
- libraryGraph.setown(_ctx->getLibraryGraph(extra, this));
- libraryGraph->onCreate(_ctx, _colocalParent);
- //Now map the inputs and outputs to the adapters
- IRoxieServerChildGraph * graph = libraryGraph->queryLoopGraph();
- for (unsigned i1=0; i1<numInputs; i1++)
- inputUsed[i1] = graph->querySetInputResult(i1, inputAdaptors[i1]);
- for (unsigned i2=0; i2<numOutputs; i2++)
- {
- unsigned outputIndex = extra.outputs.item(i2);
- Owned<IRoxieInput> output = graph->selectOutput(numInputs+outputIndex);
- outputAdaptors[i2].setInput(output);
- }
- }
- virtual void start(unsigned oid, unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CriticalBlock b(crit);
- if (error)
- throw error.getLink();
- if (factory)
- factory->noteStarted(oid);
- if (!started)
- {
- // even though it is not complete, we don't want to run this again if it fails.
- started = true;
- //see notes on splitter above
- try
- {
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- }
- catch (IException *E)
- {
- #ifdef TRACE_SPLIT
- CTXLOG("spill %d caught exception in start", activityId);
- #endif
- error.set(E);
- throw;
- }
- catch (...)
- {
- IException *E = MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught in CRoxieServerLibraryCallActivity::start");
- error.set(E);
- throw E;
- }
- //recreate the parent extract, and use it to reinitialize the graphs...
- libraryExtractBuilder.clear();
- helper.createParentExtract(libraryExtractBuilder);
- // 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
- // some inputs before we see start on others.
- for (unsigned i1 = 0; i1 < numInputs; i1++)
- {
- if (inputUsed[i1])
- inputAdaptors[i1]->setParentExtract(parentExtractSize, parentExtract);
- else
- inputAdaptors[i1]->stop(false);
- }
- for (unsigned i2 = 0; i2 < numOutputs; i2++)
- outputAdaptors[i2].setParentExtract(libraryExtractBuilder.size(), libraryExtractBuilder.getbytes());
- //call stop on all the unused inputs.
- IRoxieServerChildGraph * graph = libraryGraph->queryLoopGraph();
- graph->beforeExecute();
- ForEachItemIn(i3, extra.unusedOutputs)
- {
- Owned<IRoxieInput> output = graph->selectOutput(numInputs+extra.unusedOutputs.item(i3));
- output->stop(false);
- }
- }
- }
- virtual void stop(unsigned oid, bool aborting)
- {
- CriticalBlock b(crit);
- if (--numActiveOutputs == 0)
- {
- //call stop on all the unused inputs.
- IRoxieServerChildGraph * graph = libraryGraph->queryLoopGraph();
- graph->beforeExecute();
- ForEachItemIn(i3, extra.unusedOutputs)
- {
- Owned<IRoxieInput> output = graph->selectOutput(numInputs+extra.unusedOutputs.item(i3));
- output->stop(false);
- }
- CRoxieServerActivity::stop(aborting);
- }
- }
- void reset(unsigned oid, unsigned _processed)
- {
- noteProcessed(oid, _processed, 0, 0);
- started = false;
- error.clear();
- numActiveOutputs = numOutputs;
- if (state != STATEreset) // make sure input is only reset once
- {
- CRoxieServerActivity::reset();
- libraryGraph->reset();
- //Call reset on all unused inputs/outputs from the graph - no one else will.
- for (unsigned i1 = 0; i1 < numInputs; i1++)
- {
- if (!inputUsed[i1])
- inputAdaptors[i1]->reset();
- }
- IRoxieServerChildGraph * graph = libraryGraph->queryLoopGraph();
- ForEachItemIn(i3, extra.unusedOutputs)
- {
- Owned<IRoxieInput> output = graph->selectOutput(numInputs+extra.unusedOutputs.item(i3));
- output->reset();
- }
- }
- };
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- inputAdaptors[idx]->setInput(_in);
- }
- public:
- virtual const void *nextInGroup()
- {
- throwUnexpected(); // Internal logic error - we are not anybody's input
- }
- virtual IOutputMetaData * queryOutputMeta() const
- {
- throwUnexpected(); // should be called on outputs instead
- }
- virtual IRoxieInput *queryOutput(unsigned idx)
- {
- assertex(idx!=(unsigned)-1);
- assertex(!outputUsed[idx]);
- outputUsed[idx] = true;
- return &outputAdaptors[idx];
- }
- };
- void LibraryCallFactoryExtra::set(const LibraryCallFactoryExtra & _other)
- {
- ForEachItemIn(i1, _other.outputs)
- outputs.append(_other.outputs.item(i1));
- ForEachItemIn(i2, _other.unusedOutputs)
- unusedOutputs.append(_other.unusedOutputs.item(i2));
- maxOutputs = _other.maxOutputs;
- graphid = _other.graphid;
- libraryName.set(_other.libraryName);
- interfaceHash = _other.interfaceHash;
- embedded = _other.embedded;
- }
- void LibraryCallFactoryExtra::calcUnused()
- {
- for (unsigned i=0; i < maxOutputs; i++)
- if (!outputs.contains(i))
- unusedOutputs.append(i);
- }
- class CRoxieServerLibraryCallActivityFactory : public CRoxieServerMultiOutputFactory
- {
- private:
- CRoxieServerMultiInputInfo inputs;
- LibraryCallFactoryExtra extra;
- public:
- CRoxieServerLibraryCallActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, LibraryCallFactoryExtra & _extra)
- : CRoxieServerMultiOutputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- extra.set(_extra);
- extra.calcUnused();
- setNumOutputs(extra.outputs.ordinality());
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerLibraryCallActivity(this, _probeManager, numInputs(), numOutputs, extra);
- }
- virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
- {
- inputs.set(idx, source, sourceidx);
- }
- virtual unsigned getInput(unsigned idx, unsigned &sourceidx) const
- {
- return inputs.get(idx, sourceidx);
- }
- virtual unsigned numInputs() const { return inputs.ordinality(); }
- virtual void getXrefInfo(IPropertyTree &reply, const IRoxieContextLogger &logctx) const
- {
- addXrefLibraryInfo(reply, extra.libraryName);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerLibraryCallActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, LibraryCallFactoryExtra & _extra)
- {
- return new CRoxieServerLibraryCallActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _extra);
- }
- //=====================================================================================================
- class CRoxieServerNWayInputActivity : public CRoxieServerActivity
- {
- IHThorNWayInputArg & helper;
- IRoxieInput ** inputs;
- PointerArrayOf<IRoxieInput> selectedInputs;
- unsigned numInputs;
- public:
- CRoxieServerNWayInputActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorNWayInputArg &)basehelper), numInputs(_numInputs)
- {
- inputs = new IRoxieInput*[numInputs];
- for (unsigned i = 0; i < numInputs; i++)
- inputs[i] = NULL;
- }
- ~CRoxieServerNWayInputActivity()
- {
- delete [] inputs;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- bool selectionIsAll;
- size32_t selectionLen;
- rtlDataAttr selection;
- helper.getInputSelection(selectionIsAll, selectionLen, selection.refdata());
- selectedInputs.kill();
- if (selectionIsAll)
- {
- for (unsigned i=0; i < numInputs; i++)
- selectedInputs.append(inputs[i]);
- }
- else
- {
- const size32_t * selections = (const size32_t *)selection.getdata();
- unsigned max = selectionLen/sizeof(size32_t);
- for (unsigned i = 0; i < max; i++)
- {
- unsigned nextIndex = selections[i];
- //Check there are no duplicates..... Assumes there are a fairly small number of inputs, so n^2 search is ok.
- for (unsigned j=i+1; j < max; j++)
- {
- if (nextIndex == selections[j])
- throw MakeStringException(ROXIE_NWAY_INPUT_ERROR, "Selection list for nway input can not contain duplicates");
- }
- if (nextIndex > numInputs)
- throw MakeStringException(ROXIE_NWAY_INPUT_ERROR, "Index %d in RANGE selection list is out of range", nextIndex);
- selectedInputs.append(inputs[nextIndex-1]);
- }
- }
- ForEachItemIn(i2, selectedInputs)
- selectedInputs.item(i2)->start(parentExtractSize, parentExtract, paused);
- }
- virtual void stop(bool aborting)
- {
- ForEachItemIn(i2, selectedInputs)
- selectedInputs.item(i2)->stop(aborting);
- CRoxieServerActivity::stop(aborting);
- }
- virtual unsigned __int64 queryLocalCycles() const
- {
- __int64 localCycles = totalCycles;
- ForEachItemIn(i, selectedInputs)
- {
- localCycles -= selectedInputs.item(i)->queryTotalCycles();
- }
- if (localCycles < 0)
- localCycles = 0;
- return localCycles;
- }
- virtual IRoxieInput *queryInput(unsigned idx) const
- {
- if (selectedInputs.isItem(idx))
- return selectedInputs.item(idx);
- else
- return NULL;
- }
- virtual void reset()
- {
- ForEachItemIn(i, selectedInputs)
- selectedInputs.item(i)->reset();
- selectedInputs.kill();
- CRoxieServerActivity::reset();
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- assertex(idx < numInputs);
- inputs[idx] = _in;
- }
- virtual const void * nextInGroup()
- {
- throwUnexpected();
- }
- virtual unsigned numConcreteOutputs() const
- {
- return selectedInputs.ordinality();
- }
- virtual IRoxieInput * queryConcreteInput(unsigned idx)
- {
- if (selectedInputs.isItem(idx))
- return selectedInputs.item(idx);
- return NULL;
- }
- };
- class CRoxieServerNWayInputActivityFactory : public CRoxieServerMultiInputFactory
- {
- // bool ordered;
- public:
- CRoxieServerNWayInputActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerNWayInputActivity(this, _probeManager, numInputs());
- }
- };
- IRoxieServerActivityFactory *createRoxieServerNWayInputActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerNWayInputActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=====================================================================================================
- class CRoxieServerNWayGraphLoopResultReadActivity : public CRoxieServerActivity
- {
- IHThorNWayGraphLoopResultReadArg & helper;
- CIArrayOf<CRoxieServerActivity> resultReaders;
- PointerArrayOf<IRoxieInput> inputs;
- unsigned graphId;
- bool grouped;
- bool selectionIsAll;
- size32_t selectionLen;
- rtlDataAttr selection;
- public:
- CRoxieServerNWayGraphLoopResultReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _graphId)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorNWayGraphLoopResultReadArg &)basehelper)
- {
- grouped = helper.isGrouped();
- graphId = _graphId;
- selectionIsAll = false;
- selectionLen = 0;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- if (inputs.ordinality() == 0)
- {
- initInputSelection();
- unsigned max = selectionLen / sizeof(size32_t);
- const size32_t * selections = (const size32_t *)selection.getdata();
- IProbeManager * probeManager = NULL; // MORE!!
- for (unsigned i = 0; i < max; i++)
- {
- CRoxieServerActivity * resultInput = new CRoxieServerInternalGraphLoopResultReadActivity(factory, probeManager, graphId, selections[i]);
- resultReaders.append(*resultInput);
- inputs.append(resultInput->queryOutput(0));
- resultInput->onCreate(ctx, colocalParent);
- resultInput->start(parentExtractSize, parentExtract, paused);
- }
- }
- else
- {
- ForEachItemIn(i, inputs)
- inputs.item(i)->start(parentExtractSize, parentExtract, paused);
- }
- }
- virtual void stop(bool aborting)
- {
- ForEachItemIn(i, inputs)
- inputs.item(i)->stop(aborting);
- CRoxieServerActivity::stop(aborting);
- }
- virtual void reset()
- {
- ForEachItemIn(i, inputs)
- inputs.item(i)->reset();
- inputs.kill();
- resultReaders.kill();
- CRoxieServerActivity::reset();
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for nway graph result read");
- }
- virtual const void * nextInGroup()
- {
- throwUnexpected();
- }
- virtual unsigned numConcreteOutputs() const
- {
- return inputs.ordinality();
- }
- virtual IRoxieInput * queryConcreteInput(unsigned idx)
- {
- if (inputs.isItem(idx))
- return inputs.item(idx);
- return NULL;
- }
- virtual void gatherIterationUsage(IRoxieServerLoopResultProcessor & processor, unsigned parentExtractSize, const byte * parentExtract)
- {
- ensureCreated();
- basehelper.onStart(parentExtract, NULL);
- initInputSelection();
- unsigned max = selectionLen / sizeof(size32_t);
- const size32_t * selections = (const size32_t *)selection.getdata();
- for (unsigned i = 0; i < max; i++)
- processor.noteUseIteration(selections[i]);
- }
- virtual void associateIterationOutputs(IRoxieServerLoopResultProcessor & processor, unsigned parentExtractSize, const byte * parentExtract, IProbeManager *probeManager, IArrayOf<IRoxieInput> &probes)
- {
- //selection etc. already initialised from the gratherIterationUsage() call.
- unsigned max = selectionLen / sizeof(size32_t);
- const size32_t * selections = (const size32_t *)selection.getdata();
- for (unsigned i = 0; i < max; i++)
- inputs.append(processor.connectIterationOutput(selections[i], probeManager, probes, this, i));
- }
- protected:
- void initInputSelection()
- {
- helper.getInputSelection(selectionIsAll, selectionLen, selection.refdata());
- if (selectionIsAll)
- throw MakeStringException(ROXIE_NWAY_INPUT_ERROR, "ALL not yet supported for NWay graph inputs");
- }
- };
- class CRoxieServerNWayGraphLoopResultReadActivityFactory : public CRoxieServerActivityFactory
- {
- unsigned graphId;
- public:
- CRoxieServerNWayGraphLoopResultReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _graphId)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), graphId(_graphId)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerNWayGraphLoopResultReadActivity(this, _probeManager, graphId);
- }
- virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
- {
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for NWay GraphLoopResultRead activity");
- }
- };
- IRoxieServerActivityFactory *createRoxieServerNWayGraphLoopResultReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned graphId)
- {
- return new CRoxieServerNWayGraphLoopResultReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, graphId);
- }
- //=================================================================================
- class RoxieSteppedInput : public CInterface, implements ISteppedInput
- {
- public:
- RoxieSteppedInput(IRoxieInput * _input) { input = _input; }
- IMPLEMENT_IINTERFACE
- protected:
- virtual const void * nextInputRow()
- {
- #ifdef TRACE_SEEK_REQUESTS
- IRoxieContextLogger * logger = input->queryActivity();
- const void * ret = doNextInputRow();
- {
- CommonXmlWriter xmlwrite(XWFtrim|XWFopt|XWFnoindent);
- if (!ret)
- xmlwrite.outputBool(true,"eof");
- else if (input->queryOutputMeta()->hasXML())
- input->queryOutputMeta()->toXML((byte *) ret, xmlwrite);
- logger->CTXLOG("next() returns (%s)", xmlwrite.str());
- }
- return ret;
- #else
- return doNextInputRow();
- #endif
- }
- virtual const void * nextInputRowGE(const void * seek, unsigned numFields, bool & wasCompleteMatch, const SmartStepExtra & stepExtra)
- {
- #ifdef TRACE_SEEK_REQUESTS
- IRoxieContextLogger * logger = input->queryActivity();
- {
- CommonXmlWriter xmlwrite(XWFtrim|XWFopt|XWFnoindent);
- if (input->queryOutputMeta()->hasXML())
- input->queryOutputMeta()->toXML((byte *) seek, xmlwrite);
- logger->CTXLOG("nextInputRowGE(%d, %s%s%s, %s) seek(%s)",
- numFields,
- stepExtra.readAheadManyResults() ? "readahead " : "",
- stepExtra.returnMismatches() ? "mismatch" : "exact",
- stepExtra.onlyReturnFirstSeekMatch() ? " single-match" : "",
- stepExtra.queryExtraSeeks() ? "multi-seek":"",
- xmlwrite.str());
- }
- const void * ret = doNextInputRowGE(seek, numFields, wasCompleteMatch, stepExtra);
- {
- CommonXmlWriter xmlwrite(XWFtrim|XWFopt|XWFnoindent);
- if (!ret)
- xmlwrite.outputBool(true,"eof");
- else if (input->queryOutputMeta()->hasXML())
- input->queryOutputMeta()->toXML((byte *) ret, xmlwrite);
- logger->CTXLOG("nextInputRowGE(%d, %s%s%s, %s) result(%s)",
- numFields,
- stepExtra.readAheadManyResults() ? "readahead " : "",
- stepExtra.returnMismatches() ? "mismatch" : "exact",
- stepExtra.onlyReturnFirstSeekMatch() ? " single-match" : "",
- stepExtra.queryExtraSeeks() ? "multi-seek":"",
- xmlwrite.str());
- }
- return ret;
- #else
- return doNextInputRowGE(seek, numFields, wasCompleteMatch, stepExtra);
- #endif
- }
- virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
- {
- return input->gatherConjunctions(collector);
- }
- virtual void resetEOF()
- {
- input->resetEOF();
- }
- virtual IInputSteppingMeta * queryInputSteppingMeta()
- {
- return input->querySteppingMeta();
- }
- inline const void * doNextInputRow()
- {
- const void * ret = input->nextInGroup();
- if (!ret)
- ret = input->nextInGroup();
- return ret;
- }
- inline const void * doNextInputRowGE(const void * seek, unsigned numFields, bool & wasCompleteMatch, const SmartStepExtra & stepExtra)
- {
- assertex(wasCompleteMatch);
- return input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
- }
- protected:
- IRoxieInput * input;
- };
- //=================================================================================
- class CRoxieServerNaryActivity : public CRoxieServerMultiInputActivity
- {
- public:
- CRoxieServerNaryActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
- : CRoxieServerMultiInputActivity(_factory, _probeManager, _numInputs)
- {
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerMultiInputActivity::start(parentExtractSize, parentExtract, paused);
- for (unsigned i=0; i < numInputs; i++)
- {
- IRoxieInput * cur = inputArray[i];
- unsigned numRealInputs = cur->numConcreteOutputs();
- for (unsigned j = 0; j < numRealInputs; j++)
- {
- IRoxieInput * curReal = cur->queryConcreteInput(j);
- expandedInputs.append(curReal);
- }
- }
- }
- virtual void reset()
- {
- expandedInputs.kill();
- CRoxieServerMultiInputActivity::reset();
- }
- protected:
- PointerArrayOf<IRoxieInput> expandedInputs;
- };
- //=================================================================================
- class CRoxieStreamMerger : public CStreamMerger
- {
- public:
- CRoxieStreamMerger() : CStreamMerger(true)
- {
- inputArray = NULL;
- }
- void initInputs(unsigned _numInputs, IRoxieInput ** _inputArray)
- {
- CStreamMerger::initInputs(_numInputs);
- inputArray = _inputArray;
- }
- virtual bool pullInput(unsigned i, const void * seek, unsigned numFields, const SmartStepExtra * stepExtra)
- {
- const void * next;
- bool matches = true;
- if (seek)
- next = inputArray[i]->nextSteppedGE(seek, numFields, matches, *stepExtra);
- else
- next = nextUngrouped(inputArray[i]);
- pending[i] = next;
- pendingMatches[i] = matches;
- return (next != NULL);
- }
- virtual void releaseRow(const void * row)
- {
- ReleaseRoxieRow(row);
- }
- protected:
- IRoxieInput **inputArray;
- };
- class CRoxieServerNWayMergeActivity : public CRoxieServerNaryActivity
- {
- public:
- CRoxieServerNWayMergeActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
- : CRoxieServerNaryActivity(_factory, _probeManager, _numInputs),
- helper((IHThorNWayMergeArg &)basehelper)
- {
- initializedMeta = false;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerNaryActivity::start(parentExtractSize, parentExtract, paused);
- merger.init(helper.queryCompare(), helper.dedup(), helper.querySteppingMeta()->queryCompare());
- merger.initInputs(expandedInputs.length(), expandedInputs.getArray());
- }
- virtual void stop(bool aborting)
- {
- merger.done();
- CRoxieServerNaryActivity::stop(aborting);
- }
- virtual void reset()
- {
- merger.cleanup();
- CRoxieServerNaryActivity::reset();
- initializedMeta = false;
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- const void * next = merger.nextRow();
- if (next)
- processed++;
- return next;
- }
- virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool & wasCompleteMatch, const SmartStepExtra & stepExtra)
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- const void * next = merger.nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);
- if (next)
- processed++;
- return next;
- }
- virtual IInputSteppingMeta * querySteppingMeta()
- {
- if (expandedInputs.ordinality() == 0)
- return NULL;
- if (!initializedMeta)
- {
- meta.init(helper.querySteppingMeta(), false);
- ForEachItemIn(i, expandedInputs)
- {
- if (meta.getNumFields() == 0)
- break;
- IInputSteppingMeta * inputMeta = expandedInputs.item(i)->querySteppingMeta();
- meta.intersect(inputMeta);
- }
- initializedMeta = true;
- }
- if (meta.getNumFields() == 0)
- return NULL;
- return &meta;
- }
- protected:
- IHThorNWayMergeArg &helper;
- CRoxieStreamMerger merger;
- CSteppingMeta meta;
- bool initializedMeta;
- };
- class CRoxieServerNWayMergeActivityFactory : public CRoxieServerMultiInputFactory
- {
- public:
- CRoxieServerNWayMergeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerNWayMergeActivity(this, _probeManager, numInputs());
- }
- };
- IRoxieServerActivityFactory *createRoxieServerNWayMergeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerNWayMergeActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerNWayMergeJoinActivity : public CRoxieServerNaryActivity
- {
- public:
- CRoxieServerNWayMergeJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs, CMergeJoinProcessor & _processor)
- : CRoxieServerNaryActivity(_factory, _probeManager, _numInputs),processor(_processor),
- helper((IHThorNWayMergeJoinArg &)basehelper)
- {
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerNaryActivity::start(parentExtractSize, parentExtract, paused);
- ForEachItemIn(i1, expandedInputs)
- {
- IRoxieInput * cur = expandedInputs.item(i1);
- Owned<RoxieSteppedInput> stepInput = new RoxieSteppedInput(cur);
- processor.addInput(stepInput);
- }
- ICodeContext * codectx = ctx->queryCodeContext();
- Owned<IEngineRowAllocator> inputAllocator = codectx->getRowAllocator(helper.queryInputMeta(), activityId);
- Owned<IEngineRowAllocator> outputAllocator = codectx->getRowAllocator(helper.queryOutputMeta(), activityId);
- processor.beforeProcessing(inputAllocator, outputAllocator);
- }
- virtual void stop(bool aborting)
- {
- processor.afterProcessing();
- CRoxieServerNaryActivity::stop(aborting);
- }
- virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
- {
- return processor.gatherConjunctions(collector);
- }
- virtual void resetEOF()
- {
- processor.queryResetEOF();
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- const void * next = processor.nextInGroup();
- if (next)
- processed++;
- return next;
- }
- virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- const void * next = processor.nextGE(seek, numFields, wasCompleteMatch, stepExtra);
- if (next)
- processed++;
- return next;
- }
- virtual IInputSteppingMeta * querySteppingMeta()
- {
- return processor.queryInputSteppingMeta();
- }
- protected:
- IHThorNWayMergeJoinArg & helper;
- CMergeJoinProcessor & processor;
- };
- class CRoxieServerAndMergeJoinActivity : public CRoxieServerNWayMergeJoinActivity
- {
- public:
- CRoxieServerAndMergeJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
- : CRoxieServerNWayMergeJoinActivity(_factory, _probeManager, _numInputs, andProcessor), andProcessor(helper)
- {
- }
- protected:
- CAndMergeJoinProcessor andProcessor;
- };
- class CRoxieServerAndLeftMergeJoinActivity : public CRoxieServerNWayMergeJoinActivity
- {
- public:
- CRoxieServerAndLeftMergeJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
- : CRoxieServerNWayMergeJoinActivity(_factory, _probeManager, _numInputs, andLeftProcessor), andLeftProcessor(helper)
- {
- }
- protected:
- CAndLeftMergeJoinProcessor andLeftProcessor;
- };
- class CRoxieServerMofNMergeJoinActivity : public CRoxieServerNWayMergeJoinActivity
- {
- public:
- CRoxieServerMofNMergeJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
- : CRoxieServerNWayMergeJoinActivity(_factory, _probeManager, _numInputs, mofnProcessor), mofnProcessor(helper)
- {
- }
- protected:
- CMofNMergeJoinProcessor mofnProcessor;
- };
- class CRoxieServerProximityJoinActivity : public CRoxieServerNWayMergeJoinActivity
- {
- public:
- CRoxieServerProximityJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
- : CRoxieServerNWayMergeJoinActivity(_factory, _probeManager, _numInputs, proximityProcessor), proximityProcessor(helper)
- {
- }
- protected:
- CProximityJoinProcessor proximityProcessor;
- };
- class CRoxieServerNWayMergeJoinActivityFactory : public CRoxieServerMultiInputFactory
- {
- unsigned flags;
- public:
- CRoxieServerNWayMergeJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- Owned<IHThorNWayMergeJoinArg> helper = (IHThorNWayMergeJoinArg *) helperFactory();
- flags = helper->getJoinFlags();
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- if (flags & IHThorNWayMergeJoinArg::MJFhasrange)
- return new CRoxieServerProximityJoinActivity(this, _probeManager, numInputs());
- switch (flags & IHThorNWayMergeJoinArg::MJFkindmask)
- {
- case IHThorNWayMergeJoinArg::MJFinner:
- return new CRoxieServerAndMergeJoinActivity(this, _probeManager, numInputs());
- case IHThorNWayMergeJoinArg::MJFleftonly:
- case IHThorNWayMergeJoinArg::MJFleftouter:
- return new CRoxieServerAndLeftMergeJoinActivity(this, _probeManager, numInputs());
- case IHThorNWayMergeJoinArg::MJFmofn:
- return new CRoxieServerMofNMergeJoinActivity(this, _probeManager, numInputs());
- default:
- throwUnexpected();
- }
- }
- };
- IRoxieServerActivityFactory *createRoxieServerNWayMergeJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerNWayMergeJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerNWaySelectActivity : public CRoxieServerMultiInputActivity
- {
- IHThorNWaySelectArg &helper;
- public:
- CRoxieServerNWaySelectActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
- : CRoxieServerMultiInputActivity(_factory, _probeManager, _numInputs),
- helper((IHThorNWaySelectArg &)basehelper)
- {
- selectedInput = NULL;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerMultiInputActivity::start(parentExtractSize, parentExtract, paused);
- unsigned whichInput = helper.getInputIndex();
- selectedInput = NULL;
- if (whichInput--)
- {
- for (unsigned i=0; i < numInputs; i++)
- {
- IRoxieInput * cur = inputArray[i];
- unsigned numRealInputs = cur->numConcreteOutputs();
- if (whichInput < numRealInputs)
- {
- selectedInput = cur->queryConcreteInput(whichInput);
- break;
- }
- whichInput -= numRealInputs;
- }
- }
- }
- virtual void reset()
- {
- selectedInput = NULL;
- CRoxieServerMultiInputActivity::reset();
- }
- const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (!selectedInput)
- return NULL;
- return selectedInput->nextInGroup();
- }
- virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
- {
- if (!selectedInput)
- return false;
- return selectedInput->gatherConjunctions(collector);
- }
-
- virtual void resetEOF()
- {
- if (selectedInput)
- selectedInput->resetEOF();
- }
- virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (!selectedInput)
- return NULL;
- return selectedInput->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
- }
- IInputSteppingMeta * querySteppingMeta()
- {
- if (selectedInput)
- return selectedInput->querySteppingMeta();
- return NULL;
- }
- protected:
- IRoxieInput * selectedInput;
- };
- class CRoxieServerNWaySelectActivityFactory : public CRoxieServerMultiInputFactory
- {
- public:
- CRoxieServerNWaySelectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerNWaySelectActivity(this, _probeManager, numInputs());
- }
- };
- IRoxieServerActivityFactory *createRoxieServerNWaySelectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerNWaySelectActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerRemoteActivity : public CRoxieServerActivity, implements IRoxieServerErrorHandler
- {
- protected:
- IHThorRemoteArg &helper;
- CRemoteResultAdaptor remote;
- public:
- CRoxieServerRemoteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteID)
- : CRoxieServerActivity(_factory, _probeManager),
- helper((IHThorRemoteArg &)basehelper),
- remote(_remoteID, meta.queryOriginal(), helper, *this, false, false) // MORE - if they need it stable we'll have to think!
- {
- }
- virtual const IResolvedFile *queryVarFileInfo() const
- {
- return NULL;
- }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerActivity::onCreate(_ctx, _colocalParent);
- remote.onCreate(this, this, _ctx, _colocalParent);
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- remote.onStart(parentExtractSize, parentExtract);
- remote.setLimits(helper.getRowLimit(), (unsigned __int64) -1, I64C(0x7FFFFFFFFFFFFFFF));
- unsigned fileNo = 0; // MORE - superfiles require us to do this per file part... maybe (needs thought)
- remote.getMem(0, fileNo, 0); // the cached context is all we need to send
- remote.flush();
- remote.senddone();
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
- }
- virtual IRoxieInput *queryOutput(unsigned idx)
- {
- if (idx==(unsigned)-1)
- idx = 0;
- return idx ? NULL: &remote;
- }
- virtual void reset()
- {
- processed = remote.processed;
- remote.processed = 0;
- CRoxieServerActivity::reset();
- }
- virtual void onLimitExceeded(bool isKeyed)
- {
- if (traceLevel > 4)
- DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
- helper.onLimitExceeded();
- }
- virtual const void *createLimitFailRow(bool isKeyed)
- {
- UNIMPLEMENTED; // MORE - is there an ONFAIL for a limit folded into a remote?
- }
- virtual const void *nextInGroup()
- {
- throwUnexpected(); // I am nobody's input
- }
- };
- class CRoxieServerRemoteActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- RemoteActivityId remoteId;
- bool isRoot;
- CRoxieServerRemoteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, bool _isRoot)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), remoteId(_remoteId), isRoot(_isRoot)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerRemoteActivity(this, _probeManager, remoteId);
- }
- virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
- {
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for %s activity", getActivityText(kind));
- }
- virtual bool isSink() const
- {
- //I don't think the action version of this is implemented - but this would be the code
- return isRoot && !meta.queryOriginal();
- }
- };
- IRoxieServerActivityFactory *createRoxieServerRemoteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, bool _isRoot)
- {
- return new CRoxieServerRemoteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _isRoot);
- }
- //=================================================================================
- class CRoxieServerIterateActivity : public CRoxieServerActivity
- {
- IHThorIterateArg &helper;
- OwnedConstRoxieRow defaultRecord;
- OwnedConstRoxieRow left;
- OwnedConstRoxieRow right;
- unsigned counter;
- public:
- CRoxieServerIterateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager),
- helper((IHThorIterateArg &)basehelper)
- {
- counter = 0;
- }
- virtual bool needsAllocator() const { return true; }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- counter = 0;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- size32_t thisSize = helper.createDefault(rowBuilder);
- defaultRecord.setown(rowBuilder.finalizeRowClear(thisSize));
- }
- virtual void reset()
- {
- defaultRecord.clear();
- right.clear();
- left.clear();
- CRoxieServerActivity::reset();
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- loop
- {
- right.setown(input->nextInGroup());
- if (!right)
- {
- bool skippedGroup = (left == NULL) && (counter > 0); //we have just skipped entire group, but shouldn't output a double null
- left.clear();
- counter = 0;
- if (skippedGroup) continue;
- return NULL;
- }
- try
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- unsigned outSize = helper.transform(rowBuilder, left ? left : defaultRecord, right, ++counter);
- if (outSize)
- {
- left.setown(rowBuilder.finalizeRowClear(outSize));
- processed++;
- return left.getLink();
- }
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- }
- };
- class CRoxieServerIterateActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerIterateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerIterateActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerIterateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerIterateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerProcessActivity : public CRoxieServerActivity
- {
- IHThorProcessArg &helper;
- OwnedConstRoxieRow curRight;
- OwnedConstRoxieRow initialRight;
- unsigned counter;
- Owned<IEngineRowAllocator> rightRowAllocator;
- public:
- CRoxieServerProcessActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorProcessArg &)basehelper)
- {
- counter = 0;
- }
- virtual bool needsAllocator() const { return true; }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerActivity::onCreate(_ctx, _colocalParent);
- rightRowAllocator.setown(ctx->queryCodeContext()->getRowAllocator(QUERYINTERFACE(helper.queryRightRecordSize(), IOutputMetaData), activityId));
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- counter = 0;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- RtlDynamicRowBuilder rowBuilder(rightRowAllocator);
- size32_t thisSize = helper.createInitialRight(rowBuilder);
- initialRight.setown(rowBuilder.finalizeRowClear(thisSize));
- curRight.set(initialRight);
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- try
- {
- loop
- {
- const void * in = input->nextInGroup();
- if (!in)
- {
- bool eog = (curRight != initialRight); // processed any records?
- counter = 0;
- curRight.set(initialRight);
- if (eog)
- return NULL;
- in = input->nextInGroup();
- if (!in)
- return NULL;
- }
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- RtlDynamicRowBuilder rightRowBuilder(rightRowAllocator);
- size32_t outSize = helper.transform(rowBuilder, rightRowBuilder, in, curRight, ++counter);
- ReleaseRoxieRow(in);
- if (outSize)
- {
- //MORE: This should be returned...
- size32_t rightSize = rightRowAllocator->queryOutputMeta()->getRecordSize(rightRowBuilder.getSelf());
- curRight.setown(rightRowBuilder.finalizeRowClear(rightSize));
- processed++;
- return rowBuilder.finalizeRowClear(outSize);
- }
- }
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- };
- class CRoxieServerProcessActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerProcessActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerProcessActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerProcessActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerProcessActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerGroupActivity : public CRoxieServerActivity
- {
- IHThorGroupArg &helper;
- bool endPending;
- bool eof;
- bool first;
- const void *next;
- public:
- CRoxieServerGroupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorGroupArg &)basehelper)
- {
- next = NULL;
- endPending = false;
- eof = false;
- first = true;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- endPending = false;
- eof = false;
- first = true;
- assertex(next == NULL);
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- }
- virtual void reset()
- {
- ReleaseClearRoxieRow(next);
- CRoxieServerActivity::reset();
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (first)
- {
- next = input->nextInGroup();
- first = false;
- }
- if (eof || endPending)
- {
- endPending = false;
- return NULL;
- }
- const void * prev = next;
- next = input->nextInGroup();
- if (!next)
- next = input->nextInGroup();
- if (next)
- {
- assertex(prev);
- if (!helper.isSameGroup(prev, next))
- endPending = true;
- }
- else
- eof = true;
- if (prev)
- processed++;
- return prev;
- }
- };
- class CRoxieServerGroupActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerGroupActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerGroupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerFirstNActivity : public CRoxieServerLateStartActivity
- {
- unsigned __int64 limit;
- unsigned __int64 skip;
- unsigned doneThisGroup;
- IHThorFirstNArg &helper;
- public:
- CRoxieServerFirstNActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerLateStartActivity(_factory, _probeManager), helper((IHThorFirstNArg &)basehelper)
- {
- doneThisGroup = 0;
- limit = 0;
- skip = 0;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- doneThisGroup = 0;
- CRoxieServerLateStartActivity::start(parentExtractSize, parentExtract, paused);
- limit = helper.getLimit();
- skip = helper.numToSkip();
- lateStart(parentExtractSize, parentExtract, limit > 0);
- if (limit + skip >= limit)
- limit += skip;
- }
- const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (eof)
- return NULL;
- const void *ret;
- loop
- {
- ret = input->nextInGroup();
- if (!ret)
- {
- if (meta.isGrouped())
- {
- if (doneThisGroup > skip)
- {
- doneThisGroup = 0;
- return NULL;
- }
- doneThisGroup = 0;
- }
- ret = input->nextInGroup();
- if (!ret)
- {
- eof = true;
- return NULL;
- }
- }
- doneThisGroup++;
- if (doneThisGroup > skip)
- break;
- ReleaseRoxieRow(ret);
- }
- if (doneThisGroup <= limit)
- {
- processed++;
- return ret;
- }
- ReleaseRoxieRow(ret);
- if (meta.isGrouped())
- {
- while ((ret = input->nextInGroup()) != NULL)
- ReleaseRoxieRow(ret);
- doneThisGroup = 0;
- }
- else
- eof = true;
- return NULL;
- }
- };
- class CRoxieServerFirstNActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerFirstNActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerFirstNActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerFirstNActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerFirstNActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerSelectNActivity : public CRoxieServerActivity
- {
- bool done;
- IHThorSelectNArg &helper;
- public:
- CRoxieServerSelectNActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorSelectNArg &)basehelper)
- {
- done = false;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- done = false;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- }
- const void *defaultRow()
- {
- if (!rowAllocator)
- createRowAllocator(); // We delay as often not needed...
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- size32_t thisSize = helper.createDefault(rowBuilder);
- return rowBuilder.finalizeRowClear(thisSize);
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (done)
- return NULL;
- done = true;
- processed++; // always going to return a row!
- unsigned __int64 index = helper.getRowToSelect();
- while (--index)
- {
- const void * next = input->nextInGroup();
- if (!next)
- next = input->nextInGroup();
- if (!next)
- return defaultRow();
- ReleaseRoxieRow(next);
- }
- const void * next = input->nextInGroup();
- if (!next)
- next = input->nextInGroup();
- if (!next)
- next = defaultRow();
- return next;
- }
- };
- class CRoxieServerSelectNActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerSelectNActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerSelectNActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerSelectNActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerSelectNActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerSelfJoinActivity : public CRoxieServerActivity
- {
- IHThorJoinArg &helper;
- ICompare *collate;
- OwnedRowArray group;
- bool matchedLeft;
- BoolArray matchedRight;
- bool eof;
- bool first;
- unsigned leftIndex;
- unsigned rightIndex;
- unsigned rightOuterIndex;
- unsigned joinLimit;
- unsigned atmostLimit;
- unsigned atmostsTriggered;
- unsigned abortLimit;
- unsigned keepLimit;
- unsigned joinCounter;
- bool leftOuterJoin;
- bool rightOuterJoin;
- bool exclude;
- bool limitFail;
- bool limitOnFail;
- bool cloneLeft;
- OwnedConstRoxieRow defaultLeft;
- OwnedConstRoxieRow defaultRight;
- OwnedConstRoxieRow lhs;
- Owned<IException> failingLimit;
- bool failingOuterAtmost;
- Owned<IEngineRowAllocator> defaultAllocator;
- Owned<IRHLimitedCompareHelper> limitedhelper;
- Owned<CRHDualCache> dualcache;
- IInputBase *dualCacheInput;
- bool fillGroup()
- {
- group.clear();
- matchedLeft = false;
- matchedRight.kill();
- failingOuterAtmost = false;
- const void * next;
- unsigned groupCount = 0;
- while((next = input->nextInGroup()) != NULL)
- {
- if(groupCount==abortLimit)
- {
- if(limitFail)
- failLimit(next);
- if (ctx->queryDebugContext())
- ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
- if(limitOnFail)
- {
- assertex(!failingLimit);
- try
- {
- failLimit(next);
- }
- catch(IException * except)
- {
- failingLimit.setown(except);
- }
- assertex(failingLimit != NULL);
- group.append(next);
- groupCount++;
- break;
- }
- group.clear();
- groupCount = 0;
- while(next)
- {
- ReleaseRoxieRow(next);
- next = input->nextInGroup();
- }
- }
- else if(groupCount==atmostLimit)
- {
- atmostsTriggered++;
- if(leftOuterJoin)
- {
- group.append(next);
- groupCount++;
- failingOuterAtmost = true;
- break;
- }
- else
- {
- group.clear();
- groupCount = 0;
- while (next)
- {
- ReleaseRoxieRow(next);
- next = input->nextInGroup();
- }
- }
- }
- else
- {
- group.append(next);
- groupCount++;
- }
- }
- if(group.ordinality()==0)
- {
- eof = true;
- return false;
- }
- leftIndex = 0;
- rightIndex = 0;
- rightOuterIndex = 0;
- joinCounter = 0;
- joinLimit = keepLimit;
- ForEachItemIn(idx, group)
- matchedRight.append(false);
- return true;
- }
- void failLimit(const void * next)
- {
- helper.onMatchAbortLimitExceeded();
- CommonXmlWriter xmlwrite(XWFtrim|XWFopt );
- if (!ctx->isBlind() && input->queryOutputMeta() && input->queryOutputMeta()->hasXML())
- {
- input->queryOutputMeta()->toXML((byte *) next, xmlwrite);
- }
- throw MakeStringException(ROXIE_TOO_MANY_RESULTS, "More than %d match candidates in self-join %d for row %s", abortLimit, queryId(), xmlwrite.str());
- }
- virtual bool needsAllocator() const { return true; }
- const void *joinRecords(const void * curLeft, const void * curRight, unsigned counter, IException * except)
- {
- try
- {
- if (cloneLeft && !except)
- {
- LinkRoxieRow(curLeft);
- return curLeft;
- }
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- size32_t outsize = except ? helper.onFailTransform(rowBuilder, curLeft, curRight, except) : helper.transform(rowBuilder, curLeft, curRight, counter);
- if (outsize)
- return rowBuilder.finalizeRowClear(outsize);
- else
- return NULL;
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- void createDefaultLeft()
- {
- if (!defaultLeft)
- {
- if (!defaultAllocator)
- defaultAllocator.setown(ctx->queryCodeContext()->getRowAllocator(input->queryOutputMeta(), activityId));
- RtlDynamicRowBuilder rowBuilder(defaultAllocator);
- size32_t thisSize = helper.createDefaultLeft(rowBuilder);
- defaultLeft.setown(rowBuilder.finalizeRowClear(thisSize));
- }
- }
- void createDefaultRight()
- {
- if (!defaultRight)
- {
- if (!defaultAllocator)
- defaultAllocator.setown(ctx->queryCodeContext()->getRowAllocator(input->queryOutputMeta(), activityId));
- RtlDynamicRowBuilder rowBuilder(defaultAllocator);
- size32_t thisSize = helper.createDefaultRight(rowBuilder);
- defaultRight.setown(rowBuilder.finalizeRowClear(thisSize));
- }
- }
- public:
- CRoxieServerSelfJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorJoinArg &)basehelper)
- {
- collate = helper.queryCompareLeftRight();
- eof = false;
- first = true;
- keepLimit = 0;
- atmostLimit = 0;
- atmostsTriggered = 0;
- unsigned joinFlags = helper.getJoinFlags();
- leftOuterJoin = (joinFlags & JFleftouter) != 0;
- rightOuterJoin = (joinFlags & JFrightouter) != 0;
- cloneLeft = (joinFlags & JFtransformmatchesleft) != 0;
- exclude = (joinFlags & JFexclude) != 0;
- abortLimit = 0;
- joinLimit = 0;
- assertex((joinFlags & (JFfirst | JFfirstleft | JFfirstright)) == 0); // no longer supported
- getLimitType(joinFlags, limitFail, limitOnFail);
- if((joinFlags & JFslidingmatch) != 0)
- throw MakeStringException(ROXIE_UNIMPLEMENTED_ERROR, "Internal Error: Sliding self join not supported");
- failingOuterAtmost = false;
- matchedLeft = false;
- leftIndex = 0;
- rightIndex = 0;
- rightOuterIndex = 0;
- joinCounter = 0;
- dualCacheInput = NULL;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- eof = false;
- first = true;
- failingLimit.clear();
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- keepLimit = helper.getKeepLimit();
- if(keepLimit == 0)
- keepLimit = (unsigned)-1;
- atmostsTriggered = 0;
- atmostLimit = helper.getJoinLimit();
- if(atmostLimit == 0)
- atmostLimit = (unsigned)-1;
- else
- assertex(!rightOuterJoin);
- abortLimit = helper.getMatchAbortLimit();
- if (abortLimit == 0)
- abortLimit = (unsigned)-1;
- if (rightOuterJoin)
- createDefaultLeft();
- if (leftOuterJoin || limitOnFail)
- createDefaultRight();
- if ((helper.getJoinFlags() & JFlimitedprefixjoin) && helper.getJoinLimit())
- { //limited match join (s[1..n])
- dualcache.setown(new CRHDualCache());
- dualcache->init(CRoxieServerActivity::input);
- dualCacheInput = dualcache->queryOut1();
- failingOuterAtmost = false;
- matchedLeft = false;
- leftIndex = 0;
- rightOuterIndex = 0;
- joinCounter = 0;
- limitedhelper.setown(createRHLimitedCompareHelper());
- limitedhelper->init( helper.getJoinLimit(), dualcache->queryOut2(), collate, helper.queryPrefixCompare() );
- }
- }
- virtual void reset()
- {
- if (atmostsTriggered)
- noteStatistic(STATS_ATMOST, atmostsTriggered, 1);
- group.clear();
- CRoxieServerActivity::reset();
- defaultLeft.clear();
- defaultRight.clear();
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (limitedhelper)
- {
- while(!eof) //limited match join
- {
- if (!group.isItem(rightIndex))
- {
- lhs.setown(dualCacheInput->nextInGroup());
- if (lhs)
- {
- rightIndex = 0;
- joinCounter = 0;
- group.clear();
- limitedhelper->getGroup(group,lhs);
- }
- else
- {
- eof = true;
- }
- }
-
- if (group.isItem(rightIndex))
- {
- const void * rhs = group.item(rightIndex++);
- if(helper.match(lhs, rhs))
- {
- const void * ret = joinRecords(lhs, rhs, ++joinCounter, NULL);
- return ret;
- }
- }
- }
- return NULL;
- }
- else
- {
- if (first)
- {
- first = false;
- fillGroup();
- }
- while(!eof)
- {
- if(failingOuterAtmost)
- while(group.isItem(leftIndex))
- {
- const void * ret = joinRecords(group.item(leftIndex++), defaultRight, 0, NULL);
- if(ret)
- {
- processed++;
- return ret;
- }
- }
- if((joinLimit == 0) || !group.isItem(rightIndex))
- {
- if(leftOuterJoin && !matchedLeft && !failingLimit)
- {
- const void * ret = joinRecords(group.item(leftIndex), defaultRight, 0, NULL);
- if(ret)
- {
- matchedLeft = true;
- processed++;
- return ret;
- }
- }
- leftIndex++;
- matchedLeft = false;
- rightIndex = 0;
- joinCounter = 0;
- joinLimit = keepLimit;
- }
- if(!group.isItem(leftIndex))
- {
- if(failingLimit || failingOuterAtmost)
- {
- const void * lhs;
- while((lhs = input->nextInGroup()) != NULL) // dualCache never active here
- {
- const void * ret = joinRecords(lhs, defaultRight, 0, failingLimit);
- ReleaseRoxieRow(lhs);
- if(ret)
- {
- processed++;
- return ret;
- }
- }
- failingLimit.clear();
- }
- if(rightOuterJoin && !failingLimit)
- while(group.isItem(rightOuterIndex))
- if(!matchedRight.item(rightOuterIndex++))
- {
- const void * ret = joinRecords(defaultLeft, group.item(rightOuterIndex-1), 0, NULL);
- if(ret)
- {
- processed++;
- return ret;
- }
- }
- if(!fillGroup())
- return NULL;
- continue;
- }
- const void * lhs = group.item(leftIndex);
- if(failingLimit)
- {
- leftIndex++;
- const void * ret = joinRecords(lhs, defaultRight, 0, failingLimit);
- if(ret)
- {
- processed++;
- return ret;
- }
- }
- else
- {
- const void * rhs = group.item(rightIndex++);
- if(helper.match(lhs, rhs))
- {
- matchedLeft = true;
- matchedRight.replace(true, rightIndex-1);
- if(!exclude)
- {
- const void * ret = joinRecords(lhs, rhs, ++joinCounter, NULL);
- if(ret)
- {
- processed++;
- joinLimit--;
- return ret;
- }
- }
- }
- }
- }
- return NULL;
- }
- }
- };
- class CRoxieServerSelfJoinActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerSelfJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerSelfJoinActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerSelfJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerSelfJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=====================================================================================================
- class CRoxieServerLookupJoinActivity : public CRoxieServerTwoInputActivity
- {
- private:
- class LookupTable : public CInterface
- {
- public:
- LookupTable(IHThorHashJoinArg &helper)
- : leftRightCompare(helper.queryCompareLeftRight()), rightCompare(helper.queryCompareRight()),
- leftHash(helper.queryHashLeft()), rightHash(helper.queryHashRight())
- {
- size = 0;
- }
- virtual const void *find(const void * left) const = 0;
- virtual const void *findNext(const void * left) const = 0;
- protected:
- ICompare * leftRightCompare;
- ICompare * rightCompare;
- IHash * leftHash;
- IHash * rightHash;
- unsigned size;
- };
- class DedupLookupTable : public LookupTable
- {
- public:
- DedupLookupTable(ConstPointerArray &rightRows, IHThorHashJoinArg &helper)
- : LookupTable(helper)
- {
- size = (4*rightRows.length())/3 + 1;
- table = (const void * *)calloc(size, sizeof(void *)); // This should probably be allocated from roxiemem (and size rounded up to actual available size)
- ForEachItemIn(idx, rightRows)
- add(rightRows.item(idx));
- }
- ~DedupLookupTable()
- {
- unsigned i;
- for(i=0; i<size; i++)
- ReleaseRoxieRow(table[i]);
- free(table);
- }
- virtual const void *find(const void * left) const
- {
- unsigned index = leftHash->hash(left) % size;
- unsigned start = index;
- while (table[index])
- {
- if(leftRightCompare->docompare(left, table[index]) == 0)
- return table[index];
- index++;
- if (index==size)
- index = 0;
- if (index==start)
- throw MakeStringException(ROXIE_JOIN_ERROR, "Internal error in lookup join activity (hash table full on lookup)");
- }
- return NULL;
- }
- virtual const void *findNext(const void * left) const
- {
- return NULL;
- }
- protected:
- void add(const void * right)
- {
- unsigned index = rightHash->hash(right) % size;
- unsigned start = index;
- while (table[index])
- {
- if (rightCompare->docompare(table[index], right) == 0)
- {
- ReleaseRoxieRow(right);
- return;
- }
- index++;
- if (index==size)
- index = 0;
- if (index==start)
- throw MakeStringException(ROXIE_JOIN_ERROR, "Internal error in lookup join activity (hash table full on add)");
- }
- table[index] = right;
- }
- const void * * table;
- };
- class FewLookupTable : public LookupTable
- {
- public:
- FewLookupTable(ConstPointerArray &rightRows, IHThorHashJoinArg &helper)
- : LookupTable(helper)
- {
- size = (4*rightRows.length())/3 + 1;
- table = (const void * *)calloc(size, sizeof(void *)); // This should probably be allocated from roxiemem
- findex = fstart = BadIndex;
- ForEachItemIn(idx, rightRows)
- add(rightRows.item(idx));
- }
- ~FewLookupTable()
- {
- unsigned i;
- for(i=0; i<size; i++)
- ReleaseRoxieRow(table[i]);
- free(table);
- }
- virtual const void *find(const void * left) const
- {
- fstart = leftHash->hash(left) % size;
- findex = fstart;
- return doFind(left);
- }
- virtual const void *findNext(const void * left) const
- {
- if (findex == BadIndex)
- return NULL;
- advance();
- return doFind(left);
- }
- protected:
- void add(const void * right)
- {
- unsigned start = rightHash->hash(right) % size;
- unsigned index = start;
- while (table[index])
- {
- index++;
- if (index==size)
- index = 0;
- if (index==start)
- throwUnexpected(); //table is full, should never happen
- }
- table[index] = right;
- }
- void advance() const
- {
- findex++;
- if(findex==size)
- findex = 0;
- if(findex==fstart)
- throw MakeStringException(ROXIE_JOIN_ERROR, "Internal error in lookup join activity (hash table full on lookup)");
- }
- const void *doFind(const void * left) const
- {
- while(table[findex])
- {
- if (leftRightCompare->docompare(left, table[findex]) == 0)
- return table[findex];
- advance();
- }
- findex = BadIndex;
- return NULL;
- }
- const void * * table;
- unsigned mutable fstart;
- unsigned mutable findex;
- static unsigned const BadIndex;
- };
- class ManyLookupTable : public LookupTable
- {
- public:
- ManyLookupTable(ConstPointerArray &rightRows, IHThorHashJoinArg &helper)
- : LookupTable(helper)
- {
- rightRows.swapWith(rowtable);
- UInt64Array groups;
- unsigned numRows = rowtable.length();
- if (numRows)
- {
- unsigned groupStart = 0;
- const void *groupStartRow = rowtable.item(0);
- for (unsigned i=1; i < numRows; i++)
- {
- const void *thisRow = rowtable.item(i);
- if (rightCompare->docompare(groupStartRow, thisRow))
- {
- groups.append(makeint64(groupStart, i-groupStart));
- groupStart = i;
- groupStartRow = thisRow;
- }
- }
- groups.append(makeint64(groupStart, numRows-groupStart));
- }
- size = (4*groups.length())/3 + 1;
- table = (__uint64 *) calloc(size, sizeof(__uint64)); // This should probably be allocated from roxiemem
- ForEachItemIn(idx, groups)
- {
- unsigned __int64 group = groups.item(idx);
- unsigned groupstart = high(group);
- const void *row = rowtable.item(groupstart);
- add(row, group);
- }
- }
- ~ManyLookupTable()
- {
- ForEachItemIn(idx, rowtable)
- {
- ReleaseRoxieRow(rowtable.item(idx));
- }
- free(table);
- }
- void add(const void *row, unsigned __int64 group)
- {
- unsigned start = rightHash->hash(row) % size;
- unsigned index = start;
- while (table[index])
- {
- index++;
- if (index==size)
- index = 0;
- if (index==start)
- throwUnexpected(); //table is full, should never happen
- }
- table[index] = group;
- }
- virtual const void *find(const void * left) const
- {
- unsigned index = leftHash->hash(left) % size;
- unsigned start = index;
- while (table[index])
- {
- __uint64 group = table[index];
- currentMatch = high(group);
- const void *right = rowtable.item(currentMatch);
- if (leftRightCompare->docompare(left, right) == 0)
- {
- currentMatch++;
- matchCount = low(group) - 1;
- return right;
- }
- index++;
- if (index==size)
- index = 0;
- if (index==start)
- throw MakeStringException(ROXIE_JOIN_ERROR, "Internal error in lookup join activity (hash table full on lookup)");
- }
- matchCount = 0;
- return NULL;
- }
- virtual const void *findNext(const void * left) const
- {
- if (!matchCount)
- return NULL;
- matchCount--;
- return rowtable.item(currentMatch++);
- }
- protected:
- __uint64 *table;
- ConstPointerArray rowtable;
- mutable unsigned currentMatch;
- mutable unsigned matchCount;
- };
- IHThorHashJoinArg &helper;
- bool leftOuterJoin;
- bool exclude;
- bool eog;
- bool many;
- bool dedupRHS;
- bool useFewTable;
- bool matchedGroup;
- const void *left;
- OwnedConstRoxieRow defaultRight;
- Owned<LookupTable> table;
- unsigned keepLimit;
- unsigned atmostLimit;
- unsigned atmostsTriggered;
- unsigned limitLimit;
- unsigned joinCounter;
- bool limitFail;
- bool limitOnFail;
- bool hasGroupLimit;
- bool isSmartJoin;
- unsigned keepCount;
- bool gotMatch;
- bool cloneLeft;
- ConstPointerArray rightGroup;
- aindex_t rightGroupIndex;
- Owned<IException> failingLimit;
- ConstPointerArray filteredRight;
- ThorActivityKind activityKind;
- Owned<IEngineRowAllocator> defaultRightAllocator;
-
- void createDefaultRight()
- {
- if (!defaultRight)
- {
- if (!defaultRightAllocator)
- defaultRightAllocator.setown(ctx->queryCodeContext()->getRowAllocator(input1->queryOutputMeta(), activityId));
- RtlDynamicRowBuilder rowBuilder(defaultRightAllocator);
- size32_t thisSize = helper.createDefaultRight(rowBuilder);
- defaultRight.setown(rowBuilder.finalizeRowClear(thisSize));
- }
- }
- public:
- CRoxieServerLookupJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _useFewTable)
- : CRoxieServerTwoInputActivity(_factory, _probeManager), helper((IHThorHashJoinArg &)basehelper), useFewTable(_useFewTable)
- {
- unsigned joinFlags = helper.getJoinFlags();
- leftOuterJoin = (joinFlags & JFleftouter) != 0;
- assertex((joinFlags & JFrightouter) == 0);
- exclude = (joinFlags & JFexclude) != 0;
- many = (joinFlags & JFmanylookup) != 0;
- cloneLeft = (joinFlags & JFtransformmatchesleft) != 0;
- dedupRHS = (joinFlags & (JFmanylookup | JFmatchrequired | JFtransformMaySkip)) == 0; // optimisation: can implicitly dedup RHS unless is many lookup, or match required, or transform may skip
- left = NULL;
- activityKind = factory->getKind();
- eog = false;
- matchedGroup = false;
- gotMatch = false;
- keepLimit = 0;
- keepCount = 0;
- joinCounter = 0;
- atmostLimit = 0;
- atmostsTriggered = 0;
- limitLimit = 0;
- rightGroupIndex = 0;
- hasGroupLimit = false;
- isSmartJoin = (joinFlags & JFsmart) != 0;
- getLimitType(joinFlags, limitFail, limitOnFail);
- }
- void loadRight()
- {
- ConstPointerArray rightset;
- try
- {
- const void * next;
- while(true)
- {
- next = input1->nextInGroup();
- if(!next)
- next = input1->nextInGroup();
- if(!next)
- break;
- rightset.append(next);
- }
- if (!dedupRHS)
- {
- if (useFewTable)
- {
- table.setown(new FewLookupTable(rightset, helper)); // NOTE - takes ownership of rightset
- }
- else
- {
- if (!helper.isRightAlreadySorted())
- {
- if (helper.getJoinFlags() & JFunstable)
- {
- qsortvec(const_cast<void * *>(rightset.getArray()), rightset.ordinality(), *helper.queryCompareRight());
- }
- else
- {
- unsigned rightord = rightset.ordinality();
- MemoryAttr tempAttr(rightord*sizeof(void **)); // Temp storage for stable sort. This should probably be allocated from roxiemem
- void **temp = (void **) tempAttr.bufferBase();
- void **_rows = const_cast<void * *>(rightset.getArray());
- memcpy(temp, _rows, rightord*sizeof(void **));
- qsortvecstable(temp, rightord, *helper.queryCompareRight(), (void ***)_rows);
- for (unsigned i = 0; i < rightord; i++)
- {
- *_rows = **((void ***)_rows);
- _rows++;
- }
- }
- }
- table.setown(new ManyLookupTable(rightset, helper)); // NOTE - takes ownership of rightset
- }
- }
- else
- {
- table.setown(new DedupLookupTable(rightset, helper)); // NOTE - takes ownership of rightset
- }
- }
- catch (...)
- {
- ForEachItemIn(idx, rightset)
- ReleaseRoxieRow(rightset.item(idx));
- throw;
- }
- };
- virtual void reset()
- {
- if (atmostsTriggered)
- noteStatistic(STATS_ATMOST, atmostsTriggered, 1);
- CRoxieServerTwoInputActivity::reset();
- ReleaseClearRoxieRow(left);
- defaultRight.clear();
- table.clear();
- }
- virtual bool needsAllocator() const { return true; }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- eog = false;
- matchedGroup = false;
- left = NULL;
- CRoxieServerTwoInputActivity::start(parentExtractSize, parentExtract, paused);
- keepLimit = helper.getKeepLimit();
- if(keepLimit==0) keepLimit = static_cast<unsigned>(-1);
- atmostsTriggered = 0;
- atmostLimit = helper.getJoinLimit();
- limitLimit = helper.getMatchAbortLimit();
- hasGroupLimit = ((atmostLimit > 0) || (limitLimit > 0));
- if(atmostLimit==0) atmostLimit = static_cast<unsigned>(-1);
- if(limitLimit==0) limitLimit = static_cast<unsigned>(-1);
- getLimitType(helper.getJoinFlags(), limitFail, limitOnFail);
- switch (activityKind)
- {
- case TAKlookupjoin:
- case TAKlookupdenormalizegroup:
- case TAKsmartjoin:
- case TAKsmartdenormalizegroup:
- if (leftOuterJoin)
- createDefaultRight();
- break;
- }
- if (limitOnFail)
- createDefaultRight();
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- if (idx==1)
- input1 = _in;
- else
- {
- if ((helper.getJoinFlags() & JFparallel) != 0)
- {
- puller.setown(new CRoxieServerReadAheadInput(0)); // MORE - cant ask context for parallelJoinPreload as context is not yet set up.
- puller->setInput(0, _in);
- _in = puller;
- }
- CRoxieServerActivity::setInput(idx, _in);
- }
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if(!table)
- loadRight();
- switch (activityKind)
- {
- case TAKlookupjoin:
- case TAKsmartjoin:
- return nextInGroupJoin();
- case TAKlookupdenormalize:
- case TAKlookupdenormalizegroup:
- case TAKsmartdenormalize:
- case TAKsmartdenormalizegroup:
- return nextInGroupDenormalize();
- }
- throwUnexpected();
- }
- private:
- const void * nextInGroupJoin()
- {
- if(!table)
- loadRight();
- while(true)
- {
- const void * right = NULL;
- if(!left)
- {
- left = input->nextInGroup();
- keepCount = keepLimit;
- joinCounter = 0;
- if(!left)
- {
- if (isSmartJoin)
- left = input->nextInGroup();
- if (!left)
- {
- if(matchedGroup || eog)
- {
- matchedGroup = false;
- eog = true;
- return NULL;
- }
- eog = true;
- continue;
- }
- }
- eog = false;
- gotMatch = false;
- right = getRightFirst();
- }
- else
- right = getRightNext();
- const void * ret = NULL;
- if(failingLimit)
- {
- ret = joinException(left, failingLimit);
- }
- else
- {
- while(right)
- {
- if(helper.match(left, right))
- {
- gotMatch = true;
- if(exclude)
- break;
- ret = joinRecords(left, right, ++joinCounter);
- if(ret)
- break;
- }
- right = getRightNext();
- ret = NULL;
- }
- if(leftOuterJoin && !gotMatch)
- {
- ret = joinRecords(left, defaultRight, 0);
- gotMatch = true;
- }
- }
- if(ret)
- {
- matchedGroup = true;
- processed++;
- if(!many || (--keepCount == 0) || failingLimit)
- {
- ReleaseClearRoxieRow(left);
- failingLimit.clear();
- }
- return ret;
- }
- ReleaseClearRoxieRow(left);
- }
- }
- const void * nextInGroupDenormalize()
- {
- while(true)
- {
- left = input->nextInGroup();
- if(!left)
- {
- if (!matchedGroup || isSmartJoin)
- left = input->nextInGroup();
- if (!left)
- {
- matchedGroup = false;
- return NULL;
- }
- }
- gotMatch = false;
- const void * right = getRightFirst();
- const void * ret = NULL;
- if (failingLimit)
- ret = joinException(left, failingLimit);
- else if (activityKind == TAKlookupdenormalize || activityKind == TAKsmartdenormalize)
- {
- OwnedConstRoxieRow newLeft;
- newLeft.set(left);
- unsigned rowSize = 0;
- unsigned leftCount = 0;
- keepCount = keepLimit;
- while (right)
- {
- try
- {
- if (helper.match(left, right))
- {
- gotMatch = true;
- if (exclude)
- break;
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- unsigned thisSize = helper.transform(rowBuilder, newLeft, right, ++leftCount);
- if (thisSize)
- {
- rowSize = thisSize;
- newLeft.setown(rowBuilder.finalizeRowClear(rowSize));
- }
- if(!many || (--keepCount == 0))
- break;
- }
- right = getRightNext();
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- if (rowSize)
- ret = newLeft.getClear();
- else if (leftOuterJoin && !gotMatch)
- {
- ret = left;
- left = NULL;
- }
- }
- else
- {
- filteredRight.kill();
- keepCount = keepLimit;
- while (right)
- {
- if (helper.match(left, right))
- {
- gotMatch = true;
- if(exclude)
- break;
- filteredRight.append(right);
- if(!many || (--keepCount == 0))
- break;
- }
- right = getRightNext();
- }
- if((filteredRight.ordinality() > 0) || (leftOuterJoin && !gotMatch))
- ret = denormalizeRecords(left, filteredRight);
- filteredRight.kill();
- }
- ReleaseRoxieRow(left);
- left = NULL;
- failingLimit.clear();
- if(ret)
- {
- matchedGroup = true;
- processed++;
- return ret;
- }
- }
- }
- const void * joinRecords(const void * left, const void * right, unsigned counter)
- {
- if (cloneLeft)
- {
- LinkRoxieRow(left);
- return left;
- }
- try
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- unsigned outSize = helper.transform(rowBuilder, left, right, counter);
- if (outSize)
- return rowBuilder.finalizeRowClear(outSize);
- else
- return NULL;
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- const void * joinException(const void * left, IException * except)
- {
- try
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- unsigned outSize = helper.onFailTransform(rowBuilder, left, defaultRight, except);
- if (outSize)
- return rowBuilder.finalizeRowClear(outSize);
- else
- return NULL;
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- const void * denormalizeRecords(const void * left, ConstPointerArray & rows)
- {
- try
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- unsigned numRows = rows.ordinality();
- const void * right = numRows ? rows.item(0) : defaultRight.get();
- unsigned outSize = helper.transform(rowBuilder, left, right, numRows, (const void * *)rows.getArray());
- if (outSize)
- return rowBuilder.finalizeRowClear(outSize);
- else
- return NULL;
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- const void * getRightFirst() { if(hasGroupLimit) return fillRightGroup(); else return table->find(left); }
- const void * getRightNext() { if(hasGroupLimit) return readRightGroup(); else return table->findNext(left); }
- const void * readRightGroup() { if(rightGroup.isItem(rightGroupIndex)) return rightGroup.item(rightGroupIndex++); else return NULL; }
- const void *fillRightGroup()
- {
- rightGroup.kill();
- for(const void * right = table->find(left); right; right = table->findNext(left))
- {
- rightGroup.append(right);
- if(rightGroup.ordinality() > limitLimit)
- {
- if(limitFail)
- failLimit();
- gotMatch = true;
- if (ctx->queryDebugContext())
- ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
- if(limitOnFail)
- {
- assertex(!failingLimit);
- try
- {
- failLimit();
- }
- catch(IException * e)
- {
- failingLimit.setown(e);
- }
- assertex(failingLimit != NULL);
- }
- else
- {
- rightGroup.kill();
- }
- break;
- }
- if(rightGroup.ordinality() > atmostLimit)
- {
- atmostsTriggered++;
- rightGroup.kill();
- break;
- }
- }
- rightGroupIndex = 0;
- return readRightGroup();
- }
- void failLimit()
- {
- helper.onMatchAbortLimitExceeded();
- CommonXmlWriter xmlwrite(XWFtrim|XWFopt );
- if(!ctx->isBlind() && input->queryOutputMeta() && input->queryOutputMeta()->hasXML())
- {
- input->queryOutputMeta()->toXML(static_cast<const unsigned char *>(left), xmlwrite);
- }
- throw MakeStringException(ROXIE_TOO_MANY_RESULTS, "More than %u match candidates in join %d for row %s", limitLimit, queryId(), xmlwrite.str());
- }
-
- };
- unsigned const CRoxieServerLookupJoinActivity::FewLookupTable::BadIndex(static_cast<unsigned>(-1));
- class CRoxieServerLookupJoinActivityFactory : public CRoxieServerJoinActivityFactory
- {
- public:
- CRoxieServerLookupJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
- : CRoxieServerJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- Owned<IHThorHashJoinArg> helper = (IHThorHashJoinArg *) helperFactory();
- useFewTable = _graphNode.getPropBool("hint[@name='usefewtable']/@value", false);
- if((helper->getJoinFlags() & (JFfirst | JFfirstleft | JFfirstright | JFslidingmatch)) != 0)
- throw MakeStringException(ROXIE_INVALID_FLAGS, "Invalid flags for lookup join activity"); // code generator should never create such an activity
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerLookupJoinActivity(this, _probeManager, useFewTable);
- }
- protected:
- bool useFewTable;
- };
- IRoxieServerActivityFactory *createRoxieServerLookupJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
- {
- return new CRoxieServerLookupJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
- }
- //=====================================================================================================
- class CRoxieServerAllJoinActivity : public CRoxieServerTwoInputActivity
- {
- private:
- IHThorAllJoinArg &helper;
- bool leftOuterJoin;
- bool rightOuterJoin;
- bool exclude;
- OwnedConstRoxieRow defaultRight;
- OwnedConstRoxieRow defaultLeft;
- Owned<IEngineRowAllocator> defaultRightAllocator;
- Owned<IEngineRowAllocator> defaultLeftAllocator;
- const void *left;
- unsigned countForLeft;
- ConstPointerArray rightset;
- BoolArray matchedRight; // MORE - could use a bitset...
- unsigned keepLimit;
- bool started;
- bool eog;
- bool eos;
- bool matchedLeft;
- bool matchedGroup;
- bool leftIsGrouped;
- bool cloneLeft;
- unsigned rightIndex;
- unsigned joinCounter;
- unsigned rightOrdinality;
- ThorActivityKind activityKind;
- ConstPointerArray filteredRight;
- void createDefaultLeft()
- {
- if (!defaultLeft)
- {
- if (!defaultLeftAllocator)
- defaultLeftAllocator.setown(ctx->queryCodeContext()->getRowAllocator(input->queryOutputMeta(), activityId));
- RtlDynamicRowBuilder rowBuilder(defaultLeftAllocator);
- size32_t thisSize = helper.createDefaultLeft(rowBuilder);
- defaultLeft.setown(rowBuilder.finalizeRowClear(thisSize));
- }
- }
- void createDefaultRight()
- {
- if (!defaultRight)
- {
- if (!defaultRightAllocator)
- defaultRightAllocator.setown(ctx->queryCodeContext()->getRowAllocator(input1->queryOutputMeta(), activityId));
- RtlDynamicRowBuilder rowBuilder(defaultRightAllocator);
- size32_t thisSize = helper.createDefaultRight(rowBuilder);
- defaultRight.setown(rowBuilder.finalizeRowClear(thisSize));
- }
- }
- public:
- CRoxieServerAllJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerTwoInputActivity(_factory, _probeManager), helper((IHThorAllJoinArg &)basehelper)
- {
- unsigned joinFlags = helper.getJoinFlags();
- leftOuterJoin = (joinFlags & JFleftouter) != 0;
- rightOuterJoin = (joinFlags & JFrightouter) != 0;
- cloneLeft = (joinFlags & JFtransformmatchesleft) != 0;
- keepLimit = (unsigned) -1;
- exclude = (joinFlags & JFexclude) != 0;
- left = NULL;
- started = true;
- eog = false;
- eos = false;
- matchedLeft = false;
- matchedGroup = false;
- activityKind = factory->getKind();
- rightIndex = 0;
- rightOrdinality = 0;
- leftIsGrouped = false;
- countForLeft = 0;
- joinCounter = 0;
- }
- virtual void reset()
- {
- defaultRight.clear();
- defaultLeft.clear();
- ReleaseRoxieRowSet(rightset);
- matchedRight.kill();
- CRoxieServerTwoInputActivity::reset();
- }
- virtual bool needsAllocator() const { return true; }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- eog = false;
- eos = false;
- matchedLeft = false;
- matchedGroup = false;
- started = false;
- left = NULL;
- CRoxieServerTwoInputActivity::start(parentExtractSize, parentExtract, paused);
- keepLimit = helper.getKeepLimit();
- if(keepLimit==0)
- keepLimit = (unsigned) -1;
- countForLeft = keepLimit;
- joinCounter = 0;
- leftIsGrouped = input->queryOutputMeta()->isGrouped();
- if((activityKind==TAKalljoin || activityKind==TAKalldenormalizegroup) && leftOuterJoin)
- createDefaultRight();
- if(rightOuterJoin)
- createDefaultLeft();
- }
- void loadRight()
- {
- const void * next;
- while(true)
- {
- next = input1->nextInGroup();
- if(!next)
- next = input1->nextInGroup();
- if(!next)
- break;
- rightset.append(next);
- matchedRight.append(false);
- }
- rightIndex = 0;
- joinCounter = 0;
- rightOrdinality = rightset.ordinality();
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- if (idx==1)
- input1 = _in;
- else
- {
- if ((helper.getJoinFlags() & JFparallel) != 0)
- {
- puller.setown(new CRoxieServerReadAheadInput(0)); // MORE - cant ask context for parallelJoinPreload as context is not yet set up.
- puller->setInput(0, _in);
- _in = puller;
- }
- CRoxieServerActivity::setInput(idx, _in);
- }
- }
- const void * joinRecords(const void * left, const void * right, unsigned counter)
- {
- // MORE - could share some code with lookup join
- if (cloneLeft)
- {
- LinkRoxieRow(left);
- return left;
- }
- try
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- unsigned outSize = helper.transform(rowBuilder, left, right, counter);
- if (outSize)
- return rowBuilder.finalizeRowClear(outSize);
- else
- return NULL;
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- const void * denormalizeRecords(const void * curLeft, ConstPointerArray & rows)
- {
- try
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- unsigned numRows = rows.ordinality();
- const void * right = numRows ? rows.item(0) : defaultRight.get();
- unsigned outSize = helper.transform(rowBuilder, curLeft, right, numRows, rows.getArray());
- if (outSize)
- return rowBuilder.finalizeRowClear(outSize);
- else
- return NULL;
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if(!started)
- {
- started = true;
- left = input->nextInGroup();
- matchedLeft = false;
- countForLeft = keepLimit;
- joinCounter = 0;
- if(left == NULL)
- {
- eos = true;
- return NULL;
- }
- loadRight();
- }
- const void * ret;
- const void * right;
- if(eos)
- return NULL;
- while(true)
- {
- ret = NULL;
- if((rightIndex == rightOrdinality) || (countForLeft==0))
- {
- if(leftOuterJoin && left && !matchedLeft)
- {
- switch(activityKind)
- {
- case TAKalljoin:
- ret = joinRecords(left, defaultRight, 0);
- break;
- case TAKalldenormalize:
- ret = left;
- left = NULL;
- break;
- case TAKalldenormalizegroup:
- filteredRight.kill();
- ret = denormalizeRecords(left, filteredRight);
- break;
- default:
- throwUnexpected();
- }
- }
- rightIndex = 0;
- joinCounter = 0;
- ReleaseRoxieRow(left);
- left = NULL;
- if(ret)
- {
- matchedGroup = true;
- processed++;
- return ret;
- }
- }
- if(!left)
- {
- left = input->nextInGroup();
- matchedLeft = false;
- countForLeft = keepLimit;
- joinCounter = 0;
- }
- if(!left)
- {
- if(eog)
- {
- eos = true;
- matchedGroup = false;
- return NULL;
- }
- eog = true;
- if (matchedGroup && leftIsGrouped)
- {
- matchedGroup = false;
- return NULL;
- }
- matchedGroup = false;
- continue;
- }
- eog = false;
- switch(activityKind)
- {
- case TAKalljoin:
- while(rightIndex < rightOrdinality)
- {
- right = rightset.item(rightIndex);
- if(helper.match(left, right))
- {
- matchedLeft = true;
- matchedRight.replace(true, rightIndex);
- if(!exclude)
- ret = joinRecords(left, right, ++joinCounter);
- }
- rightIndex++;
- if(ret)
- {
- countForLeft--;
- matchedGroup = true;
- processed++;
- return ret;
- }
- }
- break;
- case TAKalldenormalize:
- {
- OwnedConstRoxieRow newLeft;
- newLeft.set(left);
- unsigned rowSize = 0;
- unsigned leftCount = 0;
- while((rightIndex < rightOrdinality) && countForLeft)
- {
- right = rightset.item(rightIndex);
- if(helper.match(left, right))
- {
- matchedLeft = true;
- matchedRight.replace(true, rightIndex);
- if(!exclude)
- {
- try
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- unsigned thisSize = helper.transform(rowBuilder, newLeft, right, ++leftCount);
- if(thisSize)
- {
- rowSize = thisSize;
- newLeft.setown(rowBuilder.finalizeRowClear(rowSize));
- --countForLeft;
- }
- }
- catch (IException *e)
- {
- throw makeWrappedException(e);
- }
- }
- }
- rightIndex++;
- }
- if(rowSize)
- {
- processed++;
- return newLeft.getClear();
- }
- }
- break;
- case TAKalldenormalizegroup:
- filteredRight.kill();
- while((rightIndex < rightOrdinality) && countForLeft)
- {
- right = rightset.item(rightIndex);
- if(helper.match(left, right))
- {
- matchedLeft = true;
- matchedRight.replace(true, rightIndex);
- filteredRight.append(right);
- --countForLeft;
- }
- ++rightIndex;
- }
- if(!exclude && filteredRight.ordinality())
- {
- ret = denormalizeRecords(left, filteredRight);
- filteredRight.kill();
- if(ret)
- {
- processed++;
- return ret;
- }
- }
- break;
- default:
- throwUnexpected();
- }
- }
- }
- };
- class CRoxieServerAllJoinActivityFactory : public CRoxieServerJoinActivityFactory
- {
- public:
- CRoxieServerAllJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- Owned<IHThorAllJoinArg> helper = (IHThorAllJoinArg *) helperFactory();
- if((helper->getJoinFlags() & (JFfirst | JFfirstleft | JFfirstright)) != 0)
- throw MakeStringException(ROXIE_INVALID_FLAGS, "Invalid flags for join all activity"); // code generator should never create such an activity
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerAllJoinActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerAllJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerAllJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=====================================================================================================
- class CRoxieServerTopNActivity : public CRoxieServerLateStartActivity
- {
- unsigned limit;
- bool hasBest;
- bool eoi;
- const void **sorted;
- unsigned sortedCount;
- unsigned curIndex;
- IHThorTopNArg &helper;
- ICompare &compare;
- public:
- CRoxieServerTopNActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerLateStartActivity(_factory, _probeManager), helper((IHThorTopNArg &)basehelper), compare(*helper.queryCompare())
- {
- sorted = NULL;
- sortedCount = 0;
- curIndex = 0;
- limit = 0;
- eoi = false;
- hasBest = false;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- assertex(sorted == NULL);
- sortedCount = 0;
- curIndex = 0;
- eoi = false;
-
- CRoxieServerLateStartActivity::start(parentExtractSize, parentExtract, paused);
- limit = (unsigned) helper.getLimit();
- hasBest = helper.hasBest();
- lateStart(parentExtractSize, parentExtract, limit > 0);
- // MORE - should we use an expanding array instead?
- if (limit > 0)
- sorted = (const void **) ctx->queryRowManager().allocate((limit+1) * sizeof(const void *), activityId);
- }
- virtual void reset()
- {
- if (sorted)
- {
- while(curIndex < sortedCount)
- ReleaseRoxieRow(sorted[curIndex++]);
- ReleaseRoxieRow(sorted);
- }
- sorted = NULL;
- CRoxieServerLateStartActivity::reset();
- }
- bool abortEarly()
- {
- if (hasBest && (sortedCount == limit))
- {
- int compare = helper.compareBest(sorted[sortedCount-1]);
- if (compare == 0)
- {
- if (meta.isGrouped())
- {
- //MORE: This would be more efficient if we had a away of skipping to the end of the incoming group.
- const void * next;
- while ((next = input->nextInGroup()) != NULL)
- ReleaseRoxieRow(next);
- }
- else
- eoi = true;
- return true;
- }
- //This only checks the lowest element - we could check all elements inserted, but it would increase the number of compares
- if (compare < 0)
- throw MakeStringException(ROXIE_TOPN_ROW_ERROR, "TOPN: row found that exceeds the best value");
- }
- return false;
- }
- void getSorted()
- {
- curIndex = 0;
- sortedCount = 0;
- if(eoi)
- return;
- const void * next;
- while ((next = input->nextInGroup()) != NULL)
- {
- if (sortedCount < limit)
- {
- binary_vec_insert_stable(next, sorted, sortedCount, compare);
- sortedCount++;
- if(abortEarly())
- return;
- }
- else
- {
- if(limit && compare.docompare(sorted[sortedCount-1], next) > 0) // MORE - if stability is an issue, need to consider whether this should be > or >=
- {
- binary_vec_insert_stable(next, sorted, sortedCount, compare); // MORE - not sure this is stable!
- ReleaseRoxieRow(sorted[sortedCount]);
- if(abortEarly())
- return;
- }
- else
- {
- ReleaseRoxieRow(next); // do not bother with insertion sort if we know next will fall off the end
- }
- }
- }
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (eof)
- return NULL;
- if (curIndex >= sortedCount)
- {
- bool eog = sortedCount != 0;
- getSorted();
- if(sortedCount == 0)
- {
- eof = true;
- return NULL;
- }
- if (eog)
- return NULL;
- }
- processed++;
- return sorted[curIndex++];
- }
- };
- class CRoxieServerTopNActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerTopNActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerTopNActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerTopNActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerTopNActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerLimitActivity : public CRoxieServerActivity
- {
- protected:
- unsigned __int64 rowLimit;
- IHThorLimitArg &helper;
- public:
- CRoxieServerLimitActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorLimitArg &)basehelper)
- {
- rowLimit = 0;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- rowLimit = helper.getRowLimit(); // could conceivably depend on context so should not compute any earlier than this
- }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- const void * ret = input->nextInGroup();
- if (ret)
- {
- processed++;
- if (processed > rowLimit)
- {
- ReleaseRoxieRow(ret);
- if (traceLevel > 4)
- DBGLOG("activityid = %d line = %d", activityId, __LINE__);
- helper.onLimitExceeded();
- }
- }
- return ret;
- }
- virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- const void * ret = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
- if (ret)
- {
- if (wasCompleteMatch)
- processed++;
- if (processed > rowLimit)
- {
- ReleaseRoxieRow(ret);
- if (traceLevel > 4)
- DBGLOG("activityid = %d line = %d", activityId, __LINE__);
- helper.onLimitExceeded();
- }
- }
- return ret;
- }
- virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
- {
- return input->gatherConjunctions(collector);
- }
- virtual void resetEOF()
- {
- //Do not reset the rowLimit
- input->resetEOF();
- }
- IInputSteppingMeta * querySteppingMeta()
- {
- return input->querySteppingMeta();
- }
- };
- class CRoxieServerLimitActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerLimitActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerLimitActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerLimitActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerLimitActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=====================================================================================================
- class CRoxieServerSkipLimitActivity : public CRoxieServerLimitActivity
- {
- ConstPointerArray buff;
- bool started;
- unsigned index;
- IHThorLimitTransformExtra * transformExtra;
- public:
- CRoxieServerSkipLimitActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _onFail)
- : CRoxieServerLimitActivity(_factory, _probeManager)
- {
- transformExtra = NULL;
- started = false;
- index = 0;
- if (_onFail)
- transformExtra = static_cast<IHThorLimitTransformExtra *>(helper.selectInterface(TAIlimittransformextra_1));
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- started = false;
- index = 0;
- CRoxieServerLimitActivity::start(parentExtractSize, parentExtract, paused);
- }
- virtual void reset()
- {
- while (buff.isItem(index))
- ReleaseRoxieRow(buff.item(index++));
- buff.kill();
- started = false;
- CRoxieServerLimitActivity::reset();
- }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (!started)
- pullInput();
- if (buff.isItem(index))
- {
- const void * next = buff.item(index++);
- if(next)
- processed++;
- return next;
- }
- return NULL;
- }
- protected:
- void pullInput()
- {
- unsigned count = 0;
- loop
- {
- const void * next = input->nextInGroup();
- if (next == NULL)
- {
- next = input->nextInGroup();
- if(next == NULL)
- break;
- buff.append(NULL);
- }
- count++;
- if (count > rowLimit)
- {
- ReleaseRoxieRow(next);
- ReleaseRoxieRowSet(buff);
- if (ctx->queryDebugContext())
- ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
- if (transformExtra)
- {
- createRowAllocator();
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- size32_t outSize = transformExtra->transformOnLimitExceeded(rowBuilder);
- if (outSize)
- buff.append(rowBuilder.finalizeRowClear(outSize));
- }
- break;
- }
- buff.append(next);
- }
- started = true;
- }
- };
- class CRoxieServerSkipLimitActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerSkipLimitActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerSkipLimitActivity(this, _probeManager, kind==TAKcreaterowlimit);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerSkipLimitActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerSkipLimitActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerCatchActivity : public CRoxieServerActivity
- {
- IHThorCatchArg &helper;
- public:
- CRoxieServerCatchActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorCatchArg &)basehelper)
- {
- }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- try
- {
- const void *ret = input->nextInGroup();
- if (ret)
- processed++;
- return ret;
- }
- catch (IException *E)
- {
- E->Release();
- helper.onExceptionCaught();
- }
- catch (...)
- {
- helper.onExceptionCaught();
- }
- throwUnexpected(); // onExceptionCaught should have thrown something
- }
- virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
- {
- try
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- const void * ret = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
- if (ret && wasCompleteMatch)
- processed++;
- return ret;
- }
- catch (IException *E)
- {
- E->Release();
- helper.onExceptionCaught();
- }
- catch (...)
- {
- helper.onExceptionCaught();
- }
- throwUnexpected(); // onExceptionCaught should have thrown something
- }
- virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
- {
- return input->gatherConjunctions(collector);
- }
- virtual void resetEOF()
- {
- input->resetEOF(); // MORE - why not in base class?
- }
- IInputSteppingMeta * querySteppingMeta()
- {
- return input->querySteppingMeta();
- }
- };
- class CRoxieServerSkipCatchActivity : public CRoxieServerActivity
- {
- ConstPointerArray buff;
- bool started;
- unsigned index;
- IHThorCatchArg &helper;
- bool createRow;
- public:
- CRoxieServerSkipCatchActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _createRow)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorCatchArg &)basehelper), createRow(_createRow)
- {
- started = false;
- index = 0;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- started = false;
- index = 0;
- try
- {
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- }
- catch (IException *E)
- {
- onException(E);
- started = true;
- }
- catch (...)
- {
- onException(MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught"));
- started = true;
- }
- }
- virtual void reset()
- {
- while (buff.isItem(index))
- ReleaseRoxieRow(buff.item(index++));
- buff.kill();
- started = false;
- CRoxieServerActivity::reset();
- }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (!started)
- pullInput();
- if (buff.isItem(index))
- {
- const void * next = buff.item(index++);
- if(next)
- processed++;
- return next;
- }
- return NULL;
- }
- protected:
- void onException(IException *E)
- {
- input->stop(true);
- ReleaseRoxieRowSet(buff);
- if (createRow)
- {
- createRowAllocator();
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- size32_t outSize = helper.transformOnExceptionCaught(rowBuilder, E);
- if (outSize)
- buff.append(rowBuilder.finalizeRowClear(outSize));
- }
- E->Release();
- }
- void pullInput()
- {
- try
- {
- bool EOGseen = false;
- loop
- {
- const void * next = input->nextInGroup();
- buff.append(next);
- if (next == NULL)
- {
- if (EOGseen)
- break;
- EOGseen = true;
- }
- else
- EOGseen = false;
- }
- }
- catch (IException *E)
- {
- onException(E);
- }
- catch (...)
- {
- onException(MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught"));
- }
- started = true;
- }
- };
- class CRoxieServerCatchActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerCatchActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- switch (kind)
- {
- case TAKcatch:
- return new CRoxieServerCatchActivity(this, _probeManager);
- case TAKskipcatch:
- return new CRoxieServerSkipCatchActivity(this, _probeManager, false);
- case TAKcreaterowcatch:
- return new CRoxieServerSkipCatchActivity(this, _probeManager, true);
- default:
- throwUnexpected();
- }
- }
- };
- IRoxieServerActivityFactory *createRoxieServerCatchActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerCatchActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerCaseActivity : public CRoxieServerActivity
- {
- IHThorCaseArg &helper;
- IRoxieInput **inputs;
- unsigned cond;
- bool unusedStopped;
- IRoxieInput *in;
- unsigned numInputs;
- public:
- CRoxieServerCaseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorCaseArg &)basehelper), numInputs(_numInputs)
- {
- unusedStopped = false;
- cond = 0;
- inputs = new IRoxieInput*[numInputs];
- for (unsigned i = 0; i < numInputs; i++)
- inputs[i] = NULL;
- in = NULL;
- }
- ~CRoxieServerCaseActivity()
- {
- delete [] inputs;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- cond = helper.getBranch();
- //CHOOSE defaults to the last argument if out of range.
- if (cond >= numInputs)
- cond = numInputs - 1;
- inputs[cond]->start(parentExtractSize, parentExtract, paused);
- for (unsigned idx = 0; idx < numInputs; idx++)
- {
- if (idx!=cond)
- inputs[idx]->stop(false); // Note: stopping unused branches early helps us avoid buffering splits too long.
- }
- in = inputs[cond];
- unusedStopped = true;
- }
- virtual void stop(bool aborting)
- {
- for (unsigned idx = 0; idx < numInputs; idx++)
- {
- if (idx==cond || !unusedStopped)
- inputs[idx]->stop(aborting);
- }
- CRoxieServerActivity::stop(aborting);
- }
- virtual void reset()
- {
- for (unsigned idx = 0; idx < numInputs; idx++)
- {
- inputs[idx]->reset();
- }
- unusedStopped = false;
- in = NULL;
- CRoxieServerActivity::reset();
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- assertex(idx < numInputs);
- inputs[idx] = _in;
- }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (in)
- {
- const void *ret = in->nextInGroup();
- if (ret)
- processed++;
- return ret;
- }
- return NULL;
- }
- };
- class CRoxieServerCaseActivityFactory : public CRoxieServerMultiInputFactory
- {
- bool graphInvariant;
- public:
- CRoxieServerCaseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _graphInvariant)
- : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- graphInvariant = _graphInvariant;
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerCaseActivity(this, _probeManager, numInputs());
- }
- virtual bool isGraphInvariant() const
- {
- return graphInvariant;
- }
- };
- IRoxieServerActivityFactory *createRoxieServerCaseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _graphInvariant)
- {
- return new CRoxieServerCaseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphInvariant);
- }
- //=================================================================================
- class CRoxieServerIfActivity : public CRoxieServerActivity
- {
- IHThorIfArg &helper;
- IRoxieInput *inputTrue;
- IRoxieInput *inputFalse;
- bool cond;
- bool unusedStopped;
- public:
- CRoxieServerIfActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorIfArg &)basehelper)
- {
- inputFalse = NULL;
- inputTrue = NULL;
- unusedStopped = false;
- cond = false;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- cond = helper.getCondition();
- if (cond)
- {
- inputTrue->start(parentExtractSize, parentExtract, paused);
- if (inputFalse)
- inputFalse->stop(false); // Note: stopping unused branches early helps us avoid buffering splits too long.
- }
- else
- {
- if (inputFalse)
- inputFalse->start(parentExtractSize, parentExtract, paused);
- inputTrue->stop(false);
- }
- unusedStopped = true;
- }
- virtual void stop(bool aborting)
- {
- if (!unusedStopped || cond)
- inputTrue->stop(aborting);
- if (inputFalse && (!unusedStopped || !cond))
- inputFalse->stop(aborting);
- CRoxieServerActivity::stop(aborting);
- }
- virtual unsigned __int64 queryLocalCycles() const
- {
- __int64 localCycles = totalCycles;
- localCycles -= inputTrue->queryTotalCycles();
- if (inputFalse)
- localCycles -= inputFalse->queryTotalCycles();
- if (localCycles < 0)
- localCycles = 0;
- return localCycles;
- }
- virtual IRoxieInput *queryInput(unsigned idx) const
- {
- switch (idx)
- {
- case 0:
- return inputTrue;
- case 1:
- return inputFalse;
- default:
- return NULL;
- }
- }
- virtual IIndexReadActivityInfo *queryIndexReadActivity()
- {
- IRoxieInput *in = cond ? inputTrue : inputFalse;
- if (in)
- return in->queryIndexReadActivity();
- return NULL;
- }
- virtual void reset()
- {
- CRoxieServerActivity::reset();
- inputTrue->reset();
- if (inputFalse)
- inputFalse->reset();
- unusedStopped = false;
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- if (idx==1)
- inputFalse = _in;
- else
- {
- assertex(!idx);
- inputTrue = _in;
- }
- }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- IRoxieInput *in = cond ? inputTrue : inputFalse;
- if (in)
- {
- const void * ret;
- if ((ret = in->nextInGroup()) != NULL)
- processed++;
- return ret;
- }
- return NULL;
- }
- };
- class CRoxieServerIfActivityFactory : public CRoxieServerActivityFactory
- {
- unsigned input2;
- unsigned input2idx;
- bool graphInvariant;
- public:
- CRoxieServerIfActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _graphInvariant)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- graphInvariant = _graphInvariant;
- input2 = (unsigned)-1;
- input2idx = (unsigned)-1;
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerIfActivity(this, _probeManager);
- }
- virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
- {
- if (idx==1)
- {
- input2 = source;
- input2idx = sourceidx;
- }
- else
- CRoxieServerActivityFactory::setInput(idx, source, sourceidx);
- }
- virtual unsigned getInput(unsigned idx, unsigned &sourceidx) const
- {
- switch (idx)
- {
- case 1:
- sourceidx = input2idx;
- return input2;
- case 0:
- return CRoxieServerActivityFactory::getInput(idx, sourceidx);
- default:
- return (unsigned) -1;
- }
- }
- virtual unsigned numInputs() const { return (input2 == (unsigned)-1) ? 1 : 2; }
- virtual bool isGraphInvariant() const
- {
- return graphInvariant;
- }
- };
- IRoxieServerActivityFactory *createRoxieServerIfActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _graphInvariant)
- {
- return new CRoxieServerIfActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphInvariant);
- }
- //=================================================================================
- class CRoxieServerActionBaseActivity : public CRoxieServerActivity
- {
- CriticalSection ecrit;
- Owned<IException> exception;
- bool executed;
- public:
- CRoxieServerActionBaseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager)
- {
- executed = false;
- }
- virtual void doExecuteAction(unsigned parentExtractSize, const byte * parentExtract) = 0;
- virtual void execute(unsigned parentExtractSize, const byte * parentExtract)
- {
- CriticalBlock b(ecrit);
- if (exception)
- throw(exception.getLink());
- if (!executed)
- {
- try
- {
- executed = true;
- start(parentExtractSize, parentExtract, false);
- doExecuteAction(parentExtractSize, parentExtract);
- stop(false);
- }
- catch (IException * E)
- {
- ctx->notifyAbort(E);
- stop(true);
- exception.set(E);
- throw;
- }
- }
- }
- virtual void reset()
- {
- executed = false;
- exception.clear();
- CRoxieServerActivity::reset();
- }
- virtual unsigned __int64 queryLocalCycles() const
- {
- return totalCycles;
- }
- virtual const void *nextInGroup()
- {
- throwUnexpected(); // I am nobody's input
- }
- virtual IRoxieInput *queryInput(unsigned idx) const
- {
- throwUnexpected(); // I am nobody's input
- }
- };
- class CRoxieServerIfActionActivity : public CRoxieServerActionBaseActivity
- {
- IHThorIfArg &helper;
- public:
- CRoxieServerIfActionActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActionBaseActivity(_factory, _probeManager), helper((IHThorIfArg &)basehelper)
- {
- }
- virtual void doExecuteAction(unsigned parentExtractSize, const byte * parentExtract)
- {
- bool cond;
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- cond = helper.getCondition();
- }
- stopDependencies(parentExtractSize, parentExtract, cond ? 2 : 1);
- executeDependencies(parentExtractSize, parentExtract, cond ? 1 : 2);
- }
- };
- class CRoxieServerIfActionActivityFactory : public CRoxieServerActivityFactory
- {
- bool isRoot;
- public:
- CRoxieServerIfActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerIfActionActivity(this, _probeManager);
- }
- virtual bool isSink() const
- {
- return isRoot;
- }
- };
- IRoxieServerActivityFactory *createRoxieServerIfActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
- {
- return new CRoxieServerIfActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
- }
- //=================================================================================
- class CRoxieServerParallelActionActivity : public CRoxieServerActionBaseActivity
- {
- public:
- CRoxieServerParallelActionActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActionBaseActivity(_factory, _probeManager)
- {
- }
- virtual void doExecuteAction(unsigned parentExtractSize, const byte * parentExtract)
- {
- #ifdef PARALLEL_EXECUTE
- CParallelActivityExecutor afor(dependencies, parentExtractSize, parentExtract);
- afor.For(dependencies.ordinality(), dependencies.ordinality(), true);
- #else
- ForEachItemIn(idx, dependencies)
- {
- dependencies.item(idx).execute(parentExtractSize, parentExtract);
- }
- #endif
- }
- };
- class CRoxieServerParallelActionActivityFactory : public CRoxieServerActivityFactory
- {
- bool isRoot;
- public:
- CRoxieServerParallelActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
- {
- assertex(!isRoot); // non-internal should be expanded out..
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerParallelActionActivity(this, _probeManager);
- }
- virtual bool isSink() const
- {
- return isRoot;
- }
- };
- IRoxieServerActivityFactory *createRoxieServerParallelActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
- {
- return new CRoxieServerParallelActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
- }
- //=================================================================================
- class CRoxieServerSequentialActionActivity : public CRoxieServerActionBaseActivity
- {
- IHThorSequentialArg &helper;
- public:
- CRoxieServerSequentialActionActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActionBaseActivity(_factory, _probeManager), helper((IHThorSequentialArg &)basehelper)
- {
- }
- virtual void doExecuteAction(unsigned parentExtractSize, const byte * parentExtract)
- {
- unsigned numBranches = helper.numBranches();
- for (unsigned branch=1; branch <= numBranches; branch++)
- executeDependencies(parentExtractSize, parentExtract, branch);
- }
- };
- class CRoxieServerSequentialActionActivityFactory : public CRoxieServerActivityFactory
- {
- bool isRoot;
- public:
- CRoxieServerSequentialActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerSequentialActionActivity(this, _probeManager);
- }
- virtual bool isSink() const
- {
- return isRoot;
- }
- };
- IRoxieServerActivityFactory *createRoxieServerSequentialActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
- {
- return new CRoxieServerSequentialActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
- }
- //=================================================================================
- class CRoxieServerWhenActivity : public CRoxieServerActivity
- {
- public:
- CRoxieServerWhenActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager)
- {
- savedExtractSize = 0;
- savedExtract = NULL;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- savedExtractSize = parentExtractSize;
- savedExtract = parentExtract;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- executeDependencies(parentExtractSize, parentExtract, WhenBeforeId);
- executeDependencies(parentExtractSize, parentExtract, WhenParallelId); // MORE: This should probably be done in parallel!
- }
- virtual void stop(bool aborting)
- {
- if (state != STATEstopped)
- {
- stopDependencies(savedExtractSize, savedExtract, aborting ? WhenSuccessId : WhenFailureId); // These ones don't get executed
- executeDependencies(savedExtractSize, savedExtract, aborting ? WhenFailureId : WhenSuccessId); // These ones do
- }
- CRoxieServerActivity::stop(aborting);
- }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext()); // bit of a waste of time....
- return input->nextInGroup();
- }
- protected:
- unsigned savedExtractSize;
- const byte *savedExtract;
- };
- class CRoxieServerWhenActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerWhenActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerWhenActivity(this, _probeManager);
- }
- };
- extern IRoxieServerActivityFactory *createRoxieServerWhenActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerWhenActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=================================================================================
- class CRoxieServerWhenActionActivity : public CRoxieServerActionBaseActivity
- {
- public:
- CRoxieServerWhenActionActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActionBaseActivity(_factory, _probeManager)
- {
- savedExtractSize = 0;
- savedExtract = NULL;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- savedExtractSize = parentExtractSize;
- savedExtract = parentExtract;
- CRoxieServerActionBaseActivity::start(parentExtractSize, parentExtract, paused);
- executeDependencies(parentExtractSize, parentExtract, WhenBeforeId);
- executeDependencies(parentExtractSize, parentExtract, WhenParallelId); // MORE: This should probably be done in parallel!
- }
- virtual void stop(bool aborting)
- {
- if (state != STATEstopped)
- {
- stopDependencies(savedExtractSize, savedExtract, aborting ? WhenSuccessId : WhenFailureId); // these are NOT going to execute
- executeDependencies(savedExtractSize, savedExtract, aborting ? WhenFailureId : WhenSuccessId);
- }
- CRoxieServerActionBaseActivity::stop(aborting);
- }
- virtual void doExecuteAction(unsigned parentExtractSize, const byte * parentExtract)
- {
- executeDependencies(parentExtractSize, parentExtract, 1);
- }
- protected:
- unsigned savedExtractSize;
- const byte *savedExtract;
- };
- class CRoxieServerWhenActionActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerWhenActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerWhenActionActivity(this, _probeManager);
- }
- virtual bool isSink() const
- {
- return isRoot;
- }
- private:
- bool isRoot;
- };
- extern IRoxieServerActivityFactory *createRoxieServerWhenActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
- {
- return new CRoxieServerWhenActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
- }
- //=================================================================================
- class CRoxieServerParseActivity : public CRoxieServerActivity, implements IMatchedAction
- {
- IHThorParseArg &helper;
- INlpParser * parser;
- INlpResultIterator * rowIter;
- const void * in;
- char * curSearchText;
- INlpParseAlgorithm * algorithm;
- size32_t curSearchTextLen;
- bool anyThisGroup;
- bool processRecord(const void * inRec)
- {
- if (helper.searchTextNeedsFree())
- rtlFree(curSearchText);
- curSearchTextLen = 0;
- curSearchText = NULL;
- helper.getSearchText(curSearchTextLen, curSearchText, inRec);
- return parser->performMatch(*this, in, curSearchTextLen, curSearchText);
- }
- public:
- CRoxieServerParseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, INlpParseAlgorithm * _algorithm)
- : CRoxieServerActivity(_factory, _probeManager),
- helper((IHThorParseArg &)basehelper), algorithm(_algorithm)
- {
- parser = NULL;
- rowIter = NULL;
- in = NULL;
- curSearchText = NULL;
- anyThisGroup = false;
- curSearchTextLen = 0;
- }
- ~CRoxieServerParseActivity()
- {
- ::Release(parser);
- }
- virtual bool needsAllocator() const { return true; }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerActivity::onCreate(_ctx, _colocalParent);
- parser = algorithm->createParser(_ctx->queryCodeContext(), activityId, helper.queryHelper(), &helper);
- rowIter = parser->queryResultIter();
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- anyThisGroup = false;
- curSearchTextLen = 0;
- curSearchText = NULL;
- in = NULL;
- parser->reset();
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- }
- virtual void reset()
- {
- if (helper.searchTextNeedsFree())
- rtlFree(curSearchText);
- curSearchText = NULL;
- ReleaseClearRoxieRow(in);
- CRoxieServerActivity::reset();
- }
- virtual unsigned onMatch(ARowBuilder & self, const void * curRecord, IMatchedResults * results, IMatchWalker * walker)
- {
- try
- {
- return helper.transform(self, curRecord, results, walker);
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- virtual const void * nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- loop
- {
- if (rowIter->isValid())
- {
- anyThisGroup = true;
- OwnedConstRoxieRow out = rowIter->getRow();
- rowIter->next();
- processed++;
- return out.getClear();
- }
- ReleaseClearRoxieRow(in);
- in = input->nextInGroup();
- if (!in)
- {
- if (anyThisGroup)
- {
- anyThisGroup = false;
- return NULL;
- }
- in = input->nextInGroup();
- if (!in)
- return NULL;
- }
- processRecord(in);
- rowIter->first();
- }
- }
- };
- class CRoxieServerParseActivityFactory : public CRoxieServerActivityFactory
- {
- Owned<INlpParseAlgorithm> algorithm;
- Owned<IHThorParseArg> helper;
- public:
- CRoxieServerParseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IResourceContext *rc)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- helper.setown((IHThorParseArg *) helperFactory());
- algorithm.setown(createThorParser(rc, *helper));
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerParseActivity(this, _probeManager, algorithm);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerParseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IResourceContext *rc)
- {
- return new CRoxieServerParseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, rc);
- }
- //=====================================================================================================
- class CRoxieServerWorkUnitWriteActivity : public CRoxieServerInternalSinkActivity
- {
- IHThorWorkUnitWriteArg &helper;
- bool isReread;
- bool grouped;
- IRoxieServerContext *serverContext;
- public:
- CRoxieServerWorkUnitWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _isReread, unsigned _numOutputs)
- : CRoxieServerInternalSinkActivity(_factory, _probeManager, _numOutputs), helper((IHThorWorkUnitWriteArg &)basehelper), isReread(_isReread)
- {
- grouped = (helper.getFlags() & POFgrouped) != 0;
- serverContext = NULL;
- }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerInternalSinkActivity::onCreate(_ctx, _colocalParent);
- serverContext = ctx->queryServerContext();
- if (!serverContext)
- {
- throw MakeStringException(ROXIE_PIPE_ERROR, "Pipe output activity cannot be executed in slave context");
- }
- }
- virtual bool needsAllocator() const { return true; }
- virtual void onExecute()
- {
- int sequence = helper.getSequence();
- const char *storedName = helper.queryName();
- if (!storedName)
- storedName = "Dataset";
- MemoryBuffer result;
- FlushingStringBuffer *response = NULL;
- bool saveInContext = (int) sequence < 0 || isReread;
- if (!meta.queryOriginal()) // this is a bit of a hack - don't know why no meta on an output....
- meta.set(input->queryOutputMeta());
- Owned<IOutputRowSerializer> rowSerializer;
- Owned<IXmlWriter> writer;
- if ((int) sequence >= 0)
- {
- response = serverContext->queryResult(sequence);
- if (response)
- {
- const IProperties *xmlns = serverContext->queryXmlns(sequence);
- response->startDataset("Dataset", helper.queryName(), sequence, (helper.getFlags() & POFextend) != 0, xmlns);
- if (response->mlFmt==MarkupFmt_XML || response->mlFmt==MarkupFmt_JSON)
- {
- unsigned int writeFlags = serverContext->getXmlFlags();
- if (response->mlFmt==MarkupFmt_JSON)
- writeFlags |= XWFnoindent;
- writer.setown(createIXmlWriter(writeFlags, 1, response, (response->mlFmt==MarkupFmt_JSON) ? WTJSON : WTStandard));
- writer->outputBeginArray("Row");
- }
- }
- }
- size32_t outputLimitBytes = 0;
- IConstWorkUnit *workunit = serverContext->queryWorkUnit();
- if (workunit)
- {
- size32_t outputLimit;
- if (helper.getFlags() & POFmaxsize)
- outputLimit = helper.getMaxSize();
- else
- outputLimit = workunit->getDebugValueInt("outputLimit", DALI_RESULT_LIMIT_DEFAULT);
- if (outputLimit>DALI_RESULT_OUTPUTMAX)
- 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);
- assertex(outputLimit<=0x1000); // 32bit limit because MemoryBuffer/CMessageBuffers involved etc.
- outputLimitBytes = outputLimit * 0x100000;
- }
- if (workunit != NULL || (response && response->isRaw))
- {
- createRowAllocator();
- rowSerializer.setown(rowAllocator->createDiskSerializer(ctx->queryCodeContext()));
- }
- __int64 initialProcessed = processed;
- RtlLinkedDatasetBuilder builder(rowAllocator);
- loop
- {
- const void *row = input->nextInGroup();
- if (saveInContext)
- {
- if (row || grouped)
- builder.append(row);
- }
- if (grouped && (processed != initialProcessed))
- {
- if (workunit)
- result.append(row == NULL);
- if (response)
- {
- if (response->isRaw)
- response->append(row == NULL);
- else
- {
- response->append("<Row __GroupBreak__=\"1\"/>"); // sensible, but need to handle on input
- }
- }
- }
- if (!row)
- {
- row = input->nextInGroup();
- if (!row)
- break;
- if (saveInContext)
- builder.append(row);
- }
- processed++;
- if (workunit)
- {
- CThorDemoRowSerializer serializerTarget(result);
- rowSerializer->serialize(serializerTarget, (const byte *) row);
- }
- if (response)
- {
- if (response->isRaw)
- {
- // MORE - should be able to serialize straight to the response...
- MemoryBuffer rowbuff;
- CThorDemoRowSerializer serializerTarget(rowbuff);
- rowSerializer->serialize(serializerTarget, (const byte *) row);
- response->append(rowbuff.length(), rowbuff.toByteArray());
- }
- else if (writer)
- {
- writer->outputBeginNested("Row", false);
- helper.serializeXml((byte *) row, *writer);
- writer->outputEndNested("Row");
- }
- else
- {
- SimpleOutputWriter x;
- helper.serializeXml((byte *) row, x);
- x.newline();
- response->append(x.str());
- }
- response->incrementRowCount();
- response->flush(false);
- }
- ReleaseRoxieRow(row);
- if (outputLimitBytes && result.length() > outputLimitBytes)
- {
- StringBuffer errMsg("Dataset too large to output to workunit (limit ");
- errMsg.append(outputLimitBytes/0x100000).append(" megabytes), in result (");
- const char *name = helper.queryName();
- if (name)
- errMsg.append("name=").append(name);
- else
- errMsg.append("sequence=").append(helper.getSequence());
- errMsg.append(")");
- throw MakeStringExceptionDirect(0, errMsg.str());
- }
- }
- if (writer)
- writer->outputEndArray("Row");
- if (saveInContext)
- serverContext->appendResultDeserialized(storedName, sequence, builder.getcount(), builder.linkrows(), (helper.getFlags() & POFextend) != 0, LINK(meta.queryOriginal()));
- if (workunit)
- serverContext->appendResultRawContext(storedName, sequence, result.length(), result.toByteArray(), processed, (helper.getFlags() & POFextend) != 0, false); // MORE - shame to do extra copy...
- }
- };
- class CRoxieServerWorkUnitWriteActivityFactory : public CRoxieServerInternalSinkFactory
- {
- bool isReread;
- public:
- CRoxieServerWorkUnitWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
- : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot)
- {
- isReread = usageCount > 0;
- Owned<IHThorWorkUnitWriteArg> helper = (IHThorWorkUnitWriteArg *) helperFactory();
- isInternal = (helper->getSequence()==ResultSequenceInternal);
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerWorkUnitWriteActivity(this, _probeManager, isReread, usageCount);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerWorkUnitWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
- {
- return new CRoxieServerWorkUnitWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot);
- }
- //=====================================================================================================
- class CRoxieServerWorkUnitWriteDictActivity : public CRoxieServerInternalSinkActivity
- {
- IHThorDictionaryWorkUnitWriteArg &helper;
- IRoxieServerContext *serverContext;
- public:
- CRoxieServerWorkUnitWriteDictActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _usageCount)
- : CRoxieServerInternalSinkActivity(_factory, _probeManager, _usageCount), helper((IHThorDictionaryWorkUnitWriteArg &)basehelper)
- {
- serverContext = NULL;
- }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerInternalSinkActivity::onCreate(_ctx, _colocalParent);
- serverContext = ctx->queryServerContext();
- if (!serverContext)
- {
- throw MakeStringException(ROXIE_PIPE_ERROR, "Write Dictionary activity cannot be executed in slave context");
- }
- }
- virtual bool needsAllocator() const { return true; }
- virtual void onExecute()
- {
- int sequence = helper.getSequence();
- const char *storedName = helper.queryName();
- assertex(storedName && *storedName);
- assertex(sequence < 0);
- RtlLinkedDictionaryBuilder builder(rowAllocator, helper.queryHashLookupInfo());
- loop
- {
- const void *row = input->nextInGroup();
- if (!row)
- {
- row = input->nextInGroup();
- if (!row)
- break;
- }
- builder.appendOwn(row);
- processed++;
- }
- serverContext->appendResultDeserialized(storedName, sequence, builder.getcount(), builder.linkrows(), (helper.getFlags() & POFextend) != 0, LINK(meta.queryOriginal()));
- }
- };
- class CRoxieServerWorkUnitWriteDictActivityFactory : public CRoxieServerInternalSinkFactory
- {
- public:
- CRoxieServerWorkUnitWriteDictActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
- : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot)
- {
- Owned<IHThorDictionaryWorkUnitWriteArg> helper = (IHThorDictionaryWorkUnitWriteArg *) helperFactory();
- isInternal = (helper->getSequence()==ResultSequenceInternal);
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerWorkUnitWriteDictActivity(this, _probeManager, usageCount);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerWorkUnitWriteDictActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
- {
- return new CRoxieServerWorkUnitWriteDictActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot);
- }
- //=================================================================================
- class CRoxieServerRemoteResultActivity : public CRoxieServerInternalSinkActivity
- {
- IHThorRemoteResultArg &helper;
- public:
- CRoxieServerRemoteResultActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numOutputs)
- : CRoxieServerInternalSinkActivity(_factory, _probeManager, _numOutputs), helper((IHThorRemoteResultArg &)basehelper)
- {
- }
- virtual void onExecute()
- {
- OwnedConstRoxieRow row = input->nextInGroup();
- helper.sendResult(row); // should be only one row or something has gone wrong!
- }
- };
- class CRoxieServerRemoteResultActivityFactory : public CRoxieServerInternalSinkFactory
- {
- public:
- CRoxieServerRemoteResultActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
- : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot)
- {
- Owned<IHThorRemoteResultArg> helper = (IHThorRemoteResultArg *) helperFactory();
- isInternal = (helper->getSequence()==ResultSequenceInternal);
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerRemoteResultActivity(this, _probeManager, usageCount);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerRemoteResultActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
- {
- return new CRoxieServerRemoteResultActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot);
- }
- //=================================================================================
- class CRoxieServerXmlParseActivity : public CRoxieServerActivity, implements IXMLSelect
- {
- IHThorXmlParseArg &helper;
- Owned<IXMLParse> xmlParser;
- const void * in;
- char * srchStr;
- unsigned numProcessedLastGroup;
- bool srchStrNeedsFree;
- Owned<IColumnProvider> lastMatch;
- public:
- IMPLEMENT_IINTERFACE;
- CRoxieServerXmlParseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager),
- helper((IHThorXmlParseArg &)basehelper)
- {
- srchStrNeedsFree = helper.searchTextNeedsFree();
- numProcessedLastGroup = 0;
- srchStr = NULL;
- in = NULL;
- }
- ~CRoxieServerXmlParseActivity()
- {
- }
- virtual bool needsAllocator() const { return true; }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- numProcessedLastGroup = 0;
- srchStr = NULL;
- in = NULL;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- }
- virtual void reset()
- {
- if (helper.searchTextNeedsFree())
- rtlFree(srchStr);
- srchStr = NULL;
- ReleaseClearRoxieRow(in);
- xmlParser.clear();
- CRoxieServerActivity::reset();
- }
- virtual void match(IColumnProvider &entry, offset_t startOffset, offset_t endOffset)
- {
- lastMatch.set(&entry);
- }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- loop
- {
- if(xmlParser)
- {
- loop
- {
- if(!xmlParser->next())
- {
- if (srchStrNeedsFree)
- {
- rtlFree(srchStr);
- srchStr = NULL;
- }
- xmlParser.clear();
- break;
- }
- if(lastMatch)
- {
- try
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- size32_t outSize = helper.transform(rowBuilder, in, lastMatch);
- lastMatch.clear();
- if (outSize)
- {
- processed++;
- return rowBuilder.finalizeRowClear(outSize);
- }
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- }
- }
- ReleaseClearRoxieRow(in);
- in = input->nextInGroup();
- if(!in)
- {
- if(numProcessedLastGroup == processed)
- in = input->nextInGroup();
- if(!in)
- {
- numProcessedLastGroup = processed;
- return NULL;
- }
- }
- size32_t srchLen;
- helper.getSearchText(srchLen, srchStr, in);
- OwnedRoxieString xmlIteratorPath(helper.getXmlIteratorPath());
- xmlParser.setown(createXMLParse(srchStr, srchLen, xmlIteratorPath, *this));
- }
- }
- };
- class CRoxieServerXmlParseActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerXmlParseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerXmlParseActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerXmlParseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerXmlParseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //=====================================================================================================
- class CRoxieServerDiskReadBaseActivity : public CRoxieServerActivity, implements IRoxieServerErrorHandler, implements IIndexReadContext
- {
- protected:
- IHThorDiskReadBaseArg &helper;
- IHThorCompoundExtra * compoundHelper;
- RemoteActivityId remoteId; // Note we copy it rather than reference
- Owned<CSkippableRemoteResultAdaptor> remote;
- unsigned numParts;
- unsigned __int64 rowLimit;
- unsigned __int64 stopAfter;
- Linked<IInMemoryIndexManager> manager;
- Owned<IInMemoryIndexCursor> cursor;
- Owned<IDirectReader> reader;
- CThorContiguousRowBuffer deserializeSource;
- Owned<ISourceRowPrefetcher> prefetcher;
- bool eof;
- bool isKeyed;
- bool variableFileName;
- bool isOpt;
- bool sorted;
- bool maySkip;
- bool isLocal;
- CachedOutputMetaData diskSize;
- Owned<const IResolvedFile> varFileInfo;
- Owned<IFileIOArray> varFiles;
- inline bool useRemote()
- {
- return remote != NULL && numParts > 1;
- }
- public:
- IMPLEMENT_IINTERFACE;
- CRoxieServerDiskReadBaseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, bool _sorted, bool _maySkip, IInMemoryIndexManager *_manager)
- : CRoxieServerActivity(_factory, _probeManager),
- helper((IHThorDiskReadBaseArg &)basehelper),
- numParts(_numParts),
- remoteId(_remoteId),
- manager(_manager),
- isLocal(_isLocal),
- sorted(_sorted),
- maySkip(_maySkip),
- deserializeSource(NULL)
- {
- if (numParts != 1 && !isLocal) // NOTE : when numParts == 0 (variable case) we create, even though we may not use
- remote.setown(new CSkippableRemoteResultAdaptor(remoteId, meta.queryOriginal(), helper, *this, sorted, false, _maySkip));
- compoundHelper = NULL;
- eof = false;
- rowLimit = (unsigned __int64) -1;
- isKeyed = false;
- stopAfter = I64C(0x7FFFFFFFFFFFFFFF);
- diskSize.set(helper.queryDiskRecordSize());
- variableFileName = allFilesDynamic || factory->queryQueryFactory().isDynamic() || ((helper.getFlags() & (TDXvarfilename|TDXdynamicfilename)) != 0);
- isOpt = (helper.getFlags() & TDRoptional) != 0;
- }
- virtual const IResolvedFile *queryVarFileInfo() const
- {
- return varFileInfo;
- }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerActivity::onCreate(_ctx, _colocalParent);
- if (remote)
- remote->onCreate(this, this, _ctx, _colocalParent);
- }
- virtual bool needsAllocator() const { return true; }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- if (compoundHelper)
- {
- rowLimit = compoundHelper->getRowLimit();
- stopAfter = compoundHelper->getChooseNLimit();
- }
- if (!helper.canMatchAny())
- eof = true;
- else
- {
- if (variableFileName)
- {
- OwnedRoxieString fileName(helper.getFileName());
- varFileInfo.setown(resolveLFN(fileName, isOpt));
- numParts = 0;
- if (varFileInfo)
- {
- Owned<IFilePartMap> map = varFileInfo->getFileMap();
- if (map)
- numParts = map->getNumParts();
- }
- }
- if (!numParts)
- {
- eof = true;
- }
- else if (useRemote())
- {
- remote->onStart(parentExtractSize, parentExtract);
- remote->setLimits(rowLimit, (unsigned __int64) -1, stopAfter);
- unsigned fileNo = 0; // MORE - superfiles require us to do this per file part... maybe (needs thought)
- // Translation into a message per channel done elsewhere....
- remote->getMem(0, fileNo, 0);
- remote->flush();
- remote->senddone();
- }
- else
- {
- if (variableFileName)
- {
- unsigned channel = isLocal ? factory->queryQueryFactory().queryChannel() : 0;
- varFiles.setown(varFileInfo->getIFileIOArray(isOpt, channel));
- manager.setown(varFileInfo->getIndexManager(isOpt, channel, varFiles, diskSize, false, 0));
- }
- assertex(manager != NULL);
- helper.createSegmentMonitors(this);
- if (cursor)
- {
- isKeyed = cursor->selectKey();
- cursor->reset();
- }
- if (!isKeyed)
- {
- reader.setown(manager->createReader(0, 0, 1));
- deserializeSource.setStream(reader);
- prefetcher.setown(diskSize.queryOriginal()->createDiskPrefetcher(ctx->queryCodeContext(), activityId));
- }
- helper.setCallback(reader ? reader->queryThorDiskCallback() : cursor);
- }
- }
- }
- virtual void append(IKeySegmentMonitor *segment)
- {
- if (!segment->isWild())
- {
- if (!cursor)
- cursor.setown(manager->createCursor());
- cursor->append(segment);
- }
- }
- virtual unsigned ordinality() const
- {
- return cursor ? cursor->ordinality() : 0;
- }
- virtual IKeySegmentMonitor *item(unsigned idx) const
- {
- return cursor ? cursor->item(idx) : 0;
- }
- virtual void setMergeBarrier(unsigned barrierOffset)
- {
- // no merging so no issue...
- }
- virtual void stop(bool aborting)
- {
- if (useRemote())
- remote->onStop(aborting);
- CRoxieServerActivity::stop(aborting);
- }
- virtual void reset()
- {
- if (useRemote())
- {
- processed = remote->processed;
- remote->processed = 0;
- remote->onReset();
- }
- varFileInfo.clear();
- eof = false;
- if (cursor)
- cursor->reset();
- deserializeSource.clearStream();
- CRoxieServerActivity::reset();
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
- }
- virtual void onLimitExceeded(bool isKeyed)
- {
- if (traceLevel > 4)
- DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
- assertex(compoundHelper);
- if (isKeyed) // MORE does this exist for diskread? should it?
- {
- if (helper.getFlags() & (TDRkeyedlimitskips|TDRkeyedlimitcreates))
- {
- if (ctx->queryDebugContext())
- ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
- throw makeLimitSkipException(true);
- }
- else
- {
- UNIMPLEMENTED;
- //compoundHelper->onKeyedLimitExceeded(); Doesn't exist - though the flags do... interesting...
- }
- }
- else
- {
- if (helper.getFlags() & (TDRlimitskips|TDRlimitcreates))
- {
- if (ctx->queryDebugContext())
- ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
- throw makeLimitSkipException(false);
- }
- else
- compoundHelper->onLimitExceeded();
- }
- }
- virtual const void * createLimitFailRow(bool isKeyed)
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- IHThorSourceLimitTransformExtra *limitTransformExtra = static_cast<IHThorSourceLimitTransformExtra *>(helper.selectInterface(TAIsourcelimittransformextra_1));
- assertex(limitTransformExtra);
- size32_t outSize = isKeyed ? limitTransformExtra->transformOnKeyedLimitExceeded(rowBuilder) : limitTransformExtra->transformOnLimitExceeded(rowBuilder);
- if (outSize)
- return rowBuilder.finalizeRowClear(outSize);
- return NULL;
- }
- };
- class CRoxieServerDiskReadActivity : public CRoxieServerDiskReadBaseActivity
- {
- IHThorCompoundReadExtra * readHelper;
- ConstPointerArray readrows;
- bool readAheadDone;
- unsigned readIndex;
- public:
- CRoxieServerDiskReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, bool _sorted, bool _maySkip, IInMemoryIndexManager *_manager)
- : CRoxieServerDiskReadBaseActivity(_factory, _probeManager, _remoteId, _numParts, _isLocal, _sorted, _maySkip, _manager)
- {
- compoundHelper = (IHThorDiskReadArg *)&helper;
- readHelper = (IHThorDiskReadArg *)&helper;
- readAheadDone = false;
- readIndex = 0;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- rowLimit = compoundHelper->getRowLimit();
- stopAfter = compoundHelper->getChooseNLimit();
- CRoxieServerDiskReadBaseActivity::start(parentExtractSize, parentExtract, paused);
- readAheadDone = false;
- readIndex = 0;
- }
- virtual void reset()
- {
- while (readrows.isItem(readIndex))
- ReleaseRoxieRow(readrows.item(readIndex++));
- readrows.kill();
- readAheadDone = false;
- readIndex = 0;
- CRoxieServerDiskReadBaseActivity::reset();
- }
- virtual const void *nextInGroup()
- {
- if (eof)
- return NULL;
- else if (useRemote())
- return remote->nextInGroup();
- else if (maySkip)
- {
- if (!readAheadDone)
- {
- unsigned preprocessed = 0;
- while (!eof)
- {
- const void *row = _nextInGroup();
- if (row)
- preprocessed++;
- if (preprocessed > rowLimit)
- {
- ReleaseRoxieRow(row);
- while (readrows.isItem(readIndex))
- ReleaseRoxieRow(readrows.item(readIndex++));
- readrows.kill();
- eof = true;
- if (ctx->queryDebugContext())
- ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
- if (helper.getFlags() & TDRlimitskips)
- return NULL;
- else if (helper.getFlags() & TDRlimitcreates)
- return createLimitFailRow(false);
- else
- throwUnexpected();
- }
- if (preprocessed > stopAfter) // MORE - bit of a strange place to check
- {
- eof = true;
- ReleaseRoxieRow(row);
- break;
- }
- readrows.append(row);
- }
- readAheadDone = true;
- }
- if (readrows.isItem(readIndex))
- {
- const void *ret = readrows.item(readIndex++);
- if (ret)
- processed++;
- return ret;
- }
- else
- {
- eof = true;
- return NULL;
- }
- }
- else
- {
- const void *ret = _nextInGroup();
- if (ret)
- {
- processed++;
- if (processed > rowLimit)
- {
- if (traceLevel > 4)
- DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
- ReleaseRoxieRow(ret);
- compoundHelper->onLimitExceeded();
- throwUnexpected(); // onLimitExceeded is not supposed to return
- }
- if (processed > stopAfter) // MORE - bit of a strange place to check
- {
- eof = true;
- ReleaseRoxieRow(ret);
- return NULL;
- }
- }
- return ret;
- }
- }
- const void *_nextInGroup()
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- unsigned transformedSize = 0;
- if (isKeyed)
- {
- loop
- {
- const void *nextCandidate = cursor->nextMatch();
- if (!nextCandidate)
- {
- eof = true;
- return NULL;
- }
- transformedSize = readHelper->transform(rowBuilder, nextCandidate);
- if (transformedSize)
- break;
- }
- }
- else // use reader...
- {
- assertex(reader != NULL);
- loop
- {
- if (deserializeSource.eos())
- {
- eof = true;
- return NULL;
- }
- prefetcher->readAhead(deserializeSource);
- const byte *nextRec = deserializeSource.queryRow();
- if (cursor && cursor->isFiltered(nextRec))
- transformedSize = 0;
- else
- transformedSize = readHelper->transform(rowBuilder, nextRec);
- deserializeSource.finishedRow();
- if (transformedSize)
- break;
- }
- }
- return rowBuilder.finalizeRowClear(transformedSize);
- }
- };
- class CRoxieServerXmlReadActivity : public CRoxieServerDiskReadBaseActivity, implements IXMLSelect
- {
- IHThorXmlReadArg * readHelper;
- Owned<IXmlToRowTransformer> rowTransformer;
- Owned<IXMLParse> xmlParser;
- Owned<IColumnProvider> lastMatch;
- unsigned __int64 localOffset;
- public:
- IMPLEMENT_IINTERFACE;
- CRoxieServerXmlReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, bool _sorted, bool _maySkip, IInMemoryIndexManager *_manager)
- : CRoxieServerDiskReadBaseActivity(_factory, _probeManager, _remoteId, _numParts, _isLocal, _sorted, _maySkip, _manager)
- {
- compoundHelper = NULL;
- readHelper = (IHThorXmlReadArg *)&helper;
- localOffset = 0;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- rowLimit = readHelper->getRowLimit();
- stopAfter = readHelper->getChooseNLimit();
- CRoxieServerDiskReadBaseActivity::start(parentExtractSize, parentExtract, paused);
- if (!useRemote())
- {
- rowTransformer.set(readHelper->queryTransformer());
- assertex(reader != NULL);
- OwnedRoxieString xmlIterator(readHelper->getXmlIteratorPath());
- xmlParser.setown(createXMLParse(*reader->querySimpleStream(), xmlIterator, *this, (0 != (TDRxmlnoroot & readHelper->getFlags()))?ptr_noRoot:ptr_none, (readHelper->getFlags() & TDRusexmlcontents) != 0));
- }
- }
- virtual void reset()
- {
- CRoxieServerDiskReadBaseActivity::reset();
- rowTransformer.clear();
- xmlParser.clear();
- }
- virtual void match(IColumnProvider &entry, offset_t startOffset, offset_t endOffset)
- {
- localOffset = startOffset;
- lastMatch.set(&entry);
- }
- virtual const void *nextInGroup()
- {
- if (eof)
- return NULL;
- else if (useRemote())
- return remote->nextInGroup();
- assertex(xmlParser != NULL);
- try
- {
- while (!eof)
- {
- //call to next() will callback on the IXmlSelect interface
- bool gotNext = false;
- gotNext = xmlParser->next();
- if(!gotNext)
- eof = true;
- else if (lastMatch)
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- unsigned sizeGot = rowTransformer->transform(rowBuilder, lastMatch, reader->queryThorDiskCallback());
- lastMatch.clear();
- localOffset = 0;
- if (sizeGot)
- {
- OwnedConstRoxieRow ret = rowBuilder.finalizeRowClear(sizeGot);
- if (processed > rowLimit)
- {
- if (traceLevel > 4)
- DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
- readHelper->onLimitExceeded();
- throwUnexpected(); // onLimitExceeded is not supposed to return
- }
- processed++;
- if (processed > stopAfter) // MORE - bit of a strange place to check
- {
- eof = true;
- return NULL;
- }
- return ret.getClear();
- }
- }
- }
- return NULL;
- }
- catch(IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- };
- class CRoxieServerCsvReadActivity : public CRoxieServerDiskReadBaseActivity
- {
- IHThorCsvReadArg *readHelper;
- ICsvParameters * csvInfo;
- unsigned headerLines;
- unsigned maxDiskSize;
- CSVSplitter csvSplitter;
- unsigned __int64 localOffset;
- const char *quotes;
- const char *separators;
- const char *terminators;
- const char *escapes;
- public:
- CRoxieServerCsvReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
- unsigned _numParts, bool _isLocal, bool _sorted, bool _maySkip, IInMemoryIndexManager *_manager,
- const char *_quotes, const char *_separators, const char *_terminators, const char *_escapes)
- : CRoxieServerDiskReadBaseActivity(_factory, _probeManager, _remoteId, _numParts, _isLocal, _sorted, _maySkip, _manager),
- quotes(_quotes), separators(_separators), terminators(_terminators), escapes(_escapes)
- {
- compoundHelper = NULL;
- readHelper = (IHThorCsvReadArg *)&helper;
- rowLimit = readHelper->getRowLimit();
- stopAfter = readHelper->getChooseNLimit();
- csvInfo = readHelper->queryCsvParameters();
- maxDiskSize = csvInfo->queryMaxSize();
- localOffset = 0;
- headerLines = 0;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- rowLimit = readHelper->getRowLimit();
- stopAfter = readHelper->getChooseNLimit();
- CRoxieServerDiskReadBaseActivity::start(parentExtractSize, parentExtract, paused);
- if (!useRemote())
- {
- headerLines = csvInfo->queryHeaderLen();
- if (headerLines && isLocal && reader->queryFilePart() != 1)
- 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...
- if (!eof)
- {
- if (varFileInfo)
- {
- const IPropertyTree *options = varFileInfo->queryProperties();
- if (options)
- {
- quotes = options->queryProp("@csvQuote");
- separators = options->queryProp("@csvSeparate");
- terminators = options->queryProp("@csvTerminate");
- escapes = options->queryProp("@csvEscape");
- }
- }
- csvSplitter.init(readHelper->getMaxColumns(), csvInfo, quotes, separators, terminators, escapes);
- }
- }
- }
- virtual const void *nextInGroup()
- {
- if (eof)
- return NULL;
- else if (useRemote())
- return remote->nextInGroup();
- try
- {
- while (!eof)
- {
- if (reader->eos())
- {
- eof = true;
- break;
- }
- // MORE - there are rumours of a csvSplitter that operates on a stream... if/when it exists, this should use it
- size32_t rowSize = 4096; // MORE - make configurable
- size32_t maxRowSize = 10*1024*1024; // MORE - make configurable
- size32_t thisLineLength;
- loop
- {
- size32_t avail;
- const void *peek = reader->peek(rowSize, avail);
- thisLineLength = csvSplitter.splitLine(avail, (const byte *)peek);
- if (thisLineLength < rowSize || avail < rowSize)
- break;
- if (rowSize == maxRowSize)
- throw MakeStringException(0, "Row too big");
- if (rowSize >= maxRowSize/2)
- rowSize = maxRowSize;
- else
- rowSize += rowSize;
- }
- if (headerLines)
- {
- headerLines--;
- reader->skip(thisLineLength);
- }
- else
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- unsigned transformedSize = readHelper->transform(rowBuilder, csvSplitter.queryLengths(), (const char * *)csvSplitter.queryData());
- reader->skip(thisLineLength);
- if (transformedSize)
- {
- OwnedConstRoxieRow ret = rowBuilder.finalizeRowClear(transformedSize);
- if (processed > rowLimit)
- {
- readHelper->onLimitExceeded();
- throwUnexpected(); // onLimitExceeded is not supposed to return
- }
- processed++;
- if (processed > stopAfter) // MORE - bit of a strange place to check
- {
- eof = true;
- return NULL;
- }
- return ret.getClear();
- }
- }
- }
- return NULL;
- }
- catch(IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- virtual void reset()
- {
- CRoxieServerDiskReadBaseActivity::reset();
- csvSplitter.reset();
- localOffset = 0;
- }
- virtual unsigned __int64 getFilePosition(const void * row)
- {
- UNIMPLEMENTED; // we know offset in the reader but not sure it helps us much
- }
- virtual unsigned __int64 getLocalFilePosition(const void * row)
- {
- UNIMPLEMENTED;
- }
- };
- class CRoxieServerDiskNormalizeActivity : public CRoxieServerDiskReadBaseActivity
- {
- IHThorDiskNormalizeArg *normalizeHelper;
- bool firstPending;
- public:
- CRoxieServerDiskNormalizeActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, bool _sorted, IInMemoryIndexManager *_manager)
- : CRoxieServerDiskReadBaseActivity(_factory, _probeManager, _remoteId, _numParts, _isLocal, _sorted, false, _manager)
- {
- compoundHelper = (IHThorDiskNormalizeArg *)&helper;
- normalizeHelper = (IHThorDiskNormalizeArg *)&helper;
- firstPending = true;
- }
- virtual void reset()
- {
- firstPending = true;
- CRoxieServerDiskReadBaseActivity::reset();
- }
- virtual const void *nextInGroup()
- {
- if (eof)
- return NULL;
- else if (useRemote())
- return remote->nextInGroup();
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- unsigned transformedSize = 0;
- if (isKeyed)
- {
- loop
- {
- while (firstPending)
- {
- const void *nextCandidate = cursor->nextMatch();
- if (!nextCandidate)
- {
- eof = true;
- return NULL;
- }
- if (normalizeHelper->first(nextCandidate))
- {
- firstPending = false;
- break;
- }
- }
- transformedSize = normalizeHelper->transform(rowBuilder);
- firstPending = !normalizeHelper->next();
- if (transformedSize)
- break;
- }
- }
- else
- {
- assertex(reader != NULL);
- loop
- {
- while (firstPending)
- {
- if (deserializeSource.eos())
- {
- eof = true;
- return NULL;
- }
- prefetcher->readAhead(deserializeSource);
- const byte *nextRec = deserializeSource.queryRow();
- if (!cursor || !cursor->isFiltered(nextRec))
- {
- if (normalizeHelper->first(nextRec))
- firstPending = false;
- }
- deserializeSource.finishedRow();
- }
- transformedSize = normalizeHelper->transform(rowBuilder);
- firstPending = !normalizeHelper->next();
- if (transformedSize)
- break;
- }
- }
- OwnedConstRoxieRow recBuffer = rowBuilder.finalizeRowClear(transformedSize);
- processed++;
- if (processed > rowLimit)
- {
- compoundHelper->onLimitExceeded();
- throwUnexpected(); // onLimitExceeded is not supposed to return
- }
- if (processed > stopAfter) // MORE - bit of a strange place to check
- {
- eof = true;
- return NULL;
- }
- return recBuffer.getClear();
- }
- };
- class CRoxieServerDiskAggregateBaseActivity : public CRoxieServerDiskReadBaseActivity
- {
- protected:
- bool done;
- public:
- CRoxieServerDiskAggregateBaseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, IInMemoryIndexManager *_manager)
- : CRoxieServerDiskReadBaseActivity(_factory, _probeManager, _remoteId, _numParts, _isLocal, false, false, _manager),
- done(false)
- {
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- done = false;
- CRoxieServerDiskReadBaseActivity::start(parentExtractSize, parentExtract, paused);
- }
- virtual IRoxieInput *queryOutput(unsigned idx)
- {
- if (idx==(unsigned)-1)
- idx = 0;
- return idx ? NULL: this;
- }
- };
- class CRoxieServerDiskCountActivity : public CRoxieServerDiskAggregateBaseActivity
- {
- IHThorDiskCountArg & countHelper;
- unsigned __int64 choosenLimit;
- IHThorSourceCountLimit *limitHelper;
- unsigned __int64 getSkippedCount()
- {
- unsigned flags = countHelper.getFlags();
- if (flags & TDRlimitskips)
- return 0;
- else if (flags & TDRlimitcreates)
- return 1;
- else
- {
- assertex(limitHelper);
- if (traceLevel > 4)
- DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
- limitHelper->onLimitExceeded();
- throwUnexpected(); // onLimitExceeded should always throw exception
- }
- }
- public:
- CRoxieServerDiskCountActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, IInMemoryIndexManager *_manager)
- : CRoxieServerDiskAggregateBaseActivity(_factory, _probeManager, _remoteId, _numParts, _isLocal, _manager),
- countHelper((IHThorDiskCountArg &)basehelper)
- {
- limitHelper = static_cast<IHThorSourceCountLimit *>(basehelper.selectInterface(TAIsourcecountlimit_1));
- choosenLimit = 0;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- choosenLimit = countHelper.getChooseNLimit();
- if (limitHelper)
- {
- rowLimit = limitHelper->getRowLimit();
- // keyedLimit = limitHelper->getKeyedLimit(); // more - should there be one?
- }
- CRoxieServerDiskAggregateBaseActivity::start(parentExtractSize, parentExtract, paused);
- }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (done) return NULL;
- done = true;
- unsigned __int64 totalCount = 0;
- if (helper.canMatchAny() && !eof)
- {
- if (useRemote())
- {
- loop
- {
- const void * next = remote->nextInGroup();
- if (!next)
- break;
- if (meta.getFixedSize() == 1)
- totalCount += *(byte *)next;
- else
- totalCount += *(unsigned __int64 *)next;
- ReleaseRoxieRow(next);
- if (totalCount > rowLimit)
- {
- totalCount = getSkippedCount();
- break;
- }
- else if (totalCount >= choosenLimit)
- {
- totalCount = choosenLimit;
- break;
- }
- }
- }
- else
- {
- if (isKeyed)
- {
- loop
- {
- const void *nextCandidate = cursor->nextMatch();
- if (!nextCandidate)
- break;
- totalCount += countHelper.numValid(nextCandidate);
- if (totalCount > rowLimit)
- {
- totalCount = getSkippedCount();
- break;
- }
- else if (totalCount >= choosenLimit)
- {
- totalCount = choosenLimit;
- break;
- }
- }
- }
- else
- {
- assertex(reader != NULL);
- while (!deserializeSource.eos())
- {
- prefetcher->readAhead(deserializeSource);
- const byte *nextRec = deserializeSource.queryRow();
- if (!cursor || !cursor->isFiltered(nextRec))
- {
- totalCount += countHelper.numValid(nextRec);
- }
- deserializeSource.finishedRow();
- if (totalCount > rowLimit)
- {
- totalCount = getSkippedCount();
- break;
- }
- else if (totalCount >= choosenLimit)
- {
- totalCount = choosenLimit;
- break;
- }
- }
- }
- }
- }
- size32_t rowSize = meta.getFixedSize();
- void * result = rowAllocator->createRow();
- if (rowSize == 1)
- *(byte *)result = (byte)totalCount;
- else
- {
- assertex(rowSize == sizeof(unsigned __int64));
- *(unsigned __int64 *)result = totalCount;
- }
- return rowAllocator->finalizeRow(rowSize, result, rowSize);
- }
- };
- class CRoxieServerDiskAggregateActivity : public CRoxieServerDiskAggregateBaseActivity
- {
- IHThorCompoundAggregateExtra & aggregateHelper;
- public:
- CRoxieServerDiskAggregateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
- unsigned _numParts, bool _isLocal, IInMemoryIndexManager *_manager)
- : CRoxieServerDiskAggregateBaseActivity(_factory, _probeManager, _remoteId, _numParts, _isLocal, _manager),
- aggregateHelper((IHThorDiskAggregateArg &)basehelper)
- {
- }
- const void * gatherMerged()
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator, false);
- size32_t finalSize = 0;
- if (useRemote())
- {
- const void * firstRow = remote->nextInGroup();
- if (!firstRow)
- {
- rowBuilder.ensureRow();
- finalSize = aggregateHelper.clearAggregate(rowBuilder);
- }
- else
- {
- // NOTE need to clone this because going to modify below, could special case 1 row only
- finalSize = cloneRow(rowBuilder, firstRow, meta);
- ReleaseRoxieRow(firstRow);
- }
- loop
- {
- const void * next = remote->nextInGroup();
- if (!next)
- break;
- finalSize = aggregateHelper.mergeAggregate(rowBuilder, next);
- ReleaseRoxieRow(next);
- }
- }
- else
- {
- aggregateHelper.clearAggregate(rowBuilder);
- if (helper.canMatchAny() && !eof)
- {
- if (isKeyed)
- {
- loop
- {
- const void *next = cursor->nextMatch();
- if (!next)
- break;
- aggregateHelper.processRow(rowBuilder, next);
- }
- }
- else
- {
- assertex(reader != NULL);
- while (!deserializeSource.eos())
- {
- prefetcher->readAhead(deserializeSource);
- const byte *nextRec = deserializeSource.queryRow();
- if (!cursor || !cursor->isFiltered(nextRec))
- {
- aggregateHelper.processRow(rowBuilder, nextRec);
- }
- deserializeSource.finishedRow();
- }
- }
- }
- finalSize = meta.getRecordSize(rowBuilder.getSelf());
- }
- return rowBuilder.finalizeRowClear(finalSize);
- }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (done) return NULL;
- const void * ret = gatherMerged();
- done = true;
- return ret;
- }
- };
- class CRoxieServerDiskGroupAggregateActivity : public CRoxieServerDiskAggregateBaseActivity
- {
- IHThorDiskGroupAggregateArg & aggregateHelper;
- RowAggregator resultAggregator;
- bool gathered;
- public:
- IMPLEMENT_IINTERFACE;
- CRoxieServerDiskGroupAggregateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, IInMemoryIndexManager *_manager)
- : CRoxieServerDiskAggregateBaseActivity(_factory, _probeManager, _remoteId, _numParts, _isLocal, _manager),
- aggregateHelper((IHThorDiskGroupAggregateArg &)basehelper),
- resultAggregator(aggregateHelper, aggregateHelper),
- gathered(false)
- {
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- gathered= false;
- CRoxieServerDiskAggregateBaseActivity::start(parentExtractSize, parentExtract, paused);
- resultAggregator.start(rowAllocator);
- }
- virtual void reset()
- {
- resultAggregator.reset();
- CRoxieServerDiskAggregateBaseActivity::reset();
- }
- void gatherMerged()
- {
- if (useRemote())
- {
- loop
- {
- const void * next = remote->nextInGroup();
- if (!next)
- break;
- resultAggregator.mergeElement(next);
- ReleaseRoxieRow(next);
- }
- }
- else
- {
- if (helper.canMatchAny() && !eof)
- {
- Owned<IInMemoryFileProcessor> processor = isKeyed ?
- createKeyedGroupAggregateRecordProcessor(cursor, resultAggregator, aggregateHelper) :
- createUnkeyedGroupAggregateRecordProcessor(cursor, resultAggregator, aggregateHelper, manager->createReader(0, 0, 1),
- ctx->queryCodeContext(), activityId);
- processor->doQuery(NULL, 0, 0, 0);
- }
- }
- gathered = true;
- }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (done)
- return NULL;
- if (!gathered)
- gatherMerged();
- Owned<AggregateRowBuilder> next = resultAggregator.nextResult();
- if (next)
- {
- processed++;
- return next->finalizeRowClear();
- }
- done = true;
- return NULL;
- }
- };
- class CRoxieServerDiskReadActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- RemoteActivityId remoteId;
- bool isLocal;
- bool sorted;
- bool maySkip;
- bool variableFileName;
- Owned<IFilePartMap> map;
- Owned<IFileIOArray> files;
- Owned<IInMemoryIndexManager> manager;
- Owned<const IResolvedFile> datafile;
- const char *quotes;
- const char *separators;
- const char *terminators;
- const char *escapes;
- CRoxieServerDiskReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), remoteId(_remoteId)
- {
- isLocal = _graphNode.getPropBool("att[@name='local']/@value") && queryFactory.queryChannel()!=0;
- Owned<IHThorDiskReadBaseArg> helper = (IHThorDiskReadBaseArg *) helperFactory();
- sorted = (helper->getFlags() & TDRunsorted) == 0;
- variableFileName = allFilesDynamic || _queryFactory.isDynamic() || ((helper->getFlags() & (TDXvarfilename|TDXdynamicfilename)) != 0);
- maySkip = (helper->getFlags() & (TDRkeyedlimitskips|TDRkeyedlimitcreates|TDRlimitskips|TDRlimitcreates)) != 0;
- quotes = separators = terminators = escapes = NULL;
- if (!variableFileName)
- {
- bool isOpt = (helper->getFlags() & TDRoptional) != 0;
- OwnedRoxieString fileName(helper->getFileName());
- datafile.setown(_queryFactory.queryPackage().lookupFileName(fileName, isOpt, true, true, _queryFactory.queryWorkUnit()));
- if (datafile)
- map.setown(datafile->getFileMap());
- bool isSimple = (map && map->getNumParts()==1 && !_queryFactory.getDebugValueBool("disableLocalOptimizations", false));
- if (isLocal || isSimple)
- {
- if (datafile)
- {
- unsigned channel = isLocal ? queryFactory.queryChannel() : 0;
- files.setown(datafile->getIFileIOArray(isOpt, channel));
- manager.setown(datafile->getIndexManager(isOpt, channel, files, helper->queryDiskRecordSize(), _graphNode.getPropBool("att[@name=\"preload\"]/@value", false), _graphNode.getPropInt("att[@name=\"_preloadSize\"]/@value", 0)));
- const IPropertyTree *options = datafile->queryProperties();
- if (options)
- {
- quotes = options->queryProp("@csvQuote");
- separators = options->queryProp("@csvSeparate");
- terminators = options->queryProp("@csvTerminate");
- escapes = options->queryProp("@csvEscape");
- }
- }
- else
- manager.setown(getEmptyIndexManager());
- }
- }
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- unsigned numParts = map ? map->getNumParts() : 0;
- switch (kind)
- {
- case TAKcsvread:
- return new CRoxieServerCsvReadActivity(this, _probeManager, remoteId, numParts, isLocal, sorted, maySkip, manager,
- quotes, separators, terminators, escapes);
- case TAKxmlread:
- return new CRoxieServerXmlReadActivity(this, _probeManager, remoteId, numParts, isLocal, sorted, maySkip, manager);
- case TAKdiskread:
- return new CRoxieServerDiskReadActivity(this, _probeManager, remoteId, numParts, isLocal, sorted, maySkip, manager);
- case TAKdisknormalize:
- return new CRoxieServerDiskNormalizeActivity(this, _probeManager, remoteId, numParts, isLocal, sorted, manager);
- case TAKdiskcount:
- return new CRoxieServerDiskCountActivity(this, _probeManager, remoteId, numParts, isLocal, manager);
- case TAKdiskaggregate:
- return new CRoxieServerDiskAggregateActivity(this, _probeManager, remoteId, numParts, isLocal, manager);
- case TAKdiskgroupaggregate:
- return new CRoxieServerDiskGroupAggregateActivity(this, _probeManager, remoteId, numParts, isLocal, manager);
- }
- throwUnexpected();
- }
- virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
- {
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for %s activity", getActivityText(kind));
- }
- virtual void getXrefInfo(IPropertyTree &reply, const IRoxieContextLogger &logctx) const
- {
- if (datafile)
- addXrefFileInfo(reply, datafile);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerDiskReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
- {
- return new CRoxieServerDiskReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode);
- }
- //=================================================================================
- class CRoxieServerIndexActivity : public CRoxieServerActivity, implements IRoxieServerErrorHandler
- {
- protected:
- IHThorIndexReadBaseArg &indexHelper;
- IHThorSteppedSourceExtra * steppedExtra;
- Linked<IKeyArray> keySet;
- Linked<TranslatorArray> translators;
- CSkippableRemoteResultAdaptor remote;
- CIndexTransformCallback callback;
- bool sorted;
- bool variableFileName;
- bool variableInfoPending;
- bool isOpt;
- bool isLocal;
- unsigned __int64 rowLimit;
- unsigned __int64 keyedLimit;
- unsigned __int64 choosenLimit;
- unsigned accepted;
- unsigned rejected;
- unsigned seekGEOffset;
- Owned<IKeyManager> tlk;
- Owned<const IResolvedFile> varFileInfo;
- const RemoteActivityId &remoteId;
- void setVariableFileInfo()
- {
- OwnedRoxieString indexName(indexHelper.getFileName());
- varFileInfo.setown(resolveLFN(indexName, isOpt));
- if (varFileInfo)
- {
- translators.setown(new TranslatorArray) ;
- keySet.setown(varFileInfo->getKeyArray(factory->queryActivityMeta(), translators, isOpt, isLocal ? factory->queryQueryFactory().queryChannel() : 0, factory->queryQueryFactory().getEnableFieldTranslation()));
- }
- variableInfoPending = false;
- }
- public:
- CRoxieServerIndexActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
- IKeyArray * _keySet, TranslatorArray *_translators, bool _sorted, bool _isLocal, bool _maySkip)
- : CRoxieServerActivity(_factory, _probeManager),
- keySet(_keySet),
- translators(_translators),
- indexHelper((IHThorIndexReadBaseArg &)basehelper),
- remote(_remoteId, meta.queryOriginal(), indexHelper, *this, _sorted, false, _maySkip),
- remoteId(_remoteId),
- sorted(_sorted),
- isLocal(_isLocal)
- {
- indexHelper.setCallback(&callback);
- steppedExtra = static_cast<IHThorSteppedSourceExtra *>(indexHelper.selectInterface(TAIsteppedsourceextra_1));
- variableFileName = allFilesDynamic || factory->queryQueryFactory().isDynamic() || ((indexHelper.getFlags() & (TIRvarfilename|TIRdynamicfilename)) != 0);
- variableInfoPending = false;
- isOpt = (indexHelper.getFlags() & TIRoptional) != 0;
- seekGEOffset = 0;
- // started = false;
- rejected = accepted = 0;
- rowLimit = choosenLimit = keyedLimit = 0;
- }
- virtual const IResolvedFile *queryVarFileInfo() const
- {
- return varFileInfo;
- }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerActivity::onCreate(_ctx, _colocalParent);
- remote.onCreate(this, this, _ctx, _colocalParent);
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- accepted = 0;
- rejected = 0;
- rowLimit = (unsigned __int64) -1;
- keyedLimit = (unsigned __int64 ) -1;
- choosenLimit = I64C(0x7fffffffffffffff);
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- remote.onStart(parentExtractSize, parentExtract);
- variableInfoPending = variableFileName;
- }
- void processAllKeys()
- {
- try
- {
- if (indexHelper.canMatchAny())
- {
- if (variableInfoPending)
- setVariableFileInfo();
- remote.setLimits(rowLimit, keyedLimit, choosenLimit);
- if (keySet)
- {
- // MORE - this recreates the segmonitors per part but not per fileno (which is a little backwards).
- // 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
- // However order is probably better to iterate fileno's inside partnos
- // MORE - also not properly supporting STEPPED I fear.
- // A superkey that mixes single and multipart or tlk and roroot keys might be hard
- for (unsigned partNo = 0; partNo < keySet->length(); partNo++)
- {
- IKeyIndexBase *thisBase = keySet->queryKeyPart(partNo);
- if (thisBase)
- {
- unsigned fileNo = 0;
- IKeyIndex *thisKey = thisBase->queryPart(fileNo);
- if (!thisKey->isTopLevelKey())
- {
- if (keyedLimit != (unsigned __int64) -1)
- {
- if ((indexHelper.getFlags() & TIRcountkeyedlimit) != 0)
- {
- Owned<IKeyManager> countKey;
- countKey.setown(createKeyManager(thisKey, 0, this));
- countKey->setLayoutTranslator(translators->item(fileNo));
- createSegmentMonitors(countKey);
- unsigned __int64 count = countKey->checkCount(keyedLimit);
- if (count > keyedLimit)
- {
- if (traceLevel > 4)
- DBGLOG("activityid = %d line = %d", activityId, __LINE__);
- onLimitExceeded(true);
- }
- }
- }
- }
- if (seekGEOffset && !thisKey->isTopLevelKey())
- {
- tlk.setown(createSingleKeyMerger(thisKey, 0, seekGEOffset, this));
- }
- else
- {
- tlk.setown(createKeyManager(thisKey, 0, this));
- tlk->setLayoutTranslator(translators->item(fileNo));
- }
- createSegmentMonitors(tlk);
- if (queryTraceLevel() > 3 || ctx->queryProbeManager())
- {
- StringBuffer out;
- printKeyedValues(out, tlk, indexHelper.queryDiskRecordSize());
- CTXLOG("Using filter %s", out.str());
- if (ctx->queryProbeManager())
- ctx->queryProbeManager()->setNodeProperty(this, "filter", out.str());
- }
- tlk->reset();
- loop // for each file part
- {
- //block for TransformCallbackAssociation
- {
- TransformCallbackAssociation associate(callback, tlk);
- if (thisKey->isTopLevelKey())
- {
- if (thisKey->isFullySorted())
- {
- while (tlk->lookup(false))
- {
- unsigned slavePart = (unsigned) tlk->queryFpos();
- if (slavePart)
- {
- accepted++;
- remote.getMem(slavePart, fileNo, 0); // the cached context is all we need to send
- if (sorted && numChannels>1)
- remote.flush(); // don't combine parts if we need result sorted, except on a 1-way
- }
- }
- }
- else
- {
- // MORE - we could check whether there are any matching parts if we wanted.
- // If people are in the habit of sending null values that would be worthwhile
- remote.getMem(0, fileNo, 0);
- }
- }
- else
- {
- if (processSingleKey(thisKey, translators->item(fileNo)))
- break;
- }
- }
- if (++fileNo < thisBase->numParts())
- {
- thisKey = thisBase->queryPart(fileNo);
- tlk->setKey(thisKey);
- tlk->setLayoutTranslator(translators->item(fileNo));
- tlk->reset();
- }
- else
- break;
- }
- tlk->releaseSegmentMonitors();
- tlk->setKey(NULL);
- }
- }
- }
- }
- remote.flush();
- remote.senddone();
- }
- catch (IException *E)
- {
- remote.setException(E);
- }
- }
- virtual void createSegmentMonitors(IKeyManager *key)
- {
- indexHelper.createSegmentMonitors(key);
- key->finishSegmentMonitors();
- }
- virtual bool processSingleKey(IKeyIndex *key, IRecordLayoutTranslator * trans) = 0;
- virtual void reset()
- {
- if (accepted)
- noteStatistic(STATS_ACCEPTED, accepted, 1);
- if (rejected)
- noteStatistic(STATS_REJECTED, rejected, 1);
- remote.onReset();
- CRoxieServerActivity::reset();
- if (varFileInfo)
- {
- keySet.clear();
- varFileInfo.clear();
- }
- variableInfoPending = false;
- }
- virtual void stop(bool aborting)
- {
- remote.onStop(aborting);
- CRoxieServerActivity::stop(aborting);
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
- }
- };
- class CRoxieServerIndexReadBaseActivity : public CRoxieServerIndexActivity
- {
- IHThorSourceLimitTransformExtra * limitTransformExtra;
- public:
- CRoxieServerIndexReadBaseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
- IKeyArray * _keySet, TranslatorArray *_translators, bool _sorted, bool _isLocal, bool _maySkip)
- : CRoxieServerIndexActivity(_factory, _probeManager, _remoteId, _keySet, _translators, _sorted, _isLocal, _maySkip)
- {
- limitTransformExtra = static_cast<IHThorSourceLimitTransformExtra *>(indexHelper.selectInterface(TAIsourcelimittransformextra_1));
- }
- virtual void reset()
- {
- remote.onReset();
- CRoxieServerIndexActivity::reset();
- }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- try
- {
- const void *ret = remote.nextInGroup();
- if (ret)
- processed++;
- return ret;
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- protected:
- virtual const void * createLimitFailRow(bool isKeyed)
- {
- createRowAllocator();
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- size32_t outSize = isKeyed ? limitTransformExtra->transformOnKeyedLimitExceeded(rowBuilder) : limitTransformExtra->transformOnLimitExceeded(rowBuilder);
- if (outSize)
- return rowBuilder.finalizeRowClear(outSize);
- return NULL;
- }
- };
- class CRoxieServerIndexReadActivity : public CRoxieServerIndexReadBaseActivity, implements IIndexReadActivityInfo
- {
- protected:
- IHThorCompoundReadExtra & readHelper;
- ISteppingMeta *rawMeta;
- CSteppingMeta steppingMeta;
- unsigned * seekSizes;
- bool optimizeSteppedPostFilter;
- ISteppingMeta * projectedMeta;
- unsigned maxSeekLookahead;
- public:
- CRoxieServerIndexReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
- IKeyArray * _keySet, TranslatorArray *_translators, bool _sorted, bool _isLocal, bool _maySkip, unsigned _maxSeekLookahead)
- : CRoxieServerIndexReadBaseActivity(_factory, _probeManager, _remoteId, _keySet, _translators, _sorted, _isLocal, _maySkip),
- readHelper((IHThorIndexReadArg &)basehelper)
- {
- rawMeta = readHelper.queryRawSteppingMeta();
- unsigned flags = indexHelper.getFlags();
- optimizeSteppedPostFilter = (flags & TIRunfilteredtransform) != 0;
- seekSizes = NULL;
- maxSeekLookahead = _maxSeekLookahead;
- if (rawMeta)
- {
- const CFieldOffsetSize * fields = rawMeta->queryFields();
- unsigned maxFields = rawMeta->getNumFields();
- seekGEOffset = fields[0].offset;
- seekSizes = new unsigned[maxFields];
- seekSizes[0] = fields[0].size;
- for (unsigned i=1; i < maxFields; i++)
- seekSizes[i] = seekSizes[i-1] + fields[i].size;
- projectedMeta = readHelper.queryProjectedSteppingMeta();
- ISteppingMeta *useMeta = projectedMeta ? projectedMeta : rawMeta;
- remote.setMergeInfo(useMeta); // also need to consider superfile case where there is a mix of multiway and singleparts.. ?
- bool hasPostFilter = readHelper.transformMayFilter() && optimizeSteppedPostFilter;
- steppingMeta.init(useMeta, hasPostFilter);
- }
- }
- ~CRoxieServerIndexReadActivity()
- {
- delete [] seekSizes;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerIndexReadBaseActivity::start(parentExtractSize, parentExtract, paused);
- steppingMeta.setDistributed();
- if (steppedExtra)
- steppingMeta.setExtra(steppedExtra);
- rowLimit = readHelper.getRowLimit();
- keyedLimit = readHelper.getKeyedLimit();
- choosenLimit = readHelper.getChooseNLimit();
- if (!paused)
- processAllKeys();
- }
- class LazyLocalKeyReader : public CInterface, implements IMessageResult, implements IMessageUnpackCursor
- {
- public:
- IMPLEMENT_IINTERFACE;
- virtual IMessageUnpackCursor *getCursor(roxiemem::IRowManager *rowMgr) const
- {
- Link();
- return const_cast<LazyLocalKeyReader*> (this);
- }
- virtual const void *getMessageHeader(unsigned &length) const
- {
- length = 0;
- return NULL;
- }
- virtual const void *getMessageMetadata(unsigned &length) const
- {
- length = 0;
- return NULL;
- }
- virtual void discard() const
- {
- // nothing to do.
- }
- unsigned keyedCount;
- unsigned matched;
- bool EOFseen;
- Owned<IKeyIndexSet> keySet;
- Owned<IKeyManager> tlk;
- CRoxieServerIndexReadActivity &owner;
- LazyLocalKeyReader(CRoxieServerIndexReadActivity &_owner, IKeyIndex *key, IRecordLayoutTranslator * trans)
- : owner(_owner)
- {
- keyedCount = 0;
- matched = 0;
- EOFseen = false;
- keySet.setown(createKeyIndexSet());
- keySet->addIndex(LINK(key));
- if (owner.seekGEOffset)
- tlk.setown(createKeyMerger(keySet, 0, owner.seekGEOffset, &owner));
- else
- tlk.setown(createKeyManager(keySet->queryPart(0), 0, &owner));
- tlk->setLayoutTranslator(trans);
- owner.indexHelper.createSegmentMonitors(tlk);
- tlk->finishSegmentMonitors();
- tlk->reset();
- }
- virtual const void *getNext(int length)
- {
- TransformCallbackAssociation associate(owner.callback, tlk);
- while (tlk->lookup(true))
- {
- keyedCount++;
- if (keyedCount > owner.keyedLimit)
- {
- owner.onLimitExceeded(true); // Should throw exception
- throwUnexpected();
- }
- size32_t transformedSize;
- RtlDynamicRowBuilder rowBuilder(owner.rowAllocator);
- byte const * keyRow = tlk->queryKeyBuffer(owner.callback.getFPosRef());
- try
- {
- transformedSize = owner.readHelper.transform(rowBuilder, keyRow);
- owner.callback.finishedRow();
- }
- catch (IException *E)
- {
- throw owner.makeWrappedException(E);
- }
- if (transformedSize)
- {
- OwnedConstRoxieRow result = rowBuilder.finalizeRowClear(transformedSize);
- matched++;
- if (matched > owner.rowLimit)
- {
- owner.onLimitExceeded(false); // Should throw exception
- throwUnexpected();
- }
- if (matched > owner.choosenLimit) // MORE - bit of a strange place to check
- {
- break;
- }
- owner.accepted++;
- return result.getClear();
- }
- else
- owner.rejected++;
- }
- EOFseen = true;
- return NULL;
- }
- virtual bool atEOF() const
- {
- return EOFseen;
- }
- virtual bool isSerialized() const
- {
- return false;
- }
- };
- virtual bool processSingleKey(IKeyIndex *key, IRecordLayoutTranslator * trans)
- {
- createRowAllocator();
- remote.injectResult(new LazyLocalKeyReader(*this, key, trans));
- return false;
- }
- virtual void onLimitExceeded(bool isKeyed)
- {
- if (traceLevel > 4)
- DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
- if (isKeyed)
- {
- if (indexHelper.getFlags() & (TIRkeyedlimitskips|TIRkeyedlimitcreates))
- {
- if (ctx->queryDebugContext())
- ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
- throw makeLimitSkipException(true);
- }
- else
- readHelper.onKeyedLimitExceeded();
- }
- else
- {
- if (indexHelper.getFlags() & (TIRlimitskips|TIRlimitcreates))
- {
- if (ctx->queryDebugContext())
- ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
- throw makeLimitSkipException(false);
- }
- else
- readHelper.onLimitExceeded();
- }
- }
- virtual void serializeSkipInfo(MemoryBuffer &out, unsigned seekLen, const void *rawSeek, unsigned numFields, const void * seek, const SmartStepExtra &stepExtra) const
- {
- out.append((unsigned short) numFields);
- out.append((unsigned short) seekLen);
- out.append((unsigned short) stepExtra.queryFlags());
- IMultipleStepSeekInfo *seeks = stepExtra.queryExtraSeeks();
- if (seeks)
- {
- unsigned lookahead = 40000/seekLen;
- if (maxSeekLookahead && (lookahead > maxSeekLookahead))
- lookahead = maxSeekLookahead;
- seeks->ensureFilled(seek, numFields, lookahead);
- out.append(lookahead != seeks->ordinality()); // seeksAreEof flag
- unsigned serialized = 1; // rawseek is always serialized...
- unsigned patchLength = out.length();
- out.append(serialized); // NOTE - we come back and patch with the actual value...
- out.append(seekLen, rawSeek);
- if (seeks->ordinality())
- {
- const void *lastSeek = rawSeek;
- byte *nextSeek = NULL;
- if (projectedMeta)
- nextSeek = (byte *) alloca(seekLen);
- for (unsigned i = 0; i < seeks->ordinality(); i++)
- {
- if (projectedMeta)
- {
- RtlStaticRowBuilder rowBuilder(nextSeek-seekGEOffset, seekGEOffset+seekLen);
- readHelper.mapOutputToInput(rowBuilder, seeks->querySeek(i), numFields); // NOTE - weird interface to mapOutputToInput means that it STARTS writing at seekGEOffset...
- }
- else
- nextSeek = (byte *) seeks->querySeek(i)+seekGEOffset;
- int diff = memcmp(nextSeek, lastSeek, seekLen);
- if (diff > 0)
- {
- serialized++;
- out.append(seekLen, nextSeek);
- lastSeek = (const byte *) out.reserve(0) - seekLen;
- }
- }
- unsigned length = out.length();
- out.setWritePos(patchLength);
- out.append(serialized);
- out.setWritePos(length);
- }
- }
- else
- {
- out.append(false);
- out.append(1);
- out.append(seekLen, rawSeek);
- }
- }
- virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- try
- {
- unsigned seeklen = 0;
- const void *rawSeek = NULL;
- if (seek && numFields)
- {
- seeklen = seekSizes[numFields-1];
- rawSeek = (const byte *)seek + seekGEOffset;
- if (projectedMeta)
- {
- byte * temp = (byte *) alloca(seeklen);
- RtlStaticRowBuilder rawBuilder(temp-seekGEOffset, seekGEOffset+seeklen);
- readHelper.mapOutputToInput(rawBuilder, seek, numFields); // NOTE - weird interface to mapOutputToInput means that it STARTS writing at seekGEOffset...
- rawSeek = (byte *)temp;
- }
- }
- const void *ret = remote.nextSteppedGE(seek, rawSeek, numFields, seeklen, wasCompleteMatch, stepExtra);
- if (ret && wasCompleteMatch) // GH pleas confirm the wasCompleteMatch I just added here is right
- processed++;
- return ret;
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- virtual IInputSteppingMeta * querySteppingMeta()
- {
- if (rawMeta && steppingEnabled && ((indexHelper.getFlags() & (TIRlimitskips|TIRlimitcreates|TIRkeyedlimitskips|TIRkeyedlimitcreates)) == 0))
- return &steppingMeta;
- return NULL;
- }
- virtual IIndexReadActivityInfo *queryIndexReadActivity()
- {
- if (variableInfoPending)
- setVariableFileInfo();
- return this;
- }
- virtual IKeyArray *getKeySet() const
- {
- return keySet.getLink();
- }
- virtual const IResolvedFile *getVarFileInfo() const
- {
- return varFileInfo.getLink();
- }
- virtual TranslatorArray *getTranslators() const
- {
- return translators.getLink();
- }
- virtual void mergeSegmentMonitors(IIndexReadContext *irc) const
- {
- indexHelper.createSegmentMonitors(irc); // NOTE: they will merge
- }
- virtual IRoxieServerActivity *queryActivity() { return this; }
- virtual const RemoteActivityId& queryRemoteId() const
- {
- return remoteId;
- }
- };
- class CRoxieServerSimpleIndexReadActivity : public CRoxieServerActivity, implements IIndexReadActivityInfo
- {
- IHThorCompoundReadExtra & readHelper;
- IHThorIndexReadBaseArg & indexHelper;
- IHThorSourceLimitTransformExtra * limitTransformExtra;
- IHThorSteppedSourceExtra * steppedExtra;
- bool eof;
- Linked<IKeyArray>keySet;
- Owned<IKeyIndexSet>keyIndexSet;
- Owned<IKeyManager> tlk;
- Linked<TranslatorArray> translators;
- CIndexTransformCallback callback;
- unsigned __int64 keyedLimit;
- unsigned rowLimit;
- unsigned chooseNLimit;
- unsigned accepted;
- unsigned rejected;
- unsigned keyedCount;
- ISteppingMeta * rawMeta;
- ISteppingMeta * projectedMeta;
- size32_t seekGEOffset;
- unsigned * seekSizes;
- CSteppingMeta steppingMeta;
- Owned<const IResolvedFile> varFileInfo;
- const RemoteActivityId &remoteId;
- bool firstRead;
- bool variableFileName;
- bool variableInfoPending;
- bool isOpt;
- bool isLocal;
- bool optimizeSteppedPostFilter;
- // MORE there may be enough in common between this and CRoxieServerIndexActivity to warrant some refactoring
- void initKeySet()
- {
- if ((keySet->length() > 1 || rawMeta != NULL) && translators->needsTranslation())
- {
- throw MakeStringException(ROXIE_UNIMPLEMENTED_ERROR, "Layout translation is not available when merging key parts or smart-stepping, as it may change record order");
- }
- keyIndexSet.setown(createKeyIndexSet());
- for (unsigned part = 0; part < keySet->length(); part++)
- {
- IKeyIndexBase *kib = keySet->queryKeyPart(part);
- if (kib)
- {
- for (unsigned subpart = 0; subpart < kib->numParts(); subpart++)
- {
- IKeyIndex *k = kib->queryPart(subpart);
- if (k)
- {
- assertex(!k->isTopLevelKey());
- keyIndexSet->addIndex(LINK(k));
- }
- }
- }
- }
- }
- void setVariableFileInfo()
- {
- OwnedRoxieString indexName(indexHelper.getFileName());
- varFileInfo.setown(resolveLFN(indexName, isOpt));
- translators.setown(new TranslatorArray) ;
- keySet.setown(varFileInfo->getKeyArray(factory->queryActivityMeta(), translators, isOpt, isLocal ? factory->queryQueryFactory().queryChannel() : 0, factory->queryQueryFactory().getEnableFieldTranslation()));
- initKeySet();
- variableInfoPending = false;
- }
- void onEOF()
- {
- callback.setManager(NULL);
- eof = true;
- tlk.clear();
- }
- public:
- CRoxieServerSimpleIndexReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
- IKeyArray *_keyArray, TranslatorArray *_translatorArray, bool _isLocal)
- : CRoxieServerActivity(_factory, _probeManager),
- readHelper((IHThorIndexReadArg &)basehelper),
- indexHelper((IHThorIndexReadArg &)basehelper),
- translators(_translatorArray),
- keySet(_keyArray),
- isLocal(_isLocal),
- remoteId(_remoteId)
- {
- rowLimit = 0;
- keyedLimit = 0;
- chooseNLimit = 0;
- indexHelper.setCallback(&callback);
- steppedExtra = static_cast<IHThorSteppedSourceExtra *>(indexHelper.selectInterface(TAIsteppedsourceextra_1));
- limitTransformExtra = static_cast<IHThorSourceLimitTransformExtra *>(indexHelper.selectInterface(TAIsourcelimittransformextra_1));
- unsigned flags = indexHelper.getFlags();
- variableFileName = allFilesDynamic || factory->queryQueryFactory().isDynamic() || ((flags & (TIRvarfilename|TIRdynamicfilename)) != 0);
- variableInfoPending = false;
- isOpt = (flags & TIRoptional) != 0;
- optimizeSteppedPostFilter = (flags & TIRunfilteredtransform) != 0;
- firstRead = true;
- accepted = 0;
- rejected = 0;
- keyedCount = 0;
- eof = false;
- rawMeta = readHelper.queryRawSteppingMeta();
- projectedMeta = readHelper.queryProjectedSteppingMeta();
- seekGEOffset = 0;
- seekSizes = NULL;
- if (rawMeta)
- {
- // MORE - should check all keys in maxFields list can actually be keyed.
- const CFieldOffsetSize * fields = rawMeta->queryFields();
- unsigned maxFields = rawMeta->getNumFields();
- seekGEOffset = fields[0].offset;
- seekSizes = new unsigned[maxFields];
- seekSizes[0] = fields[0].size;
- for (unsigned i=1; i < maxFields; i++)
- seekSizes[i] = seekSizes[i-1] + fields[i].size;
- bool hasPostFilter = readHelper.transformMayFilter() && optimizeSteppedPostFilter;
- if (projectedMeta)
- steppingMeta.init(projectedMeta, hasPostFilter);
- else
- steppingMeta.init(rawMeta, hasPostFilter);
- }
- }
- virtual const IResolvedFile *queryVarFileInfo() const
- {
- return varFileInfo;
- }
- ~CRoxieServerSimpleIndexReadActivity()
- {
- delete [] seekSizes;
- }
- virtual bool needsAllocator() const { return true; }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- firstRead = true;
- accepted = 0;
- rejected = 0;
- keyedCount = 0;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- if (steppedExtra)
- steppingMeta.setExtra(steppedExtra);
- eof = !indexHelper.canMatchAny();
- if (variableFileName)
- variableInfoPending = true;
- else
- {
- variableInfoPending = false;
- if (!keyIndexSet)
- initKeySet();
- }
- }
- virtual IIndexReadActivityInfo *queryIndexReadActivity()
- {
- if (variableInfoPending)
- setVariableFileInfo();
- return this;
- }
- virtual IKeyArray *getKeySet() const
- {
- return keySet.getLink();
- }
- virtual const IResolvedFile *getVarFileInfo() const
- {
- return varFileInfo.getLink();
- }
- virtual TranslatorArray *getTranslators() const
- {
- return translators.getLink();
- }
- virtual void mergeSegmentMonitors(IIndexReadContext *irc) const
- {
- indexHelper.createSegmentMonitors(irc); // NOTE: they will merge
- }
- virtual IRoxieServerActivity *queryActivity() { return this; }
- virtual const RemoteActivityId& queryRemoteId() const
- {
- return remoteId;
- }
-
- const void *nextInGroup()
- {
- bool matched = true;
- return nextSteppedGE(NULL, 0, matched, dummySmartStepExtra);
- }
- unsigned __int64 checkCount(unsigned __int64 limit)
- {
- unsigned numParts = keyIndexSet->numParts();
- unsigned __int64 result = 0;
- for (unsigned i = 0; i < numParts; i++)
- {
- Owned<IKeyManager> countTlk = createKeyManager(keyIndexSet->queryPart(i), 0, this);
- countTlk->setLayoutTranslator(translators->item(i));
- indexHelper.createSegmentMonitors(countTlk);
- countTlk->finishSegmentMonitors();
- result += countTlk->checkCount(limit-result);
- if (result > limit)
- break;
- }
- return result;
- }
- virtual const void *nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (eof)
- return NULL;
- if (firstRead)
- {
- if (variableInfoPending)
- setVariableFileInfo();
- rowLimit = (unsigned) readHelper.getRowLimit();
- chooseNLimit = (unsigned) readHelper.getChooseNLimit();
- unsigned numParts = keyIndexSet->numParts();
- if (!numParts)
- {
- onEOF();
- return NULL;
- }
- if (numParts > 1 || seekGEOffset)
- {
- tlk.setown(createKeyMerger(keyIndexSet, 0, seekGEOffset, this));
- // note that we don't set up translator because we don't support it. If that ever changes...
- }
- else
- {
- tlk.setown(createKeyManager(keyIndexSet->queryPart(0), 0, this));
- tlk->setLayoutTranslator(translators->item(0));
- }
- indexHelper.createSegmentMonitors(tlk);
- tlk->finishSegmentMonitors();
- if (queryTraceLevel() > 3 || ctx->queryProbeManager())
- {
- StringBuffer out;
- printKeyedValues(out, tlk, indexHelper.queryDiskRecordSize());
- CTXLOG("Using filter %s", out.str());
- if (ctx->queryProbeManager())
- ctx->queryProbeManager()->setNodeProperty(this, "filter", out.str());
- }
- tlk->reset();
- callback.setManager(tlk);
- keyedLimit = readHelper.getKeyedLimit();
- if (keyedLimit != (unsigned __int64) -1)
- {
- if ((indexHelper.getFlags() & TIRcountkeyedlimit) != 0)
- {
- unsigned __int64 count = checkCount(keyedLimit);
- if (count > keyedLimit)
- {
- if ((indexHelper.getFlags() & (TIRkeyedlimitskips|TIRkeyedlimitcreates)) == 0)
- readHelper.onKeyedLimitExceeded();
- const void * ret = NULL;
- if (indexHelper.getFlags() & TIRkeyedlimitcreates)
- ret = createKeyedLimitOnFailRow();
- onEOF();
- return ret;
- }
- keyedLimit = (unsigned __int64) -1;
- }
- }
- firstRead = false;
- }
- if (accepted == chooseNLimit)
- {
- onEOF();
- return NULL;
- }
-
- const byte * rawSeek = NULL;
- unsigned seekSize = 0;
- if (seek)
- {
- seekSize = seekSizes[numFields-1];
- rawSeek = (const byte *)seek + seekGEOffset;
- if (projectedMeta)
- {
- byte *temp = (byte *) alloca(seekSize);
- RtlStaticRowBuilder rawBuilder(temp-seekGEOffset, seekGEOffset+seekSize);
- readHelper.mapOutputToInput(rawBuilder, seek, numFields);// NOTE - weird interface to mapOutputToInput means that it STARTS writing at seekGEOffset...
- rawSeek = (byte *)temp;
- }
- #ifdef _DEBUG
- // StringBuffer seekStr;
- // for (unsigned i = 0; i < seekSize; i++)
- // {
- // seekStr.appendf("%02x ", ((unsigned char *) rawSeek)[i]);
- // }
- // DBGLOG("nextSteppedGE can skip offset %d size %d value %s", seekGEOffset, seekSize, seekStr.str());
- #endif
- }
- const byte * originalRawSeek = rawSeek;
- RtlDynamicRowBuilder rowBuilder(rowAllocator, false);
- while (rawSeek ? tlk->lookupSkip(rawSeek, seekGEOffset, seekSize) : tlk->lookup(true))
- {
- checkAbort();
- keyedCount++;
- if (keyedCount > keyedLimit)
- {
- readHelper.onKeyedLimitExceeded();
- break;
- }
- byte const * keyRow = tlk->queryKeyBuffer(callback.getFPosRef());
- #ifdef _DEBUG
- // StringBuffer recstr;
- // unsigned size = (tlk->queryRecordSize()<80) ? tlk->queryRecordSize() : 80;
- // for (unsigned i = 0; i < size; i++)
- // {
- // recstr.appendf("%02x ", ((unsigned char *) keyRow)[i]);
- // }
- // DBGLOG("nextSteppedGE Got %s", recstr.str());
- if (originalRawSeek && memcmp(keyRow + seekGEOffset, originalRawSeek, seekSize) < 0)
- assertex(!"smart seek failure");
- #endif
- size32_t transformedSize;
- rowBuilder.ensureRow();
- try
- {
- transformedSize = readHelper.transform(rowBuilder, keyRow);
- //if the post filter causes a mismatch, and the stepping condition no longer matches
- //then return a mismatch record - so the join code can start seeking on the other input.
- if (transformedSize == 0 && optimizeSteppedPostFilter && stepExtra.returnMismatches())
- {
- if (memcmp(keyRow + seekGEOffset, originalRawSeek, seekSize) != 0)
- {
- transformedSize = readHelper.unfilteredTransform(rowBuilder, keyRow);
- if (transformedSize != 0)
- wasCompleteMatch = false;
- }
- }
- callback.finishedRow();
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- if (transformedSize)
- {
- accepted++;
- if (accepted > rowLimit)
- {
- if ((indexHelper.getFlags() & (TIRlimitskips|TIRlimitcreates)) != 0)
- {
- throwUnexpected(); // should not have used simple variant if maySkip set...
- }
- if (traceLevel > 4)
- DBGLOG("activityid = %d line = %d", activityId, __LINE__);
- readHelper.onLimitExceeded();
- break;
- }
- processed++;
- #ifdef _DEBUG
- // const byte *ret = (const byte *) out.get();
- // CommonXmlWriter xmlwrite(XWFnoindent|XWFtrim|XWFopt);
- // queryOutputMeta()->toXML(ret, xmlwrite);
- // DBGLOG("ROW: {%p} %s", ret, xmlwrite.str());
- #endif
- return rowBuilder.finalizeRowClear(transformedSize);
- }
- else
- rejected++;
- rawSeek = NULL;
- }
- onEOF();
- return NULL;
- }
- virtual void reset()
- {
- onEOF();
- if (accepted)
- noteStatistic(STATS_ACCEPTED, accepted, 1);
- if (rejected)
- noteStatistic(STATS_REJECTED, rejected, 1);
- if (variableFileName)
- {
- varFileInfo.clear();
- translators.clear();
- }
- variableInfoPending = false;
- CRoxieServerActivity::reset();
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
- }
- virtual IInputSteppingMeta * querySteppingMeta()
- {
- if (rawMeta && steppingEnabled && ((indexHelper.getFlags() & (TIRlimitskips|TIRlimitcreates|TIRkeyedlimitskips|TIRkeyedlimitcreates)) == 0))
- return &steppingMeta;
- return NULL;
- }
- protected:
- const void * createKeyedLimitOnFailRow()
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- size32_t outSize = limitTransformExtra->transformOnKeyedLimitExceeded(rowBuilder);
- if (outSize)
- return rowBuilder.finalizeRowClear(outSize);
- return NULL;
- }
- };
- class CRoxieServerBaseIndexActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- Owned<IKeyArray> keySet;
- Owned<TranslatorArray> translatorArray;
- Owned<IDefRecordMeta> activityMeta;
- RemoteActivityId remoteId;
- bool isSimple;
- bool isLocal;
- bool maySkip;
- bool sorted;
- bool variableFileName;
- bool enableFieldTranslation;
- unsigned maxSeekLookahead;
- Owned<const IResolvedFile> indexfile;
- CRoxieServerSideCache *cache;
- CRoxieServerBaseIndexActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), remoteId(_remoteId)
- {
- Owned<IHThorIndexReadBaseArg> indexHelper = (IHThorIndexReadBaseArg *) helperFactory();
- unsigned flags = indexHelper->getFlags();
- sorted = (flags & TIRunordered) == 0;
- isLocal = _graphNode.getPropBool("att[@name='local']/@value") && queryFactory.queryChannel()!=0;
- rtlDataAttr indexLayoutMeta;
- size32_t indexLayoutSize;
- if(!indexHelper->getIndexLayout(indexLayoutSize, indexLayoutMeta.refdata()))
- assertex(indexLayoutSize==0);
- MemoryBuffer m;
- m.setBuffer(indexLayoutSize, indexLayoutMeta.getdata());
- activityMeta.setown(deserializeRecordMeta(m, true));
- enableFieldTranslation = queryFactory.getEnableFieldTranslation();
- translatorArray.setown(new TranslatorArray);
- variableFileName = allFilesDynamic || _queryFactory.isDynamic() || ((flags & (TIRvarfilename|TIRdynamicfilename)) != 0);
- if (!variableFileName)
- {
- bool isOpt = (flags & TIRoptional) != 0;
- OwnedRoxieString indexName(indexHelper->getFileName());
- indexfile.setown(queryFactory.queryPackage().lookupFileName(indexName, isOpt, true, true, queryFactory.queryWorkUnit()));
- if (indexfile)
- keySet.setown(indexfile->getKeyArray(activityMeta, translatorArray, isOpt, isLocal ? queryFactory.queryChannel() : 0, enableFieldTranslation));
- }
- isSimple = isLocal;
- maySkip = (flags & (TIRkeyedlimitskips|TIRlimitskips|TIRlimitcreates|TIRkeyedlimitcreates)) != 0;
- if (keySet && keySet->length()==1 && !isLocal && (flags & (TIRlimitskips|TIRlimitcreates|TIRkeyedlimitskips|TIRkeyedlimitcreates))==0)
- {
- IKeyIndexBase *thisBase = keySet->queryKeyPart(0);
- if (thisBase->numParts()==1 && !thisBase->queryPart(0)->isTopLevelKey() && !_queryFactory.getDebugValueBool("disableLocalOptimizations", false))
- isSimple = true;
- }
- int cacheSize = _graphNode.getPropInt("hint[@name='cachehits']/@value", serverSideCacheSize);
- cache = cacheSize ? new CRoxieServerSideCache(cacheSize) : NULL;
- maxSeekLookahead = _graphNode.getPropInt("hint[@name='maxseeklookahead']/@value", 0);
- }
- ~CRoxieServerBaseIndexActivityFactory()
- {
- delete cache;
- }
- virtual void getXrefInfo(IPropertyTree &reply, const IRoxieContextLogger &logctx) const
- {
- if (indexfile)
- addXrefFileInfo(reply, indexfile);
- }
- virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
- {
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for indexread activity");
- }
- virtual IRoxieServerSideCache *queryServerSideCache() const
- {
- return cache;
- }
- virtual bool getEnableFieldTranslation() const
- {
- return enableFieldTranslation;
- }
- virtual IDefRecordMeta *queryActivityMeta() const
- {
- return activityMeta;
- }
- };
- class CRoxieServerIndexReadActivityFactory : public CRoxieServerBaseIndexActivityFactory
- {
- public:
- CRoxieServerIndexReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
- : CRoxieServerBaseIndexActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- if (!variableFileName && (keySet==NULL || keySet->length()==0))
- return new CRoxieServerNullActivity(this, _probeManager);
- else if (isSimple && !maySkip)
- return new CRoxieServerSimpleIndexReadActivity(this, _probeManager, remoteId, keySet, translatorArray, isLocal);
- else
- return new CRoxieServerIndexReadActivity(this, _probeManager, remoteId, keySet, translatorArray, sorted, isLocal, maySkip, maxSeekLookahead);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerIndexReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
- {
- return new CRoxieServerIndexReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode);
- }
- //--------------------------------------------------------------------------------------------------------------------------
- class CRoxieServerNullCountActivity : public CRoxieServerActivity
- {
- bool done;
- public:
- CRoxieServerNullCountActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager)
- {
- done = false;
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- done = false;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- }
- virtual bool needsAllocator() const { return true; }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (done) return NULL;
- done = true;
- size32_t rowSize = meta.getFixedSize();
- void * nullRow = rowAllocator->createRow();
- if (rowSize == 1)
- *(byte *)nullRow = 0;
- else
- {
- assertex(rowSize == sizeof(unsigned __int64));
- *(unsigned __int64 *)nullRow = 0;
- }
- return rowAllocator->finalizeRow(rowSize, nullRow, rowSize);
- }
- };
- class CRoxieServerIndexCountActivity : public CRoxieServerIndexActivity
- {
- IHThorCompoundCountExtra & countHelper;
- IHThorSourceCountLimit * limitHelper;
- bool done;
- public:
- CRoxieServerIndexCountActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, IKeyArray * _keySet, TranslatorArray *_translators, bool _isLocal)
- : CRoxieServerIndexActivity(_factory, _probeManager, _remoteId, _keySet, _translators, false, _isLocal, false),
- countHelper((IHThorIndexCountArg &)basehelper),
- done(false)
- {
- limitHelper = static_cast<IHThorSourceCountLimit *>(basehelper.selectInterface(TAIsourcecountlimit_1));
- }
- virtual bool needsAllocator() const { return true; }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- done = false;
- CRoxieServerIndexActivity::start(parentExtractSize, parentExtract, paused);
- choosenLimit = countHelper.getChooseNLimit();
- if (limitHelper)
- {
- rowLimit = limitHelper->getRowLimit();
- keyedLimit = limitHelper->getKeyedLimit();
- }
- if (!paused)
- processAllKeys();
- }
- virtual bool processSingleKey(IKeyIndex *key, IRecordLayoutTranslator * trans)
- {
- unsigned __int64 count = 0;
- if (countHelper.hasFilter())
- {
- while (tlk->lookup(true))
- {
- try
- {
- count += countHelper.numValid(tlk->queryKeyBuffer(callback.getFPosRef()));
- callback.finishedRow();
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- accepted++;
- if (count >= choosenLimit) // MORE - what about limit?
- break;
- }
- }
- else
- count = tlk->getCount(); //MORE: GH->RKC There should be value in providing a max limit to getCount()
- if (count)
- {
- Owned<CRowArrayMessageResult> result = new CRowArrayMessageResult(ctx->queryRowManager(), false);
- if (count > choosenLimit)
- count = choosenLimit;
- void * recBuffer = rowAllocator->createRow();
- if (meta.getFixedSize() == 1)
- *(byte *)recBuffer = (byte)count;
- else
- {
- assertex(meta.getFixedSize() == sizeof(unsigned __int64));
- *(unsigned __int64 *)recBuffer = count;
- }
- recBuffer = rowAllocator->finalizeRow(meta.getFixedSize(), recBuffer, meta.getFixedSize());
- result->append(recBuffer);
- remote.injectResult(result.getClear());
- //GH->RKC for count(,choosen)/exists passing in the previous count would short-circuit this much earlier
- if (count >= choosenLimit)
- return true;
- }
- return false;
- }
- virtual void onLimitExceeded(bool isKeyed)
- {
- if (traceLevel > 4)
- DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
- if (isKeyed)
- {
- if (indexHelper.getFlags() & (TIRkeyedlimitskips|TIRkeyedlimitcreates))
- {
- if (ctx->queryDebugContext())
- ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
- throw makeLimitSkipException(true);
- }
- else
- {
- assertex(limitHelper); // Should not be able to generate exception if there was not one...
- limitHelper->onKeyedLimitExceeded();
- }
- }
- else
- {
- if (indexHelper.getFlags() & (TIRlimitskips|TIRlimitcreates))
- {
- if (ctx->queryDebugContext())
- ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
- throw makeLimitSkipException(false);
- }
- else
- {
- assertex(limitHelper);
- limitHelper->onLimitExceeded();
- }
- }
- }
- virtual const void *createLimitFailRow(bool isKeyed)
- {
- throwUnexpected();
- }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (done) return NULL;
- done = true;
- unsigned __int64 totalCount = 0;
- bool hasLimit = rowLimit != (unsigned __int64) -1;
- try
- {
- loop
- {
- const void * next = remote.nextInGroup();
- if (!next)
- break;
- if (meta.getFixedSize() == 1)
- totalCount += *(byte *)next;
- else
- totalCount += *(unsigned __int64 *) next;
- ReleaseRoxieRow(next);
- if (totalCount > rowLimit || (totalCount > choosenLimit && !hasLimit)) // can't break out early if there is a possibility of later slave throwing limit exception
- break;
- }
- if (totalCount > rowLimit)
- {
- unsigned flags = indexHelper.getFlags();
- if (flags & TIRlimitskips)
- totalCount = 0;
- else if (flags & TIRlimitcreates)
- totalCount = 1;
- else
- {
- assertex(limitHelper);
- limitHelper->onLimitExceeded();
- }
- }
- else if (totalCount > choosenLimit)
- totalCount = choosenLimit;
- }
- catch (IException *E)
- {
- if (QUERYINTERFACE(E, LimitSkipException))
- {
- totalCount = 0;
- unsigned flags = indexHelper.getFlags();
- if (E->errorCode() == KeyedLimitSkipErrorCode)
- {
- if (flags & TIRkeyedlimitcreates)
- totalCount++;
- }
- else
- {
- if (flags & TIRlimitcreates)
- totalCount++;
- }
- if (totalCount > choosenLimit)
- totalCount = choosenLimit; // would have to be weird code (and escape the optimizer...)
- E->Release();
- }
- else
- throw ;
- }
- void * result = rowAllocator->createRow();
- if (meta.getFixedSize() == 1)
- *(byte *)result = (byte)totalCount;
- else
- {
- assertex(meta.getFixedSize() == sizeof(unsigned __int64));
- *(unsigned __int64 *)result = totalCount;
- }
- return rowAllocator->finalizeRow(meta.getFixedSize(), result, meta.getFixedSize());
- }
- };
- class CRoxieServerIndexCountActivityFactory : public CRoxieServerBaseIndexActivityFactory
- {
- public:
- CRoxieServerIndexCountActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
- : CRoxieServerBaseIndexActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- if (!variableFileName && (keySet==NULL || keySet->length()==0))
- return new CRoxieServerNullCountActivity(this, _probeManager);
- // else if (isSimple)
- // return new CRoxieServerSimpleIndexCountActivity(this, keySet->queryKeyPart(0)->queryPart(0));
- else
- return new CRoxieServerIndexCountActivity(this, _probeManager, remoteId, keySet, translatorArray, isLocal);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerIndexCountActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
- {
- return new CRoxieServerIndexCountActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode);
- }
- //--------------------------------------------------------------------------------------------------------------------------
- class CRoxieServerNullIndexAggregateActivity : public CRoxieServerActivity
- {
- IHThorIndexAggregateArg &aggregateHelper;
- bool done;
- public:
- CRoxieServerNullIndexAggregateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager),
- aggregateHelper((IHThorIndexAggregateArg &)basehelper)
- {
- done = false;
- }
- virtual bool needsAllocator() const { return true; }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- done = false;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (done) return NULL;
- done = true;
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- size32_t thisSize = aggregateHelper.clearAggregate(rowBuilder);
- return rowBuilder.finalizeRowClear(thisSize);
- }
- };
- class CRoxieServerIndexAggregateActivity : public CRoxieServerIndexActivity
- {
- IHThorCompoundAggregateExtra & aggregateHelper;
- bool done;
- public:
- CRoxieServerIndexAggregateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
- IKeyArray * _keySet, TranslatorArray *_translators, bool _isLocal)
- : CRoxieServerIndexActivity(_factory, _probeManager, _remoteId, _keySet, _translators, false, _isLocal, false),
- aggregateHelper((IHThorIndexAggregateArg &)basehelper),
- done(false)
- {
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- done = false;
- CRoxieServerIndexActivity::start(parentExtractSize, parentExtract, paused);
- if (!paused)
- processAllKeys();
- }
- virtual bool needsAllocator() const { return true; }
- virtual bool processSingleKey(IKeyIndex *key, IRecordLayoutTranslator * trans)
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator, false);
- while (tlk->lookup(true))
- {
- if (!rowBuilder.exists())
- {
- rowBuilder.ensureRow();
- aggregateHelper.clearAggregate(rowBuilder);
- }
- try
- {
- aggregateHelper.processRow(rowBuilder, tlk->queryKeyBuffer(callback.getFPosRef()));
- callback.finishedRow();
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- accepted++;
- }
- if (aggregateHelper.processedAnyRows())
- {
- size32_t size = meta.getRecordSize(rowBuilder.getSelf());
- const void * recBuffer = rowBuilder.finalizeRowClear(size);
- Owned<CRowArrayMessageResult> result = new CRowArrayMessageResult(ctx->queryRowManager(), meta.isVariableSize());
- result->append(recBuffer);
- remote.injectResult(result.getClear());
- }
- return false;
- }
- virtual void onLimitExceeded(bool isKeyed)
- {
- if (traceLevel > 4)
- DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
- throwUnexpected();
- }
- virtual const void *createLimitFailRow(bool isKeyed)
- {
- throwUnexpected();
- }
- const void * gatherMerged()
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator, false);
- const void * firstRow = remote.nextInGroup();
- size32_t finalSize = 0;
- if (!firstRow)
- {
- rowBuilder.ensureRow();
- finalSize = aggregateHelper.clearAggregate(rowBuilder);
- }
- else
- {
- // NOTE need to clone this because going to modify below, could special case 1 row only
- finalSize = cloneRow(rowBuilder, firstRow, meta);
- ReleaseRoxieRow(firstRow);
- }
- loop
- {
- const void * next = remote.nextInGroup();
- if (!next)
- break;
- finalSize = aggregateHelper.mergeAggregate(rowBuilder, next);
- ReleaseRoxieRow(next);
- }
- return rowBuilder.finalizeRowClear(finalSize);
- }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (done) return NULL;
- const void * ret = gatherMerged();
- done = true;
- return ret;
- }
- };
- class CRoxieServerIndexAggregateActivityFactory : public CRoxieServerBaseIndexActivityFactory
- {
- public:
- CRoxieServerIndexAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
- : CRoxieServerBaseIndexActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- if (!variableFileName && (keySet==NULL || keySet->length()==0))
- return new CRoxieServerNullIndexAggregateActivity(this, _probeManager);
- // else if (isSimple)
- // return new CRoxieServerSimpleIndexAggregateActivity(this, keySet->queryKeyPart(0)->queryPart(0));
- else
- return new CRoxieServerIndexAggregateActivity(this, _probeManager, remoteId, keySet, translatorArray, isLocal);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerIndexAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
- {
- return new CRoxieServerIndexAggregateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode);
- }
- //--------------------------------------------------------------------------------------------------------------------------
- class CRoxieServerIndexGroupAggregateActivity : public CRoxieServerIndexActivity, implements IHThorGroupAggregateCallback
- {
- IHThorCompoundGroupAggregateExtra & aggregateHelper;
- RowAggregator singleAggregator;
- RowAggregator resultAggregator;
- unsigned groupSegCount;
- bool gathered;
- bool eof;
- public:
- CRoxieServerIndexGroupAggregateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
- IKeyArray * _keySet, TranslatorArray *_translators, bool _isLocal)
- : CRoxieServerIndexActivity(_factory, _probeManager, _remoteId, _keySet, _translators, false, _isLocal, false),
- aggregateHelper((IHThorIndexGroupAggregateArg &)basehelper),
- singleAggregator(aggregateHelper, aggregateHelper),
- resultAggregator(aggregateHelper, aggregateHelper),
- gathered(false), eof(true)
- {
- groupSegCount = 0;
- }
- IMPLEMENT_IINTERFACE
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- eof = false;
- gathered= false;
- CRoxieServerIndexActivity::start(parentExtractSize, parentExtract, paused);
- groupSegCount = 0;
- if (!paused)
- processAllKeys();
- resultAggregator.start(rowAllocator);
- }
- virtual bool needsAllocator() const { return true; }
- virtual void reset()
- {
- resultAggregator.reset();
- CRoxieServerIndexActivity::reset();
- }
- virtual void processRow(const void * next)
- {
- singleAggregator.addRow(next);
- }
- virtual void createSegmentMonitors(IKeyManager *key)
- {
- unsigned groupSegSize;
- ThorActivityKind kind = factory->getKind();
- if ((kind==TAKindexgroupcount || kind==TAKindexgroupexists))
- groupSegSize = aggregateHelper.getGroupSegmentMonitorsSize();
- else
- groupSegSize = 0;
- if (groupSegSize)
- {
- key->setMergeBarrier(groupSegSize);
- CRoxieServerIndexActivity::createSegmentMonitors(key);
- unsigned numSegs = tlk->ordinality();
- for (unsigned segNo = 0; segNo < numSegs; segNo++)
- {
- IKeySegmentMonitor *seg = tlk->item(segNo);
- if (seg->getOffset()+seg->getSize()==groupSegSize)
- {
- groupSegCount = segNo+1;
- break;
- }
- }
- assertex(groupSegCount);
- }
- else
- CRoxieServerIndexActivity::createSegmentMonitors(key);
- }
- virtual bool processSingleKey(IKeyIndex *key, IRecordLayoutTranslator * trans)
- {
- Owned<CRowArrayMessageResult> result = new CRowArrayMessageResult(ctx->queryRowManager(), meta.isVariableSize());
- singleAggregator.start(rowAllocator);
- ThorActivityKind kind = factory->getKind();
- while (tlk->lookup(true))
- {
- try
- {
- if (groupSegCount && !trans)
- {
- AggregateRowBuilder &rowBuilder = singleAggregator.addRow(tlk->queryKeyBuffer(callback.getFPosRef()));
- callback.finishedRow();
- if (kind==TAKindexgroupcount)
- {
- unsigned __int64 count = tlk->getCurrentRangeCount(groupSegCount);
- aggregateHelper.processCountGrouping(rowBuilder, count-1);
- }
- if (!tlk->nextRange(groupSegCount))
- break;
- }
- else
- {
- aggregateHelper.processRow(tlk->queryKeyBuffer(callback.getFPosRef()), this);
- callback.finishedRow();
- }
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- accepted++;
- }
- loop
- {
- Owned<AggregateRowBuilder> next = singleAggregator.nextResult();
- if (!next)
- break;
- size32_t size = next->querySize();
- result->append(next->finalizeRowClear());
- }
- remote.injectResult(result.getClear());
- singleAggregator.reset();
- return false;
- }
- virtual void onLimitExceeded(bool isKeyed)
- {
- if (traceLevel > 4)
- DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);DBGLOG("%d activityid = %d", __LINE__, activityId);
- throwUnexpected();
- }
- virtual const void *createLimitFailRow(bool isKeyed)
- {
- throwUnexpected();
- }
- void gatherMerged()
- {
- gathered = true;
- loop
- {
- const void * next = remote.nextInGroup();
- if (!next)
- break;
- resultAggregator.mergeElement(next);
- ReleaseRoxieRow(next);
- }
- }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if (eof)
- return NULL;
- if (!gathered)
- gatherMerged();
- Owned<AggregateRowBuilder> next = resultAggregator.nextResult();
- if (next)
- {
- processed++;
- return next->finalizeRowClear();
- }
- eof = true;
- return NULL;
- }
- };
- class CRoxieServerIndexGroupAggregateActivityFactory : public CRoxieServerBaseIndexActivityFactory
- {
- public:
- CRoxieServerIndexGroupAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
- : CRoxieServerBaseIndexActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- if (!variableFileName && (keySet==NULL || keySet->length()==0))
- return new CRoxieServerNullActivity(this, _probeManager);
- // else if (isSimple)
- // return new CRoxieServerSimpleIndexGroupAggregateActivity(this, keySet->queryKeyPart(0)->queryPart(0));
- else
- return new CRoxieServerIndexGroupAggregateActivity(this, _probeManager, remoteId, keySet, translatorArray, isLocal);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerIndexGroupAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
- {
- return new CRoxieServerIndexGroupAggregateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode);
- }
- //--------------------------------------------------------------------------------------------------------------------------
- class CRoxieServerIndexNormalizeActivity : public CRoxieServerIndexReadBaseActivity
- {
- IHThorCompoundNormalizeExtra & readHelper;
- public:
- CRoxieServerIndexNormalizeActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
- IKeyArray * _keySet, TranslatorArray *_translators, bool _sorted, bool _isLocal)
- : CRoxieServerIndexReadBaseActivity(_factory, _probeManager, _remoteId, _keySet, _translators, _sorted, _isLocal, false),
- readHelper((IHThorIndexNormalizeArg &)basehelper)
- {
- }
- virtual bool needsAllocator() const { return true; }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerIndexReadBaseActivity::start(parentExtractSize, parentExtract, paused);
- rowLimit = readHelper.getRowLimit();
- keyedLimit = readHelper.getKeyedLimit();
- if (!paused)
- processAllKeys();
- }
- virtual bool processSingleKey(IKeyIndex *key, IRecordLayoutTranslator * trans)
- {
- unsigned keyedCount = 0;
- RtlDynamicRowBuilder rowBuilder(rowAllocator, false);
- while (tlk->lookup(true))
- {
- keyedCount++;
- if (keyedCount > keyedLimit)
- {
- if (traceLevel > 4)
- DBGLOG("activityid = %d line = %d", activityId, __LINE__);
- onLimitExceeded(true);
- break;
- }
- size32_t transformedSize;
-
- if (readHelper.first(tlk->queryKeyBuffer(callback.getFPosRef())))
- {
- Owned<CRowArrayMessageResult> result = new CRowArrayMessageResult(ctx->queryRowManager(), meta.isVariableSize());
- do
- {
- rowBuilder.ensureRow();
- try
- {
- transformedSize = readHelper.transform(rowBuilder);
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- if (transformedSize)
- {
- // MORE - would be a good idea to stop these asap if rowlimit exceeded
- result->append(rowBuilder.finalizeRowClear(transformedSize));
- accepted++;
- }
- else
- rejected++;
- } while (readHelper.next());
- remote.injectResult(result.getClear());
- callback.finishedRow();
- }
- }
- return false;
- }
- virtual void onLimitExceeded(bool isKeyed)
- {
- if (traceLevel > 4)
- DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
- if (isKeyed)
- {
- if (indexHelper.getFlags() & (TIRkeyedlimitskips|TIRkeyedlimitcreates))
- {
- if (ctx->queryDebugContext())
- ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
- throw makeLimitSkipException(true);
- }
- else
- readHelper.onKeyedLimitExceeded();
- }
- else
- {
- if (indexHelper.getFlags() & (TIRlimitskips||TIRlimitcreates))
- {
- if (ctx->queryDebugContext())
- ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
- throw makeLimitSkipException(false);
- }
- else
- readHelper.onLimitExceeded();
- }
- }
- virtual const void *createLimitFailRow(bool isKeyed)
- {
- UNIMPLEMENTED;
- }
- };
- class CRoxieServerIndexNormalizeActivityFactory : public CRoxieServerBaseIndexActivityFactory
- {
- public:
- CRoxieServerIndexNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
- : CRoxieServerBaseIndexActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- if (!variableFileName && (keySet==NULL || keySet->length()==0))
- return new CRoxieServerNullActivity(this, _probeManager);
- else
- return new CRoxieServerIndexNormalizeActivity(this, _probeManager, remoteId, keySet, translatorArray, sorted, isLocal);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerIndexNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
- {
- return new CRoxieServerIndexNormalizeActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode);
- }
- //=================================================================================
- class CRoxieServerFetchActivity : public CRoxieServerActivity, implements IRecordPullerCallback, implements IRoxieServerErrorHandler
- {
- IHThorFetchBaseArg &helper;
- IHThorFetchContext * fetchContext;
- Linked<IFilePartMap> map;
- CRemoteResultAdaptor remote;
- RecordPullerThread puller;
- bool needsRHS;
- bool variableFileName;
- bool isOpt;
- Owned<const IResolvedFile> varFileInfo;
- public:
- CRoxieServerFetchActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, IFilePartMap *_map)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorFetchBaseArg &)basehelper), map(_map), remote(_remoteId, meta.queryOriginal(), helper, *this, true, true), puller(false)
- {
- fetchContext = static_cast<IHThorFetchContext *>(helper.selectInterface(TAIfetchcontext_1));
- needsRHS = helper.transformNeedsRhs();
- variableFileName = allFilesDynamic || factory->queryQueryFactory().isDynamic() || ((fetchContext->getFetchFlags() & (FFvarfilename|FFdynamicfilename)) != 0);
- isOpt = (fetchContext->getFetchFlags() & FFdatafileoptional) != 0;
- }
- virtual const IResolvedFile *queryVarFileInfo() const
- {
- return varFileInfo;
- }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerActivity::onCreate(_ctx, _colocalParent);
- remote.onCreate(this, this, _ctx, _colocalParent);
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- if (idx)
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
- puller.setInput(this, _in);
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- remote.onStart(parentExtractSize, parentExtract);
- remote.setLimits(helper.getRowLimit(), (unsigned __int64) -1, I64C(0x7FFFFFFFFFFFFFFF));
- if (variableFileName)
- {
- OwnedRoxieString fname(fetchContext->getFileName());
- varFileInfo.setown(resolveLFN(fname, isOpt));
- if (varFileInfo)
- map.setown(varFileInfo->getFileMap());
- }
- puller.start(parentExtractSize, parentExtract, paused, ctx->fetchPreload(), false, ctx);
- }
- virtual void stop(bool aborting)
- {
- // Called from remote, so no need to call back to it....
- puller.stop(aborting);
- CRoxieServerActivity::stop(aborting);
- }
- virtual void reset()
- {
- processed = remote.processed;
- remote.processed = 0;
- puller.reset();
- if (variableFileName)
- {
- varFileInfo.clear();
- map.clear();
- }
- CRoxieServerActivity::reset();
- }
- virtual IRoxieInput *queryOutput(unsigned idx)
- {
- if (idx==(unsigned)-1)
- idx = 0;
- return idx ? NULL : &remote;
- }
- virtual void processRow(const void *row)
- {
- // called from puller thread
- offset_t rp = fetchContext->extractPosition(row);
- unsigned partNo;
- if (isLocalFpos(rp))
- partNo = getLocalFposPart(rp) + 1;
- else
- partNo = map->mapOffset(rp);
- if (needsRHS)
- {
- Owned<IEngineRowAllocator> extractAllocator = ctx->queryCodeContext()->getRowAllocator(helper.queryExtractedSize(), activityId);
- RtlDynamicRowBuilder rb(extractAllocator, true);
- unsigned rhsSize = helper.extractJoinFields(rb, row);
- char * block = (char *) remote.getMem(partNo, 0, sizeof(rp) + sizeof(rhsSize) + rhsSize); // MORE - superfiles
- *(offset_t *) block = rp;
- block += sizeof(rp);
- *(unsigned *) block = rhsSize;
- block += sizeof(rhsSize);
- memcpy(block, rb.row(), rhsSize);
- }
- else
- *(offset_t *) remote.getMem(partNo, 0, sizeof(rp)) = rp; // MORE - superfiles
- ReleaseRoxieRow(row);
- }
- void processEOG()
- {
- #ifdef FETCH_PRESERVES_GROUPING
- UNIMPLEMENTED;
- #endif
- // else discard is correct
- }
- void processGroup(const ConstPointerArray &)
- {
- throwUnexpected();
- }
- void processDone()
- {
- // called from puller thread
- remote.flush();
- remote.senddone();
- }
- virtual bool fireException(IException *e)
- {
- return remote.fireException(e);
- }
- virtual void onLimitExceeded(bool isKeyed)
- {
- if (traceLevel > 4)
- DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
- if (isKeyed)
- throwUnexpected();
- helper.onLimitExceeded();
- }
- virtual const void *createLimitFailRow(bool isKeyed)
- {
- UNIMPLEMENTED;
- }
- virtual const void *nextInGroup()
- {
- throwUnexpected(); // I am nobody's input
- }
- };
- class CRoxieServerFetchActivityFactory : public CRoxieServerActivityFactory
- {
- RemoteActivityId remoteId;
- Owned<IFilePartMap> map;
- bool variableFileName;
- Owned<const IResolvedFile> datafile;
- public:
- CRoxieServerFetchActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), remoteId(_remoteId)
- {
- Owned<IHThorFetchBaseArg> helper = (IHThorFetchBaseArg *) helperFactory();
- IHThorFetchContext *fetchContext = static_cast<IHThorFetchContext *>(helper->selectInterface(TAIfetchcontext_1));
- variableFileName = allFilesDynamic || _queryFactory.isDynamic() || ((fetchContext->getFetchFlags() & (FFvarfilename|FFdynamicfilename)) != 0);
- if (!variableFileName)
- {
- OwnedRoxieString fname(fetchContext->getFileName());
- datafile.setown(_queryFactory.queryPackage().lookupFileName(fname,
- (fetchContext->getFetchFlags() & FFdatafileoptional) != 0,
- true, true,
- _queryFactory.queryWorkUnit()));
- if (datafile)
- map.setown(datafile->getFileMap());
- }
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerFetchActivity(this, _probeManager, remoteId, map);
- }
- virtual void getXrefInfo(IPropertyTree &reply, const IRoxieContextLogger &logctx) const
- {
- if (datafile)
- addXrefFileInfo(reply, datafile);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerFetchActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
- {
- return new CRoxieServerFetchActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode);
- }
- // MORE - is there any point keeping this now?
- class CRoxieServerDummyActivityFactory : public CRoxieServerActivityFactory // not a real activity - just used to properly link files
- {
- public:
- Owned<const IResolvedFile> indexfile;
- Owned<const IResolvedFile> datafile;
- Owned<IKeyArray> keySet;
- Owned<IFileIOArray> files;
- Owned<IFilePartMap> map;
- TranslatorArray layoutTranslators;
- CRoxieServerDummyActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool isLoadDataOnly)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- try // does not want any missing file errors to be fatal, or throw traps - just log it
- {
- if (_graphNode.getPropBool("att[@name='_isSpill']/@value", false) || _graphNode.getPropBool("att[@name='_isSpillGlobal']/@value", false))
- return; // ignore 'spills'
- bool isLocal = _graphNode.getPropBool("att[@name='local']/@value") && queryFactory.queryChannel()!=0;
- ThorActivityKind kind = getActivityKind(_graphNode);
- if (kind != TAKdiskwrite && kind != TAKindexwrite && kind != TAKpiperead && kind != TAKpipewrite)
- {
- const char *fileName = queryNodeFileName(_graphNode, kind);
- const char *indexName = queryNodeIndexName(_graphNode, kind);
- if (indexName)
- {
- bool isOpt = pretendAllOpt || _graphNode.getPropBool("att[@name='_isIndexOpt']/@value");
- indexfile.setown(queryFactory.queryPackage().lookupFileName(indexName, isOpt, true, true, queryFactory.queryWorkUnit()));
- if (indexfile)
- keySet.setown(indexfile->getKeyArray(NULL, &layoutTranslators, isOpt, isLocal ? queryFactory.queryChannel() : 0, false));
- }
- if (fileName)
- {
- bool isOpt = pretendAllOpt || _graphNode.getPropBool("att[@name='_isOpt']/@value");
- datafile.setown(_queryFactory.queryPackage().lookupFileName(fileName, isOpt, true, true, queryFactory.queryWorkUnit()));
- if (datafile)
- {
- if (isLocal)
- files.setown(datafile->getIFileIOArray(isOpt, queryFactory.queryChannel()));
- else
- map.setown(datafile->getFileMap());
- }
- }
- }
- }
- catch(IException *E)
- {
- StringBuffer errors;
- E->errorMessage(errors);
- DBGLOG("%s File error = %s", (isLoadDataOnly) ? "LOADDATAONLY" : "SUSPENDED QUERY", errors.str());
- E->Release();
- }
- }
- 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__); }
- virtual void getXrefInfo(IPropertyTree &reply, const IRoxieContextLogger &logctx) const
- {
- if (datafile)
- addXrefFileInfo(reply, datafile);
- if (indexfile)
- addXrefFileInfo(reply, indexfile);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerDummyActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool isLoadDataOnly)
- {
- return new CRoxieServerDummyActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, isLoadDataOnly);
- }
- //=====================================================================================================
- // Keyed joins...
- //
- // Input records are pulled by a puller thread, which checks each LHS record to determine which (if any) channels it
- // may have RHS matches on, and sends the relevant fields to the relevant slaves.
- // 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
- // the transform and returns rows that are created.
- // 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)
- //
- //=====================================================================================================
- class CJoinGroup;
- interface IJoinProcessor
- {
- virtual void processEOG() = 0;
- virtual CJoinGroup *createJoinGroup(const void *row) = 0;
- virtual void noteEndReceived(CJoinGroup *jg, unsigned candidateCount) = 0;
- virtual bool fireException(IException *E) = 0;
- virtual void processCompletedGroups() = 0;
- };
- //------------------------------------------------------------------------------------------------------
- // Class CJoinGroup has a record per LHS row, plus (if preserving grouping) a 'head of group' record
- // It gathers all the corresponding RHS rows, keeping track of how may slave transactions are pending in endMarkersPending
- // If preserving groups, the 'head of group' record keeps track of how many LHS records in the group are still incomplete.
- // CJoinGroup records are allocated out of the Roxie row memory manager by overloading operator new, so that they are included in the
- // per-query limits etc (Note that the pointer array block is not though).
- // Because of that, the exact size is significant - especially whether fit just under or just over a chunking threshold...
- //
- // There are two phases to the life of a JoinGroup - it is created by the puller thread that is also firing off slave requests
- // notePending will be called once for every slave request. Puller thread calls noteEndReceived(0) once when done - this corresponds to the
- // initial count when created.
- // Slave replies and are noted by the consumer thread calling addRightMatch() and noteEndReceived(n).
- // Once endMarkersPending reaches 0, JoinGroup is complete. Last thread to call noteEndReceived will process the rows and destroy the group.
- // There is no need for a critsec because although multiple threads will access at different times, only the consumer thread will
- // access any modifiable member variables while endMarkersPending != 0 (i.e. complete() is false). Once complete returns true there is a single
- // remaining reference and the JoinGroup will be processed and destroyed.
- //
- //------------------------------------------------------------------------------------------------------
- class CJoinGroup : public CInterface, implements IInterface
- {
- protected:
- const void *left; // LHS row
- PointerArrayOf<KeyedJoinHeader> rows; // matching RHS rows
- atomic_t endMarkersPending; // How many slave responses still waiting for
- CJoinGroup *groupStart; // Head of group, or NULL if not grouping
- unsigned lastPartNo;
- unsigned pos;
- unsigned candidates; // Number of RHS keyed candidates - note this may not be the same as rows.ordinality()
- public:
- #undef new
- void *operator new(size_t size, IRowManager *a, unsigned activityId)
- {
- return a->allocate(size, activityId);
- }
- #if defined(_DEBUG) && defined(_WIN32) && !defined(USING_MPATROL)
- #define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
- #endif
- void operator delete(void *ptr, IRowManager *a, unsigned activityId)
- {
- ReleaseRoxieRow(ptr);
- }
- void operator delete(void *ptr)
- {
- ReleaseRoxieRow(ptr);
- }
- public:
- IMPLEMENT_IINTERFACE;
- CJoinGroup(const void *_left, CJoinGroup *_groupStart)
- {
- #ifdef TRACE_JOINGROUPS
- DBGLOG("Creating joinGroup %p, groupstart %p", this, _groupStart);
- #endif
- candidates = 0;
- lastPartNo = 0;
- pos = 0;
- left = _left;
- groupStart = _groupStart;
- if (_groupStart)
- {
- atomic_inc(&_groupStart->endMarkersPending);
- }
- atomic_set(&endMarkersPending, 1);
- }
- ~CJoinGroup()
- {
- #ifdef TRACE_JOINGROUPS
- DBGLOG("Destroying joinGroup %p", this);
- #endif
- if (left)
- {
- ReleaseRoxieRow(left);
- ForEachItemIn(idx, rows)
- ReleaseRoxieRow(rows.item(idx));
- rows.kill();
- }
- }
- inline bool isHeadRecord() const
- {
- return left==NULL;
- }
- inline bool complete() const
- {
- return atomic_read(&endMarkersPending) == 0;
- }
- #ifdef TRACE_JOINGROUPS
- inline void notePending(unsigned lineNo)
- #else
- inline void notePending()
- #endif
- {
- assert(!complete());
- atomic_inc(&endMarkersPending);
- #ifdef TRACE_JOINGROUPS
- DBGLOG("CJoinGroup::notePending %p from %d, count became %d group count %d", this, lineNo, atomic_read(&endMarkersPending), groupStart ? atomic_read(&groupStart->endMarkersPending) : 0);
- #endif
- }
- inline bool inGroup(CJoinGroup *leader) const
- {
- return groupStart==leader;
- }
- inline const KeyedJoinHeader *queryRow(unsigned idx) const
- {
- // Single threaded by now
- assert(complete());
- return rows.item(idx);
- }
- #ifdef TRACE_JOINGROUPS
- bool noteEndReceived(unsigned candidateCount, unsigned lineNo)
- #else
- bool noteEndReceived(unsigned candidateCount)
- #endif
- {
- assert(!complete());
- if (candidateCount)
- {
- candidates += candidateCount;
- }
- #ifdef TRACE_JOINGROUPS
- 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);
- #endif
- // NOTE - as soon as endMarkersPending and groupStart->endMarkersPending are decremented to zero this object may get released asynchronously by other threads
- // There must therefore be nothing in this method after them that acceses member variables. Think of it as a delete this...
- // In particular, we can't safely reference groupStart after the dec_and_test of endMarkersPending, hence copy local first
- CJoinGroup *localGroupStart = groupStart;
- if (atomic_dec_and_test(&endMarkersPending))
- {
- if (localGroupStart)
- return atomic_dec_and_test(&localGroupStart->endMarkersPending);
- else
- return true;
- }
- else
- return false;
- }
- inline const void *queryLeft() const
- {
- return left;
- }
- void addRightMatch(KeyedJoinHeader *right)
- {
- assert(!complete());
- unsigned short partNo = right->partNo;
- if (partNo != lastPartNo)
- {
- // MORE - should we binchop? If we did we would need to be careful to find LAST match
- if (partNo > lastPartNo)
- pos = rows.length();
- while (pos>0)
- {
- if (rows.item(pos-1)->partNo <= partNo)
- break;
- pos--;
- }
- lastPartNo = partNo;
- }
- rows.add(right, pos);
- pos++;
- }
- inline unsigned rowsSeen() const
- {
- assert(complete());
- return rows.length();
- }
- inline unsigned candidateCount() const
- {
- assert(complete());
- return candidates;
- }
- };
- #ifdef TRACE_JOINGROUPS
- #define notePending() notePending(__LINE__)
- #define noteEndReceived(a) noteEndReceived(a, __LINE__)
- #endif
- class KeyedJoinRemoteAdaptor : public CRemoteResultAdaptor // MORE - not sure it should be derived from this - makes processed all wrong, for example
- {
- private:
- SafeQueueOf<const void, true> ready;
- public:
- IHThorKeyedJoinArg &helper;
- unsigned joinProcessed;
- bool isFullKey;
- bool eof;
- bool isSimple;
- bool allPulled;
- unsigned __int64 totalCycles;
- unsigned activityId;
- RecordPullerThread &puller;
- SafeQueueOf<const void, true> injected; // Used in isSimple mode
- Owned<IEngineRowAllocator> ccdRecordAllocator;
- IJoinProcessor &processor;
- KeyedJoinRemoteAdaptor(const RemoteActivityId &_remoteId, IHThorKeyedJoinArg &_helper, IRoxieServerActivity &_activity, bool _isFullKey, bool _isSimple,
- RecordPullerThread &_puller, IJoinProcessor &_processor)
- : helper(_helper),
- CRemoteResultAdaptor(_remoteId, 0, _helper, _activity, true, true),
- isFullKey(_isFullKey),
- isSimple(_isSimple),
- puller(_puller),
- processor(_processor),
- activityId(_activity.queryId())
- {
- joinProcessed = 0;
- totalCycles = 0;
- allPulled = false;
- eof = false;
- }
- virtual void onCreate(IRoxieInput *_owner, IRoxieServerErrorHandler *_errorHandler, IRoxieSlaveContext *_ctx, IHThorArg *_colocalArg)
- {
- CRemoteResultAdaptor::onCreate(_owner, _errorHandler, _ctx, _colocalArg);
- ccdRecordAllocator.setown(ctx->queryCodeContext()->getRowAllocator(QUERYINTERFACE(helper.queryJoinFieldsRecordSize(), IOutputMetaData), activityId));
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- eof = false;
- joinProcessed = 0;
- totalCycles = 0;
- allPulled = false;
- assertex(ready.ordinality()==0);
- CRemoteResultAdaptor::start(parentExtractSize, parentExtract, paused);
- }
- virtual void reset()
- {
- CRemoteResultAdaptor::reset();
- while (ready.ordinality())
- {
- const void *goer = ready.dequeue();
- if (goer)
- ReleaseRoxieRow(goer);
- }
- while (injected.ordinality())
- {
- const void *goer = injected.dequeue();
- if (goer)
- ReleaseRoxieRow(goer);
- }
- }
- inline void addResult(const void *row)
- {
- ready.enqueue(row);
- }
- virtual unsigned __int64 queryTotalCycles() const
- {
- return totalCycles;
- }
- virtual IOutputMetaData * queryOutputMeta() const
- {
- return owner->queryOutputMeta();
- }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- loop
- {
- if (eof)
- return NULL;
- processSlaveResults();
- if (ready.ordinality())
- {
- const void *result = ready.dequeue();
- if (result)
- joinProcessed++;
- return result;
- }
- else
- eof = true;
- }
- }
- private:
- void processSlaveResults()
- {
- while (!ready.ordinality())
- {
- KeyedJoinHeader *fetchedData;
- if (isSimple)
- {
- while (!allPulled && !injected.ordinality())
- {
- if (!puller.pullRecords(1))
- {
- puller.done();
- allPulled = true;
- }
- }
- fetchedData = (KeyedJoinHeader *) injected.dequeue();
- }
- else
- fetchedData = (KeyedJoinHeader *) CRemoteResultAdaptor::nextInGroup();
- if (fetchedData)
- {
- CJoinGroup *thisGroup = fetchedData->thisGroup;
- if (fetchedData->partNo == (unsigned short) -1)
- {
- #ifdef TRACE_JOINGROUPS
- CTXLOG("Got end for group %p", thisGroup);
- #endif
- unsigned candidateCount = (unsigned) fetchedData->fpos;
- ReleaseRoxieRow(fetchedData);
- processor.noteEndReceived(thisGroup, candidateCount); // note - this can throw exception. So release fetchdata before calling
- }
- else
- {
- #ifdef TRACE_JOINGROUPS
- CTXLOG("Reading another %d bytes for group %p data", ccdRecordSize, thisGroup);
- #endif
- thisGroup->addRightMatch(fetchedData);
- if (isFullKey)
- {
- #ifdef TRACE_JOINGROUPS
- CTXLOG("Calling noteEndReceived for record returned from FETCH of full keyed join");
- #endif
- processor.noteEndReceived(thisGroup, 0); // note - this can throw exception. So release fetchdata before calling
- }
- }
- }
- else
- break;
- }
- }
- };
- class CRoxieServerFullKeyedJoinHead: public CRoxieServerActivity, implements IRecordPullerCallback, implements IRoxieServerErrorHandler
- {
- IHThorKeyedJoinArg &helper;
- Owned<IKeyManager> tlk;
- Linked<IKeyArray> keySet;
- Linked<TranslatorArray> translators;
- CRemoteResultAdaptor remote;
- RecordPullerThread puller;
- IOutputMetaData *indexReadMeta;
- IJoinProcessor *joinHandler;
- bool variableIndexFileName;
- bool indexReadInputRecordVariable;
- bool isLocal;
- Owned<IEngineRowAllocator> indexReadAllocator;
- Owned<const IResolvedFile> varFileInfo;
- IRoxieInput *indexReadInput;
- IIndexReadActivityInfo *rootIndex;
- public:
- CRoxieServerFullKeyedJoinHead(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, IKeyArray * _keySet, TranslatorArray *_translators, IOutputMetaData *_indexReadMeta, IJoinProcessor *_joinHandler, bool _isLocal)
- : CRoxieServerActivity(_factory, _probeManager),
- helper((IHThorKeyedJoinArg &)basehelper),
- tlk(createKeyManager(NULL, 0, this)),
- translators(_translators),
- keySet(_keySet),
- remote(_remoteId, 0, helper, *this, true, true),
- indexReadMeta(_indexReadMeta),
- joinHandler(_joinHandler),
- puller(false),
- isLocal(_isLocal)
- {
- variableIndexFileName = allFilesDynamic || factory->queryQueryFactory().isDynamic() || ((helper.getJoinFlags() & (JFvarindexfilename|JFdynamicindexfilename)) != 0);
- indexReadInputRecordVariable = indexReadMeta->isVariableSize();
- indexReadInput = NULL;
- rootIndex = NULL;
- }
- virtual const IResolvedFile *queryVarFileInfo() const
- {
- return varFileInfo;
- }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerActivity::onCreate(_ctx, _colocalParent);
- remote.onCreate(this, this, _ctx, _colocalParent);
- indexReadAllocator.setown(ctx->queryCodeContext()->getRowAllocator(indexReadMeta, activityId));
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- if (!idx)
- puller.setInput(this, _in);
- else if (idx==1)
- indexReadInput = _in;
- else
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
- }
- virtual void serializeExtra(MemoryBuffer &out)
- {
- if (helper.getJoinFlags() & JFindexfromactivity)
- {
- assertex(rootIndex);
- const RemoteActivityId& indexId = rootIndex->queryRemoteId();
- indexId.serialize(out);
- // could mess about reserving space for length then patching it again, to avoid copy, but probably not worth it
- MemoryBuffer tmp;
- rootIndex->queryActivity()->serializeCreateStartContext(tmp);
- if (rootIndex->queryActivity()->queryVarFileInfo())
- {
- rootIndex->queryActivity()->queryVarFileInfo()->queryTimeStamp().serialize(tmp);
- tmp.append(rootIndex->queryActivity()->queryVarFileInfo()->queryCheckSum());
- }
- unsigned ctxlen = tmp.length();
- out.append(ctxlen).append(tmp);
- }
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- if (indexReadInput)
- {
- indexReadInput->start(parentExtractSize, parentExtract, true); // paused=true because we don't want to actually run the index read
- rootIndex = indexReadInput->queryIndexReadActivity();
- if (!rootIndex)
- throw MakeStringException(ROXIE_INTERNAL_ERROR,"Index in keyed join %d could not be resolved", queryId());
- }
- remote.onStart(parentExtractSize, parentExtract);
- remote.setLimits(helper.getRowLimit(), (unsigned __int64) -1, I64C(0x7FFFFFFFFFFFFFFF));
- if (rootIndex)
- {
- varFileInfo.setown(rootIndex->getVarFileInfo());
- translators.setown(rootIndex->getTranslators());
- keySet.setown(rootIndex->getKeySet());
- }
- else if (variableIndexFileName)
- {
- OwnedRoxieString indexFileName(helper.getIndexFileName());
- varFileInfo.setown(resolveLFN(indexFileName, (helper.getJoinFlags() & JFindexoptional) != 0));
- if (varFileInfo)
- {
- translators.setown(new TranslatorArray);
- keySet.setown(varFileInfo->getKeyArray(factory->queryActivityMeta(), translators, false, isLocal ? factory->queryQueryFactory().queryChannel() : 0, factory->queryQueryFactory().getEnableFieldTranslation())); // MORE - isLocal?
- }
- }
- puller.start(parentExtractSize, parentExtract, paused, ctx->fullKeyedJoinPreload(), false, ctx);
- }
- virtual void stop(bool aborting)
- {
- puller.stop(aborting);
- CRoxieServerActivity::stop(aborting);
- }
- virtual void reset()
- {
- CRoxieServerActivity::reset();
- puller.reset();
- if (varFileInfo)
- {
- keySet.clear();
- varFileInfo.clear();
- }
- }
- virtual IRoxieInput *queryOutput(unsigned idx)
- {
- if (idx==(unsigned)-1)
- idx = 0;
- return idx ? NULL : &remote;
- }
- virtual void processRow(const void *row)
- {
- // MORE - this code seems to be pretty much duplicated below in half-keyed....
- // called from front puller thread
- // buffer up an IndexRead request
- if (helper.leftCanMatch(row))
- {
- RtlDynamicRowBuilder extractedBuilder(indexReadAllocator);
- unsigned indexReadSize = helper.extractIndexReadFields(extractedBuilder, row);
- OwnedConstRoxieRow extracted;
- if (indexReadSize)
- extracted.setown(extractedBuilder.finalizeRowClear(indexReadSize));
- CJoinGroup *jg = joinHandler->createJoinGroup(row);
- for (unsigned partNo = 0; partNo < keySet->length(); partNo++)
- {
- IKeyIndexBase *thisBase = keySet->queryKeyPart(partNo);
- if (thisBase)
- {
- unsigned fileNo = 0;
- IKeyIndex *thisKey = thisBase->queryPart(fileNo);
- try
- {
- tlk->setKey(thisKey);
- tlk->setLayoutTranslator(translators->item(fileNo));
- helper.createSegmentMonitors(tlk, extracted);
- if (rootIndex)
- rootIndex->mergeSegmentMonitors(tlk);
- tlk->finishSegmentMonitors();
- tlk->reset();
- loop
- {
- typedef const void * cvp;
- if (thisKey->isTopLevelKey())
- {
- bool locallySorted = !thisKey->isFullySorted();
- while (locallySorted || tlk->lookup(false))
- {
- unsigned slavePart = locallySorted ? 0 : (unsigned) tlk->queryFpos();
- if (locallySorted || slavePart)
- {
- cvp *outputBuffer = (cvp *) remote.getMem(slavePart, fileNo, indexReadSize + sizeof(cvp) + (indexReadInputRecordVariable ? sizeof(unsigned) : 0));
- *outputBuffer++ = jg;
- if (indexReadInputRecordVariable)
- {
- *(unsigned *) outputBuffer = indexReadSize;
- outputBuffer = (cvp*) (((unsigned *) outputBuffer) + 1);
- }
- jg->notePending();
- memcpy(outputBuffer, extracted, indexReadSize);
- if (locallySorted)
- {
- for (unsigned i = 1; i < numChannels; i++)
- jg->notePending();
- break;
- }
- }
- }
- }
- else
- {
- // MORE - this code seems to be duplicated in half keyed
- unsigned accepted = 0;
- unsigned rejected = 0;
- Owned<CRowArrayMessageResult> result = new CRowArrayMessageResult(ctx->queryRowManager(), true);
- jg->notePending();
- unsigned candidateCount = 0;
- while (tlk->lookup(true))
- {
- candidateCount++;
- atomic_inc(&indexRecordsRead);
- KLBlobProviderAdapter adapter(tlk);
- offset_t recptr;
- const byte *indexRow = tlk->queryKeyBuffer(recptr);
- if (helper.indexReadMatch(extracted, indexRow, recptr, &adapter))
- {
- KeyedJoinHeader *rhs = (KeyedJoinHeader *) ctx->queryRowManager().allocate(KEYEDJOIN_RECORD_SIZE(0), activityId);
- rhs->fpos = recptr;
- rhs->thisGroup = jg;
- rhs->partNo = partNo;
- result->append(rhs);
- }
- else
- {
- rejected++;
- atomic_inc(&postFiltered);
- }
- }
- // output an end marker for the matches to this group
- KeyedJoinHeader *endMarker = (KeyedJoinHeader *) ctx->queryRowManager().allocate(KEYEDJOIN_RECORD_SIZE(0), activityId);
- endMarker->fpos = (offset_t) candidateCount;
- endMarker->thisGroup = jg;
- endMarker->partNo = (unsigned short) -1;
- result->append(endMarker);
- remote.injectResult(result.getClear());
- if (accepted)
- noteStatistic(STATS_ACCEPTED, accepted, 1);
- if (rejected)
- noteStatistic(STATS_REJECTED, rejected, 1);
- }
- if (++fileNo < thisBase->numParts())
- {
- thisKey = thisBase->queryPart(fileNo);
- tlk->setKey(thisKey);
- tlk->setLayoutTranslator(translators->item(fileNo));
- tlk->reset();
- }
- else
- break;
- }
- tlk->releaseSegmentMonitors();
- tlk->setKey(NULL);
- }
- catch (...)
- {
- tlk->releaseSegmentMonitors();
- tlk->setKey(NULL);
- throw;
- }
- }
- }
- joinHandler->noteEndReceived(jg, 0);
- }
- else
- {
- joinHandler->noteEndReceived(joinHandler->createJoinGroup(row), 0);
- }
- }
- void processGroup(const ConstPointerArray &)
- {
- throwUnexpected();
- }
- virtual void processEOG()
- {
- joinHandler->processEOG();
- }
- virtual void processDone()
- {
- // called from puller thread
- remote.flush();
- remote.senddone();
- }
- virtual void onLimitExceeded(bool isKeyed)
- {
- if (traceLevel > 4)
- DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
- if (isKeyed)
- throwUnexpected();
- helper.onLimitExceeded();
- }
- virtual const void *createLimitFailRow(bool isKeyed)
- {
- throwUnexpected();
- }
- virtual bool fireException(IException *e)
- {
- // called from puller thread on failure
- remote.fireException(LINK(e));
- return joinHandler->fireException(e);
- }
- virtual const void *nextInGroup()
- {
- throwUnexpected(); // I am nobody's input
- }
- };
- class CRoxieServerKeyedJoinBase : public CRoxieServerActivity, implements IRecordPullerCallback, implements IRoxieServerErrorHandler, implements IJoinProcessor
- {
- protected:
- IHThorKeyedJoinArg &helper;
- KeyedJoinRemoteAdaptor remote;
- RecordPullerThread puller;
- OwnedConstRoxieRow defaultRight;
- Owned<IEngineRowAllocator> defaultRightAllocator;
- unsigned joinFlags;
- unsigned atMost;
- unsigned atmostsTriggered;
- unsigned abortLimit;
- unsigned keepLimit;
- bool limitFail;
- bool limitOnFail;
- bool preserveGroups;
- bool cloneLeft;
- bool isSimple;
- bool isLocal;
- ThorActivityKind activityKind;
- CJoinGroup *groupStart;
- CriticalSection groupsCrit;
- QueueOf<CJoinGroup, false> groups;
- IRoxieInput *indexReadInput;
- IIndexReadActivityInfo *rootIndex;
- void createDefaultRight()
- {
- if (!defaultRight)
- {
- if (!defaultRightAllocator)
- defaultRightAllocator.setown(ctx->queryCodeContext()->getRowAllocator(helper.queryJoinFieldsRecordSize(), activityId));
- RtlDynamicRowBuilder rowBuilder(defaultRightAllocator);
- size32_t thisSize = helper.createDefaultRight(rowBuilder);
- defaultRight.setown(rowBuilder.finalizeRowClear(thisSize));
- }
- }
- public:
- CRoxieServerKeyedJoinBase(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _joinFlags
- , bool isFull, bool _isSimple, bool _isLocal)
- : CRoxieServerActivity(_factory, _probeManager),
- helper((IHThorKeyedJoinArg &)basehelper),
- remote(_remoteId, helper, *this, isFull, _isSimple, puller, *this),
- joinFlags(_joinFlags),
- preserveGroups(meta.isGrouped()),
- puller(false),
- isSimple(_isSimple),
- isLocal(_isLocal),
- abortLimit(0),
- keepLimit(0),
- atMost(0),
- limitFail(false),
- limitOnFail(false),
- cloneLeft(false)
- {
- groupStart = NULL;
- activityKind = _factory->getKind();
- indexReadInput = NULL;
- rootIndex = NULL;
- atmostsTriggered = 0;
- // MORE - code would be easier to read if I got more values from helper rather than passing from factory
- }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerActivity::onCreate(_ctx, _colocalParent);
- remote.onCreate(this, this, _ctx, _colocalParent);
- }
- virtual void setInput(unsigned idx, IRoxieInput *_in)
- {
- if (!idx)
- puller.setInput(this, _in);
- else if (idx==1)
- indexReadInput = _in;
- else
- throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- if (indexReadInput)
- {
- indexReadInput->start(parentExtractSize, parentExtract, true); // paused=true because we don't want to actually run the index read
- rootIndex = indexReadInput->queryIndexReadActivity();
- if (!rootIndex)
- throw MakeStringException(ROXIE_INTERNAL_ERROR,"Index in keyed join %d could not be resolved", queryId());
- }
- remote.onStart(parentExtractSize, parentExtract);
- remote.setLimits(helper.getRowLimit(), (unsigned __int64) -1, I64C(0x7FFFFFFFFFFFFFFF));
- atmostsTriggered = 0;
- atMost = helper.getJoinLimit();
- if (atMost == 0) atMost = (unsigned)-1;
- abortLimit = helper.getMatchAbortLimit();
- if (abortLimit == 0 || atMost != (unsigned) -1) abortLimit = (unsigned)-1;
- keepLimit = helper.getKeepLimit();
- if (keepLimit == 0) keepLimit = (unsigned)-1;
- getLimitType(joinFlags, limitFail, limitOnFail);
- cloneLeft = (joinFlags & JFtransformmatchesleft) != 0;
- if (joinFlags & JFleftouter)
- createDefaultRight();
- }
- virtual void stop(bool aborting)
- {
- puller.stop(aborting);
- if (indexReadInput)
- indexReadInput->stop(aborting);
- CRoxieServerActivity::stop(aborting);
- }
- virtual unsigned __int64 queryLocalCycles() const
- {
- __int64 localCycles = remote.totalCycles;
- localCycles -= puller.queryTotalCycles(); // MORE - debatable... but probably fair.
- if (localCycles < 0)
- localCycles = 0;
- return localCycles;
- }
- virtual IRoxieInput *queryInput(unsigned idx)
- {
- if (idx==0)
- return puller.queryInput();
- else if (idx==1)
- return indexReadInput;
- else
- return NULL;
- }
- virtual void reset()
- {
- totalCycles = remote.totalCycles;
- remote.totalCycles = 0;
- processed = remote.joinProcessed;
- remote.joinProcessed = 0;
- defaultRight.clear();
- if (indexReadInput)
- indexReadInput->reset();
- if (atmostsTriggered)
- noteStatistic(STATS_ATMOST, atmostsTriggered, 1);
- CRoxieServerActivity::reset();
- puller.reset();
- while (groups.ordinality())
- {
- ::Release(groups.dequeue());
- }
- }
- virtual IRoxieInput *queryOutput(unsigned idx)
- {
- if (idx==(unsigned)-1)
- idx = 0;
- return idx ? NULL : &remote;
- }
- #undef new
- virtual CJoinGroup *createJoinGroup(const void *row)
- {
- // NOTE - we need to protect access to queue, since it's also modified by consumer thread. Groupstart is only modified by puller thread.
- CriticalBlock c(groupsCrit);
- if (preserveGroups && !groupStart)
- {
- groupStart = new (&ctx->queryRowManager(), activityId) CJoinGroup(NULL, NULL);
- groups.enqueue(groupStart);
- }
- CJoinGroup *jg = new (&ctx->queryRowManager(), activityId) CJoinGroup(row, groupStart);
- groups.enqueue(jg);
- return jg;
- }
- #if defined(_DEBUG) && defined(_WIN32) && !defined(USING_MPATROL)
- #define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
- #endif
- void endGroup()
- {
- CriticalBlock c(groupsCrit);
- if (groupStart)
- noteEndReceived(groupStart, 0);
- groupStart = NULL;
- }
- virtual void noteEndReceived(CJoinGroup *jg, unsigned candidateCount)
- {
- if (jg->noteEndReceived(candidateCount))
- processCompletedGroups();
- }
- void processCompletedGroups()
- {
- loop
- {
- CriticalBlock c(groupsCrit);
- if (!groups.head()->complete())
- break;
- Owned<CJoinGroup> head = groups.dequeue();
- if (preserveGroups)
- {
- assert(head->isHeadRecord());
- assert(groups.head()->inGroup(head));
- unsigned joinGroupSize = 0;
- while (groups.ordinality() && groups.head()->inGroup(head))
- {
- Owned<CJoinGroup> finger = groups.dequeue();
- joinGroupSize += doJoinGroup(finger);
- }
- if (joinGroupSize)
- remote.addResult(NULL);
- }
- else
- doJoinGroup(head);
- if (!groups.ordinality())
- break;
- }
- }
- void failLimit(const void * left)
- {
- helper.onMatchAbortLimitExceeded();
- CommonXmlWriter xmlwrite(0);
- if (input && input->queryOutputMeta() && input->queryOutputMeta()->hasXML())
- {
- input->queryOutputMeta()->toXML((byte *) left, xmlwrite);
- }
- throw MakeStringException(ROXIE_JOIN_ERROR, "More than %d match candidates in keyed join %d for row %s", abortLimit, queryId(), xmlwrite.str());
- }
- virtual bool needsAllocator() const { return true; }
- unsigned doTransform(const void *left, const void *right, offset_t fpos_or_count, IException *except, const void **group, unsigned counter)
- {
- if (cloneLeft && !except)
- {
- LinkRoxieRow(left);
- remote.addResult((void *) left);
- return 1;
- }
-
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- unsigned outSize;
- try
- {
- outSize = except ? helper.onFailTransform(rowBuilder, left, right, fpos_or_count, except) :
- (activityKind == TAKkeyeddenormalizegroup) ? helper.transform(rowBuilder, left, right, (unsigned) fpos_or_count, group) :
- helper.transform(rowBuilder, left, right, fpos_or_count, counter);
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- if (outSize)
- {
- const void *shrunk = rowBuilder.finalizeRowClear(outSize);
- remote.addResult(shrunk);
- return 1;
- }
- else
- return 0;
- }
- unsigned doJoinGroup(CJoinGroup *jg)
- {
- unsigned matched = jg->rowsSeen();
- unsigned added = 0;
- const void *left = jg->queryLeft();
- if (jg->candidateCount() > abortLimit)
- {
- if (limitFail)
- failLimit(left);
- if (ctx->queryDebugContext())
- ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
- if (limitOnFail)
- {
- Owned<IException> except;
- try
- {
- failLimit(left);
- }
- catch(IException * e)
- {
- except.setown(e);
- }
- added = doTransform(left, defaultRight, 0, except, NULL, 0);
- }
- }
- else if (!matched || jg->candidateCount() > atMost)
- {
- if (jg->candidateCount() > atMost)
- atmostsTriggered++;
- switch (joinFlags & JFtypemask)
- {
- case JFleftouter:
- case JFleftonly:
- switch (activityKind)
- {
- case TAKkeyedjoin:
- case TAKkeyeddenormalizegroup:
- added = doTransform(left, defaultRight, 0, NULL, NULL, 0);
- break;
- case TAKkeyeddenormalize:
- LinkRoxieRow(left);
- remote.addResult((void *) left);
- added++;
- break;
- }
- break;
- }
- }
- else if (!(joinFlags & JFexclude))
- {
- unsigned idx = 0;
- switch (activityKind)
- {
- case TAKkeyedjoin:
- while (idx < matched)
- {
- const KeyedJoinHeader *rhs = jg->queryRow(idx);
- added += doTransform(left, &rhs->rhsdata, rhs->fpos, NULL, NULL, idx+1);
- if (added==keepLimit)
- break;
- idx++;
- }
- break;
- case TAKkeyeddenormalize:
- {
- OwnedConstRoxieRow newLeft;
- newLeft.set(left);
- unsigned rowSize = 0;
- unsigned rightAdded = 0;
- while (idx < matched)
- {
- const KeyedJoinHeader *rhs = jg->queryRow(idx);
- try
- {
- RtlDynamicRowBuilder rowBuilder(rowAllocator);
- size32_t transformedSize = helper.transform(rowBuilder, newLeft, &rhs->rhsdata, rhs->fpos, idx+1);
- if (transformedSize)
- {
- rowSize = transformedSize;
- newLeft.setown(rowBuilder.finalizeRowClear(rowSize));
- rightAdded++;
- if (rightAdded==keepLimit)
- break;
- }
- idx++;
- }
- catch (IException *E)
- {
- throw makeWrappedException(E);
- }
- }
- if (rowSize)
- {
- remote.addResult(newLeft.getClear());
- added++;
- }
- }
- break;
- case TAKkeyeddenormalizegroup:
- {
- ConstPointerArray extractedRows;
- while (idx < matched && idx < keepLimit)
- {
- const KeyedJoinHeader *rhs = jg->queryRow(idx);
- extractedRows.append((void *) &rhs->rhsdata);
- idx++;
- }
- added += doTransform(left, extractedRows.item(0), extractedRows.ordinality(), NULL, (const void * *)extractedRows.getArray(), 0);
- }
- break;
- }
- }
- return added;
- }
- virtual void processDone()
- {
- // called from puller thread
- remote.flush();
- remote.senddone();
- }
- virtual void onLimitExceeded(bool isKeyed)
- {
- if (traceLevel > 4)
- DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
- if (isKeyed)
- throwUnexpected();
- helper.onLimitExceeded();
- }
- virtual const void *createLimitFailRow(bool isKeyed)
- {
- throwUnexpected();
- }
- virtual bool fireException(IException *e)
- {
- // called from puller thread on failure
- return remote.fireException(e);
- }
- virtual const void *nextInGroup()
- {
- throwUnexpected(); // I am nobody's input
- }
- };
- #ifdef _MSC_VER
- #pragma warning ( push )
- #pragma warning ( disable: 4355 )
- #endif
- class CRoxieServerKeyedJoinActivity : public CRoxieServerKeyedJoinBase
- {
- CRoxieServerFullKeyedJoinHead head;
- Owned<IEngineRowAllocator> fetchInputAllocator;
- Linked<IFilePartMap> map;
- bool variableFetchFileName;
- Owned<const IResolvedFile> varFetchFileInfo;
- CachedOutputMetaData fetchInputFields;
- public:
- CRoxieServerKeyedJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_headId, IKeyArray * _key, TranslatorArray *_translators, IOutputMetaData *_indexReadMeta,
- const RemoteActivityId &_tailId, IFilePartMap *_map, unsigned _joinFlags, bool _isLocal)
- : CRoxieServerKeyedJoinBase(_factory, _probeManager, _tailId, _joinFlags, true, false, _isLocal),
- head(_factory, _probeManager, _headId, _key, _translators, _indexReadMeta, this, _isLocal),
- map(_map)
- {
- CRoxieServerKeyedJoinBase::setInput(0, head.queryOutput(0));
- variableFetchFileName = allFilesDynamic || factory->queryQueryFactory().isDynamic() || ((helper.getFetchFlags() & (FFvarfilename|FFdynamicfilename)) != 0);
- }
-
- virtual const IResolvedFile *queryVarFileInfo() const
- {
- return varFetchFileInfo;
- }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerKeyedJoinBase::onCreate(_ctx, _colocalParent);
- head.onCreate(_ctx, _colocalParent);
- fetchInputFields.set(helper.queryFetchInputRecordSize());
- fetchInputAllocator.setown(ctx->queryCodeContext()->getRowAllocator(helper.queryFetchInputRecordSize(), activityId));
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerKeyedJoinBase::start(parentExtractSize, parentExtract, paused);
- if (variableFetchFileName)
- {
- bool isFetchOpt = (helper.getFetchFlags() & FFdatafileoptional) != 0;
- OwnedRoxieString fname(helper.getFileName());
- varFetchFileInfo.setown(resolveLFN(fname, isFetchOpt));
- if (varFetchFileInfo)
- map.setown(varFetchFileInfo->getFileMap());
- }
- puller.start(parentExtractSize, parentExtract, paused, ctx->keyedJoinPreload(), false, ctx);
- }
- virtual void setInput(unsigned idx, IRoxieInput *in)
- {
- head.setInput(idx, in);
- }
- virtual void processRow(const void *_rhs)
- {
- // called from puller thread
- KeyedJoinHeader *rhs = (KeyedJoinHeader *) _rhs;
- CJoinGroup *jg = rhs->thisGroup;
- if (rhs->partNo != (unsigned short) -1)
- {
- unsigned partNo = map->mapOffset(rhs->fpos);
- RtlDynamicRowBuilder fetchBuilder(fetchInputAllocator, true);
- size32_t fisize = helper.extractFetchFields(fetchBuilder, jg->queryLeft());
- if (fetchInputFields.isVariableSize())
- {
- KeyedJoinHeader *outRow = (KeyedJoinHeader *) remote.getMem(partNo, 0, KEYEDJOIN_RECORD_SIZE(fisize + sizeof(fisize)));
- memcpy(outRow, rhs, KEYEDJOIN_RECORD_SIZE(0)); // MORE - copy constructor might be more appropriate....
- ReleaseRoxieRow(rhs);
- jg->notePending();
- memcpy(&outRow->rhsdata, &fisize, sizeof(fisize));
- memcpy((&outRow->rhsdata)+sizeof(fisize), fetchBuilder.row(), fisize);
- }
- else
- {
- KeyedJoinHeader *outRow = (KeyedJoinHeader *) remote.getMem(partNo, 0, KEYEDJOIN_RECORD_SIZE(fisize));
- memcpy(outRow, rhs, KEYEDJOIN_RECORD_SIZE(0)); // MORE - copy constructor might be more appropriate....
- ReleaseRoxieRow(rhs);
- jg->notePending();
- memcpy(&outRow->rhsdata, fetchBuilder.row(), fisize);
- }
- }
- else
- {
- unsigned candidateCount = (unsigned) rhs->fpos;
- // CTXLOG("Full keyed join - all results back from index");
- ReleaseRoxieRow(rhs);
- noteEndReceived(jg, candidateCount); // may throw exception - so release row before calling
- }
- }
- virtual void processEOG()
- {
- // called from front puller thread
- if (preserveGroups)
- endGroup();
- }
- void processGroup(const ConstPointerArray &)
- {
- throwUnexpected();
- }
- };
- #ifdef _MSC_VER
- #pragma warning ( pop )
- #endif
- class CRoxieServerHalfKeyedJoinActivity : public CRoxieServerKeyedJoinBase
- {
- IOutputMetaData *indexReadMeta;
- Owned<IEngineRowAllocator> indexReadAllocator;
- Owned<IKeyManager> tlk;
- bool variableIndexFileName;
- bool indexReadInputRecordVariable;
- Owned<const IResolvedFile> varFileInfo;
- Linked<TranslatorArray> translators;
- Linked<IKeyArray> keySet;
- Owned<IOutputMetaData> joinPrefixedMeta;
- Owned<IEngineRowAllocator> joinFieldsAllocator;
- public:
- CRoxieServerHalfKeyedJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, IKeyArray * _keySet, TranslatorArray *_translators,
- IOutputMetaData *_indexReadMeta, unsigned _joinFlags, bool _isSimple, bool _isLocal)
- : CRoxieServerKeyedJoinBase(_factory, _probeManager, _remoteId, _joinFlags, false, _isSimple, _isLocal),
- indexReadMeta(_indexReadMeta),
- tlk(createKeyManager(NULL, 0, this)),
- keySet(_keySet),
- translators(_translators)
- {
- variableIndexFileName = allFilesDynamic || factory->queryQueryFactory().isDynamic() || ((helper.getJoinFlags() & (JFvarindexfilename|JFdynamicindexfilename)) != 0);
- indexReadInputRecordVariable = indexReadMeta->isVariableSize();
- }
- virtual void serializeExtra(MemoryBuffer &out)
- {
- if (helper.getJoinFlags() & JFindexfromactivity)
- {
- assertex(rootIndex);
- const RemoteActivityId& indexId = rootIndex->queryRemoteId();
- indexId.serialize(out);
- // could mess about reserving space for length then patching it again, to avoid copy, but probably not worth it
- MemoryBuffer tmp;
- rootIndex->queryActivity()->serializeCreateStartContext(tmp);
- if (rootIndex->queryActivity()->queryVarFileInfo())
- {
- rootIndex->queryActivity()->queryVarFileInfo()->queryTimeStamp().serialize(tmp);
- tmp.append(rootIndex->queryActivity()->queryVarFileInfo()->queryCheckSum());
- }
- unsigned ctxlen = tmp.length();
- out.append(ctxlen).append(tmp);
- }
- }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- CRoxieServerKeyedJoinBase::onCreate(_ctx, _colocalParent);
- indexReadAllocator.setown(ctx->queryCodeContext()->getRowAllocator(indexReadMeta, activityId));
- IOutputMetaData *joinFieldsMeta = helper.queryJoinFieldsRecordSize();
- joinPrefixedMeta.setown(new CPrefixedOutputMeta(KEYEDJOIN_RECORD_SIZE(0), joinFieldsMeta)); // MORE - not sure if we really need this
- joinFieldsAllocator.setown(ctx->queryCodeContext()->getRowAllocator(joinPrefixedMeta, activityId));
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- CRoxieServerKeyedJoinBase::start(parentExtractSize, parentExtract, paused);
- if (rootIndex)
- {
- varFileInfo.setown(rootIndex->getVarFileInfo());
- translators.setown(rootIndex->getTranslators());
- keySet.setown(rootIndex->getKeySet());
- }
- else if (variableIndexFileName)
- {
- OwnedRoxieString indexFileName(helper.getIndexFileName());
- varFileInfo.setown(resolveLFN(indexFileName, (helper.getJoinFlags() & JFindexoptional) != 0));
- if (varFileInfo)
- {
- translators.setown(new TranslatorArray);
- keySet.setown(varFileInfo->getKeyArray(factory->queryActivityMeta(), translators, false, isLocal ? factory->queryQueryFactory().queryChannel() : 0, factory->queryQueryFactory().getEnableFieldTranslation()));
- }
- }
- puller.start(parentExtractSize, parentExtract, paused, ctx->keyedJoinPreload(), isSimple, ctx);
- }
- virtual const IResolvedFile *queryVarFileInfo() const
- {
- return varFileInfo;
- }
- virtual void reset()
- {
- CRoxieServerKeyedJoinBase::reset();
- if (varFileInfo)
- {
- keySet.clear();
- varFileInfo.clear();
- }
- }
- virtual void processRow(const void *row)
- {
- // called from front puller thread
- // buffer up an IndexRead request
- if (helper.leftCanMatch(row) && keySet)
- {
- RtlDynamicRowBuilder extractBuilder(indexReadAllocator);
- unsigned indexReadRecordSize = helper.extractIndexReadFields(extractBuilder, row);
- OwnedConstRoxieRow extracted;
- if (indexReadRecordSize)
- extracted.setown(extractBuilder.finalizeRowClear(indexReadRecordSize));
- CJoinGroup *jg = createJoinGroup(row);
- for (unsigned partNo = 0; partNo < keySet->length(); partNo++)
- {
- IKeyIndexBase *thisBase = keySet->queryKeyPart(partNo);
- if (thisBase)
- {
- unsigned fileNo = 0;
- IKeyIndex *thisKey = thisBase->queryPart(fileNo);
- tlk->setKey(thisKey);
- tlk->setLayoutTranslator(translators->item(fileNo));
- helper.createSegmentMonitors(tlk, extracted);
- if (rootIndex)
- rootIndex->mergeSegmentMonitors(tlk);
- tlk->finishSegmentMonitors();
- try
- {
- tlk->reset();
- loop
- {
- typedef const void * cvp;
- if (thisKey && thisKey->isTopLevelKey())
- {
- bool locallySorted = (!thisKey->isFullySorted());
- while (locallySorted || tlk->lookup(false))
- {
- unsigned slavePart = locallySorted ? 0 : (unsigned) tlk->queryFpos();
- if (locallySorted || slavePart)
- {
- cvp *outputBuffer = (cvp *) remote.getMem(slavePart, fileNo, indexReadRecordSize + sizeof(cvp) + (indexReadInputRecordVariable ? sizeof(unsigned) : 0));
- *outputBuffer++ = jg;
- if (indexReadInputRecordVariable)
- {
- *(unsigned *) outputBuffer = indexReadRecordSize;
- outputBuffer = (cvp *) (((unsigned *) outputBuffer) + 1);
- }
- jg->notePending();
- memcpy(outputBuffer, extracted, indexReadRecordSize);
- if (locallySorted)
- {
- for (unsigned i = 1; i < numChannels; i++)
- jg->notePending();
- break;
- }
- }
- }
- }
- else
- {
- unsigned accepted = 0;
- unsigned rejected = 0;
- Owned<CRowArrayMessageResult> result;
- if (!isSimple)
- result.setown(new CRowArrayMessageResult(ctx->queryRowManager(), true));
- // MORE - This code seems to be duplicated in keyedJoinHead
- jg->notePending();
- unsigned candidateCount = 0;
- while (tlk->lookup(true))
- {
- candidateCount++;
- atomic_inc(&indexRecordsRead);
- KLBlobProviderAdapter adapter(tlk);
- offset_t recptr;
- const byte *indexRow = tlk->queryKeyBuffer(recptr);
- if (helper.indexReadMatch(extracted, indexRow, recptr, &adapter))
- {
- RtlDynamicRowBuilder rb(joinFieldsAllocator, true);
- CPrefixedRowBuilder pb(KEYEDJOIN_RECORD_SIZE(0), rb);
- accepted++;
- KLBlobProviderAdapter adapter(tlk);
- size32_t joinFieldsSize = helper.extractJoinFields(pb, indexRow, recptr, &adapter);
- KeyedJoinHeader *rec = (KeyedJoinHeader *) rb.getUnfinalizedClear(); // lack of finalize ok as unserialized data here.
- rec->fpos = recptr;
- rec->thisGroup = jg;
- rec->partNo = partNo;
- if (isSimple)
- remote.injected.enqueue(rec);
- else
- result->append(rec);
- }
- else
- {
- rejected++;
- atomic_inc(&postFiltered);
- }
- }
- // output an end marker for the matches to this group
- KeyedJoinHeader *rec = (KeyedJoinHeader *) ctx->queryRowManager().allocate(KEYEDJOIN_RECORD_SIZE(0), activityId);
- rec->fpos = (offset_t) candidateCount;
- rec->thisGroup = jg;
- rec->partNo = (unsigned short) -1;
- if (isSimple)
- remote.injected.enqueue(rec);
- else
- {
- result->append(rec);
- remote.injectResult(result.getClear());
- }
- if (accepted)
- noteStatistic(STATS_ACCEPTED, accepted, 1);
- if (rejected)
- noteStatistic(STATS_REJECTED, rejected, 1);
- }
- if (++fileNo < thisBase->numParts())
- {
- thisKey = thisBase->queryPart(fileNo);
- tlk->setKey(thisKey);
- tlk->setLayoutTranslator(translators->item(fileNo));
- tlk->reset();
- }
- else
- break;
- }
- tlk->releaseSegmentMonitors();
- tlk->setKey(NULL);
- }
- catch (...)
- {
- tlk->releaseSegmentMonitors();
- tlk->setKey(NULL);
- throw;
- }
- }
- }
- noteEndReceived(jg, 0);
- }
- else
- {
- noteEndReceived(createJoinGroup(row), 0);
- }
- }
- virtual void processEOG()
- {
- // called from front puller thread
- if (preserveGroups)
- endGroup();
- }
- void processGroup(const ConstPointerArray &)
- {
- throwUnexpected();
- }
- };
- class CRoxieServerKeyedJoinActivityFactory : public CRoxieServerMultiInputFactory
- {
- Owned<const IResolvedFile> indexfile;
- Owned<const IResolvedFile> datafile;
- Owned<IKeyArray> keySet;
- Owned<TranslatorArray> translatorArray;
- Owned<IDefRecordMeta> activityMeta;
- RemoteActivityId headId;
- RemoteActivityId tailId;
- IOutputMetaData *indexReadMeta;
- Owned<IFilePartMap> map;
- Owned<IFileIOArray> files;
- unsigned joinFlags;
- bool isHalfKeyed;
- bool isLocal;
- bool enableFieldTranslation;
- bool variableFetchFileName;
- bool variableIndexFileName;
- bool isSimple;
- public:
- CRoxieServerKeyedJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_headId, const RemoteActivityId &_tailId, IPropertyTree &_graphNode)
- : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), headId(_headId), tailId(_tailId)
- {
- Owned<IHThorKeyedJoinArg> helper = (IHThorKeyedJoinArg *) helperFactory();
- isLocal = _graphNode.getPropBool("att[@name='local']/@value") && queryFactory.queryChannel()!=0;
- isSimple = isLocal;
- rtlDataAttr indexLayoutMeta;
- size32_t indexLayoutSize;
- if(!helper->getIndexLayout(indexLayoutSize, indexLayoutMeta.refdata()))
- assertex(indexLayoutSize== 0);
- MemoryBuffer m;
- m.setBuffer(indexLayoutSize, indexLayoutMeta.getdata());
- activityMeta.setown(deserializeRecordMeta(m, true));
- enableFieldTranslation = queryFactory.getEnableFieldTranslation();
- translatorArray.setown(new TranslatorArray);
- joinFlags = helper->getJoinFlags();
- variableIndexFileName = allFilesDynamic || _queryFactory.isDynamic() || ((joinFlags & (JFvarindexfilename|JFdynamicindexfilename)) != 0);
- variableFetchFileName = allFilesDynamic || _queryFactory.isDynamic() || ((helper->getFetchFlags() & (FFvarfilename|FFdynamicfilename)) != 0);
- if (!variableIndexFileName)
- {
- bool isOpt = (joinFlags & JFindexoptional) != 0;
- OwnedRoxieString indexFileName(helper->getIndexFileName());
- indexfile.setown(queryFactory.queryPackage().lookupFileName(indexFileName, isOpt, true, true, queryFactory.queryWorkUnit()));
- if (indexfile)
- keySet.setown(indexfile->getKeyArray(activityMeta, translatorArray, isOpt, isLocal ? queryFactory.queryChannel() : 0, enableFieldTranslation));
- }
- if (keySet && keySet->length()==1 && !isSimple)
- {
- IKeyIndexBase *thisBase = keySet->queryKeyPart(0);
- if (thisBase->numParts()==1 && !thisBase->queryPart(0)->isTopLevelKey() && !_queryFactory.getDebugValueBool("disableLocalOptimizations", false))
- isSimple = true;
- // MORE - if it's a variable filename then it MAY be simple, we don't know. Tough.
- }
- if (!simpleLocalKeyedJoins)
- isSimple = false;
- isHalfKeyed = !helper->diskAccessRequired();
- indexReadMeta = QUERYINTERFACE(helper->queryIndexReadInputRecordSize(), IOutputMetaData);
- if (!isHalfKeyed && !variableFetchFileName)
- {
- bool isFetchOpt = (helper->getFetchFlags() & FFdatafileoptional) != 0;
- datafile.setown(_queryFactory.queryPackage().lookupFileName(queryNodeFileName(_graphNode, _kind), isFetchOpt, true, true, _queryFactory.queryWorkUnit()));
- if (datafile)
- {
- if (isLocal)
- files.setown(datafile->getIFileIOArray(isFetchOpt, queryFactory.queryChannel()));
- else
- map.setown(datafile->getFileMap());
- }
- }
- }
- virtual bool getEnableFieldTranslation() const
- {
- return enableFieldTranslation;
- }
- virtual IDefRecordMeta *queryActivityMeta() const
- {
- return activityMeta;
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- if (isHalfKeyed)
- return new CRoxieServerHalfKeyedJoinActivity(this, _probeManager,
- headId, keySet, translatorArray, indexReadMeta, joinFlags, isSimple, isLocal);
- else
- return new CRoxieServerKeyedJoinActivity(this, _probeManager,
- headId, keySet, translatorArray, indexReadMeta,
- tailId, map, joinFlags, isLocal);
- }
- virtual void getXrefInfo(IPropertyTree &reply, const IRoxieContextLogger &logctx) const
- {
- if (datafile)
- addXrefFileInfo(reply, datafile);
- if (indexfile)
- addXrefFileInfo(reply, indexfile);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerKeyedJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, const RemoteActivityId &_remoteId2, IPropertyTree &_graphNode)
- {
- return new CRoxieServerKeyedJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _remoteId2, _graphNode);
- }
- //=================================================================================
- class CRoxieServerSoapActivityBase : public CRoxieServerActivity, implements ISoapCallRowProvider, implements IRoxieAbortMonitor
- {
- protected:
- Owned<ISoapCallHelper> soaphelper;
- IHThorSoapActionArg & helper;
- StringBuffer authToken;
- bool eof;
- CriticalSection crit;
- ClientCertificate *pClientCert;
- public:
- IMPLEMENT_IINTERFACE;
- CRoxieServerSoapActivityBase(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerActivity(_factory, _probeManager), helper((IHThorSoapActionArg &)basehelper)
- {
- eof = false;
- if (clientCert.certificate.length() > 0 && clientCert.privateKey.length() > 0 && clientCert.passphrase.length() > 0)
- pClientCert = &clientCert;
- else
- pClientCert = NULL;
- }
- // ISoapCallRowProvider
- virtual IHThorSoapActionArg * queryActionHelper() { return &helper; };
- virtual IHThorSoapCallArg * queryCallHelper() { return NULL; };
- virtual const void * getNextRow() { return NULL; };
- virtual void releaseRow(const void * r) { ReleaseRoxieRow(r); };
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- eof = false;
- CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
- authToken.append(ctx->queryAuthToken());
- }
- virtual void reset()
- {
- // MORE - Shouldn't we make sure thread is stopped etc???
- soaphelper.clear();
- CRoxieServerActivity::reset();
- }
- // IRoxieAbortMonitor
- virtual void checkForAbort() { checkAbort(); }
- };
- //---------------------------------------------------------------------------
- class CRoxieServerSoapRowCallActivity : public CRoxieServerSoapActivityBase
- {
- IHThorSoapCallArg & callHelper;
- public:
- CRoxieServerSoapRowCallActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerSoapActivityBase(_factory, _probeManager), callHelper((IHThorSoapCallArg &)basehelper)
- {
- }
- virtual IHThorSoapCallArg * queryCallHelper()
- {
- return &callHelper;
- }
- virtual bool needsAllocator() const { return true; }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if(eof) return NULL;
- if (soaphelper == NULL)
- {
- if (factory->getKind()==TAKhttp_rowdataset)
- soaphelper.setown(createHttpCallHelper(this, rowAllocator, authToken.str(), SCrow, pClientCert, *ctx, this));
- else
- soaphelper.setown(createSoapCallHelper(this, rowAllocator, authToken.str(), SCrow, pClientCert, *ctx, this));
- soaphelper->start();
- }
- OwnedConstRoxieRow ret = soaphelper->getRow();
- if (!ret)
- {
- eof = true;
- return NULL;
- }
- ++processed;
- return ret.getClear();
- }
- };
- class CRoxieServerSoapRowCallActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerSoapRowCallActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerSoapRowCallActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerSoapRowCallActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerSoapRowCallActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //---------------------------------------------------------------------------
- class CRoxieServerSoapRowActionActivity : public CRoxieServerSoapActivityBase
- {
- public:
- CRoxieServerSoapRowActionActivity (const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerSoapActivityBase(_factory, _probeManager)
- {}
- virtual void execute(unsigned parentExtractSize, const byte * parentExtract)
- {
- //MORE: parentExtract not passed to start - although shouldn't be a problem.
- soaphelper.setown(createSoapCallHelper(this, NULL, ctx->queryAuthToken(), SCrow, pClientCert, *ctx, this));
- soaphelper->start();
- soaphelper->waitUntilDone();
- IException *e = soaphelper->getError();
- soaphelper.clear();
- if (e)
- throw e;
- }
- virtual IRoxieInput *queryOutput(unsigned idx)
- {
- return NULL;
- }
- virtual const void *nextInGroup()
- {
- throwUnexpected(); // I am nobody's input
- }
- };
- class CRoxieServerSoapRowActionActivityFactory : public CRoxieServerActivityFactory
- {
- bool isRoot;
- public:
- CRoxieServerSoapRowActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerSoapRowActionActivity(this, _probeManager);
- }
- virtual bool isSink() const
- {
- return isRoot;
- }
- };
- IRoxieServerActivityFactory *createRoxieServerSoapRowActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
- {
- return new CRoxieServerSoapRowActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
- }
- //---------------------------------------------------------------------------
- class CRoxieServerSoapDatasetCallActivity : public CRoxieServerSoapActivityBase
- {
- IHThorSoapCallArg & callHelper;
- public:
- CRoxieServerSoapDatasetCallActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerSoapActivityBase(_factory, _probeManager), callHelper((IHThorSoapCallArg &)basehelper)
- {
- }
- virtual IHThorSoapCallArg * queryCallHelper()
- {
- return &callHelper;
- }
- virtual const void *getNextRow()
- {
- CriticalBlock b(crit);
- const void *nextrec = input->nextInGroup();
- if (!nextrec)
- {
- nextrec = input->nextInGroup();
- }
- return nextrec;
- }
- virtual bool needsAllocator() const { return true; }
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
- if(eof) return NULL;
- if (soaphelper == NULL)
- {
- soaphelper.setown(createSoapCallHelper(this, rowAllocator, authToken.str(), SCdataset, pClientCert, *ctx, this));
- soaphelper->start();
- }
- OwnedConstRoxieRow ret = soaphelper->getRow();
- if (!ret)
- {
- eof = true;
- return NULL;
- }
- ++processed;
- return ret.getClear();
- }
- };
- class CRoxieServerSoapDatasetCallActivityFactory : public CRoxieServerActivityFactory
- {
- public:
- CRoxieServerSoapDatasetCallActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerSoapDatasetCallActivity(this, _probeManager);
- }
- };
- IRoxieServerActivityFactory *createRoxieServerSoapDatasetCallActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
- {
- return new CRoxieServerSoapDatasetCallActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
- }
- //---------------------------------------------------------------------------
- class CRoxieServerSoapDatasetActionActivity : public CRoxieServerSoapActivityBase
- {
- public:
- CRoxieServerSoapDatasetActionActivity (const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
- : CRoxieServerSoapActivityBase(_factory, _probeManager)
- {}
- virtual const void *getNextRow()
- {
- CriticalBlock b(crit);
- const void *nextrec = input->nextInGroup();
- if (!nextrec)
- {
- nextrec = input->nextInGroup();
- }
- if (nextrec)
- processed++;
- return nextrec;
- }
- virtual void execute(unsigned parentExtractSize, const byte * parentExtract)
- {
- try
- {
- start(parentExtractSize, parentExtract, false);
- soaphelper.setown(createSoapCallHelper(this, NULL, ctx->queryAuthToken(), SCdataset, pClientCert, *ctx, this));
- soaphelper->start();
- soaphelper->waitUntilDone();
- IException *e = soaphelper->getError();
- soaphelper.clear();
- if (e)
- throw e;
- stop(false);
- }
- catch (IException *E)
- {
- ctx->notifyAbort(E);
- stop(true);
- throw;
- }
- catch(...)
- {
- Owned<IException> E = MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught at %s:%d", __FILE__, __LINE__);
- ctx->notifyAbort(E);
- stop(true);
- throw;
- }
- }
- virtual IRoxieInput *queryOutput(unsigned idx)
- {
- return NULL;
- }
- virtual const void *nextInGroup()
- {
- throwUnexpected(); // I am nobody's input
- }
- };
- class CRoxieServerSoapDatasetActionActivityFactory : public CRoxieServerActivityFactory
- {
- bool isRoot;
- public:
- CRoxieServerSoapDatasetActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
- : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
- {
- }
- virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
- {
- return new CRoxieServerSoapDatasetActionActivity(this, _probeManager);
- }
- virtual bool isSink() const
- {
- return isRoot;
- }
- };
- IRoxieServerActivityFactory *createRoxieServerSoapDatasetActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
- {
- return new CRoxieServerSoapDatasetActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
- }
- //=====================================================================================================
- class CGraphResults : public CInterface, implements IRoxieGraphResults
- {
- IArrayOf<IGraphResult> results;
- CriticalSection cs;
- IGraphResult & select(unsigned idx)
- {
- CriticalBlock procedure(cs);
- if (idx >= results.ordinality())
- throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Error reading graph result %d before it is calculated", idx);
- return results.item(idx);
- }
- public:
- IMPLEMENT_IINTERFACE
- void clear()
- {
- CriticalBlock procedure(cs);
- results.kill();
- }
- IRoxieInput * createIterator(unsigned id)
- {
- return select(id).createIterator();
- }
- virtual void getLinkedResult(unsigned & count, byte * * & ret, unsigned id)
- {
- select(id).getLinkedResult(count, ret);
- }
- virtual void getDictionaryResult(unsigned & count, byte * * & ret, unsigned id)
- {
- select(id).getLinkedResult(count, ret);
- }
- virtual const void * getLinkedRowResult(unsigned id)
- {
- return select(id).getLinkedRowResult();
- }
- void setResult(unsigned id, IGraphResult * result)
- {
- CriticalBlock procedure(cs);
- if (results.ordinality() <= id)
- {
- while (results.ordinality() < id)
- results.append(*new CGraphResult);
- results.append(*LINK(result));
- }
- else
- results.replace(*LINK(result), id);
- }
- void appendResult(IGraphResult * result)
- {
- CriticalBlock procedure(cs);
- results.append(*LINK(result));
- }
- };
- //===================================================================================================================
- class CPseudoArg : public CInterface, implements IHThorArg
- {
- public:
- IMPLEMENT_IINTERFACE
- virtual IOutputMetaData * queryOutputMeta() { return NULL; }
- };
- class CPseudoActivity : public CRoxieServerActivity
- {
- public:
- CPseudoActivity(IHThorArg & _helper) : CRoxieServerActivity(_helper) {}
- virtual const void *nextInGroup()
- {
- throwUnexpected(); // I am nobody's input
- }
- };
- class CActivityGraph : public CInterface, implements IActivityGraph, implements IThorChildGraph, implements ILocalGraphEx, implements IRoxieServerChildGraph
- {
- protected:
- IArrayOf<IRoxieServerActivity> activities;
- IArrayOf<IRoxieInput> probes;
- IRoxieServerActivityCopyArray sinks;
- StringAttr graphName;
- Owned<CGraphResults> results;
- CGraphResults graphLoopResults;
- ActivityArray & graphDefinition;
- CriticalSection evaluateCrit;
- IProbeManager *probeManager;
- unsigned id;
- unsigned loopCounter;
- class ActivityGraphSlaveContext : public IndirectSlaveContext
- {
- SpinLock abortLock;
- bool aborted;
- Owned<IException> exception;
- public:
- ActivityGraphSlaveContext(const IRoxieContextLogger &_logctx) : logctx(_logctx), loopCounter(0), codeContext(NULL)
- {
- aborted = false;
- }
- // Note - we must track exceptions at the child level in case there is a CATCH in parent
- virtual void notifyAbort(IException *E)
- {
- SpinBlock b(abortLock);
- if (!aborted && QUERYINTERFACE(E, InterruptedSemaphoreException) == NULL)
- {
- aborted = true;
- exception.set(E);
- }
- }
- virtual void checkAbort()
- {
- if (aborted) // NOTE - don't bother getting lock before reading this (for speed) - a false read is very unlikely and not a problem
- {
- SpinBlock b(abortLock);
- if (!exception)
- exception.setown(MakeStringException(ROXIE_INTERNAL_ERROR, "Query was aborted"));
- throw exception.getLink();
- }
- IndirectSlaveContext::checkAbort();
- }
- virtual ICodeContext *queryCodeContext()
- {
- return codeContext;
- }
- void setCodeContext(ICodeContext * _codeContext)
- {
- codeContext = _codeContext;
- }
- void setLoopCounter(unsigned _loopCounter)
- {
- loopCounter = _loopCounter;
- }
- virtual void noteChildGraph(unsigned id, IActivityGraph *childGraph)
- {
- childGraphs.setValue(id, childGraph);
- }
- virtual IActivityGraph * queryChildGraph(unsigned id)
- {
- if (queryTraceLevel() > 10)
- CTXLOG("resolveChildGraph %d", id);
- IActivityGraph *childGraph = childGraphs.getValue(id);
- assertex(childGraph);
- return childGraph;
- }
- // 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
- virtual StringBuffer &getLogPrefix(StringBuffer &ret) const
- {
- logctx.getLogPrefix(ret);
- if (loopCounter)
- ret.appendf("{%u}", loopCounter);
- return ret;
- }
- protected:
- const IRoxieContextLogger &logctx;
- unsigned loopCounter;
- ICodeContext * codeContext;
- MapXToMyClass<unsigned, unsigned, IActivityGraph> childGraphs;
- } graphSlaveContext;
- class ActivityGraphCodeContext : public IndirectCodeContext
- {
- public:
- virtual IEclGraphResults * resolveLocalQuery(__int64 activityId)
- {
- if ((unsigned) activityId == container->queryId())
- return container;
- IActivityGraph * match = slaveContext->queryChildGraph((unsigned) activityId);
- if (match)
- return match->queryLocalGraph();
- return IndirectCodeContext::resolveLocalQuery(activityId);
- }
- virtual IThorChildGraph * resolveChildQuery(__int64 activityId, IHThorArg * colocal)
- {
- IActivityGraph * match = slaveContext->queryChildGraph((unsigned) activityId);
- return LINK(match->queryChildGraph());
- }
- virtual unsigned getGraphLoopCounter() const
- {
- return container->queryLoopCounter(); // only called if value is valid
- }
- void setContainer(IRoxieSlaveContext * _slaveContext, CActivityGraph * _container)
- {
- slaveContext = _slaveContext;
- container = _container;
- }
- protected:
- IRoxieSlaveContext * slaveContext;
- CActivityGraph * container;
- } graphCodeContext;
- public:
- IMPLEMENT_IINTERFACE;
- CActivityGraph(const char *_graphName, unsigned _id, ActivityArray &x, IProbeManager *_probeManager, const IRoxieContextLogger &_logctx)
- : probeManager(_probeManager), graphDefinition(x), graphName(_graphName), graphSlaveContext(_logctx)
- {
- id = x.getLibraryGraphId();
- if (!id)
- id = _id;
- loopCounter = 0;
- graphSlaveContext.setCodeContext(&graphCodeContext);
- graphCodeContext.setContainer(&graphSlaveContext, this);
- }
- ~CActivityGraph()
- {
- if (probeManager)
- probeManager->deleteGraph((IArrayOf<IActivityBase>*)&activities, (IArrayOf<IInputBase>*)&probes);
- }
- virtual const char *queryName() const
- {
- return graphName.get();
- }
- void createGraph()
- {
- ForEachItemIn(idx, graphDefinition)
- {
- IRoxieServerActivityFactory &donor = graphDefinition.serverItem(idx);
- IRoxieServerActivity &activity = *donor.createActivity(probeManager);
- activities.append(activity);
- if (donor.isSink())
- {
- sinks.append(activity);
- if (probeManager)
- probeManager->noteSink(&activity);
- }
- }
- ForEachItemIn(idx1, graphDefinition)
- {
- IRoxieServerActivityFactory &donor = graphDefinition.serverItem(idx1);
- IRoxieServerActivity &activity = activities.item(idx1);
- unsigned inputidx = 0;
- loop
- {
- unsigned outputidx;
- unsigned source = donor.getInput(inputidx, outputidx);
- if (source==(unsigned) -1)
- break;
- connectInput(idx1, inputidx, source, outputidx, 0);
- inputidx++;
- }
- IntArray &dependencies = donor.queryDependencies();
- IntArray &dependencyIndexes = donor.queryDependencyIndexes();
- IntArray &dependencyControlIds = donor.queryDependencyControlIds();
- StringArray &dependencyEdgeIds = donor.queryDependencyEdgeIds();
- ForEachItemIn(idx2, dependencies)
- {
- IRoxieServerActivity &dependencySourceActivity = activities.item(dependencies.item(idx2));
- unsigned dependencySourceIndex = dependencyIndexes.item(idx2);
- unsigned dependencyControlId = dependencyControlIds.item(idx2);
- activity.addDependency(dependencySourceActivity, dependencySourceIndex, dependencyControlId);
- if (probeManager)
- probeManager->noteDependency( &dependencySourceActivity, dependencySourceIndex, dependencyControlId, dependencyEdgeIds.item(idx2), &activity);
- }
- }
- }
- void connectInput(unsigned target, unsigned targetIdx, unsigned source, unsigned sourceIdx, unsigned iteration)
- {
- IRoxieServerActivity &targetActivity = activities.item(target);
- IRoxieServerActivity &sourceActivity = activities.item(source);
- IRoxieInput * output = sourceActivity.queryOutput(sourceIdx);
- if (probeManager)
- {
- IInputBase * inputBase = probeManager->createProbe(static_cast<IInputBase*>(output), &sourceActivity, &targetActivity, sourceIdx, targetIdx, iteration);
- output = static_cast<IRoxieInput*>(inputBase);
- probes.append(*LINK(output));
- }
- targetActivity.setInput(targetIdx, output);
- }
- virtual void onCreate(IRoxieSlaveContext *ctx, IHThorArg *_colocalParent)
- {
- graphSlaveContext.set(ctx);
- if (graphDefinition.isMultiInstance())
- {
- graphCodeContext.set(ctx->queryCodeContext());
- ctx = &graphSlaveContext;
- }
- ForEachItemIn(idx, activities)
- {
- IRoxieServerActivity *activity = &activities.item(idx);
- if (activity)
- activity->onCreate(ctx, _colocalParent);
- }
- }
- virtual void abort()
- {
- ForEachItemIn(idx, sinks)
- {
- IRoxieServerActivity &sink = sinks.item(idx);
- sink.stop(true);
- }
- }
- virtual void reset()
- {
- ForEachItemIn(idx, sinks)
- {
- IRoxieServerActivity &sink = sinks.item(idx);
- sink.reset();
- }
- }
- Linked<IException> exception;
- CriticalSection eCrit;
- virtual void noteException(IException *E)
- {
- CriticalBlock b(eCrit);
- if (!exception)
- {
- if (graphSlaveContext.queryDebugContext())
- {
- graphSlaveContext.queryDebugContext()->checkBreakpoint(DebugStateException, NULL, exception);
- }
- exception.set(E);
- }
- }
- virtual void checkAbort()
- {
- CriticalBlock b(eCrit);
- if (exception)
- throw exception.getLink();
- }
- virtual void execute()
- {
- results.setown(new CGraphResults);
- doExecute(0, NULL);
- }
- //New child query code...
- virtual IThorChildGraph * queryChildGraph()
- {
- return this;
- }
- virtual IEclGraphResults * queryLocalGraph()
- {
- return this;
- }
- virtual IRoxieServerChildGraph * queryLoopGraph()
- {
- return this;
- }
- inline unsigned queryId() const
- {
- return id;
- }
- inline unsigned queryLoopCounter() const
- {
- return loopCounter;
- }
- void doExecute(unsigned parentExtractSize, const byte * parentExtract)
- {
- if (sinks.ordinality()==1)
- sinks.item(0).execute(parentExtractSize, parentExtract);
- #ifdef PARALLEL_EXECUTE
- else if (!probeManager && !graphDefinition.isSequential())
- {
- class casyncfor: public CAsyncFor
- {
- public:
- IActivityGraph &parent;
- unsigned parentExtractSize;
- const byte * parentExtract;
- casyncfor(IRoxieServerActivityCopyArray &_sinks, IActivityGraph &_parent, unsigned _parentExtractSize, const byte * _parentExtract) :
- sinks(_sinks), parent(_parent), parentExtractSize(_parentExtractSize), parentExtract(_parentExtract) { }
- void Do(unsigned i)
- {
- try
- {
- sinks.item(i).execute(parentExtractSize, parentExtract);
- }
- catch (IException *E)
- {
- parent.noteException(E);
- throw;
- }
- }
- private:
- IRoxieServerActivityCopyArray &sinks;
- } afor(sinks, *this, parentExtractSize, parentExtract);
- afor.For(sinks.ordinality(), sinks.ordinality());
- }
- #endif
- else
- {
- ForEachItemIn(idx, sinks)
- {
- IRoxieServerActivity &sink = sinks.item(idx);
- sink.execute(parentExtractSize, parentExtract);
- }
- }
- }
- virtual IEclGraphResults *evaluate(unsigned parentExtractSize, const byte * parentExtract)
- {
- CriticalBlock block(evaluateCrit);
- results.setown(new CGraphResults);
- try
- {
- doExecute(parentExtractSize, parentExtract);
- }
- catch (...)
- {
- DBGLOG("Exception thrown in child query - cleaning up");
- reset();
- throw;
- }
- reset();
- return results.getClear();
- }
- //interface IRoxieServerChildGraph
- virtual void beforeExecute()
- {
- results.setown(new CGraphResults);
- }
- virtual IRoxieInput * startOutput(unsigned id, unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- IRoxieInput * ret = selectOutput(id);
- ret->start(parentExtractSize, parentExtract, paused);
- return ret;
- }
- virtual IRoxieInput * selectOutput(unsigned id)
- {
- ForEachItemIn(i, sinks)
- {
- IRoxieInput * ret = sinks.item(i).querySelectOutput(id);
- if (ret)
- return ret;
- }
- throwUnexpected();
- return NULL;
- }
- virtual void setInputResult(unsigned id, IGraphResult * result)
- {
- results->setResult(id, result);
- }
- virtual bool querySetInputResult(unsigned id, IRoxieInput * input)
- {
- ForEachItemIn(i, activities)
- {
- if (activities.item(i).querySetStreamInput(id, input))
- return true;
- }
- return false;
- }
- virtual void stopUnusedOutputs()
- {
- //Hmm not sure how to do this...
- }
- virtual void afterExecute()
- {
- ForEachItemIn(i, sinks)
- {
- sinks.item(i).stop(false);
- }
- if (graphSlaveContext.queryDebugContext())
- {
- graphSlaveContext.queryDebugContext()->checkBreakpoint(DebugStateGraphFinished, NULL, NULL);
- }
- reset();
- }
- virtual IRoxieGraphResults * execute(size32_t parentExtractSize, const byte *parentExtract)
- {
- doExecute(parentExtractSize, parentExtract);
- return LINK(results);
- }
- virtual void getLinkedResult(unsigned & count, byte * * & ret, unsigned id)
- {
- results->getLinkedResult(count, ret, id);
- }
- virtual void getDictionaryResult(unsigned & count, byte * * & ret, unsigned id)
- {
- results->getLinkedResult(count, ret, id);
- }
- virtual const void * getLinkedRowResult(unsigned id)
- {
- return results->getLinkedRowResult(id);
- }
- virtual void setResult(unsigned id, IGraphResult * result)
- {
- results->setResult(id, result);
- }
- virtual IRoxieInput * createResultIterator(unsigned id)
- {
- return results->createIterator(id);
- }
- virtual void setGraphLoopResult(IGraphResult * result)
- {
- graphLoopResults.appendResult(result);
- }
- virtual IRoxieInput * createGraphLoopResultIterator(unsigned id)
- {
- try
- {
- return graphLoopResults.createIterator(id);
- }
- catch (IException * e)
- {
- e->Release();
- throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Error reading graph result %d before it is calculated", id);
- }
- }
- virtual void clearGraphLoopResults()
- {
- graphLoopResults.clear();
- }
- virtual void executeGraphLoop(size32_t parentExtractSize, const byte *parentExtract)
- {
- doExecute(parentExtractSize, parentExtract);
- }
- virtual void setGraphLoopResult(unsigned id, IGraphResult * result)
- {
- graphLoopResults.setResult(id, result);
- }
- virtual IRoxieInput * getGraphLoopResult(unsigned id)
- {
- return graphLoopResults.createIterator(id);
- }
- virtual void getProbeResponse(IPropertyTree *query)
- {
- if (probeManager)
- probeManager->getProbeResponse(query);
- }
- virtual IRoxieServerChildGraph * createGraphLoopInstance(unsigned loopCounter, unsigned parentExtractSize, const byte * parentExtract, const IRoxieContextLogger &logctx)
- {
- throwUnexpected();
- }
- virtual CGraphIterationInfo *selectGraphLoopOutput()
- {
- return NULL;
- }
- virtual void gatherIterationUsage(IRoxieServerLoopResultProcessor & processor)
- {
- throwUnexpected();
- }
- virtual void associateIterationOutputs(IRoxieServerLoopResultProcessor & processor)
- {
- throwUnexpected();
- }
- };
- class CIterationActivityGraph : public CActivityGraph
- {
- IHThorArg * colocalParent;
- unsigned fixedParentExtractSize;
- const byte * fixedParentExtract;
- unsigned graphOutputActivityIndex;
- public:
- CIterationActivityGraph(const char *_graphName, unsigned _id, ActivityArray &x, IProbeManager *_probeManager,
- unsigned _loopCounter, IRoxieSlaveContext *ctx, IHThorArg * _colocalParent, unsigned parentExtractSize, const byte * parentExtract, const IRoxieContextLogger &_logctx)
- : CActivityGraph(_graphName, _id, x, _probeManager, _logctx)
- {
- graphOutputActivityIndex = 0;
- loopCounter = _loopCounter;
- colocalParent = _colocalParent;
- graphSlaveContext.set(ctx);
- graphSlaveContext.setLoopCounter(loopCounter);
- graphCodeContext.set(ctx->queryCodeContext());
- fixedParentExtractSize = parentExtractSize;
- fixedParentExtract = parentExtract;
- }
- void createIterationGraph()
- {
- Owned<IRoxieServerActivity> pseudoActivity = new CPseudoActivity(*new CPseudoArg);
- ForEachItemIn(idx1, graphDefinition)
- activities.append(*LINK(pseudoActivity));
- graphOutputActivityIndex = queryGraphOutputIndex();
- recursiveCreateGraph(graphOutputActivityIndex);
- }
- unsigned queryGraphOutputIndex() const
- {
- ForEachItemIn(i, graphDefinition)
- if (graphDefinition.serverItem(i).getKind() == TAKgraphloopresultwrite)
- return i;
- throwUnexpected();
- }
- void recursiveCreateGraph(unsigned whichActivity)
- {
- //Check to see if already created
- IRoxieServerActivity & prevActivity = activities.item(whichActivity);
- if (prevActivity.queryId() != 0)
- {
- prevActivity.noteOutputUsed(); //We need to patch up the number of outputs for splitters.
- return;
- }
- IRoxieServerActivityFactory &donor = graphDefinition.serverItem(whichActivity);
- IRoxieServerActivity * activity = NULL;
- if (donor.isGraphInvariant())
- {
- ThorActivityKind kind = donor.getKind();
- switch (kind)
- {
- case TAKif:
- case TAKchildif:
- case TAKcase:
- case TAKchildcase: // MORE RKC->GH - what about FILTER with a graph-invariant condition and other latestart activities?
- {
- Owned<IHThorArg> helper = &donor.getHelper();
- helper->onCreate(&graphCodeContext, colocalParent, NULL);
- helper->onStart(fixedParentExtract, NULL);
- unsigned branch;
- switch (kind)
- {
- case TAKif: case TAKchildif:
- branch = static_cast<IHThorIfArg *>(helper.get())->getCondition() ? 0 : 1;
- break;
- case TAKcase: case TAKchildcase:
- branch = static_cast<IHThorCaseArg *>(helper.get())->getBranch();
- if (branch >= donor.numInputs())
- branch = donor.numInputs() - 1;
- break;
- default:
- throwUnexpected();
- }
- helper.clear();
- unsigned outputidx;
- unsigned source = donor.getInput(branch, outputidx);
- if (source ==(unsigned) -1)
- activity = createRoxieServerNullActivity(&donor, probeManager);
- else
- activity = createRoxieServerPassThroughActivity(&donor, probeManager);
- activities.replace(*activity, whichActivity);
- activity->onCreate(&graphSlaveContext, colocalParent);
- if (source ==(unsigned) -1)
- return;
- recursiveCreateGraph(source);
- connectInput(whichActivity, 0, source, outputidx, loopCounter);
- break;
- }
- }
- }
- if (!activity)
- {
- activity = donor.createActivity(probeManager);
- activities.replace(*activity, whichActivity);
- activity->onCreate(&graphSlaveContext, colocalParent);
- activity->resetOutputsUsed();
- unsigned inputidx = 0;
- loop
- {
- unsigned outputidx;
- unsigned source = donor.getInput(inputidx, outputidx);
- if (source==(unsigned) -1)
- break;
- recursiveCreateGraph(source);
- connectInput(whichActivity, inputidx, source, outputidx, loopCounter);
- inputidx++;
- }
- }
- IntArray &dependencies = donor.queryDependencies();
- IntArray &dependencyIndexes = donor.queryDependencyIndexes();
- IntArray &dependencyControlIds = donor.queryDependencyControlIds();
- ForEachItemIn(idx2, dependencies)
- {
- unsigned input = dependencies.item(idx2);
- recursiveCreateGraph(input);
- activity->addDependency(activities.item(input),dependencyIndexes.item(idx2),dependencyControlIds.item(idx2));
- }
- }
- virtual CGraphIterationInfo *selectGraphLoopOutput()
- {
- IRoxieServerActivity &sourceActivity = activities.item(graphOutputActivityIndex);
- return new CGraphIterationInfo(&sourceActivity, sourceActivity.queryOutput(0), 0, loopCounter);
- }
- virtual void gatherIterationUsage(IRoxieServerLoopResultProcessor & processor)
- {
- ForEachItemIn(i, activities)
- activities.item(i).gatherIterationUsage(processor, fixedParentExtractSize, fixedParentExtract);
- }
- virtual void associateIterationOutputs(IRoxieServerLoopResultProcessor & processor)
- {
- ForEachItemIn(i, activities)
- activities.item(i).associateIterationOutputs(processor, fixedParentExtractSize, fixedParentExtract, probeManager, probes);
- }
- };
- class CDelayedActivityGraph : public CInterface, implements IActivityGraph
- {
- StringAttr graphName;
- ActivityArray & graphDefinition;
- IProbeManager *probeManager;
- unsigned id;
- IRoxieSlaveContext * ctx;
- IHThorArg * colocalParent;
- public:
- IMPLEMENT_IINTERFACE;
- CDelayedActivityGraph(const char *_graphName, unsigned _id, ActivityArray &x, IProbeManager *_probeManager)
- : probeManager(_probeManager), graphDefinition(x)
- {
- graphName.set(_graphName);
- id = _id;
- ctx = NULL;
- colocalParent = NULL;
- }
- virtual const char *queryName() const { return graphName.get(); }
- virtual void abort() { throwUnexpected(); }
- virtual void reset() { }
- virtual void execute() { throwUnexpected(); }
- virtual void getProbeResponse(IPropertyTree *query) { throwUnexpected(); }
- virtual void noteException(IException *E) { throwUnexpected(); }
- virtual void checkAbort() { throwUnexpected(); }
- virtual IThorChildGraph * queryChildGraph() { throwUnexpected(); }
- virtual IEclGraphResults * queryLocalGraph() { throwUnexpected(); }
- virtual IRoxieServerChildGraph * queryLoopGraph() { throwUnexpected(); }
- virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
- {
- ctx = _ctx;
- colocalParent = _colocalParent;
- }
- virtual IRoxieServerChildGraph * createGraphLoopInstance(unsigned loopCounter, unsigned parentExtractSize, const byte * parentExtract, const IRoxieContextLogger &logctx)
- {
- Owned<CIterationActivityGraph> ret = new CIterationActivityGraph(graphName, id, graphDefinition, probeManager, loopCounter, ctx, colocalParent, parentExtractSize, parentExtract, logctx);
- ret->createIterationGraph();
- return ret.getClear();
- }
- };
- IActivityGraph *createActivityGraph(const char *_graphName, unsigned id, ActivityArray &childFactories, IRoxieServerActivity *parentActivity, IProbeManager *_probeManager, const IRoxieContextLogger &_logctx)
- {
- if (childFactories.isDelayed())
- {
- return new CDelayedActivityGraph(_graphName, id, childFactories, _probeManager);
- }
- else
- {
- Owned<IProbeManager> childProbe;
- if (_probeManager)
- childProbe.setown(_probeManager->startChildGraph(id, parentActivity));
- Owned<CActivityGraph> ret = new CActivityGraph(_graphName, id, childFactories, childProbe, _logctx);
- ret->createGraph();
- if (_probeManager)
- _probeManager->endChildGraph(childProbe, parentActivity);
- return ret.getClear();
- }
- }
- //================================================================================================================
- #ifdef _USE_CPPUNIT
- #include "unittests.hpp"
- // 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...
- #if _MSC_VER==1200
- #undef protected
- #endif
- static const char *sortAlgorithm;
- class TestMetaData : public CInterface, implements IOutputMetaData
- {
- public:
- IMPLEMENT_IINTERFACE;
- virtual size32_t getRecordSize(const void *) { return 10; }
- virtual size32_t getMinRecordSize() const { return 10; }
- virtual size32_t getFixedSize() const { return 10; }
- virtual void toXML(const byte * self, IXmlWriter & out) {}
- virtual unsigned getVersion() const { return OUTPUTMETADATA_VERSION; }
- virtual unsigned getMetaFlags() { return 0; }
- virtual void destruct(byte * self) {}
- virtual IOutputRowSerializer * createDiskSerializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
- virtual IOutputRowDeserializer * createDiskDeserializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
- virtual ISourceRowPrefetcher * createDiskPrefetcher(ICodeContext * ctx, unsigned activityId) { return NULL; }
- virtual IOutputMetaData * querySerializedDiskMeta() { return NULL; }
- virtual IOutputRowSerializer * createInternalSerializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
- virtual IOutputRowDeserializer * createInternalDeserializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
- virtual void walkIndirectMembers(const byte * self, IIndirectMemberVisitor & visitor) {}
- virtual IOutputMetaData * queryChildMeta(unsigned i) { return NULL; }
- } testMeta;
- class TestInput : public CInterface, implements IRoxieInput
- {
- char const * const *input;
- IRoxieSlaveContext *ctx;
- unsigned endSeen;
- bool eof;
- unsigned count;
- unsigned __int64 totalCycles;
- size32_t recordSize;
- unsigned activityId;
- public:
- enum { STATEreset, STATEstarted, STATEstopped } state;
- bool allRead;
- IMPLEMENT_IINTERFACE;
- TestInput(IRoxieSlaveContext *_ctx, char const * const *_input)
- {
- ctx = _ctx;
- input = _input;
- count = 0;
- eof = false;
- allRead = false;
- endSeen = 0;
- recordSize = testMeta.getFixedSize();
- state = STATEreset;
- totalCycles = 0;
- activityId = 1;
- }
- virtual IOutputMetaData * queryOutputMeta() const { return &testMeta; }
- virtual void prestart(unsigned parentExtractSize, const byte *parentExtract)
- {
- ASSERT(state == STATEreset);
- }
- virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
- {
- ASSERT(state == STATEreset);
- state = STATEstarted;
- }
- virtual IRoxieServerActivity *queryActivity()
- {
- throwUnexpected();
- }
- virtual IIndexReadActivityInfo *queryIndexReadActivity()
- {
- throwUnexpected();
- }
- virtual void stop(bool aborting)
- {
- state = STATEstopped;
- }
- virtual void reset()
- {
- ASSERT(state == STATEstopped);
- eof = false; count = 0; endSeen = 0; allRead = false; state = STATEreset; totalCycles = 0;
- }
- virtual void resetEOF()
- {
- throwUnexpected();
- }
- virtual void checkAbort() {}
- virtual unsigned queryId() const { return activityId; };
- virtual const void *nextInGroup()
- {
- ActivityTimer t(totalCycles, ctx->queryTimeActivities(), ctx->queryDebugContext());
- ASSERT(state == STATEstarted);
- ASSERT(allRead || !eof);
- if (eof)
- return NULL;
- const char *nextSource = input[count++];
- if (nextSource)
- {
- endSeen = 0;
- void *ret = ctx->queryRowManager().ALLOCATE(recordSize);
- memset(ret, 0, recordSize);
- strncpy((char *) ret, nextSource, recordSize);
- return ret;
- }
- else
- {
- endSeen++;
- if (endSeen==2)
- eof = true;
- return NULL;
- }
- }
- virtual bool nextGroup(ConstPointerArray & group)
- {
- const void * next;
- while ((next = nextInGroup()) != NULL)
- group.append(next);
- if (group.ordinality())
- return true;
- return false;
- }
- virtual unsigned __int64 queryTotalCycles() const { return totalCycles; }
- virtual unsigned __int64 queryLocalCycles() const { return totalCycles; }
- virtual IRoxieInput *queryInput(unsigned idx) const
- {
- return NULL;
- }
- };
- struct SortActivityTest : public ccdserver_hqlhelper::CThorSortArg {
- public:
- struct CompareClass : public ICompare {
- virtual int docompare(const void * _left, const void * _right) const {
- return memcmp(_left, _right, 5);
- }
- } compare;
- virtual ICompare * queryCompare() { return &compare; }
- virtual IOutputMetaData * queryOutputMeta()
- {
- return &testMeta;
- }
- virtual unsigned getAlgorithmFlags() { return TAFunstable; }
- virtual const char * getAlgorithm() { return sortAlgorithm; }
- };
- extern "C" IHThorArg * sortActivityTestFactory() { return new SortActivityTest; }
- struct MergeActivityTest : public ccdserver_hqlhelper::CThorMergeArg {
- static bool isDedup;
- public:
- struct CompareClass : public ICompare {
- virtual int docompare(const void * _left, const void * _right) const {
- return memcmp(_left, _right, 5);
- }
- } compare;
- virtual ICompare * queryCompare() { return &compare; }
- virtual IOutputMetaData * queryOutputMeta()
- {
- return &testMeta;
- }
- virtual bool dedup() { return isDedup; }
- };
- bool MergeActivityTest::isDedup = false;
- extern "C" IHThorArg * mergeActivityTestFactory() { return new MergeActivityTest; }
- class CcdServerTest : public CppUnit::TestFixture
- {
- CPPUNIT_TEST_SUITE(CcdServerTest);
- CPPUNIT_TEST(testSetup);
- CPPUNIT_TEST(testHeapSort);
- CPPUNIT_TEST(testInsertionSort);
- CPPUNIT_TEST(testQuickSort);
- CPPUNIT_TEST(testMerge);
- CPPUNIT_TEST(testMergeDedup);
- CPPUNIT_TEST(testMiscellaneous);
- CPPUNIT_TEST(testCleanup);
- CPPUNIT_TEST_SUITE_END();
- protected:
- SlaveContextLogger logctx;
- Owned<const IQueryDll> queryDll;
- Owned<IRoxiePackage> package;
- Owned<IRoxieSlaveContext> ctx;
- Owned<IQueryFactory> queryFactory;
- void testSetup()
- {
- roxiemem::setTotalMemoryLimit(false, 100 * 1024 * 1024, 0, NULL);
- }
- void testCleanup()
- {
- roxiemem::releaseRoxieHeap();
- }
- void init()
- {
- package.setown(createRoxiePackage(NULL, NULL));
- ctx.setown(createSlaveContext(NULL, logctx, 0, 50*1024*1024, NULL));
- queryDll.setown(createExeQueryDll("roxie"));
- queryFactory.setown(createServerQueryFactory("test", queryDll.getLink(), *package, NULL, false, false));
- timer->reset();
- }
- void testActivity(IRoxieServerActivity *activity, char const * const *input, char const * const *output)
- {
- testActivity(activity, input, NULL, output);
- }
- void testActivity(IRoxieServerActivity *activity, char const * const *input, char const * const *input2, char const * const *output)
- {
- TestInput in(ctx, input);
- TestInput in2(ctx, input2);
- IRoxieInput *out = activity->queryOutput(0);
- IOutputMetaData *meta = out->queryOutputMeta();
- activity->setInput(0, &in);
- if (input2)
- activity->setInput(1, &in2);
- void *buf = alloca(meta->getFixedSize());
- for (unsigned iteration = 0; iteration < 8; iteration++)
- {
- // 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)
- // This should be true whether we read all, some, or none of the data.
- // Should not matter if an activity is not started
- if (iteration % 4 == 0)
- activity->onCreate(ctx, NULL);
- unsigned count = 0;
- if (iteration % 4 != 3)
- {
- activity->start(0, NULL, false);
- ASSERT(in.state == TestInput::STATEstarted);
- ASSERT(!input2 || in2.state == TestInput::STATEstarted);
- loop
- {
- const void *next = out->nextInGroup();
- if (!next)
- {
- ASSERT(output[count++] == NULL);
- next = out->nextInGroup();
- if (!next)
- {
- ASSERT(output[count++] == NULL);
- break;
- }
- }
- ASSERT(output[count] != NULL);
- unsigned outsize = meta->getRecordSize(next);
- memset(buf, 0, outsize);
- strncpy((char *) buf, output[count++], outsize);
- ASSERT(memcmp(next, buf, outsize) == 0);
- ReleaseRoxieRow(next);
- if (iteration % 4 == 2)
- break;
- }
- if (iteration % 4 != 2)
- {
- // Check that reading after end is harmless
- in.allRead = true;
- const void *next = out->nextInGroup();
- ASSERT(next == NULL);
- }
- }
- activity->stop(false);
- ASSERT(in.state == TestInput::STATEstopped);
- ASSERT(!input2 || in2.state == TestInput::STATEstopped);
- activity->reset();
- ASSERT(in.state == TestInput::STATEreset);
- ASSERT(!input2 || in2.state == TestInput::STATEreset);
- ctx->queryRowManager().reportLeaks();
- ASSERT(ctx->queryRowManager().numPagesAfterCleanup(true) == 0);
- }
- }
- static int compareFunc(const void *l, const void *r)
- {
- return strcmp(*(char **) l, *(char **) r);
- }
- void testSort(unsigned type)
- {
- init();
- sortAlgorithm = NULL;
- if (type==2)
- sortAlgorithm = "heapSort";
- else if (type == 1)
- sortAlgorithm = "insertionSort";
- else
- sortAlgorithm = "quickSort";
- DBGLOG("Testing %s activity", sortAlgorithm);
- Owned <IRoxieServerActivityFactory> factory = createRoxieServerSortActivityFactory(1, 1, *queryFactory, sortActivityTestFactory, TAKsort);
- Owned <IRoxieServerActivity> activity = factory->createActivity(NULL);
- const char * test[] = { NULL, NULL };
- const char * test12345[] = { "1", "2", "3", "4", "5", NULL, NULL };
- const char * test54321[] = { "5", "4", "3", "2", "1", NULL, NULL };
- const char * test11111[] = { "1", "1", "1", "1", "1", NULL, NULL };
- const char * test11111_12345[] = { "1", "1", "1", "1", "1", NULL, "1", "2", "3", "4", "5", NULL, NULL };
- const char * test11111_54321[] = { "1", "1", "1", "1", "1", NULL, "5", "4", "3", "2", "1", NULL, NULL };
- const char * test54321_54321[] = { "5", "4", "3", "2", "1", NULL, "5", "4", "3", "2", "1", NULL, NULL };
- const char * test12345_12345[] = { "1", "2", "3", "4", "5", NULL, "1", "2", "3", "4", "5", NULL, NULL };
- testActivity(activity, test, test);
- testActivity(activity, test12345, test12345);
- testActivity(activity, test54321, test12345);
- testActivity(activity, test11111, test11111);
- testActivity(activity, test11111_12345, test11111_12345);
- testActivity(activity, test11111_54321, test11111_12345);
- testActivity(activity, test54321_54321, test12345_12345);
- // A few larger tests
- char *input[2002];
- char *output[2002];
- input[2000] = input[2001] = output[2000] = output[2001] = NULL;
- unsigned i;
- // identical
- for (i=0; i<2000; i++)
- {
- input[i] = new char[11];
- output[i] = new char[11];
- sprintf(input[i], "1");
- sprintf(output[i], "1");
- }
- testActivity(activity, input, output);
- // Ascending
- for (i=0; i<2000; i++)
- {
- sprintf(input[i], "%04d", i);
- sprintf(output[i], "%04d", i);
- }
- testActivity(activity, input, output);
- // Almost sorted
- for (i=0; i<20; i++)
- {
- unsigned h = i*100;
- sprintf(input[h], "%04d", 1900-h);
- }
- testActivity(activity, input, output);
- // Descending
- for (i=0; i<2000; i++)
- {
- sprintf(input[i], "%04d", 1999-i);
- sprintf(output[i], "%04d", i);
- }
- testActivity(activity, input, output);
- // Random
- for (i=0; i<2000; i++)
- {
- unsigned r = rand() % 1500;
- sprintf(input[i], "%04d", r);
- sprintf(output[i], "%04d", r);
- }
- qsort(output, 2000, sizeof(output[0]), compareFunc);
- testActivity(activity, input, output);
- #if 0
- // Random
- #define BIGSORTSIZE 1000000
- char **linput = new char*[BIGSORTSIZE +2];
- char **loutput = new char *[BIGSORTSIZE+2];
- linput[BIGSORTSIZE] = linput[BIGSORTSIZE+1] = loutput[BIGSORTSIZE] = loutput[BIGSORTSIZE+1] = NULL;
- for (i=0; i<BIGSORTSIZE; i++)
- {
- unsigned r = rand() % 15000;
- linput[i] = loutput[i] = new char[11];
- sprintf(linput[i], "%04d", r);
- }
- qsort(loutput, BIGSORTSIZE, 4, compareFunc);
- testActivity(activity, linput, loutput);
- for (i=0; i<BIGSORTSIZE; i++)
- {
- delete [] linput[i];
- }
- delete [] linput;
- delete [] loutput;
- #endif
- unsigned __int64 us = cycle_to_nanosec(factory->queryLocalCycles()/1000);
- DBGLOG("Simple %s sorts: activity time %u.%u ms", type==2?"Heap" : (type==1 ? "Insertion" : "Quick"), (int)(us/1000), (int)(us%1000));
- factory->resetNodeProgressInfo();
- if (type)
- {
- // Other than quicksort, it's supposed to be stable. Let's check that it is
- // All sort identical
- for (i=0; i<2000; i++)
- {
- sprintf(input[i], "1 %d", i);
- sprintf(output[i], "1 %d", i);
- }
- testActivity(activity, input, output);
- // Already sorted
- for (i=0; i<2000; i++)
- {
- sprintf(input[i], "%04d %d", i / 10, i);
- sprintf(output[i], "%04d %d", i / 10, i);
- }
- testActivity(activity, input, output);
- // Reverse order
- for (i=0; i<2000; i++)
- {
- sprintf(input[i], "%04d %d", 199 - (i / 10), i%10);
- sprintf(output[i], "%04d %d", i / 10, i%10);
- }
- testActivity(activity, input, output);
- }
- for (i=0; i<2000; i++)
- {
- delete [] input[i];
- delete [] output[i];
- }
- DBGLOG("Finished testing %s sort", type==2?"Heap" : (type==1 ? "Insertion" : "Quick"));
- }
- void testQuickSort()
- {
- testSort(0);
- }
- void testInsertionSort()
- {
- testSort(1);
- }
- void testHeapSort()
- {
- testSort(2);
- }
- void testMerge()
- {
- DBGLOG("testMerge");
- init();
- Owned <IRoxieServerActivityFactory> factory = createRoxieServerMergeActivityFactory(1, 1, *queryFactory, mergeActivityTestFactory, TAKmerge);
- factory->setInput(0,0,0);
- factory->setInput(1,0,0);
- Owned <IRoxieServerActivity> activity = factory->createActivity(NULL);
- const char * test[] = { NULL, NULL };
- const char * test12345[] = { "1", "2", "3", "4", "5", NULL, NULL };
- const char * test1122334455[] = { "1", "1", "2", "2", "3", "3", "4", "4", "5", "5", NULL, NULL };
- const char * test11111[] = { "1", "1", "1", "1", "1", NULL, NULL };
- const char * test1111111111[] = { "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", NULL, NULL };
- const char * test11111_12345[] = { "1", "1", "1", "1", "1", NULL, "1", "2", "3", "4", "5", NULL, NULL };
- const char * test1111112345[] = { "1", "1", "1", "1", "1", "1", "2", "3", "4", "5", NULL, NULL };
- 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 };
-
- testActivity(activity, test, test, test);
- testActivity(activity, test12345, test, test12345);
- testActivity(activity, test, test12345, test12345);
- testActivity(activity, test12345, test12345, test1122334455);
- testActivity(activity, test11111, test, test11111);
- testActivity(activity, test, test11111, test11111);
- testActivity(activity, test11111, test11111, test1111111111);
- testActivity(activity, test11111_12345, test, test1111112345);
- testActivity(activity, test11111_12345, test11111_12345, test11111111111122334455);
- // Should really test WHICH side gets kept...
- // Should test with more than 2 inputs...
- DBGLOG("testMerge done");
- }
- void testMergeDedup()
- {
- DBGLOG("testMergeDedup");
- init();
- MergeActivityTest::isDedup = true;
- Owned <IRoxieServerActivityFactory> factory = createRoxieServerMergeActivityFactory(1, 1, *queryFactory, mergeActivityTestFactory, TAKmerge);
- factory->setInput(0,0,0);
- factory->setInput(1,0,0);
- Owned <IRoxieServerActivity> activity = factory->createActivity(NULL);
- const char * test[] = { NULL, NULL };
- const char * test12345[] = { "1", "2", "3", "4", "5", NULL, NULL };
- const char * test11111[] = { "1", "1", "1", "1", "1", NULL, NULL };
- const char * test11111_12345[] = { "1", "1", "1", "1", "1", NULL, "1", "2", "3", "4", "5", NULL, NULL };
- const char * test1111112345[] = { "1", "1", "1", "1", "1", "1", "2", "3", "4", "5", NULL, NULL };
-
- testActivity(activity, test11111, test, test11111); // No dedup within a stream
- testActivity(activity, test11111, test11111, test11111); // No dedup within a stream
- testActivity(activity, test, test11111, test11111);
- testActivity(activity, test, test, test);
- testActivity(activity, test12345, test, test12345);
- testActivity(activity, test, test12345, test12345);
- testActivity(activity, test12345, test12345, test12345);
- testActivity(activity, test11111_12345, test, test1111112345);
- testActivity(activity, test11111_12345, test11111_12345, test1111112345);
- // Should really test WHICH side gets kept...
- // Should test with more than 2 inputs...
- DBGLOG("testMergeDedup done");
- }
- void testMiscellaneous()
- {
- DBGLOG("sizeof(CriticalSection)=%u", (unsigned) sizeof(CriticalSection));
- DBGLOG("sizeof(SpinLock)=%u", (unsigned) sizeof(SpinLock));
- DBGLOG("sizeof(CJoinGroup)=%u", (unsigned) sizeof(CJoinGroup));
- ASSERT(sizeof(CJoinGroup) <= 120);
- }
- };
- CPPUNIT_TEST_SUITE_REGISTRATION( CcdServerTest );
- CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( CcdServerTest, "CcdServerTest" );
- #endif
|