ccdactivities.cpp 205 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "platform.h"
  14. #include "jlib.hpp"
  15. #include "ccd.hpp"
  16. #include "ccdquery.hpp"
  17. #include "ccdstate.hpp"
  18. #include "ccdserver.hpp"
  19. #include "ccdcontext.hpp"
  20. #include "ccddebug.hpp"
  21. #include "ccdactivities.hpp"
  22. #include "ccdqueue.ipp"
  23. #include "ccdsnmp.hpp"
  24. #include "ccdfile.hpp"
  25. #include "ccdkey.hpp"
  26. #include "rtlkey.hpp"
  27. #include "eclrtl_imp.hpp"
  28. #include "rtlread_imp.hpp"
  29. #include "jhtree.hpp"
  30. #include "jlog.hpp"
  31. #include "jmisc.hpp"
  32. #include "udplib.hpp"
  33. #include "csvsplitter.hpp"
  34. #include "thorxmlread.hpp"
  35. #include "thorcommon.ipp"
  36. #include "jstats.h"
  37. size32_t diskReadBufferSize = 0x10000;
  38. using roxiemem::OwnedRoxieRow;
  39. using roxiemem::OwnedConstRoxieRow;
  40. using roxiemem::OwnedRoxieString;
  41. using roxiemem::IRowManager;
  42. #define maxContinuationSize 48000 // note - must fit in the 2-byte length field... but also needs to be possible to send back from Roxie server->slave in one packet
  43. size32_t serializeRow(IOutputRowSerializer * serializer, IMessagePacker *output, const void *unserialized)
  44. {
  45. CSizingSerializer sizer;
  46. serializer->serialize(sizer, (const byte *) unserialized);
  47. unsigned serializedLength = sizer.size();
  48. void *udpBuffer = output->getBuffer(serializedLength, true);
  49. CRawRowSerializer memSerializer(serializedLength, (byte *) udpBuffer);
  50. serializer->serialize(memSerializer, (const byte *) unserialized);
  51. assertex(memSerializer.size() == serializedLength);
  52. output->putBuffer(udpBuffer, serializedLength, true);
  53. return serializedLength;
  54. }
  55. inline void appendBuffer(IMessagePacker * output, size32_t size, const void * data, bool isVariable)
  56. {
  57. void *recBuffer = output->getBuffer(size, isVariable);
  58. memcpy(recBuffer, data, size);
  59. output->putBuffer(recBuffer, size, isVariable);
  60. }
  61. extern void putStatsValue(IPropertyTree *node, const char *statName, const char *statType, unsigned __int64 val)
  62. {
  63. if (val)
  64. {
  65. StringBuffer xpath;
  66. xpath.appendf("att[@name='%s']", statName);
  67. IPropertyTree *att = node->queryPropTree(xpath.str());
  68. if (!att)
  69. {
  70. att = node->addPropTree("att", createPTree());
  71. att->setProp("@name", statName);
  72. }
  73. att->setProp("@type", statType);
  74. att->setPropInt64("@value", val);
  75. }
  76. }
  77. extern void putStatsValue(StringBuffer &reply, const char *statName, const char *statType, unsigned __int64 val)
  78. {
  79. if (val)
  80. {
  81. reply.appendf(" <att name='%s' type='%s' value='%"I64F"d'/>\n", statName, statType, val);
  82. }
  83. }
  84. CActivityFactory::CActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  85. : id(_id),
  86. subgraphId(_subgraphId),
  87. queryFactory(_queryFactory),
  88. helperFactory(_helperFactory),
  89. kind(_kind)
  90. {
  91. if (helperFactory)
  92. {
  93. Owned<IHThorArg> helper = helperFactory();
  94. meta.set(helper->queryOutputMeta());
  95. }
  96. }
  97. void CActivityFactory::addChildQuery(unsigned id, ActivityArray *childQuery)
  98. {
  99. childQueries.append(*childQuery);
  100. childQueryIndexes.append(id);
  101. }
  102. ActivityArray *CActivityFactory::queryChildQuery(unsigned idx, unsigned &id)
  103. {
  104. if (childQueries.isItem(idx))
  105. {
  106. id = childQueryIndexes.item(idx);
  107. return &childQueries.item(idx);
  108. }
  109. id = 0;
  110. return NULL;
  111. }
  112. class CSlaveActivityFactory : public CActivityFactory, implements ISlaveActivityFactory
  113. {
  114. public:
  115. CSlaveActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  116. : CActivityFactory(_graphNode.getPropInt("@id", 0), _subgraphId, _queryFactory, _helperFactory, getActivityKind(_graphNode))
  117. {
  118. }
  119. virtual IQueryFactory &queryQueryFactory() const
  120. {
  121. return CActivityFactory::queryQueryFactory();
  122. }
  123. void addChildQuery(unsigned id, ActivityArray *childQuery)
  124. {
  125. CActivityFactory::addChildQuery(id, childQuery);
  126. }
  127. StringBuffer &toString(StringBuffer &ret) const
  128. {
  129. return ret.appendf("%p", this);
  130. }
  131. bool getEnableFieldTranslation() const
  132. {
  133. return queryFactory.getEnableFieldTranslation();
  134. }
  135. const char *queryQueryName() const
  136. {
  137. return queryFactory.queryQueryName();
  138. }
  139. virtual ActivityArray *queryChildQuery(unsigned idx, unsigned &id)
  140. {
  141. return CActivityFactory::queryChildQuery(idx, id);
  142. }
  143. virtual unsigned queryId() const
  144. {
  145. return CActivityFactory::queryId();
  146. }
  147. virtual ThorActivityKind getKind() const
  148. {
  149. return CActivityFactory::getKind();
  150. }
  151. virtual void noteStatistics(const StatsCollector &fromStats)
  152. {
  153. CActivityFactory::noteStatistics(fromStats);
  154. }
  155. virtual void getEdgeProgressInfo(unsigned idx, IPropertyTree &edge) const
  156. {
  157. CActivityFactory::getEdgeProgressInfo(idx, edge);
  158. }
  159. virtual void getNodeProgressInfo(IPropertyTree &node) const
  160. {
  161. CActivityFactory::getNodeProgressInfo(node);
  162. }
  163. virtual void resetNodeProgressInfo()
  164. {
  165. CActivityFactory::resetNodeProgressInfo();
  166. }
  167. virtual void getActivityMetrics(StringBuffer &reply) const
  168. {
  169. CActivityFactory::getActivityMetrics(reply);
  170. }
  171. IRoxieSlaveContext *createSlaveContext(SlaveContextLogger &logctx, IRoxieQueryPacket *packet) const
  172. {
  173. return queryFactory.createSlaveContext(logctx, packet);
  174. }
  175. virtual void getXrefInfo(IPropertyTree &reply, const IRoxieContextLogger &logctx) const
  176. {
  177. if (datafile)
  178. addXrefFileInfo(reply, datafile);
  179. }
  180. IRoxieSlaveContext *createChildQueries(IHThorArg *colocalArg, IArrayOf<IActivityGraph> &childGraphs, IProbeManager *_probeManager, SlaveContextLogger &logctx, IRoxieQueryPacket *packet) const
  181. {
  182. if (!childQueries.length())
  183. logctx.setDebuggerActive(false);
  184. if (meta.needsDestruct() || meta.needsSerializeDisk() || childQueries.length())
  185. {
  186. Owned<IRoxieSlaveContext> queryContext = queryFactory.createSlaveContext(logctx, packet);
  187. ForEachItemIn(idx, childQueries)
  188. {
  189. if (!_probeManager) // MORE - the probeAllRows is a hack!
  190. _probeManager = queryContext->queryProbeManager();
  191. IActivityGraph *childGraph = createActivityGraph(NULL, childQueryIndexes.item(idx), childQueries.item(idx), NULL, _probeManager, logctx); // MORE - the parent is wrong!
  192. childGraphs.append(*childGraph);
  193. queryContext->noteChildGraph(childQueryIndexes.item(idx), childGraph);
  194. childGraph->onCreate(queryContext, colocalArg); //NB: onCreate() on helper for activities in child graph are delayed, otherwise this would go wrong.
  195. }
  196. return queryContext.getClear();
  197. }
  198. return NULL;
  199. }
  200. Owned<const IResolvedFile> datafile;
  201. protected:
  202. static IPropertyTree *queryStatsNode(IPropertyTree *parent, const char *xpath)
  203. {
  204. StringBuffer levelx;
  205. const char *sep = strchr(xpath, '/');
  206. if (sep)
  207. levelx.append(sep-xpath, xpath);
  208. else
  209. levelx.append(xpath);
  210. IPropertyTree *child = parent->queryPropTree(levelx);
  211. if (!child)
  212. {
  213. const char *id = strchr(levelx, '[');
  214. if (!id)
  215. {
  216. child = createPTree(levelx);
  217. parent->addPropTree(levelx, child);
  218. }
  219. else
  220. {
  221. StringBuffer elem;
  222. elem.append(id-levelx, levelx);
  223. child = createPTree(elem);
  224. parent->addPropTree(elem, child);
  225. loop
  226. {
  227. StringBuffer attr, val;
  228. id++;
  229. while (*id != '=')
  230. attr.append(*id++);
  231. id++;
  232. char qu = *id++;
  233. while (*id != qu)
  234. val.append(*id++);
  235. child->setProp(attr, val);
  236. id++;
  237. if (*id == ']')
  238. {
  239. if (id[1]!='[')
  240. break;
  241. id++;
  242. }
  243. else
  244. throwUnexpected();
  245. }
  246. }
  247. }
  248. if (sep)
  249. return queryStatsNode(child, sep+1);
  250. else
  251. return child;
  252. }
  253. };
  254. //================================================================================================
  255. class CRoxieSlaveActivity : public CInterface, implements IRoxieSlaveActivity, implements ICodeContext
  256. {
  257. protected:
  258. SlaveContextLogger &logctx;
  259. Linked<IRoxieQueryPacket> packet;
  260. mutable Owned<IRoxieSlaveContext> queryContext; // bit of a hack but easier than changing the ICodeContext callback interface to remove const
  261. const CSlaveActivityFactory *basefactory;
  262. IArrayOf<IActivityGraph> childGraphs;
  263. IHThorArg *basehelper;
  264. PartNoType lastPartNo;
  265. MemoryBuffer serializedCreate;
  266. MemoryBuffer resentInfo;
  267. CachedOutputMetaData meta;
  268. Owned<IOutputRowSerializer> serializer;
  269. Owned<IEngineRowAllocator> rowAllocator;
  270. #ifdef _DEBUG
  271. Owned<IProbeManager> probeManager;
  272. #endif
  273. bool aborted;
  274. bool resent;
  275. bool isOpt;
  276. bool variableFileName;
  277. bool allowFieldTranslation;
  278. Owned<const IResolvedFile> varFileInfo;
  279. virtual void setPartNo(bool filechanged) = 0;
  280. inline void checkPartChanged(PartNoType &newPart)
  281. {
  282. if (newPart.partNo!=lastPartNo.partNo || newPart.fileNo!=lastPartNo.fileNo)
  283. {
  284. lastPartNo.partNo = newPart.partNo;
  285. bool filechanged = lastPartNo.fileNo != newPart.fileNo;
  286. lastPartNo.fileNo = newPart.fileNo;
  287. setPartNo(filechanged);
  288. }
  289. }
  290. virtual bool needsRowAllocator()
  291. {
  292. return meta.needsSerializeDisk() || meta.isVariableSize();
  293. }
  294. virtual void onCreate()
  295. {
  296. #ifdef _DEBUG
  297. // MORE - need to consider debugging....
  298. if (probeAllRows)
  299. {
  300. probeManager.setown(createProbeManager());
  301. queryContext.setown(basefactory->createChildQueries(basehelper, childGraphs, probeManager, logctx, packet));
  302. }
  303. else
  304. #endif
  305. queryContext.setown(basefactory->createChildQueries(basehelper, childGraphs, NULL, logctx, packet));
  306. if (!queryContext)
  307. queryContext.setown(basefactory->createSlaveContext(logctx, packet));
  308. if (meta.needsSerializeDisk())
  309. serializer.setown(meta.createDiskSerializer(queryContext->queryCodeContext(), basefactory->queryId()));
  310. if (needsRowAllocator())
  311. rowAllocator.setown(getRowAllocator(meta.queryOriginal(), basefactory->queryId()));
  312. unsigned parentExtractSize;
  313. serializedCreate.read(parentExtractSize);
  314. const byte * parentExtract = serializedCreate.readDirect(parentExtractSize);
  315. basehelper->onCreate(this, NULL, &serializedCreate);
  316. basehelper->onStart(parentExtract, &serializedCreate);
  317. deserializeExtra(serializedCreate);
  318. if (variableFileName) // note - in keyed join with dependent index case, kj itself won't have variableFileName but indexread might
  319. {
  320. CDateTime cacheDate(serializedCreate);
  321. unsigned checksum;
  322. serializedCreate.read(checksum);
  323. OwnedRoxieString fname(queryDynamicFileName());
  324. varFileInfo.setown(querySlaveDynamicFileCache()->lookupDynamicFile(logctx, fname, cacheDate, checksum, &packet->queryHeader(), isOpt, true));
  325. setVariableFileInfo();
  326. }
  327. }
  328. virtual void deserializeExtra(MemoryBuffer &out)
  329. {
  330. }
  331. CRoxieSlaveActivity(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory, const CSlaveActivityFactory *_factory)
  332. : logctx(_logctx), packet(_packet), basefactory(_factory)
  333. {
  334. allowFieldTranslation = _factory->getEnableFieldTranslation();
  335. resent = packet->getContinuationLength() != 0;
  336. serializedCreate.setBuffer(packet->getContextLength(), (void *) packet->queryContextData(), false);
  337. if (resent)
  338. resentInfo.setBuffer(packet->getContinuationLength(), (void *) packet->queryContinuationData(), false);
  339. basehelper = _hFactory();
  340. aborted = false;
  341. lastPartNo.partNo = 0xffff;
  342. lastPartNo.fileNo = 0xffff;
  343. isOpt = false;
  344. variableFileName = false;
  345. meta.set(basehelper->queryOutputMeta());
  346. }
  347. ~CRoxieSlaveActivity()
  348. {
  349. ::Release(basehelper);
  350. }
  351. public:
  352. IMPLEMENT_IINTERFACE;
  353. virtual const char *queryDynamicFileName() const = 0;
  354. virtual void setVariableFileInfo() = 0;
  355. virtual IIndexReadActivityInfo *queryIndexReadActivity() { throwUnexpected(); } // should only be called for index activity
  356. virtual unsigned queryId()
  357. {
  358. return basefactory->queryId();
  359. }
  360. virtual bool check()
  361. {
  362. Owned<IMessagePacker> output = ROQ->createOutputStream(packet->queryHeader(), false, logctx);
  363. doCheck(output);
  364. output->flush(true);
  365. return true;
  366. }
  367. virtual void doCheck(IMessagePacker *output)
  368. {
  369. // MORE - unsophisticated default - if this approach seems fruitful then we can add something more thorough
  370. void *recBuffer = output->getBuffer(sizeof(bool), false);
  371. bool ret = false;
  372. memcpy(recBuffer, &ret, sizeof(bool));
  373. }
  374. virtual void abort()
  375. {
  376. if (logctx.queryTraceLevel() > 2)
  377. {
  378. StringBuffer s;
  379. logctx.CTXLOG("Aborting running activity: %s", packet->queryHeader().toString(s).str());
  380. }
  381. logctx.requestAbort();
  382. aborted = true;
  383. if (queryContext)
  384. {
  385. Owned<IException> E = MakeStringException(ROXIE_ABORT_ERROR, "Roxie server requested abort for running activity");
  386. queryContext->notifyAbort(E);
  387. }
  388. }
  389. virtual IRoxieQueryPacket *queryPacket() const
  390. {
  391. return packet;
  392. }
  393. void limitExceeded(bool keyed = false)
  394. {
  395. RoxiePacketHeader &header = packet->queryHeader();
  396. StringBuffer s;
  397. logctx.CTXLOG("%sLIMIT EXCEEDED: %s", keyed ? "KEYED " : "", header.toString(s).str());
  398. header.activityId = keyed ? ROXIE_KEYEDLIMIT_EXCEEDED : ROXIE_LIMIT_EXCEEDED;
  399. Owned<IMessagePacker> output = ROQ->createOutputStream(header, false, logctx);
  400. output->flush(true);
  401. aborted = true;
  402. }
  403. virtual IThorChildGraph * resolveChildQuery(__int64 activityId, IHThorArg * colocal)
  404. {
  405. assertex(colocal == basehelper);
  406. return queryContext->queryCodeContext()->resolveChildQuery(activityId, colocal);
  407. }
  408. size32_t serializeRow(IMessagePacker *output, const void *unserialized) const
  409. {
  410. return ::serializeRow(serializer, output, unserialized);
  411. }
  412. virtual const char *loadResource(unsigned id)
  413. {
  414. return queryContext->queryCodeContext()->loadResource(id);
  415. }
  416. // Sets should not happen - they can only happen in the main Roxie server context
  417. virtual void setResultBool(const char *name, unsigned sequence, bool value) { throwUnexpected(); }
  418. virtual void setResultData(const char *name, unsigned sequence, int len, const void * data) { throwUnexpected(); }
  419. virtual void setResultDecimal(const char * stepname, unsigned sequence, int len, int precision, bool isSigned, const void *val) { throwUnexpected(); }
  420. virtual void setResultInt(const char *name, unsigned sequence, __int64 value) { throwUnexpected(); }
  421. virtual void setResultRaw(const char *name, unsigned sequence, int len, const void * data) { throwUnexpected(); }
  422. virtual void setResultReal(const char * stepname, unsigned sequence, double value) { throwUnexpected(); }
  423. virtual void setResultSet(const char *name, unsigned sequence, bool isAll, size32_t len, const void * data, ISetToXmlTransformer * transformer) { throwUnexpected(); }
  424. virtual void setResultString(const char *name, unsigned sequence, int len, const char * str) { throwUnexpected(); }
  425. virtual void setResultUInt(const char *name, unsigned sequence, unsigned __int64 value) { throwUnexpected(); }
  426. virtual void setResultUnicode(const char *name, unsigned sequence, int len, UChar const * str) { throwUnexpected(); }
  427. virtual void setResultVarString(const char * name, unsigned sequence, const char * value) { throwUnexpected(); }
  428. virtual void setResultVarUnicode(const char * name, unsigned sequence, UChar const * value) { throwUnexpected(); }
  429. // Some gets are allowed though (e.g. for ONCE values)
  430. virtual bool getResultBool(const char * name, unsigned sequence)
  431. {
  432. return queryContext->queryCodeContext()->getResultBool(name, sequence);
  433. }
  434. virtual void getResultData(unsigned & tlen, void * & tgt, const char * name, unsigned sequence)
  435. {
  436. queryContext->queryCodeContext()->getResultData(tlen, tgt, name, sequence);
  437. }
  438. virtual void getResultDecimal(unsigned tlen, int precision, bool isSigned, void * tgt, const char * stepname, unsigned sequence)
  439. {
  440. queryContext->queryCodeContext()->getResultDecimal(tlen, precision, isSigned, tgt, stepname, sequence);
  441. }
  442. virtual void getResultRaw(unsigned & tlen, void * & tgt, const char * name, unsigned sequence, IXmlToRowTransformer * xmlTransformer, ICsvToRowTransformer * csvTransformer)
  443. {
  444. queryContext->queryCodeContext()->getResultRaw(tlen, tgt, name, sequence, xmlTransformer, csvTransformer);
  445. }
  446. virtual void getResultSet(bool & isAll, size32_t & tlen, void * & tgt, const char * name, unsigned sequence, IXmlToRowTransformer * xmlTransformer, ICsvToRowTransformer * csvTransformer)
  447. {
  448. queryContext->queryCodeContext()->getResultSet(isAll, tlen, tgt, name, sequence, xmlTransformer, csvTransformer);
  449. }
  450. virtual __int64 getResultInt(const char * name, unsigned sequence)
  451. {
  452. return queryContext->queryCodeContext()->getResultInt(name, sequence);
  453. }
  454. virtual double getResultReal(const char * name, unsigned sequence)
  455. {
  456. return queryContext->queryCodeContext()->getResultReal(name, sequence);
  457. }
  458. virtual void getResultString(unsigned & tlen, char * & tgt, const char * name, unsigned sequence)
  459. {
  460. queryContext->queryCodeContext()->getResultString(tlen, tgt, name, sequence);
  461. }
  462. virtual void getResultStringF(unsigned tlen, char * tgt, const char * name, unsigned sequence)
  463. {
  464. queryContext->queryCodeContext()->getResultStringF(tlen, tgt, name, sequence);
  465. }
  466. virtual void getResultUnicode(unsigned & tlen, UChar * & tgt, const char * name, unsigned sequence)
  467. {
  468. queryContext->queryCodeContext()->getResultUnicode(tlen, tgt, name, sequence);
  469. }
  470. virtual char *getResultVarString(const char * name, unsigned sequence)
  471. {
  472. return queryContext->queryCodeContext()->getResultVarString(name, sequence);
  473. }
  474. virtual UChar *getResultVarUnicode(const char * name, unsigned sequence)
  475. {
  476. return queryContext->queryCodeContext()->getResultVarUnicode(name, sequence);
  477. }
  478. virtual void getResultRowset(size32_t & tcount, byte * * & tgt, const char * name, unsigned sequence, IEngineRowAllocator * _rowAllocator, bool isGrouped, IXmlToRowTransformer * xmlTransformer, ICsvToRowTransformer * csvTransformer)
  479. {
  480. return queryContext->queryCodeContext()->getResultRowset(tcount, tgt, name, sequence, _rowAllocator, isGrouped, xmlTransformer, csvTransformer);
  481. }
  482. virtual void getResultDictionary(size32_t & tcount, byte * * & tgt, IEngineRowAllocator * _rowAllocator, const char * name, unsigned sequence, IXmlToRowTransformer * xmlTransformer, ICsvToRowTransformer * csvTransformer, IHThorHashLookupInfo * hasher)
  483. {
  484. return queryContext->queryCodeContext()->getResultDictionary(tcount, tgt, _rowAllocator, name, sequence, xmlTransformer, csvTransformer, hasher);
  485. }
  486. virtual unsigned getResultHash(const char * name, unsigned sequence) { throwUnexpected(); }
  487. // Not yet thought about these....
  488. virtual char *getWuid() { throwUnexpected(); } // caller frees return string.
  489. virtual void getExternalResultRaw(unsigned & tlen, void * & tgt, const char * wuid, const char * stepname, unsigned sequence, IXmlToRowTransformer * xmlTransformer, ICsvToRowTransformer * csvTransformer) { throwUnexpected(); } // shouldn't really be here, but it broke thor.
  490. virtual void executeGraph(const char * graphName, bool realThor, size32_t parentExtractSize, const void * parentExtract) { throwUnexpected(); }
  491. virtual unsigned __int64 getDatasetHash(const char * name, unsigned __int64 hash) { throwUnexpected(); return 0; }
  492. virtual char * getExpandLogicalName(const char * logicalName) { throwUnexpected(); }
  493. virtual void addWuException(const char * text, unsigned code, unsigned severity, const char * source) { throwUnexpected(); }
  494. virtual void addWuAssertFailure(unsigned code, const char * text, const char * filename, unsigned lineno, unsigned column, bool isAbort) { throwUnexpected(); }
  495. virtual IUserDescriptor *queryUserDescriptor() { throwUnexpected(); }
  496. virtual unsigned getNodes() { throwUnexpected(); }
  497. virtual unsigned getNodeNum() { throwUnexpected(); }
  498. virtual char *getFilePart(const char *logicalPart, bool create=false) { throwUnexpected(); } // caller frees return string.
  499. virtual unsigned __int64 getFileOffset(const char *logicalPart) { throwUnexpected(); }
  500. virtual IDistributedFileTransaction *querySuperFileTransaction() { throwUnexpected(); }
  501. virtual char *getJobName() { throwUnexpected(); } // caller frees return string.
  502. virtual char *getJobOwner() { throwUnexpected(); } // caller frees return string.
  503. virtual char *getClusterName() { throwUnexpected(); } // caller frees return str.
  504. virtual char *getGroupName() { throwUnexpected(); } // caller frees return string.
  505. virtual char * queryIndexMetaData(char const * lfn, char const * xpath) { throwUnexpected(); }
  506. virtual char *getDaliServers() { return queryContext->queryCodeContext()->getDaliServers(); }
  507. // The below are called on Roxie server and passed in context
  508. virtual unsigned getPriority() const { throwUnexpected(); }
  509. virtual char *getPlatform() { throwUnexpected(); }
  510. virtual char *getEnv(const char *name, const char *defaultValue) const { throwUnexpected(); }
  511. virtual char *getOS() { throwUnexpected(); }
  512. virtual unsigned logString(const char *text) const
  513. {
  514. if (text && *text)
  515. {
  516. logctx.CTXLOG("USER: %s", text);
  517. return strlen(text);
  518. }
  519. else
  520. return 0;
  521. }
  522. virtual const IContextLogger &queryContextLogger() const
  523. {
  524. return logctx;
  525. }
  526. virtual IEngineRowAllocator * getRowAllocator(IOutputMetaData * meta, unsigned activityId) const
  527. {
  528. return queryContext->queryCodeContext()->getRowAllocator(meta, activityId);
  529. }
  530. virtual const char *cloneVString(const char *str) const
  531. {
  532. return queryContext->queryCodeContext()->cloneVString(str);
  533. }
  534. virtual const char *cloneVString(size32_t len, const char *str) const
  535. {
  536. return queryContext->queryCodeContext()->cloneVString(len, str);
  537. }
  538. virtual void getRowXML(size32_t & lenResult, char * & result, IOutputMetaData & info, const void * row, unsigned flags)
  539. {
  540. convertRowToXML(lenResult, result, info, row, flags);
  541. }
  542. const void * fromXml(IEngineRowAllocator * rowAllocator, size32_t len, const char * utf8, IXmlToRowTransformer * xmlTransformer, bool stripWhitespace)
  543. {
  544. return createRowFromXml(rowAllocator, len, utf8, xmlTransformer, stripWhitespace);
  545. }
  546. virtual IEngineContext *queryEngineContext() { return NULL; }
  547. virtual IWorkUnit *updateWorkUnit() const { throwUnexpected(); }
  548. };
  549. //================================================================================================
  550. class OptimizedRowBuilder : public ARowBuilder, public CInterface
  551. {
  552. public:
  553. OptimizedRowBuilder(IEngineRowAllocator * _rowAllocator, const CachedOutputMetaData & _meta, IMessagePacker * _output, IOutputRowSerializer * _serializer)
  554. : dynamicBuilder(_rowAllocator, false), meta(_meta), serializer(_serializer), output(_output)
  555. {
  556. useDynamic = serializer != NULL || meta.isVariableSize();
  557. }
  558. IMPLEMENT_IINTERFACE
  559. virtual IEngineRowAllocator *queryAllocator() const
  560. {
  561. return dynamicBuilder.queryAllocator();
  562. }
  563. virtual byte * createSelf()
  564. {
  565. if (useDynamic)
  566. {
  567. dynamicBuilder.ensureRow();
  568. self = dynamicBuilder.getSelf();
  569. }
  570. else
  571. self = static_cast<byte *>(output->getBuffer(meta.getFixedSize(), false));
  572. return self;
  573. }
  574. virtual byte * ensureCapacity(size32_t required, const char * fieldName)
  575. {
  576. if (useDynamic)
  577. {
  578. self = dynamicBuilder.ensureCapacity(required, fieldName);
  579. return static_cast<byte *>(self);
  580. }
  581. else
  582. {
  583. size32_t fixedLength = meta.getFixedSize();
  584. if (required <= fixedLength)
  585. return static_cast<byte *>(self);
  586. // This should never happen!
  587. rtlReportFieldOverflow(required, fixedLength, fieldName);
  588. return NULL;
  589. }
  590. }
  591. virtual void reportMissingRow() const
  592. {
  593. throw MakeStringException(MSGAUD_user, 1000, "OptimizedRowBuilder::row() is NULL");
  594. }
  595. inline void ensureRow()
  596. {
  597. if (!self)
  598. createSelf();
  599. }
  600. inline void clear()
  601. {
  602. if (useDynamic)
  603. dynamicBuilder.clear();
  604. self = NULL;
  605. }
  606. size_t writeToOutput(size32_t transformedSize, bool outputIfEmpty)
  607. {
  608. size32_t outputSize = transformedSize;
  609. if (transformedSize || outputIfEmpty)
  610. {
  611. if (useDynamic)
  612. {
  613. OwnedConstRoxieRow result = dynamicBuilder.finalizeRowClear(transformedSize);
  614. if (serializer)
  615. outputSize = serializeRow(serializer, output, result);
  616. else
  617. {
  618. self = static_cast<byte *>(output->getBuffer(transformedSize, true));
  619. memcpy(self, result, transformedSize);
  620. output->putBuffer(self, transformedSize, true);
  621. }
  622. }
  623. else
  624. {
  625. output->putBuffer(self, transformedSize, false);
  626. }
  627. }
  628. clear();
  629. return outputSize;
  630. }
  631. private:
  632. RtlDynamicRowBuilder dynamicBuilder;
  633. const CachedOutputMetaData & meta;
  634. IMessagePacker * output;
  635. IOutputRowSerializer * serializer;
  636. bool useDynamic;
  637. };
  638. class OptimizedKJRowBuilder : public ARowBuilder, public CInterface
  639. {
  640. // Rules are different enough that we can't easily derive from OptimizedRowBuilder
  641. public:
  642. IMPLEMENT_IINTERFACE;
  643. OptimizedKJRowBuilder(IEngineRowAllocator * _rowAllocator, const CachedOutputMetaData & _meta, IMessagePacker * _output)
  644. : dynamicBuilder(_rowAllocator, false), meta(_meta), output(_output)
  645. {
  646. useDynamic = meta.isVariableSize();
  647. }
  648. virtual IEngineRowAllocator *queryAllocator() const
  649. {
  650. return dynamicBuilder.queryAllocator();
  651. }
  652. virtual byte * createSelf()
  653. {
  654. if (useDynamic)
  655. {
  656. dynamicBuilder.ensureRow();
  657. self = dynamicBuilder.getSelf();
  658. return self;
  659. }
  660. else
  661. {
  662. self = static_cast<byte *>(output->getBuffer(KEYEDJOIN_RECORD_SIZE(meta.getFixedSize()), true)) + KEYEDJOIN_RECORD_SIZE(0);
  663. return self ;
  664. }
  665. }
  666. virtual byte * ensureCapacity(size32_t required, const char * fieldName)
  667. {
  668. if (useDynamic)
  669. {
  670. self = dynamicBuilder.ensureCapacity(required, fieldName);
  671. return self;
  672. }
  673. else
  674. {
  675. size32_t fixedLength = meta.getFixedSize();
  676. if (required <= fixedLength)
  677. return self;
  678. rtlReportFieldOverflow(required, fixedLength, fieldName);
  679. return NULL;
  680. }
  681. }
  682. virtual void reportMissingRow() const
  683. {
  684. throw MakeStringException(MSGAUD_user, 1000, "OptimizedKJRowBuilder::row() is NULL");
  685. }
  686. inline void ensureRow()
  687. {
  688. if (!self)
  689. createSelf();
  690. }
  691. void writeToOutput(size32_t transformedSize, offset_t recptr, CJoinGroup *jg, unsigned short partNo)
  692. {
  693. KeyedJoinHeader *rec;
  694. if (useDynamic)
  695. {
  696. OwnedConstRoxieRow result = dynamicBuilder.finalizeRowClear(transformedSize);
  697. rec = (KeyedJoinHeader *) (output->getBuffer(KEYEDJOIN_RECORD_SIZE(transformedSize), true));
  698. memcpy(&rec->rhsdata, result, transformedSize);
  699. }
  700. else
  701. {
  702. rec = (KeyedJoinHeader *)(self - KEYEDJOIN_RECORD_SIZE(0));
  703. }
  704. rec->fpos = recptr;
  705. rec->thisGroup = jg;
  706. rec->partNo = partNo;
  707. output->putBuffer(rec, KEYEDJOIN_RECORD_SIZE(transformedSize), true);
  708. self = NULL;
  709. }
  710. private:
  711. RtlDynamicRowBuilder dynamicBuilder;
  712. const CachedOutputMetaData & meta;
  713. IMessagePacker * output;
  714. bool useDynamic;
  715. };
  716. //================================================================================================
  717. class CRoxieDiskReadBaseActivity : public CRoxieSlaveActivity, implements IIndexReadContext//, implements IDiskReadActivity
  718. {
  719. friend class RecordProcessor;
  720. friend class KeyedRecordProcessor;
  721. friend class UnkeyedRecordProcessor;
  722. friend class UnkeyedVariableRecordProcessor;
  723. friend class KeyedNormalizeRecordProcessor;
  724. friend class UnkeyedNormalizeRecordProcessor;
  725. friend class KeyedCountRecordProcessor;
  726. friend class UnkeyedCountRecordProcessor;
  727. friend class UnkeyedVariableCountRecordProcessor;
  728. friend class KeyedAggregateRecordProcessor;
  729. friend class UnkeyedAggregateRecordProcessor;
  730. friend class UnkeyedVariableAggregateRecordProcessor;
  731. friend class KeyedGroupAggregateRecordProcessor;
  732. friend class UnkeyedGroupAggregateRecordProcessor;
  733. friend class UnkeyedVariableGroupAggregateRecordProcessor;
  734. protected:
  735. IHThorDiskReadBaseArg *helper;
  736. unsigned processed;
  737. unsigned parallelPartNo;
  738. unsigned numParallel;
  739. bool isKeyed;
  740. bool forceUnkeyed;
  741. offset_t readPos;
  742. CachedOutputMetaData diskSize;
  743. Owned<IInMemoryIndexCursor> cursor;
  744. Linked<IInMemoryIndexManager> manager;
  745. Owned<IInMemoryFileProcessor> processor;
  746. Owned<IFileIOArray> varFiles;
  747. CriticalSection pcrit;
  748. public:
  749. IMPLEMENT_IINTERFACE;
  750. CRoxieDiskReadBaseActivity(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory, const CSlaveActivityFactory *_aFactory,
  751. IInMemoryIndexManager *_manager,
  752. unsigned _parallelPartNo, unsigned _numParallel, bool _forceUnkeyed)
  753. : CRoxieSlaveActivity(_logctx, _packet, _hFactory, _aFactory),
  754. manager(_manager),
  755. parallelPartNo(_parallelPartNo),
  756. numParallel(_numParallel),
  757. forceUnkeyed(_forceUnkeyed)
  758. {
  759. helper = (IHThorDiskReadBaseArg *) basehelper;
  760. variableFileName = allFilesDynamic || basefactory->queryQueryFactory().isDynamic() || ((helper->getFlags() & (TDXvarfilename|TDXdynamicfilename)) != 0);
  761. isOpt = (helper->getFlags() & TDRoptional) != 0;
  762. diskSize.set(helper->queryDiskRecordSize());
  763. processed = 0;
  764. readPos = 0;
  765. isKeyed = false;
  766. if (resent)
  767. {
  768. bool usedKey;
  769. resentInfo.read(processed);
  770. resentInfo.read(usedKey);
  771. if (usedKey)
  772. {
  773. cursor.setown(manager->createCursor());
  774. cursor->deserializeCursorPos(resentInfo);
  775. isKeyed = true;
  776. }
  777. else
  778. resentInfo.read(readPos);
  779. assertex(resentInfo.remaining() == 0);
  780. }
  781. }
  782. virtual void onCreate()
  783. {
  784. CRoxieSlaveActivity::onCreate();
  785. helper->createSegmentMonitors(this);
  786. if (!resent)
  787. isKeyed = (cursor && !forceUnkeyed) ? cursor->selectKey() : false;
  788. }
  789. virtual const char *queryDynamicFileName() const
  790. {
  791. return helper->getFileName();
  792. }
  793. virtual void setVariableFileInfo()
  794. {
  795. unsigned channel = packet->queryHeader().channel;
  796. varFiles.setown(varFileInfo->getIFileIOArray(isOpt, channel)); // MORE could combine
  797. manager.setown(varFileInfo->getIndexManager(isOpt, channel, varFiles, diskSize, false, 0));
  798. }
  799. inline bool queryKeyed() const
  800. {
  801. return isKeyed;
  802. }
  803. void setParallel(unsigned _partno, unsigned _numParallel)
  804. {
  805. assertex(!processor);
  806. parallelPartNo = _partno;
  807. numParallel = _numParallel;
  808. }
  809. virtual StringBuffer &toString(StringBuffer &ret) const
  810. {
  811. return ret.appendf("DiskRead %u", packet->queryHeader().activityId);
  812. }
  813. virtual void append(IKeySegmentMonitor *segment)
  814. {
  815. if (!segment->isWild())
  816. {
  817. if (!cursor)
  818. cursor.setown(manager->createCursor());
  819. cursor->append(segment);
  820. }
  821. }
  822. virtual unsigned ordinality() const
  823. {
  824. return cursor ? cursor->ordinality() : 0;
  825. }
  826. virtual IKeySegmentMonitor *item(unsigned idx) const
  827. {
  828. return cursor ? cursor->item(idx) : 0;
  829. }
  830. virtual void setMergeBarrier(unsigned barrierOffset)
  831. {
  832. // no merging so no issue...
  833. }
  834. virtual void abort()
  835. {
  836. aborted = true;
  837. CriticalBlock p(pcrit);
  838. if (processor)
  839. processor->abort();
  840. }
  841. virtual bool process()
  842. {
  843. MTIME_SECTION(timer, "CRoxieDiskReadBaseActivity::process");
  844. atomic_inc(&diskReadStarted);
  845. Owned<IMessagePacker> output = ROQ->createOutputStream(packet->queryHeader(), false, logctx);
  846. doProcess(output);
  847. helper->setCallback(NULL);
  848. logctx.flush(true, aborted);
  849. if (aborted)
  850. {
  851. output->abort();
  852. return false;
  853. }
  854. else
  855. {
  856. output->flush(true);
  857. atomic_inc(&diskReadCompleted);
  858. return true;
  859. }
  860. }
  861. virtual void doCheck(IMessagePacker *output)
  862. {
  863. // for in-memory diskread activities, not a lot to check. If it got this far the answer is 'true'...
  864. void *recBuffer = output->getBuffer(sizeof(bool), false);
  865. bool ret = true;
  866. memcpy(recBuffer, &ret, sizeof(bool));
  867. }
  868. virtual void doProcess(IMessagePacker * output) = 0;
  869. virtual void setPartNo(bool filechanged)
  870. {
  871. throwUnexpected();
  872. }
  873. };
  874. class CRoxieDiskBaseActivityFactory : public CSlaveActivityFactory
  875. {
  876. protected:
  877. Owned<IFileIOArray> fileArray;
  878. Owned<IInMemoryIndexManager> manager;
  879. public:
  880. CRoxieDiskBaseActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  881. : CSlaveActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory)
  882. {
  883. Owned<IHThorDiskReadBaseArg> helper = (IHThorDiskReadBaseArg *) helperFactory();
  884. bool variableFileName = allFilesDynamic || queryFactory.isDynamic() || ((helper->getFlags() & (TDXvarfilename|TDXdynamicfilename)) != 0);
  885. if (!variableFileName)
  886. {
  887. bool isOpt = (helper->getFlags() & TDRoptional) != 0;
  888. OwnedRoxieString fileName(helper->getFileName());
  889. datafile.setown(_queryFactory.queryPackage().lookupFileName(fileName, isOpt, true, true, _queryFactory.queryWorkUnit()));
  890. if (datafile)
  891. {
  892. unsigned channel = queryFactory.queryChannel();
  893. fileArray.setown(datafile->getIFileIOArray(isOpt, channel));
  894. manager.setown(datafile->getIndexManager(isOpt, channel, fileArray, helper->queryDiskRecordSize(), _graphNode.getPropBool("att[@name=\"preload\"]/@value", false), _graphNode.getPropInt("att[@name=\"_preloadSize\"]/@value", 0)));
  895. Owned<IPropertyTreeIterator> memKeyInfo = queryFactory.queryPackage().getInMemoryIndexInfo(_graphNode);
  896. if (memKeyInfo)
  897. {
  898. ForEach(*memKeyInfo)
  899. {
  900. IPropertyTree &info = memKeyInfo->query();
  901. manager->setKeyInfo(info);
  902. }
  903. }
  904. }
  905. else
  906. manager.setown(getEmptyIndexManager());
  907. }
  908. }
  909. ~CRoxieDiskBaseActivityFactory()
  910. {
  911. }
  912. };
  913. //================================================================================================
  914. class CRoxieDiskReadActivity;
  915. class CRoxieCsvReadActivity;
  916. class CRoxieXmlReadActivity;
  917. IInMemoryFileProcessor *createKeyedRecordProcessor(IInMemoryIndexCursor *cursor, CRoxieDiskReadActivity &owner, bool resent);
  918. IInMemoryFileProcessor *createUnkeyedRecordProcessor(IInMemoryIndexCursor *cursor, CRoxieDiskReadActivity &owner, bool variableDisk, IDirectReader *reader);
  919. IInMemoryFileProcessor *createCsvRecordProcessor(CRoxieCsvReadActivity &owner, IDirectReader *reader, bool _skipHeader, const IResolvedFile *datafile);
  920. IInMemoryFileProcessor *createXmlRecordProcessor(CRoxieXmlReadActivity &owner, IDirectReader *reader);
  921. class CRoxieDiskReadActivity : public CRoxieDiskReadBaseActivity
  922. {
  923. friend class ReadRecordProcessor;
  924. protected:
  925. IHThorDiskReadArg *helper;
  926. public:
  927. IMPLEMENT_IINTERFACE;
  928. CRoxieDiskReadActivity(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory, const CSlaveActivityFactory *_aFactory,
  929. IInMemoryIndexManager *_manager)
  930. : CRoxieDiskReadBaseActivity(_logctx, _packet, _hFactory, _aFactory, _manager, 0, 1, false)
  931. {
  932. onCreate();
  933. helper = (IHThorDiskReadArg *) basehelper;
  934. }
  935. virtual StringBuffer &toString(StringBuffer &ret) const
  936. {
  937. return ret.appendf("DiskRead %u", packet->queryHeader().activityId);
  938. }
  939. virtual void doProcess(IMessagePacker * output)
  940. {
  941. {
  942. CriticalBlock p(pcrit);
  943. processor.setown(isKeyed ? createKeyedRecordProcessor(cursor, *this, resent) :
  944. createUnkeyedRecordProcessor(cursor, *this, diskSize.isVariableSize(), manager->createReader(readPos, parallelPartNo, numParallel)));
  945. }
  946. unsigned __int64 rowLimit = helper->getRowLimit();
  947. unsigned __int64 stopAfter = helper->getChooseNLimit();
  948. processor->doQuery(output, processed, rowLimit, stopAfter);
  949. }
  950. size32_t doTransform(IMessagePacker * output, const void *src) const
  951. {
  952. OptimizedRowBuilder rowBuilder(rowAllocator, meta, output, serializer);
  953. unsigned transformedSize = helper->transform(rowBuilder, src);
  954. return rowBuilder.writeToOutput(transformedSize, false);
  955. }
  956. };
  957. class CRoxieCsvReadActivity : public CRoxieDiskReadBaseActivity
  958. {
  959. public:
  960. friend class CsvRecordProcessor;
  961. protected:
  962. IHThorCsvReadArg *helper;
  963. const IResolvedFile *datafile;
  964. public:
  965. IMPLEMENT_IINTERFACE;
  966. CRoxieCsvReadActivity(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory,
  967. const CSlaveActivityFactory *_aFactory, IInMemoryIndexManager *_manager, const IResolvedFile *_datafile)
  968. : CRoxieDiskReadBaseActivity(_logctx, _packet, _hFactory, _aFactory, _manager, 0, 1, true), datafile(_datafile)
  969. {
  970. onCreate();
  971. helper = (IHThorCsvReadArg *) basehelper;
  972. }
  973. virtual StringBuffer &toString(StringBuffer &ret) const
  974. {
  975. return ret.appendf("CsvRead %u", packet->queryHeader().activityId);
  976. }
  977. virtual void doProcess(IMessagePacker * output)
  978. {
  979. {
  980. CriticalBlock p(pcrit);
  981. processor.setown(
  982. createCsvRecordProcessor(*this,
  983. manager->createReader(readPos, parallelPartNo, numParallel),
  984. packet->queryHeader().channel==1 && !resent,
  985. varFileInfo ? varFileInfo.get() : datafile));
  986. }
  987. unsigned __int64 rowLimit = helper->getRowLimit();
  988. unsigned __int64 stopAfter = helper->getChooseNLimit();
  989. processor->doQuery(output, processed, rowLimit, stopAfter);
  990. }
  991. size32_t doTransform(IMessagePacker * output, unsigned *srcLen, const char **src) const
  992. {
  993. OptimizedRowBuilder rowBuilder(rowAllocator, meta, output, serializer);
  994. unsigned transformedSize = helper->transform(rowBuilder, srcLen, src);
  995. return rowBuilder.writeToOutput(transformedSize, false);
  996. }
  997. };
  998. class CRoxieXmlReadActivity : public CRoxieDiskReadBaseActivity
  999. {
  1000. public:
  1001. friend class XmlRecordProcessor;
  1002. protected:
  1003. IHThorXmlReadArg *helper;
  1004. public:
  1005. IMPLEMENT_IINTERFACE;
  1006. CRoxieXmlReadActivity(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory, const CSlaveActivityFactory *_aFactory,
  1007. IInMemoryIndexManager *_manager)
  1008. : CRoxieDiskReadBaseActivity(_logctx, _packet, _hFactory, _aFactory, _manager, 0, 1, true)
  1009. {
  1010. onCreate();
  1011. helper = (IHThorXmlReadArg *) basehelper;
  1012. }
  1013. virtual StringBuffer &toString(StringBuffer &ret) const
  1014. {
  1015. return ret.appendf("XmlRead %u", packet->queryHeader().activityId);
  1016. }
  1017. virtual void doProcess(IMessagePacker * output)
  1018. {
  1019. {
  1020. CriticalBlock p(pcrit);
  1021. processor.setown(createXmlRecordProcessor(*this, manager->createReader(readPos, parallelPartNo, numParallel)));
  1022. }
  1023. unsigned __int64 rowLimit = helper->getRowLimit();
  1024. unsigned __int64 stopAfter = helper->getChooseNLimit();
  1025. processor->doQuery(output, processed, rowLimit, stopAfter);
  1026. }
  1027. size32_t doTransform(IMessagePacker * output, IXmlToRowTransformer *rowTransformer, IColumnProvider *lastMatch, IThorDiskCallback *callback) const
  1028. {
  1029. OptimizedRowBuilder rowBuilder(rowAllocator, meta, output, serializer);
  1030. unsigned transformedSize = rowTransformer->transform(rowBuilder, lastMatch, callback);
  1031. return rowBuilder.writeToOutput(transformedSize, false);
  1032. }
  1033. };
  1034. class CRoxieDiskReadActivityFactory : public CRoxieDiskBaseActivityFactory
  1035. {
  1036. public:
  1037. IMPLEMENT_IINTERFACE;
  1038. CRoxieDiskReadActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  1039. : CRoxieDiskBaseActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory)
  1040. {
  1041. }
  1042. virtual IRoxieSlaveActivity *createActivity(SlaveContextLogger &logctx, IRoxieQueryPacket *packet) const
  1043. {
  1044. return new CRoxieDiskReadActivity(logctx, packet, helperFactory, this, manager);
  1045. }
  1046. virtual StringBuffer &toString(StringBuffer &s) const
  1047. {
  1048. return CSlaveActivityFactory::toString(s.append("DiskRead "));
  1049. }
  1050. };
  1051. class CRoxieCsvReadActivityFactory : public CRoxieDiskBaseActivityFactory
  1052. {
  1053. public:
  1054. IMPLEMENT_IINTERFACE;
  1055. CRoxieCsvReadActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  1056. : CRoxieDiskBaseActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory)
  1057. {
  1058. }
  1059. virtual IRoxieSlaveActivity *createActivity(SlaveContextLogger &logctx, IRoxieQueryPacket *packet) const
  1060. {
  1061. return new CRoxieCsvReadActivity(logctx, packet, helperFactory, this, manager, datafile);
  1062. }
  1063. virtual StringBuffer &toString(StringBuffer &s) const
  1064. {
  1065. return CSlaveActivityFactory::toString(s.append("DiskRead "));
  1066. }
  1067. };
  1068. class CRoxieXmlReadActivityFactory : public CRoxieDiskBaseActivityFactory
  1069. {
  1070. public:
  1071. IMPLEMENT_IINTERFACE;
  1072. CRoxieXmlReadActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  1073. : CRoxieDiskBaseActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory)
  1074. {
  1075. }
  1076. virtual IRoxieSlaveActivity *createActivity(SlaveContextLogger &logctx, IRoxieQueryPacket *packet) const
  1077. {
  1078. return new CRoxieXmlReadActivity(logctx, packet, helperFactory, this, manager);
  1079. }
  1080. virtual StringBuffer &toString(StringBuffer &s) const
  1081. {
  1082. return CSlaveActivityFactory::toString(s.append("DiskRead "));
  1083. }
  1084. };
  1085. //================================================================================================
  1086. // Note - the classes below could be commoned up to make the code smaller, but they have been deliberately unrolled to
  1087. // keep to a bare minimum the number of virtual calls/variable tests per record scanned. This is very speed critical.
  1088. class RecordProcessor : public CInterface, implements IInMemoryFileProcessor
  1089. {
  1090. protected:
  1091. IInMemoryIndexCursor *cursor; // Unkeyed variants still may need to check segmonitors in here
  1092. bool aborted;
  1093. const char *endRec;
  1094. static inline size32_t roundDown(size32_t got, size32_t fixedSize)
  1095. {
  1096. // Make sure that the buffer size we process is a multiple of the fixed record size
  1097. return (got / fixedSize) * fixedSize;
  1098. }
  1099. static size32_t getBufferSize(size32_t fixedSize)
  1100. {
  1101. // Calculate appropriate buffer size for fixed size record processors
  1102. assert(fixedSize);
  1103. unsigned recordsPerBuffer = diskReadBufferSize / fixedSize;
  1104. if (!recordsPerBuffer)
  1105. recordsPerBuffer = 1;
  1106. return fixedSize * recordsPerBuffer;
  1107. }
  1108. public:
  1109. IMPLEMENT_IINTERFACE;
  1110. RecordProcessor(IInMemoryIndexCursor *_cursor) : cursor(_cursor)
  1111. {
  1112. aborted = false;
  1113. endRec = NULL;
  1114. }
  1115. virtual void abort()
  1116. {
  1117. aborted = true;
  1118. endRec = NULL; // speeds up the abort in some of the derived classes
  1119. }
  1120. };
  1121. //================================================================================================
  1122. // Base class for all varieties of RecordProcessor used by disk read activity
  1123. class ReadRecordProcessor : public RecordProcessor
  1124. {
  1125. protected:
  1126. CRoxieDiskReadActivity &owner;
  1127. IHThorDiskReadArg *helper;
  1128. public:
  1129. ReadRecordProcessor(IInMemoryIndexCursor *_cursor, CRoxieDiskReadActivity &_owner)
  1130. : RecordProcessor(_cursor), owner(_owner)
  1131. {
  1132. helper = _owner.helper;
  1133. }
  1134. };
  1135. // Used by disk read when an in-memory index is available
  1136. class KeyedRecordProcessor : public ReadRecordProcessor
  1137. {
  1138. bool resent;
  1139. public:
  1140. KeyedRecordProcessor(IInMemoryIndexCursor *_cursor, CRoxieDiskReadActivity &_owner, bool _resent) : ReadRecordProcessor(_cursor, _owner)
  1141. {
  1142. resent = _resent;
  1143. helper->setCallback(cursor);
  1144. }
  1145. virtual void doQuery(IMessagePacker *output, unsigned processed, unsigned __int64 rowLimit, unsigned __int64 stopAfter)
  1146. {
  1147. // doQuery needs to be as fast as possible - we are making a virtual call to it per query in order to avoid tests of loop-invariants within it
  1148. unsigned totalSizeSent = 0;
  1149. IInMemoryIndexCursor *lc = cursor;
  1150. if (!resent)
  1151. lc->reset();
  1152. bool continuationFailed = false;
  1153. while (!aborted)
  1154. {
  1155. const void *nextCandidate = lc->nextMatch();
  1156. if (!nextCandidate)
  1157. break;
  1158. unsigned transformedSize = owner.doTransform(output, nextCandidate);
  1159. if (transformedSize)
  1160. {
  1161. processed++;
  1162. if (processed > rowLimit)
  1163. {
  1164. owner.limitExceeded();
  1165. break;
  1166. }
  1167. if (processed == stopAfter)
  1168. break;
  1169. totalSizeSent += transformedSize;
  1170. if (totalSizeSent > indexReadChunkSize && !continuationFailed)
  1171. {
  1172. MemoryBuffer si;
  1173. unsigned short siLen = 0;
  1174. si.append(siLen);
  1175. si.append(processed);
  1176. si.append(true); // using a key
  1177. lc->serializeCursorPos(si);
  1178. if (si.length() <= maxContinuationSize)
  1179. {
  1180. siLen = si.length() - sizeof(siLen);
  1181. si.writeDirect(0, sizeof(siLen), &siLen);
  1182. output->sendMetaInfo(si.toByteArray(), si.length());
  1183. return;
  1184. }
  1185. else
  1186. continuationFailed = true;
  1187. }
  1188. }
  1189. }
  1190. }
  1191. };
  1192. IInMemoryFileProcessor *createKeyedRecordProcessor(IInMemoryIndexCursor *cursor, CRoxieDiskReadActivity &owner, bool resent)
  1193. {
  1194. return new KeyedRecordProcessor(cursor, owner, resent);
  1195. }
  1196. // Used by disk read when an in-memory index is NOT available
  1197. // We use different variants for fixed versus variable sized records, in order to make the fixed version as fast as possible
  1198. class UnkeyedRecordProcessor : public ReadRecordProcessor
  1199. {
  1200. protected:
  1201. Owned<IDirectReader> reader;
  1202. public:
  1203. IMPLEMENT_IINTERFACE;
  1204. UnkeyedRecordProcessor(IInMemoryIndexCursor *_cursor, CRoxieDiskReadActivity &_owner, IDirectReader *_reader)
  1205. : ReadRecordProcessor(_cursor, _owner), reader(_reader)
  1206. {
  1207. }
  1208. virtual void doQuery(IMessagePacker *output, unsigned processed, unsigned __int64 rowLimit, unsigned __int64 stopAfter)
  1209. {
  1210. unsigned totalSizeSent = 0;
  1211. helper->setCallback(reader->queryThorDiskCallback());
  1212. size32_t recordSize = owner.diskSize.getFixedSize();
  1213. size32_t bufferSize = getBufferSize(recordSize);
  1214. while (!aborted && !reader->eos())
  1215. {
  1216. size32_t gotSize;
  1217. const char *firstRec = (const char *) reader->peek(bufferSize, gotSize);
  1218. if (!gotSize)
  1219. break;
  1220. gotSize = roundDown(gotSize, recordSize);
  1221. const char *nextRec = firstRec;
  1222. endRec = firstRec + gotSize;
  1223. while (nextRec < endRec)
  1224. {
  1225. size32_t transformedSize;
  1226. if (cursor && cursor->isFiltered(nextRec))
  1227. transformedSize = 0;
  1228. else
  1229. transformedSize = owner.doTransform(output, nextRec);
  1230. nextRec += recordSize;
  1231. if (transformedSize)
  1232. {
  1233. processed++;
  1234. if (processed > rowLimit)
  1235. {
  1236. owner.limitExceeded();
  1237. return;
  1238. }
  1239. if (processed == stopAfter)
  1240. return;
  1241. totalSizeSent += transformedSize;
  1242. if (totalSizeSent > indexReadChunkSize)
  1243. {
  1244. MemoryBuffer si;
  1245. unsigned short siLen = 0;
  1246. si.append(siLen);
  1247. si.append(processed);
  1248. si.append(false); // not using a key
  1249. offset_t readPos = reader->tell() + (nextRec - firstRec);
  1250. si.append(readPos);
  1251. siLen = si.length() - sizeof(siLen);
  1252. si.writeDirect(0, sizeof(siLen), &siLen);
  1253. output->sendMetaInfo(si.toByteArray(), si.length());
  1254. return;
  1255. }
  1256. }
  1257. }
  1258. reader->skip(gotSize);
  1259. }
  1260. }
  1261. };
  1262. class UnkeyedVariableRecordProcessor : public UnkeyedRecordProcessor
  1263. {
  1264. public:
  1265. UnkeyedVariableRecordProcessor(IInMemoryIndexCursor *_cursor, CRoxieDiskReadActivity &_owner, IDirectReader *_reader)
  1266. : UnkeyedRecordProcessor(_cursor, _owner, _reader), deserializeSource(_reader)
  1267. {
  1268. prefetcher.setown(owner.diskSize.queryOriginal()->createDiskPrefetcher(owner.queryContext->queryCodeContext(), owner.basefactory->queryId()));
  1269. }
  1270. virtual void doQuery(IMessagePacker *output, unsigned processed, unsigned __int64 rowLimit, unsigned __int64 stopAfter)
  1271. {
  1272. unsigned totalSizeSent = 0;
  1273. helper->setCallback(reader->queryThorDiskCallback());
  1274. while (!aborted && !deserializeSource.eos())
  1275. {
  1276. // This loop is the inner loop for memory diskreads - so keep it efficient!
  1277. prefetcher->readAhead(deserializeSource);
  1278. const byte *nextRec = deserializeSource.queryRow();
  1279. size32_t transformedSize;
  1280. if (cursor && cursor->isFiltered(nextRec))
  1281. transformedSize = 0;
  1282. else
  1283. transformedSize = owner.doTransform(output, nextRec);
  1284. deserializeSource.finishedRow();
  1285. if (transformedSize)
  1286. {
  1287. processed++;
  1288. if (processed > rowLimit)
  1289. {
  1290. owner.limitExceeded();
  1291. return;
  1292. }
  1293. if (processed == stopAfter)
  1294. return;
  1295. totalSizeSent += transformedSize;
  1296. if (totalSizeSent > indexReadChunkSize)
  1297. {
  1298. MemoryBuffer si;
  1299. unsigned short siLen = 0;
  1300. si.append(siLen);
  1301. si.append(processed);
  1302. si.append(false); // not using a key
  1303. offset_t readPos = deserializeSource.tell();
  1304. si.append(readPos);
  1305. siLen = si.length() - sizeof(siLen);
  1306. si.writeDirect(0, sizeof(siLen), &siLen);
  1307. output->sendMetaInfo(si.toByteArray(), si.length());
  1308. return;
  1309. }
  1310. }
  1311. }
  1312. }
  1313. protected:
  1314. CThorContiguousRowBuffer deserializeSource;
  1315. Owned<ISourceRowPrefetcher> prefetcher;
  1316. };
  1317. IInMemoryFileProcessor *createUnkeyedRecordProcessor(IInMemoryIndexCursor *cursor, CRoxieDiskReadActivity &owner, bool variableDisk, IDirectReader *_reader)
  1318. {
  1319. if (variableDisk)
  1320. return new UnkeyedVariableRecordProcessor(cursor, owner, _reader);
  1321. else
  1322. return new UnkeyedRecordProcessor(cursor, owner, _reader);
  1323. }
  1324. //================================================================================================
  1325. // RecordProcessor used by CSV read activity. We don't try to index these or optimize fixed size cases...
  1326. class CsvRecordProcessor : public RecordProcessor
  1327. {
  1328. protected:
  1329. CRoxieCsvReadActivity &owner;
  1330. IHThorCsvReadArg *helper;
  1331. Owned<IDirectReader> reader;
  1332. bool skipHeader;
  1333. const IResolvedFile *datafile;
  1334. public:
  1335. IMPLEMENT_IINTERFACE;
  1336. CsvRecordProcessor(CRoxieCsvReadActivity &_owner, IDirectReader *_reader, bool _skipHeader, const IResolvedFile *_datafile)
  1337. : RecordProcessor(NULL), owner(_owner), reader(_reader), datafile(_datafile)
  1338. {
  1339. helper = _owner.helper;
  1340. skipHeader = _skipHeader;
  1341. helper->setCallback(reader->queryThorDiskCallback());
  1342. }
  1343. virtual void doQuery(IMessagePacker *output, unsigned processed, unsigned __int64 rowLimit, unsigned __int64 stopAfter)
  1344. {
  1345. unsigned totalSizeSent = 0;
  1346. ICsvParameters * csvInfo = helper->queryCsvParameters();
  1347. unsigned headerLines = skipHeader ? csvInfo->queryHeaderLen() : 0;
  1348. const char *quotes = NULL;
  1349. const char *separators = NULL;
  1350. const char *terminators = NULL;
  1351. const char *escapes = NULL;
  1352. CSVSplitter csvSplitter;
  1353. if (datafile)
  1354. {
  1355. const IPropertyTree *options = datafile->queryProperties();
  1356. if (options)
  1357. {
  1358. quotes = options->queryProp("@csvQuote");
  1359. separators = options->queryProp("@csvSeparate");
  1360. terminators = options->queryProp("@csvTerminate");
  1361. escapes = options->queryProp("@csvEscape");
  1362. }
  1363. }
  1364. csvSplitter.init(helper->getMaxColumns(), csvInfo, quotes, separators, terminators, escapes);
  1365. while (!aborted)
  1366. {
  1367. // MORE - there are rumours of a csvSplitter that operates on a stream... if/when it exists, this should use it
  1368. if (reader->eos())
  1369. {
  1370. break;
  1371. }
  1372. size32_t rowSize = 4096; // MORE - make configurable
  1373. size32_t maxRowSize = 10*1024*1024; // MORE - make configurable
  1374. size32_t thisLineLength;
  1375. loop
  1376. {
  1377. size32_t avail;
  1378. const void *peek = reader->peek(rowSize, avail);
  1379. thisLineLength = csvSplitter.splitLine(avail, (const byte *)peek);
  1380. if (thisLineLength < rowSize || avail < rowSize)
  1381. break;
  1382. if (rowSize == maxRowSize)
  1383. throw MakeStringException(0, "Row too big");
  1384. if (rowSize >= maxRowSize/2)
  1385. rowSize = maxRowSize;
  1386. else
  1387. rowSize += rowSize;
  1388. }
  1389. if (!thisLineLength)
  1390. break;
  1391. if (headerLines)
  1392. {
  1393. headerLines--;
  1394. reader->skip(thisLineLength);
  1395. }
  1396. else
  1397. {
  1398. unsigned transformedSize = owner.doTransform(output, csvSplitter.queryLengths(), (const char * *)csvSplitter.queryData());
  1399. reader->skip(thisLineLength);
  1400. if (transformedSize)
  1401. {
  1402. processed++;
  1403. if (processed > rowLimit)
  1404. {
  1405. owner.limitExceeded();
  1406. return;
  1407. }
  1408. if (processed == stopAfter)
  1409. return;
  1410. totalSizeSent += transformedSize;
  1411. if (totalSizeSent > indexReadChunkSize)
  1412. {
  1413. MemoryBuffer si;
  1414. unsigned short siLen = 0;
  1415. si.append(siLen);
  1416. si.append(processed);
  1417. si.append(false); // not using a key
  1418. offset_t readPos = reader->tell();
  1419. si.append(readPos);
  1420. siLen = si.length() - sizeof(siLen);
  1421. si.writeDirect(0, sizeof(siLen), &siLen);
  1422. output->sendMetaInfo(si.toByteArray(), si.length());
  1423. return;
  1424. }
  1425. }
  1426. }
  1427. }
  1428. }
  1429. };
  1430. //================================================================================================
  1431. // RecordProcessor used by XML read activity. We don't try to index these or optimize fixed size cases...
  1432. class XmlRecordProcessor : public RecordProcessor, implements IXMLSelect
  1433. {
  1434. public:
  1435. IMPLEMENT_IINTERFACE;
  1436. XmlRecordProcessor(CRoxieXmlReadActivity &_owner, IDirectReader *_reader)
  1437. : RecordProcessor(NULL), owner(_owner), reader(_reader)
  1438. {
  1439. helper = _owner.helper;
  1440. helper->setCallback(reader->queryThorDiskCallback());
  1441. }
  1442. virtual void match(IColumnProvider &entry, offset_t startOffset, offset_t endOffset)
  1443. {
  1444. lastMatch.set(&entry);
  1445. }
  1446. virtual void doQuery(IMessagePacker *output, unsigned processed, unsigned __int64 rowLimit, unsigned __int64 stopAfter)
  1447. {
  1448. #if 0
  1449. // xml read does not support continuation record stuff as too hard to serialize state of xml parser
  1450. unsigned totalSizeSent = 0;
  1451. #endif
  1452. Linked<IXmlToRowTransformer> rowTransformer = helper->queryTransformer();
  1453. OwnedRoxieString xmlIterator(helper->getXmlIteratorPath());
  1454. Owned<IXMLParse> xmlParser = createXMLParse(*reader->querySimpleStream(), xmlIterator, *this, (0 != (TDRxmlnoroot & helper->getFlags()))?ptr_noRoot:ptr_none, (helper->getFlags() & TDRusexmlcontents) != 0);
  1455. while (!aborted)
  1456. {
  1457. //call to next() will callback on the IXmlSelect interface
  1458. bool gotNext = false;
  1459. gotNext = xmlParser->next();
  1460. if(!gotNext)
  1461. break;
  1462. else if (lastMatch)
  1463. {
  1464. unsigned transformedSize = owner.doTransform(output, rowTransformer, lastMatch, reader->queryThorDiskCallback());
  1465. lastMatch.clear();
  1466. if (transformedSize)
  1467. {
  1468. processed++;
  1469. if (processed > rowLimit)
  1470. {
  1471. owner.limitExceeded();
  1472. return;
  1473. }
  1474. if (processed == stopAfter)
  1475. return;
  1476. #if 0
  1477. // xml read does not support continuation record stuff as too hard to serialize state of xml parser
  1478. totalSizeSent += transformedSize;
  1479. if (totalSizeSent > indexReadChunkSize)
  1480. {
  1481. MemoryBuffer si;
  1482. unsigned short siLen = 0;
  1483. si.append(siLen);
  1484. si.append(processed);
  1485. si.append(false); // not using a key
  1486. readPos = inputFileIOStream->tell();
  1487. si.append(readPos);
  1488. siLen = si.length() - sizeof(siLen);
  1489. si.writeDirect(0, sizeof(siLen), &siLen);
  1490. output->sendMetaInfo(si.toByteArray(), si.length());
  1491. return;
  1492. }
  1493. #endif
  1494. }
  1495. }
  1496. }
  1497. }
  1498. protected:
  1499. CRoxieXmlReadActivity &owner;
  1500. IHThorXmlReadArg *helper;
  1501. Owned<IColumnProvider> lastMatch;
  1502. Owned<IDirectReader> reader;
  1503. };
  1504. IInMemoryFileProcessor *createCsvRecordProcessor(CRoxieCsvReadActivity &owner, IDirectReader *_reader, bool _skipHeader, const IResolvedFile *datafile)
  1505. {
  1506. return new CsvRecordProcessor(owner, _reader, _skipHeader, datafile);
  1507. }
  1508. IInMemoryFileProcessor *createXmlRecordProcessor(CRoxieXmlReadActivity &owner, IDirectReader *_reader)
  1509. {
  1510. return new XmlRecordProcessor(owner, _reader);
  1511. }
  1512. ISlaveActivityFactory *createRoxieCsvReadActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  1513. {
  1514. return new CRoxieCsvReadActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory);
  1515. }
  1516. ISlaveActivityFactory *createRoxieXmlReadActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  1517. {
  1518. return new CRoxieXmlReadActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory);
  1519. }
  1520. ISlaveActivityFactory *createRoxieDiskReadActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  1521. {
  1522. return new CRoxieDiskReadActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory);
  1523. }
  1524. //================================================================================================
  1525. class CRoxieDiskNormalizeActivity;
  1526. IInMemoryFileProcessor *createKeyedNormalizeRecordProcessor(IInMemoryIndexCursor *cursor, CRoxieDiskNormalizeActivity &owner, bool resent);
  1527. IInMemoryFileProcessor *createUnkeyedNormalizeRecordProcessor(IInMemoryIndexCursor *cursor, CRoxieDiskNormalizeActivity &owner, IDirectReader *reader);
  1528. class CRoxieDiskNormalizeActivity : public CRoxieDiskReadBaseActivity
  1529. {
  1530. friend class NormalizeRecordProcessor;
  1531. protected:
  1532. IHThorDiskNormalizeArg *helper;
  1533. public:
  1534. IMPLEMENT_IINTERFACE;
  1535. CRoxieDiskNormalizeActivity(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory, const CSlaveActivityFactory *_aFactory,
  1536. IInMemoryIndexManager *_manager)
  1537. : CRoxieDiskReadBaseActivity(_logctx, _packet, _hFactory, _aFactory, _manager, 0, 1, false)
  1538. {
  1539. onCreate();
  1540. helper = (IHThorDiskNormalizeArg *) basehelper;
  1541. }
  1542. virtual StringBuffer &toString(StringBuffer &ret) const
  1543. {
  1544. return ret.appendf("DiskNormalize %u", packet->queryHeader().activityId);
  1545. }
  1546. virtual void doProcess(IMessagePacker * output)
  1547. {
  1548. {
  1549. CriticalBlock p(pcrit);
  1550. processor.setown(isKeyed ?
  1551. createKeyedNormalizeRecordProcessor(cursor, *this, resent) :
  1552. createUnkeyedNormalizeRecordProcessor(cursor, *this, manager->createReader(readPos, parallelPartNo, numParallel)));
  1553. }
  1554. unsigned __int64 rowLimit = helper->getRowLimit();
  1555. unsigned __int64 stopAfter = helper->getChooseNLimit();
  1556. processor->doQuery(output, processed, rowLimit, stopAfter);
  1557. }
  1558. size32_t doNormalizeTransform(IMessagePacker * output) const
  1559. {
  1560. OptimizedRowBuilder rowBuilder(rowAllocator, meta, output, serializer);
  1561. unsigned transformedSize = helper->transform(rowBuilder);
  1562. return rowBuilder.writeToOutput(transformedSize, false);
  1563. }
  1564. };
  1565. class CRoxieDiskNormalizeActivityFactory : public CRoxieDiskBaseActivityFactory
  1566. {
  1567. public:
  1568. IMPLEMENT_IINTERFACE;
  1569. CRoxieDiskNormalizeActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  1570. : CRoxieDiskBaseActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory)
  1571. {
  1572. }
  1573. virtual IRoxieSlaveActivity *createActivity(SlaveContextLogger &logctx, IRoxieQueryPacket *packet) const
  1574. {
  1575. return new CRoxieDiskNormalizeActivity(logctx, packet, helperFactory, this, manager);
  1576. }
  1577. virtual StringBuffer &toString(StringBuffer &s) const
  1578. {
  1579. return CSlaveActivityFactory::toString(s.append("DiskNormalize "));
  1580. }
  1581. };
  1582. ISlaveActivityFactory *createRoxieDiskNormalizeActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  1583. {
  1584. return new CRoxieDiskNormalizeActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory);
  1585. }
  1586. //================================================================================================
  1587. // RecordProcessors used by Disk Normalize activity.
  1588. class NormalizeRecordProcessor : public RecordProcessor
  1589. {
  1590. public:
  1591. NormalizeRecordProcessor(IInMemoryIndexCursor *_cursor, CRoxieDiskNormalizeActivity &_owner)
  1592. : RecordProcessor(_cursor), owner(_owner)
  1593. {
  1594. helper = _owner.helper;
  1595. }
  1596. protected:
  1597. CRoxieDiskNormalizeActivity &owner;
  1598. IHThorDiskNormalizeArg *helper;
  1599. };
  1600. // Used when we have an in-memory key that matches at least some of the filter conditions
  1601. class KeyedNormalizeRecordProcessor : public NormalizeRecordProcessor
  1602. {
  1603. public:
  1604. KeyedNormalizeRecordProcessor(IInMemoryIndexCursor *_cursor, CRoxieDiskNormalizeActivity &_owner, bool _resent)
  1605. : NormalizeRecordProcessor(_cursor, _owner)
  1606. {
  1607. resent = _resent;
  1608. helper->setCallback(cursor);
  1609. }
  1610. virtual void doQuery(IMessagePacker *output, unsigned processed, unsigned __int64 rowLimit, unsigned __int64 stopAfter)
  1611. {
  1612. // doQuery needs to be as fast as possible - we are making a virtual call to it per query in order to avoid tests of loop-invariants within it
  1613. unsigned totalSizeSent = 0;
  1614. IInMemoryIndexCursor *lc = cursor;
  1615. if (!resent)
  1616. lc->reset();
  1617. bool continuationFailed = false;
  1618. while (!aborted)
  1619. {
  1620. const void *nextCandidate = lc->nextMatch();
  1621. if (!nextCandidate)
  1622. break;
  1623. if (helper->first(nextCandidate))
  1624. {
  1625. do
  1626. {
  1627. size32_t transformedSize = owner.doNormalizeTransform(output);
  1628. if (transformedSize)
  1629. {
  1630. processed++;
  1631. if (processed > rowLimit)
  1632. {
  1633. owner.limitExceeded();
  1634. return;
  1635. }
  1636. totalSizeSent += transformedSize;
  1637. if (processed == stopAfter)
  1638. return;
  1639. }
  1640. } while (helper->next());
  1641. if (totalSizeSent > indexReadChunkSize && !continuationFailed)
  1642. {
  1643. MemoryBuffer si;
  1644. unsigned short siLen = 0;
  1645. si.append(siLen);
  1646. si.append(processed);
  1647. si.append(true); // using a key
  1648. lc->serializeCursorPos(si);
  1649. if (si.length() <= maxContinuationSize)
  1650. {
  1651. siLen = si.length() - sizeof(siLen);
  1652. si.writeDirect(0, sizeof(siLen), &siLen);
  1653. output->sendMetaInfo(si.toByteArray(), si.length());
  1654. return;
  1655. }
  1656. else
  1657. continuationFailed = true;
  1658. }
  1659. }
  1660. }
  1661. }
  1662. private:
  1663. bool resent;
  1664. };
  1665. // Used when we have no key
  1666. // Not split into variable vs fixed varieties (unlike others). We could if there was a demand
  1667. class UnkeyedNormalizeRecordProcessor : public NormalizeRecordProcessor
  1668. {
  1669. public:
  1670. IMPLEMENT_IINTERFACE;
  1671. UnkeyedNormalizeRecordProcessor(IInMemoryIndexCursor *_cursor, CRoxieDiskNormalizeActivity &_owner, IDirectReader *_reader)
  1672. : NormalizeRecordProcessor(_cursor, _owner), reader(_reader), deserializeSource(_reader)
  1673. {
  1674. prefetcher.setown(owner.diskSize.queryOriginal()->createDiskPrefetcher(owner.queryContext->queryCodeContext(), owner.basefactory->queryId()));
  1675. }
  1676. virtual void doQuery(IMessagePacker *output, unsigned processed, unsigned __int64 rowLimit, unsigned __int64 stopAfter)
  1677. {
  1678. unsigned totalSizeSent = 0;
  1679. helper->setCallback(reader->queryThorDiskCallback());
  1680. while (!aborted && !deserializeSource.eos())
  1681. {
  1682. prefetcher->readAhead(deserializeSource);
  1683. const byte *nextRec = deserializeSource.queryRow();
  1684. if (!cursor || !cursor->isFiltered(nextRec))
  1685. {
  1686. if (helper->first(nextRec))
  1687. {
  1688. do
  1689. {
  1690. size32_t transformedSize = owner.doNormalizeTransform(output);
  1691. if (transformedSize)
  1692. {
  1693. processed++;
  1694. if (processed > rowLimit)
  1695. {
  1696. owner.limitExceeded();
  1697. return;
  1698. }
  1699. totalSizeSent += transformedSize;
  1700. if (processed == stopAfter)
  1701. return;
  1702. }
  1703. } while (helper->next());
  1704. }
  1705. }
  1706. deserializeSource.finishedRow();
  1707. if (totalSizeSent > indexReadChunkSize)
  1708. {
  1709. MemoryBuffer si;
  1710. unsigned short siLen = 0;
  1711. si.append(siLen);
  1712. si.append(processed);
  1713. si.append(false); // not using a key
  1714. offset_t readPos = deserializeSource.tell();
  1715. si.append(readPos);
  1716. siLen = si.length() - sizeof(siLen);
  1717. si.writeDirect(0, sizeof(siLen), &siLen);
  1718. output->sendMetaInfo(si.toByteArray(), si.length());
  1719. return;
  1720. }
  1721. }
  1722. }
  1723. protected:
  1724. Owned<IDirectReader> reader;
  1725. CThorContiguousRowBuffer deserializeSource;
  1726. Owned<ISourceRowPrefetcher> prefetcher;
  1727. };
  1728. IInMemoryFileProcessor *createKeyedNormalizeRecordProcessor(IInMemoryIndexCursor *cursor, CRoxieDiskNormalizeActivity &owner, bool resent)
  1729. {
  1730. return new KeyedNormalizeRecordProcessor(cursor, owner, resent);
  1731. }
  1732. IInMemoryFileProcessor *createUnkeyedNormalizeRecordProcessor(IInMemoryIndexCursor *cursor, CRoxieDiskNormalizeActivity &owner, IDirectReader *_reader)
  1733. {
  1734. return new UnkeyedNormalizeRecordProcessor(cursor, owner, _reader);
  1735. }
  1736. //================================================================================================
  1737. class CRoxieDiskCountActivity;
  1738. IInMemoryFileProcessor *createKeyedCountRecordProcessor(IInMemoryIndexCursor *cursor, CRoxieDiskCountActivity &owner);
  1739. IInMemoryFileProcessor *createUnkeyedCountRecordProcessor(IInMemoryIndexCursor *cursor, CRoxieDiskCountActivity &owner, bool variableDisk, IDirectReader *reader);
  1740. class CRoxieDiskCountActivity : public CRoxieDiskReadBaseActivity
  1741. {
  1742. friend class CountRecordProcessor;
  1743. protected:
  1744. IHThorDiskCountArg *helper;
  1745. public:
  1746. IMPLEMENT_IINTERFACE;
  1747. CRoxieDiskCountActivity(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory, const CSlaveActivityFactory *_aFactory,
  1748. IInMemoryIndexManager *_manager)
  1749. : CRoxieDiskReadBaseActivity(_logctx, _packet, _hFactory, _aFactory, _manager, 0, 1, false)
  1750. {
  1751. onCreate();
  1752. helper = (IHThorDiskCountArg *) basehelper;
  1753. }
  1754. virtual StringBuffer &toString(StringBuffer &ret) const
  1755. {
  1756. return ret.appendf("DiskCount %u", packet->queryHeader().activityId);
  1757. }
  1758. virtual void doProcess(IMessagePacker * output)
  1759. {
  1760. {
  1761. CriticalBlock p(pcrit);
  1762. processor.setown(isKeyed ?
  1763. createKeyedCountRecordProcessor(cursor, *this) :
  1764. createUnkeyedCountRecordProcessor(cursor, *this, diskSize.isVariableSize(), manager->createReader(readPos, parallelPartNo, numParallel)));
  1765. }
  1766. unsigned __int64 stopAfter = helper->getChooseNLimit();
  1767. processor->doQuery(output, processed, (unsigned __int64) -1, stopAfter);
  1768. }
  1769. };
  1770. class CRoxieDiskCountActivityFactory : public CRoxieDiskBaseActivityFactory
  1771. {
  1772. public:
  1773. IMPLEMENT_IINTERFACE;
  1774. CRoxieDiskCountActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  1775. : CRoxieDiskBaseActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory)
  1776. {
  1777. }
  1778. virtual IRoxieSlaveActivity *createActivity(SlaveContextLogger &logctx, IRoxieQueryPacket *packet) const
  1779. {
  1780. return new CRoxieDiskCountActivity(logctx, packet, helperFactory, this, manager);
  1781. }
  1782. virtual StringBuffer &toString(StringBuffer &s) const
  1783. {
  1784. return CSlaveActivityFactory::toString(s.append("DiskRead "));
  1785. }
  1786. };
  1787. //================================================================================================
  1788. // RecordProcessors used by Disk Normalize activity.
  1789. // Note - the classes below could be commoned up to make the code smaller, but they have been deliberately unrolled to
  1790. // keep to a bare minimum the number of virtual calls/variable tests per record scanned. This is very speed critical.
  1791. class CountRecordProcessor : public RecordProcessor
  1792. {
  1793. public:
  1794. CountRecordProcessor(IInMemoryIndexCursor *_cursor, CRoxieDiskCountActivity &_owner)
  1795. : RecordProcessor(_cursor), owner(_owner)
  1796. {
  1797. helper = _owner.helper;
  1798. }
  1799. protected:
  1800. CRoxieDiskCountActivity &owner;
  1801. IHThorDiskCountArg *helper;
  1802. };
  1803. // Used when we have an in-memory key that matches at least some of the filter conditions
  1804. class KeyedCountRecordProcessor : public CountRecordProcessor
  1805. {
  1806. public:
  1807. KeyedCountRecordProcessor(IInMemoryIndexCursor *_cursor, CRoxieDiskCountActivity &_owner) : CountRecordProcessor(_cursor, _owner)
  1808. {
  1809. helper->setCallback(cursor);
  1810. }
  1811. virtual void doQuery(IMessagePacker *output, unsigned processed, unsigned __int64 rowLimit, unsigned __int64 stopAfter)
  1812. {
  1813. // doQuery needs to be as fast as possible - we are making a virtual call to it per query in order to avoid tests of loop-invariants within it
  1814. unsigned recordSize = owner.meta.getFixedSize();
  1815. void *recBuffer = output->getBuffer(recordSize, false);
  1816. IInMemoryIndexCursor *lc = cursor;
  1817. lc->reset();
  1818. unsigned __int64 totalCount = 0;
  1819. while (!aborted)
  1820. {
  1821. const void *nextCandidate = lc->nextMatch();
  1822. if (!nextCandidate)
  1823. break;
  1824. totalCount += helper->numValid(nextCandidate);
  1825. if (totalCount >= stopAfter)
  1826. {
  1827. totalCount = stopAfter;
  1828. break;
  1829. }
  1830. }
  1831. if (!aborted)
  1832. {
  1833. assert(!owner.serializer); // A count can never need serializing, surely!
  1834. if (recordSize == 1)
  1835. *(byte *)recBuffer = (byte)totalCount;
  1836. else
  1837. {
  1838. assertex(recordSize == sizeof(unsigned __int64));
  1839. *(unsigned __int64 *)recBuffer = totalCount;
  1840. }
  1841. output->putBuffer(recBuffer, recordSize, false);
  1842. }
  1843. }
  1844. };
  1845. IInMemoryFileProcessor *createKeyedCountRecordProcessor(IInMemoryIndexCursor *cursor, CRoxieDiskCountActivity &owner)
  1846. {
  1847. return new KeyedCountRecordProcessor(cursor, owner);
  1848. }
  1849. // Used when there is no key, fixed records
  1850. class UnkeyedCountRecordProcessor : public CountRecordProcessor
  1851. {
  1852. protected:
  1853. Owned<IDirectReader> reader;
  1854. public:
  1855. UnkeyedCountRecordProcessor(IInMemoryIndexCursor *_cursor, CRoxieDiskCountActivity &_owner, IDirectReader *_reader)
  1856. : CountRecordProcessor(_cursor, _owner), reader(_reader)
  1857. {
  1858. }
  1859. // This version is used for fixed size rows only - variable size rows use more derived class which overrides
  1860. virtual void doQuery(IMessagePacker *output, unsigned processed, unsigned __int64 rowLimit, unsigned __int64 stopAfter)
  1861. {
  1862. unsigned outputRecordSize = owner.meta.getFixedSize();
  1863. void *recBuffer = output->getBuffer(outputRecordSize, false);
  1864. helper->setCallback(reader->queryThorDiskCallback());
  1865. unsigned __int64 totalCount = 0;
  1866. size32_t recordSize = owner.diskSize.getFixedSize();
  1867. size32_t bufferSize = getBufferSize(recordSize);
  1868. while (!aborted && !reader->eos())
  1869. {
  1870. size32_t gotSize;
  1871. const char *nextRec = (const char *) reader->peek(bufferSize, gotSize);
  1872. if (!gotSize)
  1873. break;
  1874. gotSize = roundDown(gotSize, recordSize);
  1875. if (cursor)
  1876. {
  1877. const char *endRec = nextRec + gotSize;
  1878. loop
  1879. {
  1880. // This loop is the inner loop for memory disk counts - so keep it efficient!
  1881. if (nextRec >= endRec)
  1882. break;
  1883. if (!cursor->isFiltered(nextRec))
  1884. {
  1885. totalCount += helper->numValid(nextRec);
  1886. if (totalCount >= stopAfter)
  1887. break;
  1888. }
  1889. nextRec += recordSize;
  1890. }
  1891. }
  1892. else
  1893. totalCount += helper->numValid(gotSize, nextRec);
  1894. if (totalCount >= stopAfter)
  1895. {
  1896. totalCount = stopAfter;
  1897. break;
  1898. }
  1899. reader->skip(gotSize);
  1900. }
  1901. if (!aborted)
  1902. {
  1903. assert(!owner.serializer); // A count can never need serializing, surely!
  1904. if (outputRecordSize == 1)
  1905. *(byte *)recBuffer = (byte)totalCount;
  1906. else
  1907. {
  1908. assertex(outputRecordSize == sizeof(unsigned __int64));
  1909. *(unsigned __int64 *)recBuffer = totalCount;
  1910. }
  1911. output->putBuffer(recBuffer, outputRecordSize, false);
  1912. }
  1913. }
  1914. };
  1915. // Used when there is no key, variable records
  1916. class UnkeyedVariableCountRecordProcessor : public UnkeyedCountRecordProcessor
  1917. {
  1918. public:
  1919. UnkeyedVariableCountRecordProcessor(IInMemoryIndexCursor *_cursor, CRoxieDiskCountActivity &_owner, IDirectReader *_reader)
  1920. : UnkeyedCountRecordProcessor(_cursor, _owner, _reader), deserializeSource(reader)
  1921. {
  1922. prefetcher.setown(owner.diskSize.queryOriginal()->createDiskPrefetcher(owner.queryContext->queryCodeContext(), owner.basefactory->queryId()));
  1923. }
  1924. // This version is used for variable size rows
  1925. virtual void doQuery(IMessagePacker *output, unsigned processed, unsigned __int64 rowLimit, unsigned __int64 stopAfter)
  1926. {
  1927. unsigned outputRecordSize = owner.meta.getFixedSize();
  1928. void *recBuffer = output->getBuffer(outputRecordSize, false);
  1929. helper->setCallback(reader->queryThorDiskCallback());
  1930. unsigned __int64 totalCount = 0;
  1931. while (!aborted && !deserializeSource.eos())
  1932. {
  1933. prefetcher->readAhead(deserializeSource);
  1934. const byte *nextRec = deserializeSource.queryRow();
  1935. if (!cursor || !cursor->isFiltered(nextRec))
  1936. {
  1937. totalCount += helper->numValid(nextRec);
  1938. if (totalCount >= stopAfter)
  1939. {
  1940. totalCount = stopAfter;
  1941. break;
  1942. }
  1943. }
  1944. deserializeSource.finishedRow();
  1945. }
  1946. if (!aborted)
  1947. {
  1948. assert(!owner.serializer); // A count can never need serializing, surely!
  1949. if (outputRecordSize == 1)
  1950. *(byte *)recBuffer = (byte)totalCount;
  1951. else
  1952. {
  1953. assertex(outputRecordSize == sizeof(unsigned __int64));
  1954. *(unsigned __int64 *)recBuffer = totalCount;
  1955. }
  1956. output->putBuffer(recBuffer, outputRecordSize, false);
  1957. }
  1958. }
  1959. protected:
  1960. CThorContiguousRowBuffer deserializeSource;
  1961. Owned<ISourceRowPrefetcher> prefetcher;
  1962. };
  1963. IInMemoryFileProcessor *createUnkeyedCountRecordProcessor(IInMemoryIndexCursor *cursor, CRoxieDiskCountActivity &owner, bool variableDisk, IDirectReader *reader)
  1964. {
  1965. if (variableDisk)
  1966. return new UnkeyedVariableCountRecordProcessor(cursor, owner, reader);
  1967. else
  1968. return new UnkeyedCountRecordProcessor(cursor, owner, reader);
  1969. }
  1970. ISlaveActivityFactory *createRoxieDiskCountActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  1971. {
  1972. return new CRoxieDiskCountActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory);
  1973. }
  1974. //================================================================================================
  1975. class CRoxieDiskAggregateActivity;
  1976. IInMemoryFileProcessor *createKeyedAggregateRecordProcessor(IInMemoryIndexCursor *cursor, CRoxieDiskAggregateActivity &owner);
  1977. IInMemoryFileProcessor *createUnkeyedAggregateRecordProcessor(IInMemoryIndexCursor *cursor, CRoxieDiskAggregateActivity &owner, bool variableDisk, IDirectReader *reader);
  1978. class CRoxieDiskAggregateActivity : public CRoxieDiskReadBaseActivity
  1979. {
  1980. friend class AggregateRecordProcessor;
  1981. protected:
  1982. IHThorDiskAggregateArg *helper;
  1983. public:
  1984. IMPLEMENT_IINTERFACE;
  1985. CRoxieDiskAggregateActivity(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory, const CSlaveActivityFactory *_aFactory,
  1986. IInMemoryIndexManager *_manager,
  1987. unsigned _parallelPartNo, unsigned _numParallel, bool _forceUnkeyed)
  1988. : CRoxieDiskReadBaseActivity(_logctx, _packet, _hFactory, _aFactory, _manager, _parallelPartNo, _numParallel, _forceUnkeyed)
  1989. {
  1990. onCreate();
  1991. helper = (IHThorDiskAggregateArg *) basehelper;
  1992. }
  1993. virtual bool needsRowAllocator()
  1994. {
  1995. return true;
  1996. }
  1997. virtual StringBuffer &toString(StringBuffer &ret) const
  1998. {
  1999. return ret.appendf("DiskAggregate %u", packet->queryHeader().activityId);
  2000. }
  2001. virtual void doProcess(IMessagePacker * output)
  2002. {
  2003. {
  2004. CriticalBlock p(pcrit);
  2005. processor.setown(isKeyed ? createKeyedAggregateRecordProcessor(cursor, *this) :
  2006. createUnkeyedAggregateRecordProcessor(cursor, *this, diskSize.isVariableSize(), manager->createReader(readPos, parallelPartNo, numParallel)));
  2007. }
  2008. processor->doQuery(output, 0, 0, 0);
  2009. }
  2010. };
  2011. //================================================================================================
  2012. class CParallelRoxieActivity : public CRoxieSlaveActivity
  2013. {
  2014. protected:
  2015. CIArrayOf<CRoxieDiskReadBaseActivity> parts;
  2016. unsigned numParallel;
  2017. CriticalSection parCrit;
  2018. Owned<IOutputRowDeserializer> deserializer;
  2019. public:
  2020. IMPLEMENT_IINTERFACE;
  2021. CParallelRoxieActivity(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory, const CSlaveActivityFactory *_factory, unsigned _numParallel)
  2022. : CRoxieSlaveActivity(_logctx, _packet, _hFactory, _factory), numParallel(_numParallel)
  2023. {
  2024. assertex(numParallel > 1);
  2025. }
  2026. virtual void abort()
  2027. {
  2028. ForEachItemIn(idx, parts)
  2029. {
  2030. parts.item(idx).abort();
  2031. }
  2032. }
  2033. virtual void setPartNo(bool filechanged) { throwUnexpected(); }
  2034. virtual StringBuffer &toString(StringBuffer &ret) const
  2035. {
  2036. return parts.item(0).toString(ret);
  2037. }
  2038. virtual const char *queryDynamicFileName() const
  2039. {
  2040. throwUnexpected();
  2041. }
  2042. virtual void setVariableFileInfo()
  2043. {
  2044. throwUnexpected();
  2045. }
  2046. virtual void doProcess(IMessagePacker * output) = 0;
  2047. virtual void processRow(CDummyMessagePacker &output) = 0;
  2048. virtual bool process()
  2049. {
  2050. if (numParallel == 1)
  2051. {
  2052. return parts.item(0).process();
  2053. }
  2054. else
  2055. {
  2056. MTIME_SECTION(timer, "CParallelRoxieActivity::process");
  2057. atomic_inc(&diskReadStarted);
  2058. Owned<IMessagePacker> output = ROQ->createOutputStream(packet->queryHeader(), false, logctx);
  2059. class casyncfor: public CAsyncFor
  2060. {
  2061. CIArrayOf<CRoxieDiskReadBaseActivity> &parts;
  2062. CParallelRoxieActivity &parent;
  2063. public:
  2064. casyncfor(CIArrayOf<CRoxieDiskReadBaseActivity> &_parts, CParallelRoxieActivity &_parent)
  2065. : parts(_parts), parent(_parent)
  2066. {
  2067. }
  2068. void Do(unsigned i)
  2069. {
  2070. try
  2071. {
  2072. CDummyMessagePacker d;
  2073. parts.item(i).doProcess(&d);
  2074. d.flush(true);
  2075. parent.processRow(d);
  2076. }
  2077. catch (IException *)
  2078. {
  2079. // if one throws exception, may as well abort the rest
  2080. parent.abort();
  2081. throw;
  2082. }
  2083. }
  2084. } afor(parts, *this);
  2085. afor.For(numParallel, numParallel);
  2086. //for (unsigned i = 0; i < numParallel; i++) afor.Do(i); // use this instead of line above to make them serial - handy for debugging!
  2087. logctx.flush(true, aborted);
  2088. if (aborted)
  2089. {
  2090. output->abort();
  2091. return false;
  2092. }
  2093. else
  2094. {
  2095. doProcess(output);
  2096. output->flush(true);
  2097. atomic_inc(&diskReadCompleted);
  2098. return true;
  2099. }
  2100. return true;
  2101. }
  2102. }
  2103. };
  2104. class CParallelRoxieDiskAggregateActivity : public CParallelRoxieActivity
  2105. {
  2106. protected:
  2107. IHThorDiskAggregateArg *helper;
  2108. OwnedConstRoxieRow finalRow;
  2109. public:
  2110. IMPLEMENT_IINTERFACE;
  2111. CParallelRoxieDiskAggregateActivity(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory, const CSlaveActivityFactory *_aFactory,
  2112. IInMemoryIndexManager *_manager, unsigned _numParallel) :
  2113. CParallelRoxieActivity(_logctx, _packet, _hFactory, _aFactory, _numParallel)
  2114. {
  2115. helper = (IHThorDiskAggregateArg *) basehelper;
  2116. onCreate();
  2117. if (meta.needsSerializeDisk())
  2118. {
  2119. // MORE - avoiding serializing to dummy would be more efficient...
  2120. deserializer.setown(meta.createDiskDeserializer(queryContext->queryCodeContext(), basefactory->queryId()));
  2121. }
  2122. CRoxieDiskAggregateActivity *part0 = new CRoxieDiskAggregateActivity(_logctx, _packet, _hFactory, _aFactory, _manager, 0, numParallel, false);
  2123. parts.append(*part0);
  2124. if (part0->queryKeyed())
  2125. {
  2126. numParallel = 1;
  2127. part0->setParallel(0, 1);
  2128. }
  2129. else
  2130. {
  2131. for (unsigned i = 1; i < numParallel; i++)
  2132. parts.append(*new CRoxieDiskAggregateActivity(_logctx, _packet, _hFactory, _aFactory, _manager, i, numParallel, true));
  2133. }
  2134. }
  2135. ~CParallelRoxieDiskAggregateActivity()
  2136. {
  2137. finalRow.clear();
  2138. }
  2139. virtual bool needsRowAllocator()
  2140. {
  2141. return true;
  2142. }
  2143. virtual void doProcess(IMessagePacker *output)
  2144. {
  2145. if (!aborted)
  2146. {
  2147. if (!finalRow)
  2148. {
  2149. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  2150. size32_t size = helper->clearAggregate(rowBuilder);
  2151. finalRow.setown(rowBuilder.finalizeRowClear(size));
  2152. }
  2153. //GH-RKC: This can probably be cleaner and more efficient using the OptimizedRowBuilder class introduced since I fixed this code
  2154. if (serializer)
  2155. serializeRow(output, finalRow);
  2156. else
  2157. {
  2158. size32_t size = meta.getRecordSize(finalRow);
  2159. appendBuffer(output, size, finalRow, meta.isVariableSize());
  2160. }
  2161. }
  2162. finalRow.clear();
  2163. helper->setCallback(NULL);
  2164. }
  2165. virtual void processRow(CDummyMessagePacker &d)
  2166. {
  2167. CriticalBlock c(parCrit);
  2168. MemoryBuffer &m = d.data;
  2169. RtlDynamicRowBuilder finalBuilder(rowAllocator, false);
  2170. if (deserializer)
  2171. {
  2172. Owned<ISerialStream> stream = createMemoryBufferSerialStream(m);
  2173. CThorStreamDeserializerSource rowSource(stream);
  2174. while (m.remaining())
  2175. {
  2176. RecordLengthType *rowLen = (RecordLengthType *) m.readDirect(sizeof(RecordLengthType));
  2177. if (!*rowLen)
  2178. break;
  2179. RecordLengthType len = *rowLen;
  2180. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  2181. size_t outsize = deserializer->deserialize(rowBuilder, rowSource);
  2182. if (!finalBuilder.exists())
  2183. finalBuilder.swapWith(rowBuilder);
  2184. else
  2185. {
  2186. const void * deserialized = rowBuilder.finalizeRowClear(outsize);
  2187. helper->mergeAggregate(finalBuilder, deserialized);
  2188. ReleaseRoxieRow(deserialized);
  2189. }
  2190. }
  2191. }
  2192. else
  2193. {
  2194. RecordLengthType len = meta.getFixedSize();
  2195. while (m.remaining())
  2196. {
  2197. const void *row;
  2198. if (!meta.isFixedSize())
  2199. {
  2200. RecordLengthType *rowLen = (RecordLengthType *) m.readDirect(sizeof(RecordLengthType));
  2201. if (!*rowLen)
  2202. break;
  2203. len = *rowLen;
  2204. }
  2205. row = m.readDirect(len);
  2206. if (!finalBuilder.exists())
  2207. cloneRow(finalBuilder, row, meta);
  2208. else
  2209. helper->mergeAggregate(finalBuilder, row);
  2210. }
  2211. }
  2212. if (finalBuilder.exists())
  2213. {
  2214. size32_t finalSize = meta.getRecordSize(finalBuilder.getSelf()); // MORE - can probably track it above...
  2215. finalRow.setown(finalBuilder.finalizeRowClear(finalSize));
  2216. }
  2217. }
  2218. };
  2219. class CRoxieDiskAggregateActivityFactory : public CRoxieDiskBaseActivityFactory
  2220. {
  2221. public:
  2222. IMPLEMENT_IINTERFACE;
  2223. CRoxieDiskAggregateActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  2224. : CRoxieDiskBaseActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory)
  2225. {
  2226. }
  2227. virtual IRoxieSlaveActivity *createActivity(SlaveContextLogger &logctx, IRoxieQueryPacket *packet) const
  2228. {
  2229. if (parallelAggregate > 1)
  2230. return new CParallelRoxieDiskAggregateActivity(logctx, packet, helperFactory, this, manager, parallelAggregate);
  2231. else
  2232. return new CRoxieDiskAggregateActivity(logctx, packet, helperFactory, this, manager, 0, 1, false);
  2233. }
  2234. virtual StringBuffer &toString(StringBuffer &s) const
  2235. {
  2236. return CSlaveActivityFactory::toString(s.append("DiskRead "));
  2237. }
  2238. };
  2239. //================================================================================================
  2240. // RecordProcessors used by Disk Aggregate activity.
  2241. // Note - the classes below could be commoned up to make the code smaller, but they have been deliberately unrolled to
  2242. // keep to a bare minimum the number of virtual calls/variable tests per record scanned. This is very speed critical.
  2243. class AggregateRecordProcessor : public RecordProcessor
  2244. {
  2245. public:
  2246. AggregateRecordProcessor(IInMemoryIndexCursor *_cursor, CRoxieDiskAggregateActivity &_owner) : RecordProcessor(_cursor), owner(_owner)
  2247. {
  2248. helper = _owner.helper;
  2249. }
  2250. protected:
  2251. CRoxieDiskAggregateActivity &owner;
  2252. IHThorDiskAggregateArg *helper;
  2253. };
  2254. // Used when we have an in-memory key that matches at least some of the filter conditions
  2255. class KeyedAggregateRecordProcessor : public AggregateRecordProcessor
  2256. {
  2257. public:
  2258. KeyedAggregateRecordProcessor(IInMemoryIndexCursor *_cursor, CRoxieDiskAggregateActivity &_owner) : AggregateRecordProcessor(_cursor, _owner)
  2259. {
  2260. helper->setCallback(cursor);
  2261. }
  2262. virtual void doQuery(IMessagePacker *output, unsigned processed, unsigned __int64 rowLimit, unsigned __int64 stopAfter)
  2263. {
  2264. // doQuery needs to be as fast as possible - we are making a virtual call to it per query in order to avoid tests of loop-invariants within it
  2265. OptimizedRowBuilder rowBuilder(owner.rowAllocator, owner.meta, output, owner.serializer);
  2266. helper->clearAggregate(rowBuilder);
  2267. IInMemoryIndexCursor *lc = cursor;
  2268. lc->reset();
  2269. while (!aborted)
  2270. {
  2271. const void *nextCandidate = lc->nextMatch();
  2272. if (!nextCandidate)
  2273. break;
  2274. helper->processRow(rowBuilder, nextCandidate);
  2275. }
  2276. if (!aborted)
  2277. {
  2278. if (helper->processedAnyRows())
  2279. {
  2280. size32_t finalSize = owner.meta.getRecordSize(rowBuilder.getSelf());
  2281. rowBuilder.writeToOutput(finalSize, true);
  2282. }
  2283. }
  2284. }
  2285. };
  2286. IInMemoryFileProcessor *createKeyedAggregateRecordProcessor(IInMemoryIndexCursor *cursor, CRoxieDiskAggregateActivity &owner)
  2287. {
  2288. return new KeyedAggregateRecordProcessor(cursor, owner);
  2289. }
  2290. // Used when we have no key - fixed size records
  2291. class UnkeyedAggregateRecordProcessor : public AggregateRecordProcessor
  2292. {
  2293. public:
  2294. UnkeyedAggregateRecordProcessor(IInMemoryIndexCursor *_cursor, CRoxieDiskAggregateActivity &_owner, IDirectReader *_reader)
  2295. : AggregateRecordProcessor(_cursor, _owner), reader(_reader)
  2296. {
  2297. helper->setCallback(reader->queryThorDiskCallback());
  2298. }
  2299. // Note that variable size record handler overrides this class
  2300. virtual void doQuery(IMessagePacker *output, unsigned processed, unsigned __int64 rowLimit, unsigned __int64 stopAfter)
  2301. {
  2302. OptimizedRowBuilder rowBuilder(owner.rowAllocator, owner.meta, output, owner.serializer);
  2303. helper->clearAggregate(rowBuilder);
  2304. size32_t recordSize = owner.diskSize.getFixedSize();
  2305. size32_t bufferSize = getBufferSize(recordSize);
  2306. while (!aborted)
  2307. {
  2308. size32_t gotSize;
  2309. const char *firstRec = (const char *) reader->peek(bufferSize, gotSize);
  2310. if (!gotSize)
  2311. break;
  2312. gotSize = roundDown(gotSize, recordSize);
  2313. const char *nextRec = firstRec;
  2314. endRec = firstRec + gotSize;
  2315. // This loop is the inner loop for memory diskreads - so keep it efficient!
  2316. if (cursor) // Moved this test out of the loop below for speed!
  2317. {
  2318. while (nextRec <= endRec)
  2319. {
  2320. if (!cursor->isFiltered(nextRec))
  2321. helper->processRow(rowBuilder, nextRec);
  2322. nextRec += recordSize;
  2323. }
  2324. }
  2325. else
  2326. {
  2327. while (nextRec <= endRec)
  2328. {
  2329. helper->processRow(rowBuilder, nextRec);
  2330. nextRec += recordSize;
  2331. }
  2332. }
  2333. reader->skip(gotSize);
  2334. }
  2335. if (!aborted)
  2336. {
  2337. if (helper->processedAnyRows())
  2338. {
  2339. size32_t finalSize = owner.meta.getRecordSize(rowBuilder.getSelf());
  2340. rowBuilder.writeToOutput(finalSize, true);
  2341. }
  2342. }
  2343. }
  2344. protected:
  2345. Owned<IDirectReader> reader;
  2346. };
  2347. // Used when we have no key - variablesize records
  2348. class UnkeyedVariableAggregateRecordProcessor : public UnkeyedAggregateRecordProcessor
  2349. {
  2350. public:
  2351. UnkeyedVariableAggregateRecordProcessor(IInMemoryIndexCursor *_cursor, CRoxieDiskAggregateActivity &_owner, IDirectReader *_reader)
  2352. : UnkeyedAggregateRecordProcessor(_cursor, _owner, _reader), deserializeSource(_reader)
  2353. {
  2354. prefetcher.setown(owner.diskSize.queryOriginal()->createDiskPrefetcher(owner.queryContext->queryCodeContext(), owner.basefactory->queryId()));
  2355. }
  2356. virtual void doQuery(IMessagePacker *output, unsigned processed, unsigned __int64 rowLimit, unsigned __int64 stopAfter)
  2357. {
  2358. OptimizedRowBuilder rowBuilder(owner.rowAllocator, owner.meta, output, owner.serializer);
  2359. helper->clearAggregate(rowBuilder);
  2360. while (!aborted && !deserializeSource.eos())
  2361. {
  2362. prefetcher->readAhead(deserializeSource);
  2363. const byte *nextRec = deserializeSource.queryRow();
  2364. if (!cursor || !cursor->isFiltered(nextRec))
  2365. {
  2366. helper->processRow(rowBuilder, nextRec);
  2367. }
  2368. deserializeSource.finishedRow();
  2369. }
  2370. if (!aborted)
  2371. {
  2372. if (helper->processedAnyRows())
  2373. {
  2374. size32_t finalSize = owner.meta.getRecordSize(rowBuilder.getSelf());
  2375. rowBuilder.writeToOutput(finalSize, true);
  2376. }
  2377. }
  2378. }
  2379. protected:
  2380. CThorContiguousRowBuffer deserializeSource;
  2381. Owned<ISourceRowPrefetcher> prefetcher;
  2382. };
  2383. IInMemoryFileProcessor *createUnkeyedAggregateRecordProcessor(IInMemoryIndexCursor *_cursor, CRoxieDiskAggregateActivity &_owner, bool variableDisk, IDirectReader *_reader)
  2384. {
  2385. if (variableDisk)
  2386. return new UnkeyedVariableAggregateRecordProcessor(_cursor, _owner, _reader);
  2387. else
  2388. return new UnkeyedAggregateRecordProcessor(_cursor, _owner, _reader);
  2389. }
  2390. ISlaveActivityFactory *createRoxieDiskAggregateActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  2391. {
  2392. return new CRoxieDiskAggregateActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory);
  2393. }
  2394. //================================================================================================
  2395. class CRoxieDiskGroupAggregateActivity : public CRoxieDiskReadBaseActivity
  2396. {
  2397. protected:
  2398. IHThorDiskGroupAggregateArg *helper;
  2399. RowAggregator results;
  2400. void outputResults(IMessagePacker *output)
  2401. {
  2402. if (!aborted)
  2403. {
  2404. loop
  2405. {
  2406. Owned<AggregateRowBuilder> next = results.nextResult();
  2407. if (!next)
  2408. break;
  2409. unsigned rowSize = next->querySize();
  2410. OwnedConstRoxieRow row(next->finalizeRowClear());
  2411. if (serializer)
  2412. {
  2413. serializeRow(output, row);
  2414. }
  2415. else
  2416. {
  2417. void *recBuffer = output->getBuffer(rowSize, meta.isVariableSize());
  2418. memcpy(recBuffer, row, rowSize);
  2419. output->putBuffer(recBuffer, rowSize, meta.isVariableSize());
  2420. }
  2421. }
  2422. }
  2423. }
  2424. public:
  2425. IMPLEMENT_IINTERFACE;
  2426. CRoxieDiskGroupAggregateActivity(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory, const CSlaveActivityFactory *_aFactory,
  2427. IInMemoryIndexManager *_manager,
  2428. unsigned partNo, unsigned numParts, bool _forceUnkeyed)
  2429. : CRoxieDiskReadBaseActivity(_logctx, _packet, _hFactory, _aFactory, _manager, partNo, numParts, _forceUnkeyed),
  2430. helper((IHThorDiskGroupAggregateArg *) basehelper),
  2431. results(*helper, *helper)
  2432. {
  2433. onCreate();
  2434. results.start(rowAllocator);
  2435. }
  2436. virtual bool needsRowAllocator()
  2437. {
  2438. return true;
  2439. }
  2440. virtual StringBuffer &toString(StringBuffer &ret) const
  2441. {
  2442. return ret.appendf("DiskGroupAggregate %u", packet->queryHeader().activityId);
  2443. }
  2444. virtual void doProcess(IMessagePacker * output)
  2445. {
  2446. {
  2447. CriticalBlock p(pcrit);
  2448. processor.setown(isKeyed ?
  2449. createKeyedGroupAggregateRecordProcessor(cursor, results, *helper) :
  2450. createUnkeyedGroupAggregateRecordProcessor(cursor, results, *helper, manager->createReader(readPos, parallelPartNo, numParallel),
  2451. queryContext->queryCodeContext(), basefactory->queryId()));
  2452. }
  2453. processor->doQuery(output, 0, 0, 0);
  2454. if (!aborted)
  2455. outputResults(output);
  2456. results.reset();
  2457. }
  2458. };
  2459. class CParallelRoxieDiskGroupAggregateActivity : public CParallelRoxieActivity
  2460. {
  2461. protected:
  2462. IHThorDiskGroupAggregateArg *helper;
  2463. RowAggregator resultAggregator;
  2464. Owned<IRowManager> rowManager;
  2465. public:
  2466. IMPLEMENT_IINTERFACE;
  2467. CParallelRoxieDiskGroupAggregateActivity(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory, const CSlaveActivityFactory *_aFactory,
  2468. IInMemoryIndexManager *_manager, unsigned _numParallel) :
  2469. CParallelRoxieActivity(_logctx, _packet, _hFactory, _aFactory, _numParallel),
  2470. helper((IHThorDiskGroupAggregateArg *) basehelper),
  2471. resultAggregator(*helper, *helper)
  2472. {
  2473. onCreate();
  2474. resultAggregator.start(rowAllocator);
  2475. if (meta.needsSerializeDisk())
  2476. {
  2477. // MORE - avoiding serializing to dummy would be more efficient...
  2478. deserializer.setown(meta.createDiskDeserializer(queryContext->queryCodeContext(), basefactory->queryId()));
  2479. }
  2480. CRoxieDiskGroupAggregateActivity *part0 = new CRoxieDiskGroupAggregateActivity(_logctx, _packet, _hFactory, _aFactory, _manager, 0, numParallel, false);
  2481. parts.append(*part0);
  2482. if (part0->queryKeyed())
  2483. {
  2484. numParallel = 1;
  2485. part0->setParallel(0, 1);
  2486. }
  2487. else
  2488. {
  2489. for (unsigned i = 1; i < numParallel; i++)
  2490. parts.append(*new CRoxieDiskGroupAggregateActivity(_logctx, _packet, _hFactory, _aFactory, _manager, i, numParallel, true));
  2491. }
  2492. }
  2493. virtual bool needsRowAllocator()
  2494. {
  2495. return true;
  2496. }
  2497. virtual void doProcess(IMessagePacker *output)
  2498. {
  2499. if (!aborted)
  2500. {
  2501. loop
  2502. {
  2503. Owned<AggregateRowBuilder> next = resultAggregator.nextResult();
  2504. if (!next)
  2505. break;
  2506. unsigned rowSize = next->querySize();
  2507. OwnedConstRoxieRow row(next->finalizeRowClear());
  2508. if (serializer)
  2509. {
  2510. serializeRow(output, row);
  2511. }
  2512. else
  2513. {
  2514. void *recBuffer = output->getBuffer(rowSize, meta.isVariableSize());
  2515. memcpy(recBuffer, row, rowSize);
  2516. output->putBuffer(recBuffer, rowSize, meta.isVariableSize());
  2517. }
  2518. }
  2519. }
  2520. resultAggregator.reset();
  2521. helper->setCallback(NULL);
  2522. }
  2523. void processRow(CDummyMessagePacker &d)
  2524. {
  2525. CriticalBlock b(parCrit); // MORE - use a spinlock
  2526. MemoryBuffer &m = d.data;
  2527. Owned<ISerialStream> stream = createMemoryBufferSerialStream(m);
  2528. CThorStreamDeserializerSource rowSource(stream);
  2529. while (m.remaining())
  2530. {
  2531. const void *row;
  2532. if (meta.isFixedSize() && !deserializer)
  2533. {
  2534. row = m.readDirect(meta.getFixedSize());
  2535. resultAggregator.mergeElement(row);
  2536. }
  2537. else
  2538. {
  2539. RecordLengthType *rowLen = (RecordLengthType *) m.readDirect(sizeof(RecordLengthType));
  2540. if (!*rowLen)
  2541. break;
  2542. RecordLengthType len = *rowLen;
  2543. if (deserializer)
  2544. {
  2545. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  2546. size_t outsize = deserializer->deserialize(rowBuilder, rowSource);
  2547. OwnedConstRoxieRow deserialized = rowBuilder.finalizeRowClear(outsize);
  2548. resultAggregator.mergeElement(deserialized);
  2549. }
  2550. else
  2551. {
  2552. row = m.readDirect(len);
  2553. resultAggregator.mergeElement(row);
  2554. }
  2555. }
  2556. }
  2557. }
  2558. };
  2559. class CRoxieDiskGroupAggregateActivityFactory : public CRoxieDiskBaseActivityFactory
  2560. {
  2561. public:
  2562. IMPLEMENT_IINTERFACE;
  2563. CRoxieDiskGroupAggregateActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  2564. : CRoxieDiskBaseActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory)
  2565. {
  2566. }
  2567. virtual IRoxieSlaveActivity *createActivity(SlaveContextLogger &logctx, IRoxieQueryPacket *packet) const
  2568. {
  2569. if (parallelAggregate > 1)
  2570. return new CParallelRoxieDiskGroupAggregateActivity(logctx, packet, helperFactory, this, manager, parallelAggregate);
  2571. else
  2572. return new CRoxieDiskGroupAggregateActivity(logctx, packet, helperFactory, this, manager, 0, 1, false);
  2573. }
  2574. virtual StringBuffer &toString(StringBuffer &s) const
  2575. {
  2576. return CSlaveActivityFactory::toString(s.append("DiskRead "));
  2577. }
  2578. };
  2579. //================================================================================================
  2580. // RecordProcessors used by Disk Group Aggregate activity.
  2581. // Note - the classes below could be commoned up to make the code smaller, but they have been deliberately unrolled to
  2582. // keep to a bare minimum the number of virtual calls/variable tests per record scanned. This is very speed critical.
  2583. class GroupAggregateRecordProcessor : public RecordProcessor, implements IHThorGroupAggregateCallback
  2584. {
  2585. public:
  2586. IMPLEMENT_IINTERFACE;
  2587. GroupAggregateRecordProcessor(IInMemoryIndexCursor *_cursor, RowAggregator &_results, IHThorDiskGroupAggregateArg &_helper)
  2588. : RecordProcessor(_cursor),
  2589. results(_results),
  2590. helper(_helper)
  2591. {
  2592. }
  2593. virtual void processRow(const void * next)
  2594. {
  2595. results.addRow(next);
  2596. }
  2597. protected:
  2598. RowAggregator &results;
  2599. IHThorDiskGroupAggregateArg &helper;
  2600. };
  2601. // Used when we have an in-memory key that matches at least some of the filter conditions
  2602. class KeyedGroupAggregateRecordProcessor : public GroupAggregateRecordProcessor
  2603. {
  2604. public:
  2605. KeyedGroupAggregateRecordProcessor(IInMemoryIndexCursor *_cursor, RowAggregator &_results, IHThorDiskGroupAggregateArg &_helper)
  2606. : GroupAggregateRecordProcessor(_cursor, _results, _helper)
  2607. {
  2608. helper.setCallback(cursor);
  2609. }
  2610. virtual void doQuery(IMessagePacker *output, unsigned processed, unsigned __int64 rowLimit, unsigned __int64 stopAfter)
  2611. {
  2612. // doQuery needs to be as fast as possible - we are making a virtual call to it per query in order to avoid tests of loop-invariants within it
  2613. IInMemoryIndexCursor *lc = cursor;
  2614. lc->reset();
  2615. while (!aborted)
  2616. {
  2617. const void *nextCandidate = lc->nextMatch();
  2618. if (!nextCandidate)
  2619. break;
  2620. helper.processRow(nextCandidate, this);
  2621. }
  2622. }
  2623. };
  2624. IInMemoryFileProcessor *createKeyedGroupAggregateRecordProcessor(IInMemoryIndexCursor *cursor, RowAggregator &results, IHThorDiskGroupAggregateArg &helper)
  2625. {
  2626. return new KeyedGroupAggregateRecordProcessor(cursor, results, helper);
  2627. }
  2628. // Used when we have no key, fixed size records. Variable size records use more derived class
  2629. class UnkeyedGroupAggregateRecordProcessor : public GroupAggregateRecordProcessor
  2630. {
  2631. public:
  2632. IMPLEMENT_IINTERFACE;
  2633. UnkeyedGroupAggregateRecordProcessor(IInMemoryIndexCursor *_cursor, RowAggregator &_results, IHThorDiskGroupAggregateArg &_helper, IDirectReader *_reader)
  2634. : GroupAggregateRecordProcessor(_cursor, _results, _helper), reader(_reader)
  2635. {
  2636. helper.setCallback(reader->queryThorDiskCallback());
  2637. }
  2638. virtual void doQuery(IMessagePacker *output, unsigned processed, unsigned __int64 rowLimit, unsigned __int64 stopAfter)
  2639. {
  2640. size32_t recordSize = helper.queryDiskRecordSize()->getFixedSize();
  2641. size32_t bufferSize = getBufferSize(recordSize);
  2642. while (!aborted && !reader->eos())
  2643. {
  2644. size32_t gotSize;
  2645. const char *firstRec = (const char *) reader->peek(bufferSize, gotSize);
  2646. if (!gotSize)
  2647. break;
  2648. gotSize = roundDown(gotSize, recordSize);
  2649. const char *nextRec = firstRec;
  2650. endRec = firstRec + gotSize;
  2651. // This loop is the inner loop for memory diskreads - so keep it efficient!
  2652. if (cursor)
  2653. {
  2654. while (nextRec <= endRec)
  2655. {
  2656. if (!cursor->isFiltered(nextRec))
  2657. helper.processRow(nextRec, this);
  2658. nextRec += recordSize;
  2659. }
  2660. }
  2661. else
  2662. {
  2663. helper.processRows(gotSize, firstRec, this);
  2664. }
  2665. reader->skip(gotSize);
  2666. }
  2667. }
  2668. protected:
  2669. Owned<IDirectReader> reader;
  2670. };
  2671. // Used when we have no key, variable size records.
  2672. class UnkeyedVariableGroupAggregateRecordProcessor : public UnkeyedGroupAggregateRecordProcessor
  2673. {
  2674. public:
  2675. UnkeyedVariableGroupAggregateRecordProcessor(IInMemoryIndexCursor *_cursor, RowAggregator &_results, IHThorDiskGroupAggregateArg &_helper, IDirectReader *_reader,
  2676. ICodeContext *ctx, unsigned activityId)
  2677. : UnkeyedGroupAggregateRecordProcessor(_cursor, _results, _helper, _reader), deserializeSource(_reader)
  2678. {
  2679. prefetcher.setown(helper.queryDiskRecordSize()->createDiskPrefetcher(ctx, activityId));
  2680. }
  2681. virtual void doQuery(IMessagePacker *output, unsigned processed, unsigned __int64 rowLimit, unsigned __int64 stopAfter)
  2682. {
  2683. helper.setCallback(reader->queryThorDiskCallback());
  2684. while (!aborted && !deserializeSource.eos())
  2685. {
  2686. // This loop is the inner loop for memory diskreads - so keep it efficient!
  2687. prefetcher->readAhead(deserializeSource);
  2688. const byte *nextRec = deserializeSource.queryRow();
  2689. if (!cursor || !cursor->isFiltered(nextRec))
  2690. helper.processRow(nextRec, this);
  2691. deserializeSource.finishedRow();
  2692. }
  2693. }
  2694. protected:
  2695. CThorContiguousRowBuffer deserializeSource;
  2696. Owned<ISourceRowPrefetcher> prefetcher;
  2697. };
  2698. IInMemoryFileProcessor *createUnkeyedGroupAggregateRecordProcessor(IInMemoryIndexCursor *cursor, RowAggregator &results, IHThorDiskGroupAggregateArg &helper, IDirectReader *reader, ICodeContext *ctx, unsigned activityId)
  2699. {
  2700. if (helper.queryDiskRecordSize()->isVariableSize())
  2701. return new UnkeyedVariableGroupAggregateRecordProcessor(cursor, results, helper, reader, ctx, activityId);
  2702. else
  2703. return new UnkeyedGroupAggregateRecordProcessor(cursor, results, helper, reader);
  2704. }
  2705. ISlaveActivityFactory *createRoxieDiskGroupAggregateActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  2706. {
  2707. return new CRoxieDiskGroupAggregateActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory);
  2708. }
  2709. //================================================================================================
  2710. class CRoxieKeyedActivityFactory : public CSlaveActivityFactory
  2711. {
  2712. protected:
  2713. Owned<IKeyArray> keyArray;
  2714. Owned<TranslatorArray> layoutTranslators;
  2715. Owned<IDefRecordMeta> activityMeta;
  2716. CRoxieKeyedActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  2717. : CSlaveActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory)
  2718. {
  2719. }
  2720. public:
  2721. inline IKeyArray *queryKeyArray() const { return keyArray; }
  2722. inline TranslatorArray *queryLayoutTranslators() const { return layoutTranslators; }
  2723. inline IDefRecordMeta *queryActivityMeta() const { return activityMeta; }
  2724. };
  2725. class CRoxieIndexActivityFactory : public CRoxieKeyedActivityFactory
  2726. {
  2727. public:
  2728. IMPLEMENT_IINTERFACE;
  2729. CRoxieIndexActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  2730. : CRoxieKeyedActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory)
  2731. {
  2732. }
  2733. void init(IHThorIndexReadBaseArg * helper, IPropertyTree &graphNode)
  2734. {
  2735. rtlDataAttr indexLayoutMeta;
  2736. size32_t indexLayoutSize;
  2737. if(!helper->getIndexLayout(indexLayoutSize, indexLayoutMeta.refdata()))
  2738. assertex(indexLayoutSize== 0);
  2739. MemoryBuffer m;
  2740. m.setBuffer(indexLayoutSize, indexLayoutMeta.getdata());
  2741. activityMeta.setown(deserializeRecordMeta(m, true));
  2742. layoutTranslators.setown(new TranslatorArray);
  2743. bool variableFileName = allFilesDynamic || queryFactory.isDynamic() || ((helper->getFlags() & (TIRvarfilename|TIRdynamicfilename)) != 0);
  2744. if (!variableFileName)
  2745. {
  2746. bool isOpt = (helper->getFlags() & TIRoptional) != 0;
  2747. OwnedRoxieString indexName(helper->getFileName());
  2748. datafile.setown(queryFactory.queryPackage().lookupFileName(indexName, isOpt, true, true, queryFactory.queryWorkUnit()));
  2749. if (datafile)
  2750. keyArray.setown(datafile->getKeyArray(activityMeta, layoutTranslators, isOpt, queryFactory.queryChannel(), queryFactory.getEnableFieldTranslation()));
  2751. }
  2752. }
  2753. };
  2754. class CRoxieKeyedActivity : public CRoxieSlaveActivity
  2755. {
  2756. // Common base class for all activities that deal with keys - keyed join or indexread and its allies
  2757. protected:
  2758. Owned<IKeyManager> tlk;
  2759. Linked<TranslatorArray> layoutTranslators;
  2760. Linked<IKeyArray> keyArray;
  2761. IDefRecordMeta *activityMeta;
  2762. bool createSegmentMonitorsPending;
  2763. virtual void createSegmentMonitors() = 0;
  2764. virtual void setPartNo(bool filechanged)
  2765. {
  2766. if (!lastPartNo.partNo)
  2767. {
  2768. assertex(filechanged);
  2769. Owned<IKeyIndexSet> allKeys = createKeyIndexSet();
  2770. for (unsigned subpart = 0; subpart < keyArray->length(); subpart++)
  2771. {
  2772. IKeyIndexBase *kib = keyArray->queryKeyPart(subpart);
  2773. if (kib)
  2774. {
  2775. IKeyIndex *k = kib->queryPart(lastPartNo.fileNo);
  2776. if (k)
  2777. {
  2778. assertex(!k->isTopLevelKey());
  2779. allKeys->addIndex(LINK(k));
  2780. }
  2781. }
  2782. }
  2783. if (allKeys->numParts())
  2784. {
  2785. tlk.setown(createKeyMerger(allKeys, 0, 0, &logctx));
  2786. createSegmentMonitorsPending = true;
  2787. }
  2788. else
  2789. tlk.clear();
  2790. }
  2791. else
  2792. {
  2793. IKeyIndexBase *kib = keyArray->queryKeyPart(lastPartNo.partNo);
  2794. assertex(kib != NULL);
  2795. IKeyIndex *k = kib->queryPart(lastPartNo.fileNo);
  2796. if (filechanged)
  2797. {
  2798. tlk.setown(createKeyManager(k, 0, &logctx));
  2799. createSegmentMonitorsPending = true;
  2800. }
  2801. else
  2802. tlk->setKey(k);
  2803. }
  2804. }
  2805. virtual void setVariableFileInfo()
  2806. {
  2807. layoutTranslators.setown(new TranslatorArray);
  2808. keyArray.setown(varFileInfo->getKeyArray(activityMeta, layoutTranslators, isOpt, packet->queryHeader().channel, allowFieldTranslation));
  2809. }
  2810. CRoxieKeyedActivity(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory, const CRoxieKeyedActivityFactory *_aFactory)
  2811. : CRoxieSlaveActivity(_logctx, _packet, _hFactory, _aFactory),
  2812. keyArray(_aFactory->queryKeyArray()),
  2813. layoutTranslators(_aFactory->queryLayoutTranslators()),
  2814. activityMeta(_aFactory->queryActivityMeta()),
  2815. createSegmentMonitorsPending(true)
  2816. {
  2817. }
  2818. };
  2819. class CRoxieIndexActivity : public CRoxieKeyedActivity
  2820. {
  2821. // Common base class for indexread, indexcount and related activities
  2822. protected:
  2823. const CRoxieIndexActivityFactory *factory;
  2824. PartNoType *inputData; // list of channels
  2825. IHThorIndexReadBaseArg * indexHelper;
  2826. unsigned inputCount;
  2827. unsigned inputsDone;
  2828. unsigned processed;
  2829. unsigned keyprocessed;
  2830. unsigned steppingOffset;
  2831. unsigned steppingLength;
  2832. unsigned short numSkipFields;
  2833. unsigned numSeeks;
  2834. bool seeksAreEof;
  2835. bool lastRowCompleteMatch;
  2836. CIndexTransformCallback callback;
  2837. SmartStepExtra stepExtra; // just used for flags - a little unnecessary...
  2838. const byte *steppingRow;
  2839. bool checkLimit(unsigned __int64 limit)
  2840. {
  2841. assertex(!resent);
  2842. unsigned __int64 result = 0;
  2843. unsigned inputsDone = 0;
  2844. bool ret = true;
  2845. unsigned saveStepping = steppingOffset;
  2846. steppingOffset = 0;
  2847. while (!aborted && inputsDone < inputCount)
  2848. {
  2849. checkPartChanged(inputData[inputsDone]);
  2850. if (tlk)
  2851. {
  2852. createSegmentMonitors();
  2853. result += tlk->checkCount(limit-result);
  2854. if (result > limit)
  2855. {
  2856. ret = false;
  2857. break;
  2858. }
  2859. }
  2860. inputsDone++;
  2861. }
  2862. if (saveStepping)
  2863. {
  2864. steppingOffset = saveStepping;
  2865. lastPartNo.partNo = 0xffff;
  2866. lastPartNo.fileNo = 0xffff;
  2867. tlk.clear();
  2868. }
  2869. return ret;
  2870. }
  2871. public:
  2872. IMPLEMENT_IINTERFACE;
  2873. CRoxieIndexActivity(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory, const CRoxieIndexActivityFactory *_aFactory, unsigned _steppingOffset)
  2874. : CRoxieKeyedActivity(_logctx, _packet, _hFactory, _aFactory),
  2875. factory(_aFactory),
  2876. steppingOffset(_steppingOffset),
  2877. stepExtra(SSEFreadAhead, NULL)
  2878. {
  2879. indexHelper = (IHThorIndexReadBaseArg *) basehelper;
  2880. variableFileName = allFilesDynamic || basefactory->queryQueryFactory().isDynamic() || ((indexHelper->getFlags() & (TIRvarfilename|TIRdynamicfilename)) != 0);
  2881. isOpt = (indexHelper->getFlags() & TDRoptional) != 0;
  2882. inputData = NULL;
  2883. inputCount = 0;
  2884. inputsDone = 0;
  2885. processed = 0;
  2886. keyprocessed = 0;
  2887. numSkipFields = 0;
  2888. lastRowCompleteMatch = true; // default is we only return complete matches....
  2889. seeksAreEof = false;
  2890. steppingLength = 0;
  2891. steppingRow = NULL;
  2892. numSeeks = 0;
  2893. if (packet->getSmartStepInfoLength())
  2894. {
  2895. const byte *smartStepInfoValue = packet->querySmartStepInfoData();
  2896. numSkipFields = * (unsigned short *) smartStepInfoValue;
  2897. smartStepInfoValue += sizeof(unsigned short);
  2898. steppingLength = * (unsigned short *) smartStepInfoValue;
  2899. smartStepInfoValue += sizeof(unsigned short);
  2900. unsigned flags = * (unsigned short *) smartStepInfoValue;
  2901. smartStepInfoValue += sizeof(unsigned short);
  2902. seeksAreEof = * (bool *) smartStepInfoValue;
  2903. smartStepInfoValue += sizeof(bool);
  2904. numSeeks = * (unsigned *) smartStepInfoValue;
  2905. smartStepInfoValue += sizeof(unsigned);
  2906. assertex(numSeeks); // Given that we put the first seek in here to there should always be at least one!
  2907. steppingRow = smartStepInfoValue; // the first of them...
  2908. stepExtra.set(flags, NULL);
  2909. if (logctx.queryTraceLevel() > 10)
  2910. {
  2911. logctx.CTXLOG("%d seek rows provided. mismatch(%d) readahead(%d) onlyfirst(%d)", numSeeks,
  2912. (int)stepExtra.returnMismatches(), (int)stepExtra.readAheadManyResults(), (int)stepExtra.onlyReturnFirstSeekMatch());
  2913. if (logctx.queryTraceLevel() > 15)
  2914. {
  2915. for (unsigned i = 0; i < numSeeks; i++)
  2916. {
  2917. StringBuffer b;
  2918. for (unsigned j = 0; j < steppingLength; j++)
  2919. b.appendf("%02x ", steppingRow[i*steppingLength + j]);
  2920. logctx.CTXLOG("Seek row %d: %s", i+1, b.str());
  2921. }
  2922. }
  2923. }
  2924. }
  2925. else
  2926. {
  2927. if (logctx.queryTraceLevel() > 10)
  2928. logctx.CTXLOG("0 seek rows provided.");
  2929. }
  2930. }
  2931. virtual void onCreate()
  2932. {
  2933. CRoxieKeyedActivity::onCreate();
  2934. inputData = (PartNoType *) serializedCreate.readDirect(0);
  2935. inputCount = (serializedCreate.length() - serializedCreate.getPos()) / sizeof(*inputData);
  2936. indexHelper->setCallback(&callback);
  2937. }
  2938. virtual const char *queryDynamicFileName() const
  2939. {
  2940. return indexHelper->getFileName();
  2941. }
  2942. virtual void createSegmentMonitors()
  2943. {
  2944. if (createSegmentMonitorsPending)
  2945. {
  2946. createSegmentMonitorsPending = false;
  2947. tlk->setLayoutTranslator(layoutTranslators->item(lastPartNo.fileNo));
  2948. indexHelper->createSegmentMonitors(tlk);
  2949. tlk->finishSegmentMonitors();
  2950. }
  2951. }
  2952. bool sendContinuation(IMessagePacker * output)
  2953. {
  2954. MemoryBuffer si;
  2955. unsigned short siLen = 0;
  2956. si.append(siLen);
  2957. si.append(lastRowCompleteMatch);
  2958. si.append(inputsDone);
  2959. si.append(processed);
  2960. si.append(keyprocessed);
  2961. si.append(lastPartNo.partNo);
  2962. si.append(lastPartNo.fileNo);
  2963. tlk->serializeCursorPos(si);
  2964. if (si.length() <= maxContinuationSize)
  2965. {
  2966. siLen = si.length() - sizeof(siLen);
  2967. si.writeDirect(0, sizeof(siLen), &siLen);
  2968. output->sendMetaInfo(si.toByteArray(), si.length());
  2969. logctx.flush(true, aborted);
  2970. output->flush(true);
  2971. return true;
  2972. }
  2973. else
  2974. return false;
  2975. }
  2976. void readContinuationInfo()
  2977. {
  2978. resentInfo.read(lastRowCompleteMatch);
  2979. resentInfo.read(inputsDone);
  2980. resentInfo.read(processed);
  2981. resentInfo.read(keyprocessed);
  2982. resentInfo.read(lastPartNo.partNo);
  2983. resentInfo.read(lastPartNo.fileNo);
  2984. setPartNo(true);
  2985. tlk->deserializeCursorPos(resentInfo);
  2986. assertex(resentInfo.remaining() == 0);
  2987. }
  2988. virtual void setPartNo(bool fileChanged)
  2989. {
  2990. // NOTE - may be used by both indexread and normalize...
  2991. if (steppingOffset) // MORE - may be other cases too - eg want output sorted and there are multiple subfiles...
  2992. {
  2993. unsigned i = 0;
  2994. Owned<IKeyIndexSet> allKeys = createKeyIndexSet();
  2995. while (!aborted && i < inputCount)
  2996. {
  2997. PartNoType &part = inputData[i];
  2998. lastPartNo.partNo = part.partNo;
  2999. lastPartNo.fileNo = part.fileNo; // This is a hack so that the translator can be retrieved. We don't support record translation properly when doing keymerging...)
  3000. // MORE - this code looks like it could be commoned up with code in CRoxieKeyedActivity::setPartNo
  3001. if (!lastPartNo.partNo)
  3002. {
  3003. for (unsigned subpart = 0; subpart < keyArray->length(); subpart++)
  3004. {
  3005. IKeyIndexBase *kib = keyArray->queryKeyPart(subpart);
  3006. if (kib)
  3007. {
  3008. IKeyIndex *k = kib->queryPart(lastPartNo.fileNo);
  3009. if (k)
  3010. {
  3011. assertex(!k->isTopLevelKey());
  3012. allKeys->addIndex(LINK(k));
  3013. }
  3014. }
  3015. }
  3016. }
  3017. else
  3018. {
  3019. IKeyIndexBase *kib = keyArray->queryKeyPart(part.partNo);
  3020. assertex(kib != NULL);
  3021. IKeyIndex *k = kib->queryPart(part.fileNo);
  3022. allKeys->addIndex(LINK(k));
  3023. }
  3024. i++;
  3025. }
  3026. if (allKeys->numParts())
  3027. tlk.setown(::createKeyMerger(allKeys, 0, steppingOffset, &logctx));
  3028. else
  3029. tlk.clear();
  3030. createSegmentMonitorsPending = true;
  3031. }
  3032. else
  3033. CRoxieKeyedActivity::setPartNo(fileChanged);
  3034. }
  3035. };
  3036. //================================================================================================
  3037. class CRoxieIndexReadActivity : public CRoxieIndexActivity, implements IIndexReadActivityInfo
  3038. {
  3039. protected:
  3040. IHThorCompoundReadExtra * readHelper;
  3041. public:
  3042. IMPLEMENT_IINTERFACE;
  3043. CRoxieIndexReadActivity(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory, const CRoxieIndexActivityFactory *_aFactory, unsigned _steppingOffset)
  3044. : CRoxieIndexActivity(_logctx, _packet, _hFactory, _aFactory, _steppingOffset)
  3045. {
  3046. onCreate();
  3047. readHelper = (IHThorIndexReadArg *) basehelper;
  3048. if (resent)
  3049. readContinuationInfo();
  3050. }
  3051. virtual StringBuffer &toString(StringBuffer &ret) const
  3052. {
  3053. return ret.appendf("IndexRead %u", packet->queryHeader().activityId);
  3054. }
  3055. /* Notes on Global smart stepping implementation:
  3056. When smart stepping, I get from the Roxie server:
  3057. 1 or more seek positions
  3058. some flags
  3059. I can read from the index in an order that matches the seek positions order (because of index merger), and which match my hard filter (they may not match my postfilter)
  3060. I can skip forwards in the index to the first record GE a skip position
  3061. I am not going to try to implement a (possible future) flag to return mismatches after any but the last of the seek positions (yet)
  3062. I want to return M matching (keyed matches, seek field matches, and postfilter matches) rows for all provided seek positions
  3063. where M is 1 if SSEFonlyReturnFirstSeekMatch flag set, otherwise all...
  3064. THEN once we are beyond the last provided seek:
  3065. if returnMismatches flag set,
  3066. current row = (next row matching keyed filter)
  3067. if someNewAsYetUnnamedAndUnimplementedFlag flag set
  3068. //if the post filter matches then there may be scope for returning all records which match the seek fields of that first match
  3069. // But not very likely to help unless terms correlated, and may well hinder
  3070. return current row and all following rows matching keyed filter, seek data from current row, and postfilter
  3071. return next row matching keyed filter (even if doesn't match postfilter)
  3072. else
  3073. return next N rows matching keyed filter and postfilter (where N depends on readAheadManyResults flag - 1 if not set)
  3074. */
  3075. inline void advanceToNextSeek()
  3076. {
  3077. assertex(numSeeks != 0);
  3078. if (--numSeeks)
  3079. steppingRow += steppingLength;
  3080. else
  3081. steppingRow = NULL;
  3082. }
  3083. virtual bool process()
  3084. {
  3085. MTIME_SECTION(timer, "CRoxieIndexReadActivity ::process");
  3086. unsigned __int64 keyedLimit = readHelper->getKeyedLimit();
  3087. unsigned __int64 limit = readHelper->getRowLimit();
  3088. if (!resent && (keyedLimit != (unsigned __int64) -1) && ((keyedLimit > preabortIndexReadsThreshold) || (indexHelper->getFlags() & TIRcountkeyedlimit) != 0)) // Don't recheck the limit every time!
  3089. {
  3090. if (!checkLimit(keyedLimit))
  3091. {
  3092. limitExceeded(true);
  3093. return true;
  3094. }
  3095. }
  3096. unsigned __int64 stopAfter = readHelper->getChooseNLimit();
  3097. Owned<IMessagePacker> output = ROQ->createOutputStream(packet->queryHeader(), false, logctx);
  3098. OptimizedRowBuilder rowBuilder(rowAllocator, meta, output, serializer);
  3099. unsigned totalSizeSent = 0;
  3100. unsigned skipped = 0;
  3101. unsigned processedBefore = processed;
  3102. unsigned keyprocessedBefore = keyprocessed;
  3103. bool continuationFailed = false;
  3104. const byte *rawSeek = NULL;
  3105. if (steppingRow)
  3106. rawSeek = steppingRow;
  3107. bool continuationNeeded = false;
  3108. while (!aborted && inputsDone < inputCount)
  3109. {
  3110. if (!resent || !steppingOffset) // Bit of a hack... In the resent case, we have already set up the tlk, and all keys are processed at once in the steppingOffset case (which makes checkPartChanged gives a false positive in this case)
  3111. checkPartChanged(inputData[inputsDone]);
  3112. if (tlk)
  3113. {
  3114. createSegmentMonitors();
  3115. tlk->reset(resent);
  3116. resent = false;
  3117. {
  3118. TransformCallbackAssociation associate(callback, tlk); // want to destroy this before we advance to next key...
  3119. while (!aborted && (rawSeek ? tlk->lookupSkip(rawSeek, steppingOffset, steppingLength) : tlk->lookup(true)))
  3120. {
  3121. rawSeek = NULL; // only want to do the seek first time we look for a particular seek value
  3122. keyprocessed++;
  3123. if ((keyedLimit != (unsigned __int64) -1) && keyprocessed > keyedLimit)
  3124. {
  3125. logctx.noteStatistic(STATS_ACCEPTED, keyprocessed-keyprocessedBefore, 1);
  3126. logctx.noteStatistic(STATS_REJECTED, skipped, 1);
  3127. limitExceeded(true);
  3128. break;
  3129. }
  3130. atomic_inc(&indexRecordsRead);
  3131. size32_t transformedSize;
  3132. const byte * keyRow = tlk->queryKeyBuffer(callback.getFPosRef());
  3133. int diff = 0;
  3134. if (steppingRow)
  3135. {
  3136. diff = memcmp(keyRow+steppingOffset, steppingRow, steppingLength);
  3137. assertex(diff >= 0);
  3138. }
  3139. while (diff > 0)
  3140. {
  3141. advanceToNextSeek();
  3142. if (!steppingRow)
  3143. break;
  3144. diff = memcmp(keyRow+steppingOffset, steppingRow, steppingLength);
  3145. if (diff < 0)
  3146. {
  3147. rawSeek = steppingRow;
  3148. break;
  3149. }
  3150. }
  3151. if (diff >= 0)
  3152. {
  3153. if (diff > 0 && seeksAreEof)
  3154. {
  3155. assertex(!steppingRow);
  3156. break;
  3157. }
  3158. rowBuilder.ensureRow();
  3159. transformedSize = readHelper->transform(rowBuilder, keyRow);
  3160. callback.finishedRow();
  3161. if (transformedSize)
  3162. {
  3163. if (logctx.queryTraceLevel() > 15)
  3164. {
  3165. StringBuffer b;
  3166. for (unsigned j = 0; j < (steppingLength ? steppingLength : 6); j++)
  3167. b.appendf("%02x ", keyRow[steppingOffset + j]);
  3168. logctx.CTXLOG("Returning seek row %s", b.str());
  3169. }
  3170. // Did get a match
  3171. processed++;
  3172. if (limit && processed > limit)
  3173. {
  3174. logctx.noteStatistic(STATS_ACCEPTED, processed-processedBefore, 1);
  3175. logctx.noteStatistic(STATS_REJECTED, skipped, 1);
  3176. limitExceeded(false);
  3177. break;
  3178. }
  3179. if (processed > stopAfter)
  3180. {
  3181. logctx.noteStatistic(STATS_ACCEPTED, processed-processedBefore, 1);
  3182. logctx.noteStatistic(STATS_REJECTED, skipped, 1);
  3183. logctx.flush(true, false);
  3184. output->flush(true);
  3185. return true;
  3186. }
  3187. rowBuilder.writeToOutput(transformedSize, true);
  3188. totalSizeSent += transformedSize;
  3189. if (totalSizeSent > indexReadChunkSize || (steppingOffset && !steppingRow && !stepExtra.readAheadManyResults()))
  3190. continuationNeeded = true;
  3191. lastRowCompleteMatch = true;
  3192. if (steppingRow && stepExtra.onlyReturnFirstSeekMatch())
  3193. advanceToNextSeek();
  3194. }
  3195. else
  3196. {
  3197. // Didn't get a match
  3198. if (steppingOffset && !steppingRow && stepExtra.returnMismatches())
  3199. {
  3200. transformedSize = readHelper->unfilteredTransform(rowBuilder, keyRow);
  3201. if (transformedSize) // will only be zero in odd situations where codegen can't work out how to transform (eg because of a skip)
  3202. {
  3203. callback.finishedRow();
  3204. rowBuilder.writeToOutput(transformedSize, true);
  3205. totalSizeSent += transformedSize;
  3206. continuationNeeded = true;
  3207. lastRowCompleteMatch = false;
  3208. }
  3209. }
  3210. else
  3211. {
  3212. atomic_inc(&postFiltered);
  3213. skipped++;
  3214. }
  3215. }
  3216. }
  3217. if (continuationNeeded && !continuationFailed)
  3218. {
  3219. if (logctx.queryTraceLevel() > 10)
  3220. logctx.CTXLOG("Indexread returning partial result set %d rows from %d seeks, %d scans, %d skips", processed-processedBefore, tlk->querySeeks(), tlk->queryScans(), tlk->querySkips());
  3221. if (sendContinuation(output))
  3222. {
  3223. logctx.noteStatistic(STATS_ACCEPTED, processed-processedBefore, 1);
  3224. logctx.noteStatistic(STATS_REJECTED, skipped, 1);
  3225. return true;
  3226. }
  3227. else
  3228. {
  3229. // This is actually pretty fatal for smart-stepping case
  3230. if (logctx.queryTraceLevel())
  3231. logctx.CTXLOG("Indexread unable to return partial result set");
  3232. continuationFailed = true;
  3233. }
  3234. }
  3235. rowBuilder.clear();
  3236. }
  3237. }
  3238. }
  3239. if (steppingOffset)
  3240. inputsDone = inputCount;
  3241. else
  3242. inputsDone++;
  3243. }
  3244. if (tlk) // a very early abort can mean it is NULL.... MORE is this the right place to put it or should it be inside the loop??
  3245. {
  3246. if (logctx.queryTraceLevel() > 10 && !aborted)
  3247. {
  3248. logctx.CTXLOG("Indexread returning result set %d rows from %d seeks, %d scans, %d skips", processed-processedBefore, tlk->querySeeks(), tlk->queryScans(), tlk->querySkips());
  3249. if (steppingOffset)
  3250. logctx.CTXLOG("Indexread return: steppingOffset %d, steppingRow %p, stepExtra.returnMismatches() %d",steppingOffset, steppingRow, (int) stepExtra.returnMismatches());
  3251. }
  3252. logctx.noteStatistic(STATS_ACCEPTED, processed-processedBefore, 1);
  3253. logctx.noteStatistic(STATS_REJECTED, skipped, 1);
  3254. }
  3255. logctx.flush(true, aborted);
  3256. if (aborted)
  3257. output->abort();
  3258. else
  3259. output->flush(true);
  3260. return !aborted;
  3261. }
  3262. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  3263. {
  3264. return this;
  3265. }
  3266. virtual IKeyArray *getKeySet() const
  3267. {
  3268. return keyArray.getLink();
  3269. }
  3270. virtual const IResolvedFile *getVarFileInfo() const
  3271. {
  3272. return varFileInfo.getLink();
  3273. }
  3274. virtual TranslatorArray *getTranslators() const
  3275. {
  3276. return layoutTranslators.getLink();
  3277. }
  3278. virtual void mergeSegmentMonitors(IIndexReadContext *irc) const
  3279. {
  3280. indexHelper->createSegmentMonitors(irc); // NOTE: they will merge;
  3281. }
  3282. virtual IRoxieServerActivity *queryActivity() { throwUnexpected(); }
  3283. virtual const RemoteActivityId &queryRemoteId() const { throwUnexpected(); }
  3284. };
  3285. //================================================================================================
  3286. class CRoxieIndexReadActivityFactory : public CRoxieIndexActivityFactory
  3287. {
  3288. unsigned steppingOffset;
  3289. public:
  3290. CRoxieIndexReadActivityFactory(IPropertyTree &graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  3291. : CRoxieIndexActivityFactory(graphNode, _subgraphId, _queryFactory, _helperFactory)
  3292. {
  3293. Owned<IHThorIndexReadArg> helper = (IHThorIndexReadArg *) helperFactory();
  3294. init(helper, graphNode);
  3295. ISteppingMeta *rawMeta = helper->queryRawSteppingMeta();
  3296. if (rawMeta)
  3297. {
  3298. // MORE - should check all keys in maxFields list can actually be keyed.
  3299. const CFieldOffsetSize * fields = rawMeta->queryFields();
  3300. steppingOffset = fields[0].offset;
  3301. }
  3302. else
  3303. {
  3304. steppingOffset = 0;
  3305. }
  3306. }
  3307. virtual IRoxieSlaveActivity *createActivity(SlaveContextLogger &logctx, IRoxieQueryPacket *packet) const
  3308. {
  3309. return new CRoxieIndexReadActivity(logctx, packet, helperFactory, this, steppingOffset);
  3310. }
  3311. virtual StringBuffer &toString(StringBuffer &s) const
  3312. {
  3313. return CSlaveActivityFactory::toString(s.append("INDEXREAD "));
  3314. }
  3315. };
  3316. ISlaveActivityFactory *createRoxieIndexReadActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  3317. {
  3318. return new CRoxieIndexReadActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory);
  3319. }
  3320. //================================================================================================
  3321. //MORE: Very similar to the indexRead code, but I'm not sure it's worth commoning up....
  3322. class CRoxieIndexNormalizeActivity : public CRoxieIndexActivity
  3323. {
  3324. protected:
  3325. IHThorCompoundNormalizeExtra * normalizeHelper;
  3326. public:
  3327. IMPLEMENT_IINTERFACE;
  3328. CRoxieIndexNormalizeActivity(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory, const CRoxieIndexActivityFactory *_aFactory)
  3329. : CRoxieIndexActivity(_logctx, _packet, _hFactory, _aFactory, 0) //MORE - stepping?
  3330. {
  3331. onCreate();
  3332. normalizeHelper = (IHThorIndexNormalizeArg *) basehelper;
  3333. if (resent)
  3334. readContinuationInfo();
  3335. }
  3336. virtual StringBuffer &toString(StringBuffer &ret) const
  3337. {
  3338. return ret.appendf("IndexNormalize %u", packet->queryHeader().activityId);
  3339. }
  3340. virtual bool process()
  3341. {
  3342. MTIME_SECTION(timer, "CRoxieIndexNormalizeActivity ::process");
  3343. unsigned __int64 keyedLimit = normalizeHelper->getKeyedLimit();
  3344. unsigned __int64 rowLimit = normalizeHelper->getRowLimit();
  3345. if (!resent && (keyedLimit != (unsigned __int64) -1) && (indexHelper->getFlags() & TIRcountkeyedlimit) != 0) // Don't recheck the limit every time!
  3346. {
  3347. if (!checkLimit(keyedLimit))
  3348. {
  3349. limitExceeded(true);
  3350. return true;
  3351. }
  3352. }
  3353. unsigned __int64 stopAfter = normalizeHelper->getChooseNLimit();
  3354. Owned<IMessagePacker> output = ROQ->createOutputStream(packet->queryHeader(), false, logctx);
  3355. OptimizedRowBuilder rowBuilder(rowAllocator, meta, output, serializer);
  3356. unsigned totalSizeSent = 0;
  3357. unsigned skipped = 0;
  3358. unsigned processedBefore = processed;
  3359. bool continuationFailed = false;
  3360. while (!aborted && inputsDone < inputCount)
  3361. {
  3362. checkPartChanged(inputData[inputsDone]);
  3363. if (tlk)
  3364. {
  3365. createSegmentMonitors();
  3366. tlk->reset(resent);
  3367. resent = false;
  3368. TransformCallbackAssociation associate(callback, tlk);
  3369. while (!aborted && tlk->lookup(true))
  3370. {
  3371. keyprocessed++;
  3372. if (keyedLimit && processed > keyedLimit)
  3373. {
  3374. logctx.noteStatistic(STATS_ACCEPTED, processed-processedBefore, 1);
  3375. logctx.noteStatistic(STATS_REJECTED, skipped, 1);
  3376. limitExceeded(true);
  3377. break;
  3378. }
  3379. atomic_inc(&indexRecordsRead);
  3380. if (normalizeHelper->first(tlk->queryKeyBuffer(callback.getFPosRef())))
  3381. {
  3382. do
  3383. {
  3384. rowBuilder.ensureRow();
  3385. size32_t transformedSize = normalizeHelper->transform(rowBuilder);
  3386. if (transformedSize)
  3387. {
  3388. processed++;
  3389. if (processed > rowLimit)
  3390. {
  3391. logctx.noteStatistic(STATS_ACCEPTED, processed-processedBefore, 1);
  3392. logctx.noteStatistic(STATS_REJECTED, skipped, 1);
  3393. limitExceeded(false);
  3394. break;
  3395. }
  3396. if (processed > stopAfter)
  3397. {
  3398. logctx.noteStatistic(STATS_ACCEPTED, processed-processedBefore, 1);
  3399. logctx.noteStatistic(STATS_REJECTED, skipped, 1);
  3400. logctx.flush(true, aborted);
  3401. output->flush(true);
  3402. return true;
  3403. }
  3404. totalSizeSent += rowBuilder.writeToOutput(transformedSize, true);
  3405. }
  3406. } while (normalizeHelper->next());
  3407. callback.finishedRow();
  3408. if (totalSizeSent > indexReadChunkSize && !continuationFailed)
  3409. {
  3410. if (sendContinuation(output))
  3411. {
  3412. logctx.noteStatistic(STATS_ACCEPTED, processed-processedBefore, 1);
  3413. logctx.noteStatistic(STATS_REJECTED, skipped, 1);
  3414. return true;
  3415. }
  3416. else
  3417. continuationFailed = true;
  3418. }
  3419. }
  3420. else
  3421. {
  3422. atomic_inc(&postFiltered);
  3423. skipped++;
  3424. }
  3425. }
  3426. }
  3427. inputsDone++;
  3428. }
  3429. if (tlk) // a very early abort can mean it is NULL....
  3430. {
  3431. logctx.noteStatistic(STATS_ACCEPTED, processed-processedBefore, 1);
  3432. logctx.noteStatistic(STATS_REJECTED, skipped, 1);
  3433. }
  3434. logctx.flush(true, aborted);
  3435. if (aborted)
  3436. output->abort();
  3437. else
  3438. output->flush(true);
  3439. return !aborted;
  3440. }
  3441. };
  3442. //================================================================================================
  3443. class CRoxieIndexNormalizeActivityFactory : public CRoxieIndexActivityFactory
  3444. {
  3445. public:
  3446. CRoxieIndexNormalizeActivityFactory(IPropertyTree &graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  3447. : CRoxieIndexActivityFactory(graphNode, _subgraphId, _queryFactory, _helperFactory)
  3448. {
  3449. Owned<IHThorIndexNormalizeArg> helper = (IHThorIndexNormalizeArg *) helperFactory();
  3450. init(helper, graphNode);
  3451. }
  3452. virtual IRoxieSlaveActivity *createActivity(SlaveContextLogger &logctx, IRoxieQueryPacket *packet) const
  3453. {
  3454. return new CRoxieIndexNormalizeActivity(logctx, packet, helperFactory, this);
  3455. }
  3456. virtual StringBuffer &toString(StringBuffer &s) const
  3457. {
  3458. return CSlaveActivityFactory::toString(s.append("IndexNormalize "));
  3459. }
  3460. };
  3461. ISlaveActivityFactory *createRoxieIndexNormalizeActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  3462. {
  3463. return new CRoxieIndexNormalizeActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory);
  3464. }
  3465. //================================================================================================
  3466. class CRoxieIndexCountActivity : public CRoxieIndexActivity
  3467. {
  3468. protected:
  3469. IHThorCompoundCountExtra * countHelper;
  3470. IHThorSourceCountLimit * limitHelper;
  3471. unsigned __int64 choosenLimit;
  3472. unsigned __int64 rowLimit;
  3473. unsigned __int64 keyedLimit;
  3474. public:
  3475. IMPLEMENT_IINTERFACE;
  3476. CRoxieIndexCountActivity(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory, const CRoxieIndexActivityFactory *_aFactory)
  3477. : CRoxieIndexActivity(_logctx, _packet, _hFactory, _aFactory, 0)
  3478. {
  3479. onCreate();
  3480. countHelper = (IHThorIndexCountArg *) basehelper;
  3481. limitHelper = static_cast<IHThorSourceCountLimit *>(basehelper->selectInterface(TAIsourcecountlimit_1));
  3482. assertex(!resent);
  3483. choosenLimit = countHelper->getChooseNLimit();
  3484. if (limitHelper)
  3485. {
  3486. rowLimit = limitHelper->getRowLimit();
  3487. keyedLimit = limitHelper->getKeyedLimit();
  3488. }
  3489. else
  3490. rowLimit = keyedLimit = (unsigned __int64) -1;
  3491. }
  3492. virtual StringBuffer &toString(StringBuffer &ret) const
  3493. {
  3494. return ret.appendf("IndexCount %u", packet->queryHeader().activityId);
  3495. }
  3496. virtual bool process()
  3497. {
  3498. MTIME_SECTION(timer, "CRoxieIndexCountActivity ::process");
  3499. Owned<IMessagePacker> output = ROQ->createOutputStream(packet->queryHeader(), false, logctx);
  3500. unsigned skipped = 0;
  3501. unsigned processedBefore = processed;
  3502. unsigned __int64 count = 0;
  3503. while (!aborted && inputsDone < inputCount && count < choosenLimit)
  3504. {
  3505. checkPartChanged(inputData[inputsDone]);
  3506. if (tlk)
  3507. {
  3508. createSegmentMonitors();
  3509. tlk->reset(false);
  3510. if (countHelper->hasFilter())
  3511. {
  3512. callback.setManager(tlk);
  3513. while (!aborted && (count < choosenLimit) && tlk->lookup(true))
  3514. {
  3515. keyprocessed++;
  3516. atomic_inc(&indexRecordsRead);
  3517. count += countHelper->numValid(tlk->queryKeyBuffer(callback.getFPosRef()));
  3518. if (count > rowLimit)
  3519. limitExceeded(false);
  3520. else if (count > keyedLimit)
  3521. limitExceeded(true);
  3522. callback.finishedRow();
  3523. }
  3524. callback.setManager(NULL);
  3525. }
  3526. else
  3527. {
  3528. //MORE: GH->RKC There should be value in providing a choosenLimit to getCount()
  3529. //MORE: note that tlk->checkCount() is NOT suitable as it makes assumptions about the segmonitors (only checks leading ones)
  3530. count += tlk->getCount();
  3531. if (count > rowLimit)
  3532. limitExceeded(false);
  3533. else if (count > keyedLimit)
  3534. limitExceeded(true); // MORE - is this right?
  3535. }
  3536. }
  3537. inputsDone++;
  3538. }
  3539. if (!aborted && count)
  3540. {
  3541. if (count > choosenLimit)
  3542. count = choosenLimit;
  3543. processed++;
  3544. assertex(!serializer);
  3545. void *recBuffer = output->getBuffer(meta.getFixedSize(), false);
  3546. if (meta.getFixedSize() == 1)
  3547. *(byte *)recBuffer = (byte)count;
  3548. else
  3549. {
  3550. assertex(meta.getFixedSize() == sizeof(unsigned __int64));
  3551. *(unsigned __int64 *)recBuffer = count;
  3552. }
  3553. output->putBuffer(recBuffer, meta.getFixedSize(), false);
  3554. }
  3555. if (tlk) // a very early abort can mean it is NULL....
  3556. {
  3557. logctx.noteStatistic(STATS_ACCEPTED, processed-processedBefore, 1);
  3558. logctx.noteStatistic(STATS_REJECTED, skipped, 1);
  3559. }
  3560. if (aborted)
  3561. output->abort();
  3562. else
  3563. output->flush(true);
  3564. return !aborted;
  3565. }
  3566. };
  3567. //================================================================================================
  3568. class CRoxieIndexCountActivityFactory : public CRoxieIndexActivityFactory
  3569. {
  3570. public:
  3571. CRoxieIndexCountActivityFactory(IPropertyTree &graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  3572. : CRoxieIndexActivityFactory(graphNode, _subgraphId, _queryFactory, _helperFactory)
  3573. {
  3574. Owned<IHThorIndexCountArg> helper = (IHThorIndexCountArg *) helperFactory();
  3575. init(helper, graphNode);
  3576. }
  3577. virtual IRoxieSlaveActivity *createActivity(SlaveContextLogger &logctx, IRoxieQueryPacket *packet) const
  3578. {
  3579. return new CRoxieIndexCountActivity(logctx, packet, helperFactory, this);
  3580. }
  3581. virtual StringBuffer &toString(StringBuffer &s) const
  3582. {
  3583. return CSlaveActivityFactory::toString(s.append("INDEXCOUNT "));
  3584. }
  3585. };
  3586. ISlaveActivityFactory *createRoxieIndexCountActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  3587. {
  3588. return new CRoxieIndexCountActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory);
  3589. }
  3590. //================================================================================================
  3591. class CRoxieIndexAggregateActivity : public CRoxieIndexActivity
  3592. {
  3593. protected:
  3594. IHThorCompoundAggregateExtra * aggregateHelper;
  3595. public:
  3596. IMPLEMENT_IINTERFACE;
  3597. CRoxieIndexAggregateActivity(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory, const CRoxieIndexActivityFactory *_aFactory)
  3598. : CRoxieIndexActivity(_logctx, _packet, _hFactory, _aFactory, 0)
  3599. {
  3600. onCreate();
  3601. aggregateHelper = (IHThorIndexAggregateArg *) basehelper;
  3602. assertex(!resent);
  3603. }
  3604. virtual StringBuffer &toString(StringBuffer &ret) const
  3605. {
  3606. return ret.appendf("IndexAggregate %u", packet->queryHeader().activityId);
  3607. }
  3608. virtual bool process()
  3609. {
  3610. MTIME_SECTION(timer, "CRoxieIndexAggregateActivity ::process");
  3611. Owned<IMessagePacker> output = ROQ->createOutputStream(packet->queryHeader(), false, logctx);
  3612. OptimizedRowBuilder rowBuilder(rowAllocator, meta, output, serializer);
  3613. rowBuilder.ensureRow();
  3614. aggregateHelper->clearAggregate(rowBuilder);
  3615. unsigned skipped = 0;
  3616. unsigned processedBefore = processed;
  3617. while (!aborted && inputsDone < inputCount)
  3618. {
  3619. checkPartChanged(inputData[inputsDone]);
  3620. if (tlk)
  3621. {
  3622. createSegmentMonitors();
  3623. tlk->reset(false);
  3624. callback.setManager(tlk);
  3625. while (!aborted && tlk->lookup(true))
  3626. {
  3627. keyprocessed++;
  3628. atomic_inc(&indexRecordsRead);
  3629. aggregateHelper->processRow(rowBuilder, tlk->queryKeyBuffer(callback.getFPosRef()));
  3630. callback.finishedRow();
  3631. }
  3632. callback.setManager(NULL);
  3633. }
  3634. inputsDone++;
  3635. }
  3636. if (!aborted && aggregateHelper->processedAnyRows())
  3637. {
  3638. processed++;
  3639. size32_t transformedSize = meta.getRecordSize(rowBuilder.getSelf());
  3640. rowBuilder.writeToOutput(transformedSize, true);
  3641. }
  3642. if (tlk) // a very early abort can mean it is NULL....
  3643. {
  3644. logctx.noteStatistic(STATS_ACCEPTED, processed-processedBefore, 1);
  3645. logctx.noteStatistic(STATS_REJECTED, skipped, 1);
  3646. }
  3647. logctx.flush(true, aborted);
  3648. if (aborted)
  3649. output->abort();
  3650. else
  3651. output->flush(true);
  3652. return !aborted;
  3653. }
  3654. };
  3655. //================================================================================================
  3656. class CRoxieIndexAggregateActivityFactory : public CRoxieIndexActivityFactory
  3657. {
  3658. public:
  3659. CRoxieIndexAggregateActivityFactory(IPropertyTree &graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  3660. : CRoxieIndexActivityFactory(graphNode, _subgraphId, _queryFactory, _helperFactory)
  3661. {
  3662. Owned<IHThorIndexAggregateArg> helper = (IHThorIndexAggregateArg *) helperFactory();
  3663. init(helper, graphNode);
  3664. }
  3665. virtual IRoxieSlaveActivity *createActivity(SlaveContextLogger &logctx, IRoxieQueryPacket *packet) const
  3666. {
  3667. return new CRoxieIndexAggregateActivity(logctx, packet, helperFactory, this);
  3668. }
  3669. virtual StringBuffer &toString(StringBuffer &s) const
  3670. {
  3671. return CSlaveActivityFactory::toString(s.append("INDEXAGGREGATE "));
  3672. }
  3673. };
  3674. ISlaveActivityFactory *createRoxieIndexAggregateActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  3675. {
  3676. return new CRoxieIndexAggregateActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory);
  3677. }
  3678. //================================================================================================
  3679. class CRoxieIndexGroupAggregateActivity : public CRoxieIndexActivity, implements IHThorGroupAggregateCallback
  3680. {
  3681. protected:
  3682. IHThorCompoundGroupAggregateExtra * aggregateHelper;
  3683. RowAggregator results;
  3684. unsigned groupSegCount;
  3685. ThorActivityKind kind;
  3686. public:
  3687. IMPLEMENT_IINTERFACE;
  3688. CRoxieIndexGroupAggregateActivity(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory, const CRoxieIndexActivityFactory *_aFactory, ThorActivityKind _kind)
  3689. : CRoxieIndexActivity(_logctx, _packet, _hFactory, _aFactory, 0),
  3690. aggregateHelper((IHThorIndexGroupAggregateArg *) basehelper),
  3691. results(*aggregateHelper, *aggregateHelper), kind(_kind)
  3692. {
  3693. onCreate();
  3694. results.start(rowAllocator);
  3695. assertex(!resent);
  3696. groupSegCount = 0;
  3697. }
  3698. virtual bool needsRowAllocator()
  3699. {
  3700. return true;
  3701. }
  3702. virtual StringBuffer &toString(StringBuffer &ret) const
  3703. {
  3704. return ret.appendf("IndexGroupAggregate %u", packet->queryHeader().activityId);
  3705. }
  3706. virtual void processRow(const void * next)
  3707. {
  3708. results.addRow(next);
  3709. }
  3710. virtual void createSegmentMonitors()
  3711. {
  3712. if (createSegmentMonitorsPending)
  3713. {
  3714. unsigned groupSegSize;
  3715. if ((kind==TAKindexgroupcount || kind==TAKindexgroupexists))
  3716. groupSegSize = aggregateHelper->getGroupSegmentMonitorsSize();
  3717. else
  3718. groupSegSize = 0;
  3719. tlk->setMergeBarrier(groupSegSize);
  3720. CRoxieIndexActivity::createSegmentMonitors();
  3721. if (groupSegSize)
  3722. {
  3723. // MORE - this code should be moved to somewhere common so ccdserver can share it
  3724. unsigned numSegs = tlk->ordinality();
  3725. for (unsigned segNo = 0; segNo < numSegs; segNo++)
  3726. {
  3727. IKeySegmentMonitor *seg = tlk->item(segNo);
  3728. if (seg->getOffset()+seg->getSize()==groupSegSize)
  3729. {
  3730. groupSegCount = segNo+1;
  3731. break;
  3732. }
  3733. }
  3734. assertex(groupSegCount);
  3735. }
  3736. else
  3737. groupSegCount = 0;
  3738. }
  3739. }
  3740. virtual bool process()
  3741. {
  3742. MTIME_SECTION(timer, "CRoxieIndexGroupAggregateActivity ::process");
  3743. Owned<IRowManager> rowManager = roxiemem::createRowManager(0, NULL, logctx, NULL, true); // MORE - should not really use default limits
  3744. Owned<IMessagePacker> output = ROQ->createOutputStream(packet->queryHeader(), false, logctx);
  3745. unsigned processedBefore = processed;
  3746. try
  3747. {
  3748. while (!aborted && inputsDone < inputCount)
  3749. {
  3750. checkPartChanged(inputData[inputsDone]);
  3751. if (tlk)
  3752. {
  3753. createSegmentMonitors();
  3754. tlk->reset(false);
  3755. callback.setManager(tlk);
  3756. while (!aborted && tlk->lookup(true))
  3757. {
  3758. if (groupSegCount && !layoutTranslators->item(lastPartNo.fileNo))
  3759. {
  3760. AggregateRowBuilder &rowBuilder = results.addRow(tlk->queryKeyBuffer(callback.getFPosRef()));
  3761. callback.finishedRow();
  3762. if (kind == TAKindexgroupcount)
  3763. {
  3764. unsigned __int64 count = tlk->getCurrentRangeCount(groupSegCount);
  3765. aggregateHelper->processCountGrouping(rowBuilder, count-1);
  3766. }
  3767. if (!tlk->nextRange(groupSegCount))
  3768. break;
  3769. }
  3770. else
  3771. {
  3772. keyprocessed++;
  3773. atomic_inc(&indexRecordsRead);
  3774. aggregateHelper->processRow(tlk->queryKeyBuffer(callback.getFPosRef()), this);
  3775. callback.finishedRow();
  3776. }
  3777. }
  3778. callback.setManager(NULL);
  3779. }
  3780. inputsDone++;
  3781. }
  3782. if (!aborted)
  3783. {
  3784. loop
  3785. {
  3786. Owned<AggregateRowBuilder> next = results.nextResult();
  3787. if (!next)
  3788. break;
  3789. unsigned rowSize = next->querySize();
  3790. OwnedConstRoxieRow row(next->finalizeRowClear());
  3791. if (serializer)
  3792. {
  3793. serializeRow(output, row);
  3794. }
  3795. else
  3796. {
  3797. void *recBuffer = output->getBuffer(rowSize, meta.isVariableSize());
  3798. memcpy(recBuffer, row, rowSize);
  3799. output->putBuffer(recBuffer, rowSize, meta.isVariableSize());
  3800. }
  3801. }
  3802. }
  3803. }
  3804. catch (...)
  3805. {
  3806. results.reset(); // kill entries before the rowManager dies.
  3807. throw;
  3808. }
  3809. results.reset();
  3810. if (tlk) // a very early abort can mean it is NULL....
  3811. {
  3812. logctx.noteStatistic(STATS_ACCEPTED, processed-processedBefore, 1);
  3813. logctx.noteStatistic(STATS_REJECTED, 0, 1);
  3814. }
  3815. logctx.flush(true, aborted);
  3816. if (aborted)
  3817. output->abort();
  3818. else
  3819. output->flush(true);
  3820. return !aborted;
  3821. }
  3822. };
  3823. //================================================================================================
  3824. class CRoxieIndexGroupAggregateActivityFactory : public CRoxieIndexActivityFactory
  3825. {
  3826. ThorActivityKind kind;
  3827. public:
  3828. CRoxieIndexGroupAggregateActivityFactory(IPropertyTree &graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  3829. : CRoxieIndexActivityFactory(graphNode, _subgraphId, _queryFactory, _helperFactory), kind(_kind)
  3830. {
  3831. Owned<IHThorIndexGroupAggregateArg> helper = (IHThorIndexGroupAggregateArg *) helperFactory();
  3832. init(helper, graphNode);
  3833. }
  3834. virtual IRoxieSlaveActivity *createActivity(SlaveContextLogger &logctx, IRoxieQueryPacket *packet) const
  3835. {
  3836. return new CRoxieIndexGroupAggregateActivity(logctx, packet, helperFactory, this, kind);
  3837. }
  3838. virtual StringBuffer &toString(StringBuffer &s) const
  3839. {
  3840. return CSlaveActivityFactory::toString(s.append("INDEXGROUPAGGREGATE "));
  3841. }
  3842. };
  3843. ISlaveActivityFactory *createRoxieIndexGroupAggregateActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  3844. {
  3845. return new CRoxieIndexGroupAggregateActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory, _kind);
  3846. }
  3847. //================================================================================================
  3848. class CRoxieFetchActivityFactory : public CSlaveActivityFactory
  3849. {
  3850. public:
  3851. IMPLEMENT_IINTERFACE;
  3852. Owned<IFileIOArray> fileArray;
  3853. CRoxieFetchActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  3854. : CSlaveActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory)
  3855. {
  3856. Owned<IHThorFetchBaseArg> helper = (IHThorFetchBaseArg *) helperFactory();
  3857. IHThorFetchContext * fetchContext = static_cast<IHThorFetchContext *>(helper->selectInterface(TAIfetchcontext_1));
  3858. bool variableFileName = allFilesDynamic || queryFactory.isDynamic() || ((fetchContext->getFetchFlags() & (FFvarfilename|FFdynamicfilename)) != 0);
  3859. if (!variableFileName)
  3860. {
  3861. bool isOpt = (fetchContext->getFetchFlags() & FFdatafileoptional) != 0;
  3862. OwnedRoxieString fname(fetchContext->getFileName());
  3863. datafile.setown(_queryFactory.queryPackage().lookupFileName(fname, isOpt, true, true, _queryFactory.queryWorkUnit()));
  3864. if (datafile)
  3865. fileArray.setown(datafile->getIFileIOArray(isOpt, queryFactory.queryChannel()));
  3866. }
  3867. }
  3868. virtual IRoxieSlaveActivity *createActivity(SlaveContextLogger &logctx, IRoxieQueryPacket *packet) const;
  3869. virtual StringBuffer &toString(StringBuffer &s) const
  3870. {
  3871. return CSlaveActivityFactory::toString(s.append("FETCH "));
  3872. }
  3873. inline IFileIO *getFilePart(unsigned partNo, offset_t &_base) const
  3874. {
  3875. return fileArray->getFilePart(partNo, _base);
  3876. }
  3877. };
  3878. class CRoxieFetchActivityBase : public CRoxieSlaveActivity
  3879. {
  3880. protected:
  3881. IHThorFetchBaseArg *helper;
  3882. IHThorFetchContext * fetchContext;
  3883. const CRoxieFetchActivityFactory *factory;
  3884. Owned<IFileIO> rawFile;
  3885. Owned<ISerialStream> rawStream;
  3886. CThorStreamDeserializerSource deserializeSource;
  3887. offset_t base;
  3888. char *inputData;
  3889. char *inputLimit;
  3890. Owned<IFileIOArray> varFiles;
  3891. bool needsRHS;
  3892. virtual size32_t doFetch(ARowBuilder & rowBuilder, offset_t pos, offset_t rawpos, void *inputData) = 0;
  3893. public:
  3894. IMPLEMENT_IINTERFACE;
  3895. CRoxieFetchActivityBase(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory, const CRoxieFetchActivityFactory *_aFactory)
  3896. : CRoxieSlaveActivity(_logctx, _packet, _hFactory, _aFactory), factory(_aFactory)
  3897. {
  3898. helper = (IHThorFetchBaseArg *) basehelper;
  3899. fetchContext = static_cast<IHThorFetchContext *>(helper->selectInterface(TAIfetchcontext_1));
  3900. base = 0;
  3901. variableFileName = allFilesDynamic || basefactory->queryQueryFactory().isDynamic() || ((fetchContext->getFetchFlags() & (FFvarfilename|FFdynamicfilename)) != 0);
  3902. isOpt = (fetchContext->getFetchFlags() & FFdatafileoptional) != 0;
  3903. onCreate();
  3904. inputData = (char *) serializedCreate.readDirect(0);
  3905. inputLimit = inputData + (serializedCreate.length() - serializedCreate.getPos());
  3906. needsRHS = helper->transformNeedsRhs();
  3907. }
  3908. virtual const char *queryDynamicFileName() const
  3909. {
  3910. return fetchContext->getFileName();
  3911. }
  3912. virtual void setVariableFileInfo()
  3913. {
  3914. varFiles.setown(varFileInfo->getIFileIOArray(isOpt, packet->queryHeader().channel));
  3915. }
  3916. virtual bool process();
  3917. virtual StringBuffer &toString(StringBuffer &ret) const
  3918. {
  3919. return ret.appendf("Fetch %u", packet->queryHeader().activityId);
  3920. }
  3921. virtual void setPartNo(bool filechanged);
  3922. };
  3923. bool CRoxieFetchActivityBase::process()
  3924. {
  3925. MTIME_SECTION(timer, "CRoxieFetchActivityBase::process");
  3926. Owned<IMessagePacker> output = ROQ->createOutputStream(packet->queryHeader(), false, logctx);
  3927. unsigned accepted = 0;
  3928. unsigned rejected = 0;
  3929. unsigned __int64 rowLimit = helper->getRowLimit();
  3930. OptimizedRowBuilder rowBuilder(rowAllocator, meta, output, serializer);
  3931. while (!aborted && inputData < inputLimit)
  3932. {
  3933. checkPartChanged(*(PartNoType *) inputData);
  3934. inputData += sizeof(PartNoType);
  3935. offset_t rp = *(offset_t *)inputData;
  3936. inputData += sizeof(offset_t);
  3937. unsigned rhsSize;
  3938. if (needsRHS)
  3939. {
  3940. rhsSize = *(unsigned *)inputData;
  3941. inputData += sizeof(unsigned);
  3942. }
  3943. else
  3944. rhsSize = 0;
  3945. offset_t pos;
  3946. if (isLocalFpos(rp))
  3947. pos = getLocalFposOffset(rp);
  3948. else
  3949. pos = rp-base;
  3950. unsigned thisSize = doFetch(rowBuilder, pos, rp, inputData);
  3951. inputData += rhsSize;
  3952. if (thisSize)
  3953. {
  3954. rowBuilder.writeToOutput(thisSize, true);
  3955. accepted++;
  3956. if (accepted > rowLimit)
  3957. {
  3958. logctx.noteStatistic(STATS_DISK_SEEKS, accepted+rejected, 1);
  3959. logctx.noteStatistic(STATS_ACCEPTED, accepted, 1);
  3960. logctx.noteStatistic(STATS_REJECTED, rejected, 1);
  3961. limitExceeded();
  3962. return true;
  3963. }
  3964. }
  3965. else
  3966. rejected++;
  3967. }
  3968. logctx.noteStatistic(STATS_DISK_SEEKS, accepted+rejected, 1);
  3969. logctx.noteStatistic(STATS_ACCEPTED, accepted, 1);
  3970. logctx.noteStatistic(STATS_REJECTED, rejected, 1);
  3971. logctx.flush(true, aborted);
  3972. if (aborted)
  3973. output->abort();
  3974. else
  3975. output->flush(true);
  3976. return !aborted;
  3977. }
  3978. class CRoxieFetchActivity : public CRoxieFetchActivityBase
  3979. {
  3980. Owned<IEngineRowAllocator> diskAllocator;
  3981. Owned<IOutputRowDeserializer> rowDeserializer;
  3982. public:
  3983. CRoxieFetchActivity(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory, const CRoxieFetchActivityFactory *_aFactory)
  3984. : CRoxieFetchActivityBase(_logctx, _packet, _hFactory, _aFactory)
  3985. {
  3986. IHThorFetchContext * fetchContext = static_cast<IHThorFetchContext *>(helper->selectInterface(TAIfetchcontext_1));
  3987. IOutputMetaData *diskMeta = fetchContext->queryDiskRecordSize();
  3988. diskAllocator.setown(getRowAllocator(diskMeta, basefactory->queryId()));
  3989. rowDeserializer.setown(diskMeta->createDiskDeserializer(queryContext->queryCodeContext(), basefactory->queryId()));
  3990. }
  3991. virtual size32_t doFetch(ARowBuilder & rowBuilder, offset_t pos, offset_t rawpos, void *inputData)
  3992. {
  3993. RtlDynamicRowBuilder diskRowBuilder(diskAllocator);
  3994. deserializeSource.reset(pos);
  3995. unsigned sizeRead = rowDeserializer->deserialize(diskRowBuilder.ensureRow(), deserializeSource);
  3996. OwnedConstRoxieRow rawBuffer = diskRowBuilder.finalizeRowClear(sizeRead);
  3997. // note the swapped parameters - left and right map to input and raw differently for JOIN vs FETCH
  3998. IHThorFetchArg *h = (IHThorFetchArg *) helper;
  3999. return h->transform(rowBuilder, rawBuffer, inputData, rawpos);
  4000. }
  4001. };
  4002. IRoxieSlaveActivity *CRoxieFetchActivityFactory::createActivity(SlaveContextLogger &logctx, IRoxieQueryPacket *packet) const
  4003. {
  4004. return new CRoxieFetchActivity(logctx, packet, helperFactory, this);
  4005. }
  4006. //------------------------------------------------------------------------------------
  4007. class CRoxieCSVFetchActivity : public CRoxieFetchActivityBase
  4008. {
  4009. CSVSplitter csvSplitter;
  4010. public:
  4011. CRoxieCSVFetchActivity(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory, const CRoxieFetchActivityFactory *_aFactory, unsigned _maxColumns)
  4012. : CRoxieFetchActivityBase(_logctx, _packet, _hFactory, _aFactory)
  4013. {
  4014. const char * quotes = NULL;
  4015. const char * separators = NULL;
  4016. const char * terminators = NULL;
  4017. const char * escapes = NULL;
  4018. const IResolvedFile *fileInfo = varFileInfo ? varFileInfo : factory->datafile;
  4019. if (fileInfo)
  4020. {
  4021. const IPropertyTree *options = fileInfo->queryProperties();
  4022. if (options)
  4023. {
  4024. quotes = options->queryProp("@csvQuote");
  4025. separators = options->queryProp("@csvSeparate");
  4026. terminators = options->queryProp("@csvTerminate");
  4027. escapes = options->queryProp("@csvEscape");
  4028. }
  4029. }
  4030. IHThorCsvFetchArg *h = (IHThorCsvFetchArg *) helper;
  4031. ICsvParameters *csvInfo = h->queryCsvParameters();
  4032. csvSplitter.init(_maxColumns, csvInfo, quotes, separators, terminators, escapes);
  4033. }
  4034. virtual size32_t doFetch(ARowBuilder & rowBuilder, offset_t pos, offset_t rawpos, void *inputData)
  4035. {
  4036. IHThorCsvFetchArg *h = (IHThorCsvFetchArg *) helper;
  4037. rawStream->reset(pos);
  4038. size32_t rowSize = 4096; // MORE - make configurable
  4039. size32_t maxRowSize = 10*1024*1024; // MORE - make configurable
  4040. loop
  4041. {
  4042. size32_t avail;
  4043. const void *peek = rawStream->peek(rowSize, avail);
  4044. if (csvSplitter.splitLine(avail, (const byte *)peek) < rowSize || avail < rowSize)
  4045. break;
  4046. if (rowSize == maxRowSize)
  4047. throw MakeStringException(0, "Row too big");
  4048. if (rowSize >= maxRowSize/2)
  4049. rowSize = maxRowSize;
  4050. else
  4051. rowSize += rowSize;
  4052. }
  4053. return h->transform(rowBuilder, csvSplitter.queryLengths(), (const char * *)csvSplitter.queryData(), inputData, rawpos);
  4054. }
  4055. };
  4056. class CRoxieXMLFetchActivity : public CRoxieFetchActivityBase, implements IXMLSelect
  4057. {
  4058. Owned<IXMLParse> parser;
  4059. Owned<IColumnProvider> lastMatch;
  4060. Owned<IFileIOStream> rawStreamX;
  4061. unsigned streamBufferSize;
  4062. public:
  4063. IMPLEMENT_IINTERFACE;
  4064. CRoxieXMLFetchActivity(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory, const CRoxieFetchActivityFactory *_aFactory, unsigned _streamBufferSize)
  4065. : CRoxieFetchActivityBase(_logctx, _packet, _hFactory, _aFactory),
  4066. streamBufferSize(_streamBufferSize)
  4067. {
  4068. }
  4069. virtual size32_t doFetch(ARowBuilder & rowBuilder, offset_t pos, offset_t rawpos, void *inputData)
  4070. {
  4071. rawStreamX->seek(pos, IFSbegin);
  4072. try
  4073. {
  4074. while(!lastMatch)
  4075. if(!parser->next())
  4076. throw MakeStringException(ROXIE_RECORD_FETCH_ERROR, "XML parse error at position %"I64F"d", pos);
  4077. IHThorXmlFetchArg *h = (IHThorXmlFetchArg *) helper;
  4078. unsigned thisSize = h->transform(rowBuilder, lastMatch, inputData, rawpos);
  4079. lastMatch.clear();
  4080. parser->reset();
  4081. return thisSize;
  4082. }
  4083. catch (IException *E)
  4084. {
  4085. ::Release(E);
  4086. throw MakeStringException(ROXIE_RECORD_FETCH_ERROR, "XML parse error at position %"I64F"d", pos);
  4087. }
  4088. }
  4089. virtual void match(IColumnProvider & entry, offset_t startOffset, offset_t endOffset)
  4090. {
  4091. lastMatch.set(&entry);
  4092. }
  4093. virtual void setPartNo(bool filechanged)
  4094. {
  4095. CRoxieFetchActivityBase::setPartNo(filechanged);
  4096. rawStreamX.setown(createBufferedIOStream(rawFile, streamBufferSize));
  4097. parser.setown(createXMLParse(*rawStreamX, "/", *this));
  4098. }
  4099. };
  4100. void CRoxieFetchActivityBase::setPartNo(bool filechanged)
  4101. {
  4102. rawFile.setown(variableFileName ? varFiles->getFilePart(lastPartNo.partNo, base) : factory->getFilePart(lastPartNo.partNo, base)); // MORE - superfiles
  4103. assertex(rawFile != NULL);
  4104. rawStream.setown(createFileSerialStream(rawFile, 0, -1, 0));
  4105. deserializeSource.setStream(rawStream);
  4106. }
  4107. class CRoxieCSVFetchActivityFactory : public CRoxieFetchActivityFactory
  4108. {
  4109. unsigned maxColumns;
  4110. public:
  4111. CRoxieCSVFetchActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  4112. : CRoxieFetchActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory)
  4113. {
  4114. Owned<IHThorCsvFetchArg> helper = (IHThorCsvFetchArg*) helperFactory();
  4115. maxColumns = helper->getMaxColumns();
  4116. ICsvParameters *csvInfo = helper->queryCsvParameters();
  4117. assertex(!csvInfo->queryEBCDIC());
  4118. }
  4119. virtual IRoxieSlaveActivity *createActivity(SlaveContextLogger &logctx, IRoxieQueryPacket *packet) const
  4120. {
  4121. return new CRoxieCSVFetchActivity(logctx, packet, helperFactory, this, maxColumns);
  4122. }
  4123. };
  4124. class CRoxieXMLFetchActivityFactory : public CRoxieFetchActivityFactory
  4125. {
  4126. public:
  4127. CRoxieXMLFetchActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  4128. : CRoxieFetchActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory)
  4129. {
  4130. }
  4131. virtual IRoxieSlaveActivity *createActivity(SlaveContextLogger &logctx, IRoxieQueryPacket *packet) const
  4132. {
  4133. return new CRoxieXMLFetchActivity(logctx, packet, helperFactory, this, 4096);
  4134. }
  4135. };
  4136. ISlaveActivityFactory *createRoxieFetchActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  4137. {
  4138. return new CRoxieFetchActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory);
  4139. }
  4140. ISlaveActivityFactory *createRoxieCSVFetchActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  4141. {
  4142. return new CRoxieCSVFetchActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory);
  4143. }
  4144. ISlaveActivityFactory *createRoxieXMLFetchActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  4145. {
  4146. return new CRoxieXMLFetchActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory);
  4147. }
  4148. //================================================================================================
  4149. class CRoxieKeyedJoinIndexActivityFactory : public CRoxieKeyedActivityFactory
  4150. {
  4151. public:
  4152. IMPLEMENT_IINTERFACE;
  4153. CRoxieKeyedJoinIndexActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  4154. : CRoxieKeyedActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory)
  4155. {
  4156. Owned<IHThorKeyedJoinArg> helper = (IHThorKeyedJoinArg *) helperFactory();
  4157. rtlDataAttr indexLayoutMeta;
  4158. size32_t indexLayoutSize;
  4159. if(!helper->getIndexLayout(indexLayoutSize, indexLayoutMeta.refdata()))
  4160. assertex(indexLayoutSize== 0);
  4161. MemoryBuffer m;
  4162. m.setBuffer(indexLayoutSize, indexLayoutMeta.getdata());
  4163. activityMeta.setown(deserializeRecordMeta(m, true));
  4164. layoutTranslators.setown(new TranslatorArray);
  4165. bool variableFileName = allFilesDynamic || queryFactory.isDynamic() || ((helper->getJoinFlags() & (JFvarindexfilename|JFdynamicindexfilename)) != 0);
  4166. if (!variableFileName)
  4167. {
  4168. bool isOpt = (helper->getJoinFlags() & JFindexoptional) != 0;
  4169. OwnedRoxieString indexFileName(helper->getIndexFileName());
  4170. datafile.setown(_queryFactory.queryPackage().lookupFileName(indexFileName, isOpt, true, true, _queryFactory.queryWorkUnit()));
  4171. if (datafile)
  4172. keyArray.setown(datafile->getKeyArray(activityMeta, layoutTranslators, isOpt, queryFactory.queryChannel(), queryFactory.getEnableFieldTranslation()));
  4173. }
  4174. }
  4175. virtual IRoxieSlaveActivity *createActivity(SlaveContextLogger &logctx, IRoxieQueryPacket *packet) const;
  4176. virtual StringBuffer &toString(StringBuffer &s) const
  4177. {
  4178. return CSlaveActivityFactory::toString(s.append("KEYEDJOIN INDEX "));
  4179. }
  4180. };
  4181. class CRoxieKeyedJoinIndexActivity : public CRoxieKeyedActivity
  4182. {
  4183. IHThorKeyedJoinArg *helper;
  4184. const CRoxieKeyedJoinIndexActivityFactory *factory;
  4185. unsigned inputLength;
  4186. char *inputData;
  4187. Owned<IRoxieSlaveActivity> rootIndexActivity;
  4188. IIndexReadActivityInfo *rootIndex;
  4189. unsigned processed;
  4190. unsigned candidateCount;
  4191. unsigned keepCount;
  4192. unsigned inputDone;
  4193. public:
  4194. IMPLEMENT_IINTERFACE;
  4195. CRoxieKeyedJoinIndexActivity(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory, const CRoxieKeyedJoinIndexActivityFactory *_aFactory)
  4196. : factory(_aFactory), CRoxieKeyedActivity(_logctx, _packet, _hFactory, _aFactory)
  4197. {
  4198. helper = (IHThorKeyedJoinArg *) basehelper;
  4199. variableFileName = allFilesDynamic || basefactory->queryQueryFactory().isDynamic() || ((helper->getJoinFlags() & (JFvarindexfilename|JFdynamicindexfilename)) != 0);
  4200. inputDone = 0;
  4201. processed = 0;
  4202. candidateCount = 0;
  4203. keepCount = 0;
  4204. rootIndex = NULL;
  4205. onCreate();
  4206. inputData = (char *) serializedCreate.readDirect(0);
  4207. inputLength = (serializedCreate.length() - serializedCreate.getPos());
  4208. if (resent)
  4209. {
  4210. resentInfo.read(inputDone);
  4211. inputData += inputDone;
  4212. resentInfo.read(processed);
  4213. resentInfo.read(candidateCount);
  4214. resentInfo.read(keepCount);
  4215. resentInfo.read(lastPartNo.partNo);
  4216. resentInfo.read(lastPartNo.fileNo);
  4217. setPartNo(true);
  4218. tlk->deserializeCursorPos(resentInfo);
  4219. assertex(resentInfo.remaining() == 0);
  4220. }
  4221. }
  4222. ~CRoxieKeyedJoinIndexActivity()
  4223. {
  4224. }
  4225. virtual void deserializeExtra(MemoryBuffer &buff)
  4226. {
  4227. if (helper->getJoinFlags() & JFindexfromactivity)
  4228. {
  4229. RemoteActivityId indexActivityId(buff);
  4230. assertex(indexActivityId.activityId);
  4231. unsigned indexCtxLen;
  4232. buff.read(indexCtxLen);
  4233. const void *indexCtx = buff.readDirect(indexCtxLen);
  4234. //We create a packet for the index activity to use. Header, trace info and parentextract are clone of mine, context info is copied from buff
  4235. MemoryBuffer indexPacketData;
  4236. indexPacketData.append(sizeof(RoxiePacketHeader), &packet->queryHeader());
  4237. indexPacketData.append(packet->getTraceLength(), packet->queryTraceInfo());
  4238. const byte *parentExtract = (const byte *) packet->queryContextData();
  4239. unsigned parentExtractLen = *(unsigned*) parentExtract;
  4240. indexPacketData.append(parentExtractLen);
  4241. indexPacketData.append(parentExtractLen, parentExtract + sizeof(unsigned));
  4242. indexPacketData.append(indexCtxLen, indexCtx);
  4243. RoxiePacketHeader *newHeader = (RoxiePacketHeader *) indexPacketData.toByteArray();
  4244. newHeader->continueSequence = 0;
  4245. newHeader->activityId = indexActivityId.activityId;
  4246. newHeader->queryHash = indexActivityId.queryHash;
  4247. Owned<IRoxieQueryPacket> indexPacket = createRoxiePacket(indexPacketData);
  4248. Owned<ISlaveActivityFactory> indexActivityFactory = factory->queryQueryFactory().getSlaveActivityFactory(indexActivityId.activityId);
  4249. assertex(indexActivityFactory != NULL);
  4250. rootIndexActivity.setown(indexActivityFactory->createActivity(logctx, indexPacket));
  4251. rootIndex = rootIndexActivity->queryIndexReadActivity();
  4252. varFileInfo.setown(rootIndex->getVarFileInfo());
  4253. layoutTranslators.setown(rootIndex->getTranslators());
  4254. keyArray.setown(rootIndex->getKeySet());
  4255. }
  4256. }
  4257. virtual const char *queryDynamicFileName() const
  4258. {
  4259. return helper->getIndexFileName();
  4260. }
  4261. virtual bool process();
  4262. virtual StringBuffer &toString(StringBuffer &ret) const
  4263. {
  4264. return ret.appendf("KeyedJoinIndex %u", packet->queryHeader().activityId);
  4265. }
  4266. virtual void createSegmentMonitors()
  4267. {
  4268. // This is called to create the segmonitors that apply to ALL rows - not the per-row ones
  4269. // At present there are none. However we should still set up the layout translation.
  4270. if (createSegmentMonitorsPending)
  4271. {
  4272. createSegmentMonitorsPending = false;
  4273. tlk->setLayoutTranslator(layoutTranslators->item(lastPartNo.fileNo));
  4274. }
  4275. }
  4276. };
  4277. IRoxieSlaveActivity *CRoxieKeyedJoinIndexActivityFactory::createActivity(SlaveContextLogger &logctx, IRoxieQueryPacket *packet) const
  4278. {
  4279. return new CRoxieKeyedJoinIndexActivity(logctx, packet, helperFactory, this);
  4280. }
  4281. bool CRoxieKeyedJoinIndexActivity::process()
  4282. {
  4283. MTIME_SECTION(timer, "CRoxieKeyedJoinIndexActivity::process");
  4284. Owned<IMessagePacker> output = ROQ->createOutputStream(packet->queryHeader(), false, logctx);
  4285. IOutputMetaData *joinFieldsMeta = helper->queryJoinFieldsRecordSize();
  4286. Owned<IEngineRowAllocator> joinFieldsAllocator = getRowAllocator(joinFieldsMeta, basefactory->queryId());
  4287. OptimizedKJRowBuilder rowBuilder(joinFieldsAllocator, joinFieldsMeta, output);
  4288. unsigned __int64 rowLimit = helper->getRowLimit();
  4289. unsigned atmost = helper->getJoinLimit();
  4290. if (!atmost) atmost = (unsigned) -1;
  4291. unsigned abortLimit = helper->getMatchAbortLimit();
  4292. if (!abortLimit) abortLimit = (unsigned) -1;
  4293. if (abortLimit < atmost)
  4294. atmost = abortLimit;
  4295. unsigned keepLimit = helper->getKeepLimit();
  4296. unsigned joinFlags = helper->getJoinFlags();
  4297. if (joinFlags & (JFtransformMaySkip | JFfetchMayFilter))
  4298. keepLimit = 0;
  4299. if ((joinFlags & (JFexclude|JFleftouter)) == (JFexclude|JFleftouter) && (!(joinFlags & JFfetchMayFilter))) // For left-only joins, all we care about is existance of a match. Return as soon as we know that there is one
  4300. keepLimit = 1;
  4301. unsigned processedBefore = processed;
  4302. unsigned rejected = 0;
  4303. CachedOutputMetaData inputFields(helper->queryIndexReadInputRecordSize());
  4304. unsigned inputSize = inputFields.getFixedSize();
  4305. unsigned totalSizeSent = 0;
  4306. // Now go fetch the records
  4307. bool continuationFailed = false;
  4308. while (!aborted && inputDone < inputLength)
  4309. {
  4310. checkPartChanged(*(PartNoType *) inputData);
  4311. CJoinGroup *jg = *(CJoinGroup **) (inputData + sizeof(PartNoType)); // NOTE - this is a pointer in Roxie server's address space - don't go following it!
  4312. char *inputRow = inputData+sizeof(PartNoType)+sizeof(const void *);
  4313. if (inputFields.isVariableSize())
  4314. {
  4315. inputSize = *(unsigned *)inputRow;
  4316. inputRow += sizeof(unsigned);
  4317. }
  4318. if (tlk)
  4319. {
  4320. createSegmentMonitors();
  4321. helper->createSegmentMonitors(tlk, inputRow);
  4322. if (rootIndex)
  4323. rootIndex->mergeSegmentMonitors(tlk);
  4324. tlk->finishSegmentMonitors();
  4325. if (logctx.queryTraceLevel() >= 20)
  4326. {
  4327. StringBuffer out;
  4328. printKeyedValues(out, tlk, helper->queryIndexRecordSize());
  4329. logctx.CTXLOG("Using filter %s", out.str());
  4330. }
  4331. if (!resent && (atmost != (unsigned) -1) && ((atmost > preabortKeyedJoinsThreshold) || (joinFlags & JFcountmatchabortlimit) || (keepLimit != 0)))
  4332. {
  4333. unsigned __int64 precount = tlk->checkCount(atmost);
  4334. if (precount > atmost)
  4335. {
  4336. candidateCount = atmost+1;
  4337. if (logctx.queryTraceLevel() > 5)
  4338. logctx.CTXLOG("Pre-aborting since candidate count is at least %"I64F"d", precount);
  4339. }
  4340. else
  4341. {
  4342. if (logctx.queryTraceLevel() > 10)
  4343. logctx.CTXLOG("NOT Pre-aborting since candidate count is %"I64F"d", precount);
  4344. tlk->reset(false);
  4345. }
  4346. }
  4347. else
  4348. tlk->reset(resent);
  4349. resent = false;
  4350. while (candidateCount <= atmost)
  4351. {
  4352. if (tlk->lookup(true))
  4353. {
  4354. candidateCount++;
  4355. atomic_inc(&indexRecordsRead);
  4356. KLBlobProviderAdapter adapter(tlk);
  4357. offset_t recptr;
  4358. const byte *indexRow = tlk->queryKeyBuffer(recptr);
  4359. if (helper->indexReadMatch(inputRow, indexRow, recptr, &adapter))
  4360. {
  4361. processed++;
  4362. if (keepLimit)
  4363. {
  4364. keepCount++;
  4365. if (keepCount > keepLimit)
  4366. break;
  4367. }
  4368. if (processed > rowLimit)
  4369. {
  4370. if (logctx.queryTraceLevel() > 1)
  4371. {
  4372. StringBuffer s;
  4373. logctx.CTXLOG("limit exceeded for %s", packet->queryHeader().toString(s).str());
  4374. }
  4375. logctx.noteStatistic(STATS_ACCEPTED, processed-processedBefore, 1);
  4376. logctx.noteStatistic(STATS_REJECTED, rejected, 1);
  4377. limitExceeded();
  4378. return true;
  4379. }
  4380. unsigned totalSize = 0;
  4381. if (helper->diskAccessRequired())
  4382. {
  4383. const void *self = output->getBuffer(KEYEDJOIN_RECORD_SIZE(0), true);
  4384. KeyedJoinHeader *rec = (KeyedJoinHeader *) self;
  4385. rec->fpos = recptr;
  4386. rec->thisGroup = jg;
  4387. rec->partNo = lastPartNo.partNo;
  4388. output->putBuffer(self, KEYEDJOIN_RECORD_SIZE(0), true);
  4389. }
  4390. else
  4391. {
  4392. KLBlobProviderAdapter adapter(tlk);
  4393. totalSize = helper->extractJoinFields(rowBuilder, indexRow, recptr, &adapter);
  4394. rowBuilder.writeToOutput(totalSize, recptr, jg, lastPartNo.partNo);
  4395. }
  4396. totalSizeSent += KEYEDJOIN_RECORD_SIZE(totalSize);
  4397. if (totalSizeSent > indexReadChunkSize && !continuationFailed)
  4398. {
  4399. MemoryBuffer si;
  4400. unsigned short siLen = 0;
  4401. si.append(siLen);
  4402. si.append(inputDone);
  4403. si.append(processed);
  4404. si.append(candidateCount);
  4405. si.append(keepCount);
  4406. si.append(lastPartNo.partNo);
  4407. si.append(lastPartNo.fileNo);
  4408. tlk->serializeCursorPos(si);
  4409. if (si.length() <= maxContinuationSize)
  4410. {
  4411. siLen = si.length() - sizeof(siLen);
  4412. si.writeDirect(0, sizeof(siLen), &siLen);
  4413. output->sendMetaInfo(si.toByteArray(), si.length());
  4414. logctx.flush(true, aborted);
  4415. output->flush(true);
  4416. logctx.noteStatistic(STATS_ACCEPTED, processed-processedBefore, 1);
  4417. logctx.noteStatistic(STATS_REJECTED, rejected, 1);
  4418. return true;
  4419. }
  4420. else
  4421. continuationFailed = true;
  4422. }
  4423. }
  4424. else
  4425. {
  4426. rejected++;
  4427. atomic_inc(&postFiltered);
  4428. }
  4429. }
  4430. else
  4431. break;
  4432. }
  4433. tlk->releaseSegmentMonitors();
  4434. }
  4435. // output an end marker for the matches to this group
  4436. KeyedJoinHeader *rec = (KeyedJoinHeader *) output->getBuffer(KEYEDJOIN_RECORD_SIZE(0), true);
  4437. rec->fpos = candidateCount;
  4438. rec->thisGroup = jg;
  4439. rec->partNo = (unsigned short) -1;
  4440. output->putBuffer(rec, KEYEDJOIN_RECORD_SIZE(0), true);
  4441. totalSizeSent += KEYEDJOIN_RECORD_SIZE(0); // note - don't interrupt here though - too complicated.
  4442. candidateCount = 0;
  4443. keepCount = 0;
  4444. inputData = inputRow + inputSize;
  4445. inputDone += sizeof(PartNoType) + sizeof(const void *);
  4446. if (inputFields.isVariableSize())
  4447. inputDone += sizeof(unsigned);
  4448. inputDone += inputSize;
  4449. }
  4450. if (tlk)
  4451. {
  4452. logctx.noteStatistic(STATS_ACCEPTED, processed-processedBefore, 1);
  4453. logctx.noteStatistic(STATS_REJECTED, rejected, 1);
  4454. }
  4455. logctx.flush(true, aborted);
  4456. if (aborted)
  4457. output->abort();
  4458. else
  4459. output->flush(true);
  4460. return !aborted;
  4461. }
  4462. //================================================================================================
  4463. ISlaveActivityFactory *createRoxieKeyedJoinIndexActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  4464. {
  4465. return new CRoxieKeyedJoinIndexActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory);
  4466. }
  4467. //================================================================================================
  4468. class CRoxieKeyedJoinFetchActivityFactory : public CSlaveActivityFactory
  4469. {
  4470. public:
  4471. IMPLEMENT_IINTERFACE;
  4472. Owned<IFileIOArray> fileArray;
  4473. CRoxieKeyedJoinFetchActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  4474. : CSlaveActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory)
  4475. {
  4476. Owned<IHThorKeyedJoinArg> helper = (IHThorKeyedJoinArg *) helperFactory();
  4477. assertex(helper->diskAccessRequired());
  4478. bool variableFileName = allFilesDynamic || queryFactory.isDynamic() || ((helper->getFetchFlags() & (FFvarfilename|FFdynamicfilename)) != 0);
  4479. if (!variableFileName)
  4480. {
  4481. bool isOpt = (helper->getFetchFlags() & FFdatafileoptional) != 0;
  4482. OwnedRoxieString fileName(helper->getFileName());
  4483. datafile.setown(_queryFactory.queryPackage().lookupFileName(fileName, isOpt, true, true, _queryFactory.queryWorkUnit()));
  4484. if (datafile)
  4485. fileArray.setown(datafile->getIFileIOArray(isOpt, queryFactory.queryChannel()));
  4486. }
  4487. }
  4488. virtual IRoxieSlaveActivity *createActivity(SlaveContextLogger &logctx, IRoxieQueryPacket *packet) const;
  4489. virtual StringBuffer &toString(StringBuffer &s) const
  4490. {
  4491. return CSlaveActivityFactory::toString(s.append("KEYEDJOIN FETCH "));
  4492. }
  4493. IFileIO *getFilePart(unsigned partNo, offset_t &_base) const
  4494. {
  4495. return fileArray->getFilePart(partNo, _base);
  4496. }
  4497. };
  4498. class CRoxieKeyedJoinFetchActivity : public CRoxieSlaveActivity
  4499. {
  4500. IHThorKeyedJoinArg *helper;
  4501. Owned<IFileIO> rawFile;
  4502. const CRoxieKeyedJoinFetchActivityFactory *factory;
  4503. offset_t base;
  4504. const char *inputLimit;
  4505. const char *inputData;
  4506. Owned<IFileIOArray> varFiles;
  4507. Owned<ISerialStream> rawStream;
  4508. CThorStreamDeserializerSource deserializeSource;
  4509. virtual void setPartNo(bool filechanged)
  4510. {
  4511. rawFile.setown(variableFileName ? varFiles->getFilePart(lastPartNo.partNo, base) : factory->getFilePart(lastPartNo.partNo, base)); // MORE - superfiles
  4512. rawStream.setown(createFileSerialStream(rawFile, 0, -1, 0));
  4513. deserializeSource.setStream(rawStream);
  4514. }
  4515. public:
  4516. IMPLEMENT_IINTERFACE;
  4517. CRoxieKeyedJoinFetchActivity(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory, const CRoxieKeyedJoinFetchActivityFactory *_aFactory)
  4518. : factory(_aFactory),
  4519. CRoxieSlaveActivity(_logctx, _packet, _hFactory, _aFactory)
  4520. {
  4521. // MORE - no continuation row support?
  4522. base = 0;
  4523. helper = (IHThorKeyedJoinArg *) basehelper;
  4524. variableFileName = allFilesDynamic || basefactory->queryQueryFactory().isDynamic() || ((helper->getFetchFlags() & (FFvarfilename|FFdynamicfilename)) != 0);
  4525. onCreate();
  4526. inputData = (const char *) serializedCreate.readDirect(0);
  4527. inputLimit = inputData + (serializedCreate.length() - serializedCreate.getPos());
  4528. }
  4529. ~CRoxieKeyedJoinFetchActivity()
  4530. {
  4531. }
  4532. virtual const char *queryDynamicFileName() const
  4533. {
  4534. return helper->getFileName();
  4535. }
  4536. virtual void setVariableFileInfo()
  4537. {
  4538. varFiles.setown(varFileInfo->getIFileIOArray(isOpt, packet->queryHeader().channel));
  4539. }
  4540. virtual bool process();
  4541. virtual StringBuffer &toString(StringBuffer &ret) const
  4542. {
  4543. return ret.appendf("KeyedJoinFetch %u", packet->queryHeader().activityId);
  4544. }
  4545. };
  4546. bool CRoxieKeyedJoinFetchActivity::process()
  4547. {
  4548. MTIME_SECTION(timer, "CRoxieKeyedJoinFetchActivity::process");
  4549. // MORE - where we are returning everything there is an optimization or two to be had
  4550. Owned<IMessagePacker> output = ROQ->createOutputStream(packet->queryHeader(), false, logctx);
  4551. unsigned processed = 0;
  4552. unsigned skipped = 0;
  4553. unsigned __int64 rowLimit = helper->getRowLimit();
  4554. unsigned totalSizeSent = 0;
  4555. Owned<IOutputRowDeserializer> rowDeserializer = helper->queryDiskRecordSize()->createDiskDeserializer(queryContext->queryCodeContext(), basefactory->queryId());
  4556. Owned<IEngineRowAllocator> diskAllocator = getRowAllocator(helper->queryDiskRecordSize(), basefactory->queryId());
  4557. RtlDynamicRowBuilder diskRowBuilder(diskAllocator);
  4558. IOutputMetaData *joinFieldsMeta = helper->queryJoinFieldsRecordSize();
  4559. Owned<IEngineRowAllocator> joinFieldsAllocator = getRowAllocator(joinFieldsMeta, basefactory->queryId());
  4560. OptimizedKJRowBuilder jfRowBuilder(joinFieldsAllocator, joinFieldsMeta, output);
  4561. CachedOutputMetaData inputFields(helper->queryFetchInputRecordSize());
  4562. size32_t inputSize = inputFields.getFixedSize();
  4563. while (!aborted && inputData < inputLimit)
  4564. {
  4565. checkPartChanged(*(PartNoType *) inputData);
  4566. inputData += sizeof(PartNoType);
  4567. offset_t rp;
  4568. memcpy(&rp, inputData, sizeof(rp));
  4569. offset_t pos;
  4570. if (isLocalFpos(rp))
  4571. pos = getLocalFposOffset(rp);
  4572. else
  4573. pos = rp-base;
  4574. deserializeSource.reset(pos);
  4575. unsigned sizeRead = rowDeserializer->deserialize(diskRowBuilder.ensureRow(), deserializeSource);
  4576. OwnedConstRoxieRow rawBuffer = diskRowBuilder.finalizeRowClear(sizeRead);
  4577. const KeyedJoinHeader *headerPtr = (KeyedJoinHeader *) inputData;
  4578. inputData = &headerPtr->rhsdata[0];
  4579. if (inputFields.isVariableSize())
  4580. {
  4581. memcpy(&inputSize, inputData, sizeof(inputSize));
  4582. inputData += sizeof(inputSize);
  4583. }
  4584. if (helper->fetchMatch(inputData, rawBuffer))
  4585. {
  4586. unsigned thisSize = helper->extractJoinFields(jfRowBuilder, rawBuffer, rp, (IBlobProvider*)NULL);
  4587. jfRowBuilder.writeToOutput(thisSize, headerPtr->fpos, headerPtr->thisGroup, headerPtr->partNo);
  4588. totalSizeSent += KEYEDJOIN_RECORD_SIZE(thisSize);
  4589. processed++;
  4590. if (processed > rowLimit)
  4591. {
  4592. logctx.noteStatistic(STATS_DISK_SEEKS, processed+skipped, 1);
  4593. logctx.noteStatistic(STATS_ACCEPTED, processed, 1);
  4594. logctx.noteStatistic(STATS_REJECTED, skipped, 1);
  4595. limitExceeded();
  4596. return true;
  4597. }
  4598. }
  4599. else
  4600. {
  4601. skipped++;
  4602. KeyedJoinHeader *out = (KeyedJoinHeader *) output->getBuffer(KEYEDJOIN_RECORD_SIZE(0), true);
  4603. out->fpos = 0;
  4604. out->thisGroup = headerPtr->thisGroup;
  4605. out->partNo = (unsigned short) -1;
  4606. output->putBuffer(out, KEYEDJOIN_RECORD_SIZE(0), true);
  4607. totalSizeSent += KEYEDJOIN_RECORD_SIZE(0);
  4608. }
  4609. inputData += inputSize;
  4610. }
  4611. logctx.noteStatistic(STATS_DISK_SEEKS, processed+skipped, 1);
  4612. logctx.noteStatistic(STATS_ACCEPTED, processed, 1);
  4613. logctx.noteStatistic(STATS_REJECTED, skipped, 1);
  4614. logctx.flush(true, aborted);
  4615. if (aborted)
  4616. {
  4617. output->abort();
  4618. if (logctx.queryTraceLevel() > 5)
  4619. {
  4620. StringBuffer s;
  4621. logctx.CTXLOG("CRoxieKeyedJoinFetchActivity aborted: %s", packet->queryHeader().toString(s).str());
  4622. }
  4623. }
  4624. else
  4625. {
  4626. output->flush(true);
  4627. if (logctx.queryTraceLevel() > 5)
  4628. {
  4629. StringBuffer s;
  4630. logctx.CTXLOG("CRoxieKeyedJoinFetchActivity completed: %d records returned(%d bytes), %d skipped: %s", processed, totalSizeSent, skipped, packet->queryHeader().toString(s).str());
  4631. }
  4632. }
  4633. return !aborted;
  4634. }
  4635. IRoxieSlaveActivity *CRoxieKeyedJoinFetchActivityFactory::createActivity(SlaveContextLogger &logctx, IRoxieQueryPacket *packet) const
  4636. {
  4637. return new CRoxieKeyedJoinFetchActivity(logctx, packet, helperFactory, this);
  4638. }
  4639. ISlaveActivityFactory *createRoxieKeyedJoinFetchActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory)
  4640. {
  4641. return new CRoxieKeyedJoinFetchActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory);
  4642. }
  4643. //================================================================================================
  4644. class CRoxieRemoteActivity : public CRoxieSlaveActivity
  4645. {
  4646. protected:
  4647. IHThorRemoteArg * remoteHelper;
  4648. unsigned processed;
  4649. unsigned remoteId;
  4650. public:
  4651. IMPLEMENT_IINTERFACE;
  4652. CRoxieRemoteActivity(SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, HelperFactory *_hFactory, const CSlaveActivityFactory *_aFactory, unsigned _remoteId)
  4653. : CRoxieSlaveActivity(_logctx, _packet, _hFactory, _aFactory),
  4654. remoteId(_remoteId)
  4655. {
  4656. remoteHelper = (IHThorRemoteArg *) basehelper;
  4657. processed = 0;
  4658. onCreate();
  4659. }
  4660. virtual StringBuffer &toString(StringBuffer &ret) const
  4661. {
  4662. return ret.appendf("Remote %u", packet->queryHeader().activityId);
  4663. }
  4664. virtual const char *queryDynamicFileName() const
  4665. {
  4666. throwUnexpected();
  4667. }
  4668. virtual void setVariableFileInfo()
  4669. {
  4670. throwUnexpected();
  4671. }
  4672. virtual bool process()
  4673. {
  4674. MTIME_SECTION(timer, "CRoxieRemoteActivity ::process");
  4675. Owned<IMessagePacker> output = ROQ->createOutputStream(packet->queryHeader(), false, logctx);
  4676. unsigned __int64 rowLimit = remoteHelper->getRowLimit();
  4677. rtlRowBuilder remoteExtractBuilder;
  4678. remoteHelper->createParentExtract(remoteExtractBuilder);
  4679. Linked<IActivityGraph> remoteQuery = queryContext->queryChildGraph(remoteId);
  4680. Linked<IRoxieServerChildGraph> remoteGraph = remoteQuery->queryLoopGraph();
  4681. try
  4682. {
  4683. remoteGraph->beforeExecute();
  4684. Owned<IRoxieInput> input = remoteGraph->startOutput(0, remoteExtractBuilder.size(), remoteExtractBuilder.getbytes(), false);
  4685. while (!aborted)
  4686. {
  4687. const void * next = input->nextInGroup();
  4688. if (!next)
  4689. {
  4690. next = input->nextInGroup();
  4691. if (!next)
  4692. break;
  4693. }
  4694. size32_t nextSize = meta.getRecordSize(next);
  4695. //MORE - what about grouping?
  4696. processed++;
  4697. if (processed > rowLimit)
  4698. {
  4699. ReleaseRoxieRow(next);
  4700. limitExceeded();
  4701. break;
  4702. }
  4703. if (serializer)
  4704. serializeRow(output, next);
  4705. else
  4706. {
  4707. void * recBuffer = output->getBuffer(nextSize, meta.isVariableSize());
  4708. memcpy(recBuffer, next, nextSize);
  4709. output->putBuffer(recBuffer, nextSize, meta.isVariableSize());
  4710. }
  4711. ReleaseRoxieRow(next);
  4712. }
  4713. remoteGraph->afterExecute();
  4714. }
  4715. catch (IException *E)
  4716. {
  4717. remoteGraph->afterExecute();
  4718. if (aborted)
  4719. ::Release(E);
  4720. else
  4721. throw;
  4722. }
  4723. catch (...)
  4724. {
  4725. remoteGraph->afterExecute();
  4726. throw;
  4727. }
  4728. logctx.flush(true, aborted);
  4729. if (aborted)
  4730. output->abort();
  4731. else
  4732. output->flush(true);
  4733. return !aborted;
  4734. }
  4735. virtual void setPartNo(bool filechanged)
  4736. {
  4737. throwUnexpected();
  4738. }
  4739. };
  4740. //================================================================================================
  4741. class CRoxieRemoteActivityFactory : public CSlaveActivityFactory
  4742. {
  4743. unsigned remoteId;
  4744. public:
  4745. IMPLEMENT_IINTERFACE;
  4746. CRoxieRemoteActivityFactory(IPropertyTree &graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, unsigned _remoteId)
  4747. : CSlaveActivityFactory(graphNode, _subgraphId, _queryFactory, _helperFactory), remoteId(_remoteId)
  4748. {
  4749. }
  4750. virtual IRoxieSlaveActivity *createActivity(SlaveContextLogger &logctx, IRoxieQueryPacket *packet) const
  4751. {
  4752. return new CRoxieRemoteActivity(logctx, packet, helperFactory, this, remoteId);
  4753. }
  4754. virtual StringBuffer &toString(StringBuffer &s) const
  4755. {
  4756. return CSlaveActivityFactory::toString(s.append("Remote "));
  4757. }
  4758. };
  4759. ISlaveActivityFactory *createRoxieRemoteActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, unsigned _remoteId)
  4760. {
  4761. return new CRoxieRemoteActivityFactory(_graphNode, _subgraphId, _queryFactory, _helperFactory, _remoteId);
  4762. }
  4763. //================================================================================================
  4764. class CRoxieDummyActivityFactory : public CSlaveActivityFactory // not a real activity - just used to properly link files
  4765. {
  4766. protected:
  4767. Owned<const IResolvedFile> indexfile;
  4768. Owned<IKeyArray> keyArray;
  4769. Owned<IFileIOArray> fileArray;
  4770. TranslatorArray layoutTranslators;
  4771. public:
  4772. IMPLEMENT_IINTERFACE;
  4773. CRoxieDummyActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, bool isLoadDataOnly)
  4774. : CSlaveActivityFactory(_graphNode, _subgraphId, _queryFactory, NULL)
  4775. {
  4776. if (_graphNode.getPropBool("att[@name='_isSpill']/@value", false) || _graphNode.getPropBool("att[@name='_isSpillGlobal']/@value", false))
  4777. return; // ignore 'spills'
  4778. try // operations does not want any missing file errors to be fatal, or throw traps - just log it
  4779. {
  4780. bool isOpt = _graphNode.getPropBool("att[@name='_isOpt']/@value") || pretendAllOpt;
  4781. const char *fileName = queryNodeFileName(_graphNode);
  4782. const char *indexName = queryNodeIndexName(_graphNode);
  4783. if (indexName && (!fileName || !streq(indexName, fileName)))
  4784. {
  4785. indexfile.setown(_queryFactory.queryPackage().lookupFileName(indexName, isOpt, true, true, _queryFactory.queryWorkUnit()));
  4786. if (indexfile)
  4787. keyArray.setown(indexfile->getKeyArray(NULL, &layoutTranslators, isOpt, queryFactory.queryChannel(), queryFactory.getEnableFieldTranslation()));
  4788. }
  4789. if (fileName)
  4790. {
  4791. datafile.setown(_queryFactory.queryPackage().lookupFileName(fileName, isOpt, true, true, _queryFactory.queryWorkUnit()));
  4792. if (datafile)
  4793. fileArray.setown(datafile->getIFileIOArray(isOpt, queryFactory.queryChannel()));
  4794. }
  4795. }
  4796. catch(IException *E)
  4797. {
  4798. StringBuffer errors;
  4799. E->errorMessage(errors);
  4800. DBGLOG("%s File error = %s", (isLoadDataOnly) ? "LOADDATAONLY" : "SUSPENDED QUERY", errors.str());
  4801. E->Release();
  4802. }
  4803. }
  4804. virtual IRoxieSlaveActivity *createActivity(SlaveContextLogger &logctx, IRoxieQueryPacket *packet) const
  4805. {
  4806. throwUnexpected(); // don't actually want to create an activity
  4807. }
  4808. };
  4809. //================================================================================================
  4810. ISlaveActivityFactory *createRoxieDummyActivityFactory(IPropertyTree &_graphNode, unsigned _subgraphId, IQueryFactory &_queryFactory, bool isLoadDataOnly)
  4811. {
  4812. // MORE - bool isLoadDataOnly may need to be an enum if more than just LOADDATAONLY and suspended queries use this
  4813. return new CRoxieDummyActivityFactory(_graphNode, _subgraphId, _queryFactory, isLoadDataOnly);
  4814. }