workunit.cpp 390 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005
  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 "jlib.hpp"
  14. #include "workunit.hpp"
  15. #include "jprop.hpp"
  16. #include "jmisc.hpp"
  17. #include "jexcept.hpp"
  18. #include "jiter.ipp"
  19. #include "jptree.hpp"
  20. #include "jtime.ipp"
  21. #include "jencrypt.hpp"
  22. #include "junicode.hpp"
  23. #include "jlzw.hpp"
  24. #include "jregexp.hpp"
  25. #include "eclrtl.hpp"
  26. #include "deftype.hpp"
  27. #include <time.h>
  28. #include "mpbase.hpp"
  29. #include "daclient.hpp"
  30. #include "dadfs.hpp"
  31. #include "dafdesc.hpp"
  32. #include "dasds.hpp"
  33. #include "danqs.hpp"
  34. #include "dautils.hpp"
  35. #include "dllserver.hpp"
  36. #include "thorplugin.hpp"
  37. #include "thorhelper.hpp"
  38. #include "workflow.hpp"
  39. #include "nbcd.hpp"
  40. #include "seclib.hpp"
  41. #include "wuerror.hpp"
  42. #include "wujobq.hpp"
  43. #include "environment.hpp"
  44. #include "workunit.ipp"
  45. static int workUnitTraceLevel = 1;
  46. static StringBuffer &getXPath(StringBuffer &wuRoot, const char *wuid)
  47. {
  48. // MORE - can fold in the date
  49. return wuRoot.append("/WorkUnits/").append(wuid);
  50. }
  51. //To be called by eclserver, but esp etc. won't know, so we need to store it.
  52. static StringBuffer & appendLibrarySuffix(StringBuffer & suffix)
  53. {
  54. #ifdef _WIN32
  55. suffix.append("W");
  56. #else
  57. suffix.append("L");
  58. #endif
  59. #ifdef __64BIT__
  60. suffix.append("64");
  61. #else
  62. suffix.append("32");
  63. #endif
  64. return suffix;
  65. }
  66. typedef MapStringTo<bool> UniqueScopes;
  67. static void wuAccessError(const char *username, const char *action, const char *wuscope, const char *wuid, bool excpt, bool log)
  68. {
  69. StringBuffer err;
  70. err.append("Workunit Access Denied - action: ").append(action).append(" user:").append(username ? username : "<Unknown>");
  71. if (wuid)
  72. err.append(" workunit:").append(wuid);
  73. if (wuscope)
  74. err.append(" scope:").append(wuscope);
  75. //MORE - we would need more information passed in from outside if we want to make the audit message format the same as from higher level ESP calls
  76. SYSLOG(AUDIT_TYPE_ACCESS_FAILURE, err.str());
  77. if (log)
  78. LOG(MCuserError, "%s", err.str());
  79. if (excpt)
  80. throw MakeStringException(WUERR_AccessError, "%s", err.str());
  81. }
  82. static bool checkWuScopeSecAccess(const char *wuscope, ISecManager *secmgr, ISecUser *secuser, int required, const char *action, bool excpt, bool log)
  83. {
  84. if (!secmgr || !secuser)
  85. return true;
  86. bool ret = secmgr->authorizeEx(RT_WORKUNIT_SCOPE, *secuser, wuscope)>=required;
  87. if (!ret && (log || excpt))
  88. wuAccessError(secuser->getName(), action, wuscope, NULL, excpt, log);
  89. return ret;
  90. }
  91. static bool checkWuScopeListSecAccess(const char *wuscope, ISecResourceList *scopes, int required, const char *action, bool excpt, bool log)
  92. {
  93. if (!scopes)
  94. return true;
  95. bool ret=true;
  96. if (wuscope)
  97. {
  98. Owned<ISecResource> res=scopes->getResource(wuscope);
  99. if (!res || res->getAccessFlags()<required)
  100. ret=false;
  101. }
  102. else
  103. {
  104. for (int seq=0; ret && seq<scopes->count(); seq++)
  105. {
  106. ISecResource *res=scopes->queryResource(seq);
  107. if (res && res->getAccessFlags()<required)
  108. return false;
  109. }
  110. }
  111. if (!ret && (log || excpt))
  112. wuAccessError(NULL, action, wuscope, NULL, excpt, log);
  113. return ret;
  114. }
  115. static bool checkWuSecAccess(IConstWorkUnit &cw, ISecManager *secmgr, ISecUser *secuser, int required, const char *action, bool excpt, bool log)
  116. {
  117. if (!secmgr || !secuser)
  118. return true;
  119. bool ret=secmgr->authorizeEx(RT_WORKUNIT_SCOPE, *secuser, cw.queryWuScope())>=required;
  120. if (!ret && (log || excpt))
  121. {
  122. wuAccessError(secuser->getName(), action, cw.queryWuScope(), cw.queryWuid(), excpt, log);
  123. }
  124. return ret;
  125. }
  126. static bool checkWuSecAccess(const char *wuid, ISecManager *secmgr, ISecUser *secuser, int required, const char *action, bool excpt, bool log)
  127. {
  128. if (!secmgr || !secuser)
  129. return true;
  130. Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
  131. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid);
  132. bool ret=secmgr->authorizeEx(RT_WORKUNIT_SCOPE, *secuser, cw->queryWuScope())>=required;
  133. if (!ret && (log || excpt))
  134. {
  135. wuAccessError(secuser->getName(), action, cw->queryWuScope(), cw->queryWuid(), excpt, log);
  136. }
  137. return ret;
  138. }
  139. void doDescheduleWorkkunit(char const * wuid)
  140. {
  141. StringBuffer xpath;
  142. xpath.append("*/*/*/");
  143. ncnameEscape(wuid, xpath);
  144. Owned<IRemoteConnection> conn = querySDS().connect("/Schedule", myProcessSession(), RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT);
  145. if(!conn) return;
  146. Owned<IPropertyTree> root = conn->getRoot();
  147. bool more;
  148. do more = root->removeProp(xpath.str()); while(more);
  149. }
  150. //======================================================
  151. /*
  152. * Graph progress support
  153. */
  154. CWuGraphStats::CWuGraphStats(IPropertyTree *_progress, StatisticCreatorType _creatorType, const char * _creator, const char * _rootScope, unsigned _id)
  155. : progress(_progress), creatorType(_creatorType), creator(_creator), id(_id)
  156. {
  157. StatisticScopeType scopeType = SSTgraph;
  158. StatsScopeId rootScopeId;
  159. verifyex(rootScopeId.setScopeText(_rootScope));
  160. collector.setown(createStatisticsGatherer(_creatorType, _creator, rootScopeId));
  161. }
  162. void CWuGraphStats::beforeDispose()
  163. {
  164. Owned<IStatisticCollection> stats = collector->getResult();
  165. MemoryBuffer compressed;
  166. {
  167. MemoryBuffer serialized;
  168. serializeStatisticCollection(serialized, stats);
  169. compressToBuffer(compressed, serialized.length(), serialized.toByteArray());
  170. }
  171. unsigned minActivity = 0;
  172. unsigned maxActivity = 0;
  173. stats->getMinMaxActivity(minActivity, maxActivity);
  174. StringBuffer tag;
  175. tag.append("sg").append(id);
  176. //Replace the particular subgraph statistics added by this creator
  177. StringBuffer qualified(tag);
  178. qualified.append("[@creator='").append(creator).append("']");
  179. progress->removeProp(qualified);
  180. IPropertyTree * subgraph = progress->addPropTree(tag);
  181. subgraph->setProp("@c", queryCreatorTypeName(creatorType));
  182. subgraph->setProp("@creator", creator);
  183. subgraph->setPropInt("@minActivity", minActivity);
  184. subgraph->setPropInt("@maxActivity", maxActivity);
  185. subgraph->setPropBin("Stats", compressed.length(), compressed.toByteArray());
  186. if (!progress->getPropBool("@stats", false))
  187. progress->setPropBool("@stats", true);
  188. }
  189. IStatisticGatherer & CWuGraphStats::queryStatsBuilder()
  190. {
  191. return *collector;
  192. }
  193. class CConstGraphProgress : public CInterface, implements IConstWUGraphProgress
  194. {
  195. public:
  196. IMPLEMENT_IINTERFACE;
  197. CConstGraphProgress(const char *_wuid, const char *_graphName, IPropertyTree *_progress) : wuid(_wuid), graphName(_graphName), progress(_progress)
  198. {
  199. if (!progress)
  200. progress.setown(createPTree());
  201. formatVersion = progress->getPropInt("@format", PROGRESS_FORMAT_V);
  202. }
  203. virtual IPropertyTree * getProgressTree()
  204. {
  205. if (progress->getPropBool("@stats"))
  206. return createProcessTreeFromStats(); // Should we cache that?
  207. return LINK(progress);
  208. }
  209. virtual unsigned queryFormatVersion()
  210. {
  211. return formatVersion;
  212. }
  213. protected:
  214. CConstGraphProgress(const char *_wuid, const char *_graphName) : wuid(_wuid), graphName(_graphName)
  215. {
  216. formatVersion = PROGRESS_FORMAT_V;
  217. }
  218. static void expandStats(IPropertyTree * target, IStatisticCollection & collection)
  219. {
  220. StringBuffer formattedValue;
  221. unsigned numStats = collection.getNumStatistics();
  222. for (unsigned i=0; i < numStats; i++)
  223. {
  224. StatisticKind kind;
  225. unsigned __int64 value;
  226. collection.getStatistic(kind, value, i);
  227. formatStatistic(formattedValue.clear(), value, kind);
  228. target->setProp(queryTreeTag(kind), formattedValue);
  229. }
  230. }
  231. void expandProcessTreeFromStats(IPropertyTree * rootTarget, IPropertyTree * target, IStatisticCollection * collection)
  232. {
  233. expandStats(target, *collection);
  234. StringBuffer scopeName;
  235. Owned<IStatisticCollectionIterator> activityIter = &collection->getScopes(NULL, false);
  236. ForEach(*activityIter)
  237. {
  238. IStatisticCollection & cur = activityIter->query();
  239. cur.getScope(scopeName.clear());
  240. const char * id = scopeName.str();
  241. const char * tag;
  242. IPropertyTree * curTarget = target;
  243. switch (cur.queryScopeType())
  244. {
  245. case SSTedge:
  246. tag = "edge";
  247. id += strlen(EdgeScopePrefix);
  248. break;
  249. case SSTactivity:
  250. tag = "node";
  251. id += strlen(ActivityScopePrefix);
  252. break;
  253. case SSTsubgraph:
  254. //All subgraphs are added a root elements in the progress tree
  255. curTarget = rootTarget;
  256. tag = "node";
  257. id += strlen(SubGraphScopePrefix);
  258. break;
  259. case SSTfunction:
  260. //MORE:Should function scopes be included in the graph scope somehow, and if so how?
  261. continue;
  262. default:
  263. throwUnexpected();
  264. }
  265. IPropertyTree * next = curTarget->addPropTree(tag);
  266. next->setProp("@id", id);
  267. expandProcessTreeFromStats(rootTarget, next, &cur);
  268. }
  269. }
  270. IPropertyTree * createProcessTreeFromStats()
  271. {
  272. MemoryBuffer compressed;
  273. MemoryBuffer serialized;
  274. Owned<IPropertyTree> progressTree = createPTree();
  275. Owned<IPropertyTreeIterator> iter = progress->getElements("sg*");
  276. ForEach(*iter)
  277. {
  278. IPropertyTree & curSubGraph = iter->query();
  279. curSubGraph.getPropBin("Stats", compressed.clear());
  280. //Protect against updates that delete the stats while we are iterating
  281. if (compressed.length())
  282. {
  283. decompressToBuffer(serialized.clear(), compressed);
  284. Owned<IStatisticCollection> collection = createStatisticCollection(serialized);
  285. expandProcessTreeFromStats(progressTree, progressTree, collection);
  286. }
  287. }
  288. return progressTree.getClear();
  289. }
  290. protected:
  291. Linked<IPropertyTree> progress;
  292. StringAttr wuid, graphName;
  293. unsigned formatVersion;
  294. };
  295. extern WORKUNIT_API IConstWUGraphProgress *createConstGraphProgress(const char *_wuid, const char *_graphName, IPropertyTree *_progress)
  296. {
  297. return new CConstGraphProgress(_wuid, _graphName, _progress);
  298. }
  299. //--------------------------------------------------------------------------------------------------------------------
  300. /*
  301. * Create a user friendly description a scope/stats combination. Only currently used for elapsed time for root subgraphs
  302. */
  303. static void createDefaultDescription(StringBuffer & description, StatisticKind kind, StatisticScopeType scopeType, const char * scope)
  304. {
  305. switch (kind)
  306. {
  307. case StTimeElapsed:
  308. {
  309. if (scopeType != SSTsubgraph)
  310. break;
  311. //Create a default description for a root subgraph
  312. const char * colon = strchr(scope, ':');
  313. if (!colon)
  314. break;
  315. const char * subgraph = colon+1;
  316. //Check for nested subgraph
  317. if (strchr(subgraph, ':'))
  318. break;
  319. assertex(strncmp(subgraph, SubGraphScopePrefix, strlen(SubGraphScopePrefix)) == 0);
  320. StringAttr graphname;
  321. graphname.set(scope, colon - scope);
  322. unsigned subId = atoi(subgraph + strlen(SubGraphScopePrefix));
  323. formatGraphTimerLabel(description, graphname, 0, subId);
  324. }
  325. }
  326. }
  327. /* Represents a single statistic */
  328. class ExtractedStatistic : public CInterfaceOf<IConstWUStatistic>
  329. {
  330. public:
  331. virtual IStringVal & getDescription(IStringVal & str, bool createDefault) const
  332. {
  333. if (!description && createDefault)
  334. {
  335. StringBuffer desc;
  336. createDefaultDescription(desc, kind, scopeType, scope);
  337. str.set(desc);
  338. return str;
  339. }
  340. str.set(description);
  341. return str;
  342. }
  343. virtual IStringVal & getCreator(IStringVal & str) const
  344. {
  345. str.set(creator);
  346. return str;
  347. }
  348. virtual const char * queryScope() const
  349. {
  350. return scope;
  351. }
  352. virtual IStringVal & getFormattedValue(IStringVal & str) const
  353. {
  354. StringBuffer formatted;
  355. formatStatistic(formatted, value, measure);
  356. str.set(formatted);
  357. return str;
  358. }
  359. virtual StatisticMeasure getMeasure() const
  360. {
  361. return measure;
  362. }
  363. virtual StatisticKind getKind() const
  364. {
  365. return kind;
  366. }
  367. virtual StatisticCreatorType getCreatorType() const
  368. {
  369. return creatorType;
  370. }
  371. virtual StatisticScopeType getScopeType() const
  372. {
  373. return scopeType;
  374. }
  375. virtual unsigned __int64 getValue() const
  376. {
  377. return value;
  378. }
  379. virtual unsigned __int64 getCount() const
  380. {
  381. return count;
  382. }
  383. virtual unsigned __int64 getMax() const
  384. {
  385. return max;
  386. }
  387. virtual unsigned __int64 getTimestamp() const
  388. {
  389. return timeStamp;
  390. }
  391. virtual bool matches(const IStatisticsFilter * filter) const
  392. {
  393. return filter->matches(creatorType, creator, scopeType, scope, measure, kind, value);
  394. }
  395. public:
  396. StringBuffer creator;
  397. StringBuffer description;
  398. StringBuffer scope;
  399. StatisticMeasure measure;
  400. StatisticKind kind;
  401. StatisticCreatorType creatorType;
  402. StatisticScopeType scopeType;
  403. unsigned __int64 value;
  404. unsigned __int64 count;
  405. unsigned __int64 max;
  406. unsigned __int64 timeStamp;
  407. };
  408. //---------------------------------------------------------------------------------------------------------------------
  409. /*
  410. * The following compare functions are used to ensure that comparison are consistent with
  411. * compareScopeName() in jstats. This ensures that the scope iterators from different sources
  412. * are processed in a consistent order
  413. */
  414. static int compareGraphNode(IInterface * const *ll, IInterface * const *rr)
  415. {
  416. IPropertyTree *l = (IPropertyTree *) *ll;
  417. IPropertyTree *r = (IPropertyTree *) *rr;
  418. const char * lname = l->queryName();
  419. const char * rname = r->queryName();
  420. return compareScopeName(lname, rname);
  421. }
  422. static int compareSubGraphStatsNode(IInterface * const *ll, IInterface * const *rr)
  423. {
  424. IPropertyTree *l = (IPropertyTree *) *ll;
  425. IPropertyTree *r = (IPropertyTree *) *rr;
  426. return compareScopeName(l->queryName(), r->queryName());
  427. }
  428. static int compareSubGraphNode(IInterface * const *ll, IInterface * const *rr)
  429. {
  430. IPropertyTree *l = (IPropertyTree *) *ll;
  431. IPropertyTree *r = (IPropertyTree *) *rr;
  432. return l->getPropInt("@id") - r->getPropInt("@id");
  433. }
  434. static int compareActivityNode(IInterface * const *ll, IInterface * const *rr)
  435. {
  436. IPropertyTree *l = (IPropertyTree *) *ll;
  437. IPropertyTree *r = (IPropertyTree *) *rr;
  438. return l->getPropInt("@id") - r->getPropInt("@id");
  439. }
  440. static int compareEdgeNode(IInterface * const *ll, IInterface * const *rr)
  441. {
  442. IPropertyTree *l = (IPropertyTree *) *ll;
  443. IPropertyTree *r = (IPropertyTree *) *rr;
  444. //MORE: Edge needs more work
  445. const char * leftId = l->queryProp("@id");
  446. const char * rightId = r->queryProp("@id");
  447. unsigned leftAc = atoi(leftId);
  448. unsigned rightAc = atoi(rightId);
  449. if (leftAc != rightAc)
  450. return (int)(leftAc - rightAc);
  451. const char * leftSep = strchr(leftId, '_');
  452. const char * rightSep = strchr(rightId, '_');
  453. assertex(leftSep && rightSep);
  454. return atoi(leftSep+1) - atoi(rightSep+1);
  455. }
  456. //---------------------------------------------------------------------------------------------------------------------
  457. /*
  458. * A class for implementing a scope iterator that walks through graph progress information
  459. * Very similar to CConstGraphProgressStatisticsIterator.
  460. * The code has been cloned rather than commoned up because CConstGraphProgressStatisticsIterator
  461. * will be deprecated and deleted once this is fully functional (or implemented in terms of this).
  462. */
  463. class CConstGraphProgressScopeIterator : public CInterfaceOf<IConstWUScopeIterator>
  464. {
  465. public:
  466. CConstGraphProgressScopeIterator(const char * wuid, const IStatisticsFilter * _filter) : filter(_filter)
  467. {
  468. if (filter)
  469. scopes.appendList(filter->queryScope(), ":");
  470. const char * searchGraph = "*";
  471. if (scopes.ordinality())
  472. searchGraph = scopes.item(0);
  473. rootPath.append("/GraphProgress/").append(wuid).append('/');
  474. bool singleGraph = false;
  475. if (!containsWildcard(searchGraph))
  476. {
  477. rootPath.append(searchGraph).append("/");
  478. singleGraph = true;
  479. }
  480. //Don't lock the statistics while we iterate - any partial updates must not cause problems
  481. if (daliClientActive())
  482. conn.setown(querySDS().connect(rootPath.str(), myProcessSession(), RTM_NONE, SDS_LOCK_TIMEOUT));
  483. if (conn && !singleGraph)
  484. {
  485. graphIter.setown(conn->queryRoot()->getElements("*"));
  486. graphIter.setown(createSortedIterator(*graphIter, compareGraphNode));
  487. }
  488. valid = false;
  489. }
  490. IMPLEMENT_IINTERFACE_USING(CInterfaceOf<IConstWUScopeIterator>)
  491. virtual bool first()
  492. {
  493. valid = false;
  494. if (!conn)
  495. return false;
  496. if (graphIter && !graphIter->first())
  497. return false;
  498. if (!firstSubGraph())
  499. {
  500. if (!nextGraph())
  501. return false;
  502. }
  503. valid = true;
  504. return true;
  505. }
  506. virtual bool next()
  507. {
  508. if (!nextChildScope())
  509. {
  510. if (!nextSubGraph())
  511. {
  512. if (!nextGraph())
  513. {
  514. valid = false;
  515. return false;
  516. }
  517. }
  518. }
  519. return true;
  520. }
  521. virtual bool isValid()
  522. {
  523. return valid;
  524. }
  525. protected:
  526. bool firstSubGraph()
  527. {
  528. IPropertyTree & graphNode = graphIter ? graphIter->query() : *conn->queryRoot();
  529. const char * xpath = "sg*";
  530. StringBuffer childXpath;
  531. if (scopes.isItem(1))
  532. {
  533. const char * scope1 = scopes.item(1);
  534. if (strnicmp(scope1, "sg", 2) == 0)
  535. {
  536. childXpath.append(scope1);
  537. xpath = childXpath.str();
  538. }
  539. }
  540. subgraphIter.setown(graphNode.getElements(xpath));
  541. if (subgraphIter)
  542. subgraphIter.setown(createSortedIterator(*subgraphIter, compareSubGraphStatsNode));
  543. else
  544. subgraphIter.setown(graphNode.getElements("sg0"));
  545. if (!subgraphIter->first())
  546. return false;
  547. if (firstStat())
  548. return true;
  549. return nextSubGraph();
  550. }
  551. bool nextSubGraph()
  552. {
  553. for (;;)
  554. {
  555. if (!subgraphIter->next())
  556. return false;
  557. if (firstStat())
  558. return true;
  559. }
  560. }
  561. bool nextGraph()
  562. {
  563. if (!graphIter)
  564. return false;
  565. for (;;)
  566. {
  567. if (!graphIter->next())
  568. return false;
  569. if (firstSubGraph())
  570. return true;
  571. }
  572. }
  573. bool firstStat()
  574. {
  575. IPropertyTree & curSubGraph = subgraphIter->query();
  576. if (!checkSubGraph())
  577. return false;
  578. curSubGraph.getPropBin("Stats", compressed.clear());
  579. //Don't crash on old format progress...
  580. if (compressed.length() == 0)
  581. return false;
  582. decompressToBuffer(serialized.clear(), compressed);
  583. Owned<IStatisticCollection> collection = createStatisticCollection(serialized);
  584. statsIterator.timeStamp = collection->queryWhenCreated();
  585. if (!beginCollection(*collection))
  586. return false;
  587. //The root element of a collection is a graph - but it is only there to nest the subgraphs in.
  588. //Do not iterate it as a separate element - unless it has some stats.
  589. if ((collection->queryScopeType() != SSTgraph) || (collection->getNumStatistics() != 0))
  590. return true;
  591. return next();
  592. }
  593. bool beginCollection(IStatisticCollection & collection)
  594. {
  595. collections.append(OLINK(collection));
  596. if (checkScope())
  597. return true;
  598. return nextChildScope();
  599. }
  600. bool nextChildScope()
  601. {
  602. for (;;)
  603. {
  604. if (collections.ordinality() == 0)
  605. return false;
  606. IStatisticCollection * curCollection = &collections.tos();
  607. if (childIterators.ordinality() < collections.ordinality())
  608. {
  609. if (!filter || filter->recurseChildScopes(curScopeType, curScopeName))
  610. {
  611. //Start iterating the children for the current collection
  612. childIterators.append(curCollection->getScopes(NULL, true));
  613. if (!childIterators.tos().first())
  614. {
  615. finishCollection();
  616. continue;
  617. }
  618. }
  619. else
  620. {
  621. //Don't walk the child scopes
  622. collections.pop();
  623. continue;
  624. }
  625. }
  626. else if (!childIterators.tos().next())
  627. {
  628. finishCollection();
  629. continue;
  630. }
  631. if (beginCollection(childIterators.tos().query()))
  632. return true;
  633. }
  634. }
  635. void finishCollection()
  636. {
  637. collections.pop();
  638. childIterators.pop();
  639. }
  640. bool checkSubGraph()
  641. {
  642. if (!filter)
  643. return true;
  644. IPropertyTree & curSubGraph = subgraphIter->query();
  645. StatisticCreatorType creatorType = queryCreatorType(curSubGraph.queryProp("@c"));
  646. const char * creator = curSubGraph.queryProp("@creator");
  647. if (!filter->matches(creatorType, creator, SSTall, NULL, SMeasureAll, StKindAll, AnyStatisticValue))
  648. return false;
  649. statsIterator.creatorType = creatorType;
  650. statsIterator.creator.set(creator);
  651. return true;
  652. }
  653. bool checkScope()
  654. {
  655. if (!filter)
  656. return true;
  657. IStatisticCollection * collection = &collections.tos();
  658. curScopeType = collection->queryScopeType();
  659. collection->getFullScope(curScopeName.clear());
  660. return filter->matches(SCTall, NULL, curScopeType, curScopeName, SMeasureAll, StKindAll, AnyStatisticValue);
  661. }
  662. virtual void playProperties(IWuScopeVisitor & visitor) override
  663. {
  664. /*
  665. MORE: Code from the statsIterator class should be inlined here - code will be much simpler
  666. but it currently needs an implementation of the IConstWUStatistic 3rd parameter
  667. IStatisticCollection & collection = collections.tos();
  668. ForEachItemIn(i, collection)
  669. {
  670. StatisticKind kind;
  671. unsigned __int64 value;
  672. collection->getStatistic(kind, value, i);
  673. visitor.noteStatistic(kind, value, *this);
  674. }
  675. */
  676. statsIterator.reset(curScopeName, curScopeType, collections.tos());
  677. ForEach(statsIterator)
  678. statsIterator.play(visitor);
  679. }
  680. virtual bool getStat(StatisticKind kind, unsigned __int64 & value) const
  681. {
  682. return collections.tos().getStatistic(kind, value);
  683. }
  684. virtual const char * queryAttribute(WuAttr attr) const
  685. {
  686. return nullptr;
  687. }
  688. virtual const char * queryHint(const char * kind) const
  689. {
  690. return nullptr;
  691. }
  692. virtual const char * queryScope() const override
  693. {
  694. return curScopeName;
  695. }
  696. virtual StatisticScopeType getScopeType() const override
  697. {
  698. return curScopeType;
  699. }
  700. private:
  701. class ScopeStatisticsIterator : public CInterfaceOf<IConstWUStatisticIterator>, public IConstWUStatistic
  702. {
  703. friend class CConstGraphProgressScopeIterator; // cleaner if this was removed + setScope() functions added.
  704. public:
  705. void reset(const char * _scopeName, StatisticScopeType _scopeType, IStatisticCollection & _collection)
  706. {
  707. scope.set(_scopeName);
  708. scopeType = _scopeType;
  709. collection = &_collection;
  710. numStats = collection->getNumStatistics();
  711. }
  712. IMPLEMENT_IINTERFACE_USING(CInterfaceOf<IConstWUStatisticIterator>)
  713. // interface IConstWUStatisticIterator
  714. virtual IConstWUStatistic & query() override
  715. {
  716. return *this;
  717. }
  718. virtual bool first() override
  719. {
  720. curStatIndex = 0;
  721. if (curStatIndex >= numStats)
  722. return false;
  723. collection->getStatistic(kind, value, curStatIndex);
  724. //MORE: Allow filtering:
  725. /*
  726. * if (filter && !filter->matches(SCTall, NULL, SSTall, NULL, queryMeasure(kind), kind, value))
  727. continue;
  728. */
  729. return true;
  730. }
  731. virtual bool next() override
  732. {
  733. for (;;)
  734. {
  735. ++curStatIndex;
  736. if (curStatIndex >= numStats)
  737. return false;
  738. collection->getStatistic(kind, value, curStatIndex);
  739. //MORE: Allow stats filtering
  740. return true;
  741. }
  742. }
  743. virtual bool isValid() override
  744. {
  745. return curStatIndex < numStats;
  746. }
  747. //interface IConstWUStatistic
  748. virtual IStringVal & getDescription(IStringVal & str, bool createDefault) const override
  749. {
  750. if (createDefault)
  751. {
  752. StringBuffer description;
  753. createDefaultDescription(description, kind, scopeType, scope);
  754. str.set(description);
  755. }
  756. return str;
  757. }
  758. virtual IStringVal & getCreator(IStringVal & str) const override
  759. {
  760. str.set(creator);
  761. return str;
  762. }
  763. virtual const char * queryScope() const override
  764. {
  765. return scope;
  766. }
  767. virtual IStringVal & getFormattedValue(IStringVal & str) const override
  768. {
  769. StringBuffer formatted;
  770. formatStatistic(formatted, value, kind);
  771. str.set(formatted);
  772. return str;
  773. }
  774. virtual StatisticMeasure getMeasure() const override
  775. {
  776. return queryMeasure(kind);
  777. }
  778. virtual StatisticKind getKind() const override
  779. {
  780. return kind;
  781. }
  782. virtual StatisticCreatorType getCreatorType() const override
  783. {
  784. return creatorType;
  785. }
  786. virtual StatisticScopeType getScopeType() const override
  787. {
  788. return scopeType;
  789. }
  790. virtual unsigned __int64 getValue() const override
  791. {
  792. return value;
  793. }
  794. virtual unsigned __int64 getCount() const override
  795. {
  796. return 1;
  797. }
  798. virtual unsigned __int64 getMax() const override
  799. {
  800. return 0;
  801. }
  802. virtual unsigned __int64 getTimestamp() const override
  803. {
  804. return timeStamp;
  805. }
  806. //MORE: I'm not sure this function should be in this interface
  807. virtual bool matches(const IStatisticsFilter * filter) const override
  808. {
  809. return filter->matches(SCTall, NULL, SSTall, NULL, queryMeasure(kind), kind, value);
  810. }
  811. void play(IWuScopeVisitor & visitor)
  812. {
  813. visitor.noteStatistic(kind, value, *this);
  814. }
  815. protected:
  816. IStatisticCollection * collection = nullptr;
  817. StringBuffer creator;
  818. StringBuffer scope;
  819. StatisticKind kind;
  820. StatisticCreatorType creatorType;
  821. StatisticScopeType scopeType;
  822. unsigned __int64 value = 0;
  823. unsigned __int64 timeStamp;
  824. unsigned curStatIndex = 0;
  825. unsigned numStats = 0;
  826. } statsIterator;
  827. Owned<IRemoteConnection> conn;
  828. StringBuffer curScopeName;
  829. StatisticScopeType curScopeType = SSTnone;
  830. const IStatisticsFilter * filter;
  831. StringArray scopes;
  832. StringBuffer rootPath;
  833. Owned<IPropertyTreeIterator> graphIter;
  834. Owned<IPropertyTreeIterator> subgraphIter;
  835. IArrayOf<IStatisticCollection> collections;
  836. IArrayOf<IStatisticCollectionIterator> childIterators;
  837. MemoryBuffer compressed;
  838. MemoryBuffer serialized;
  839. bool valid;
  840. };
  841. int compareStatisticScopes(IConstWUStatistic & left, IConstWUStatistic & right)
  842. {
  843. return compareScopeName(left.queryScope(), right.queryScope());
  844. }
  845. int compareStatisticScopes(IInterface * const * left, IInterface * const * right)
  846. {
  847. return compareStatisticScopes(*static_cast<IConstWUStatistic *>(*left), *static_cast<IConstWUStatistic *>(*right));
  848. }
  849. /*
  850. * An implementation of IConstWUScopeIterator for global workunit statistics.
  851. */
  852. class WorkUnitStatisticsScopeIterator : public CInterfaceOf<IConstWUScopeIterator>
  853. {
  854. public:
  855. WorkUnitStatisticsScopeIterator(const IArrayOf<IConstWUStatistic> & _statistics, const IStatisticsFilter * _filter)
  856. {
  857. ForEachItemIn(i, _statistics)
  858. {
  859. IConstWUStatistic & cur = _statistics.item(i);
  860. if (cur.matches(_filter))
  861. statistics.append(OLINK(cur));
  862. }
  863. statistics.sort(compareStatisticScopes);
  864. }
  865. virtual bool first() override
  866. {
  867. curIndex = 0;
  868. return initScope();
  869. }
  870. virtual bool next() override
  871. {
  872. curIndex += numStatistics;
  873. return initScope();
  874. }
  875. virtual bool isValid() override
  876. {
  877. return statistics.isItem(curIndex);
  878. }
  879. virtual const char * queryScope() const override
  880. {
  881. return statistics.item(curIndex).queryScope();
  882. }
  883. virtual StatisticScopeType getScopeType() const override
  884. {
  885. return statistics.item(curIndex).getScopeType();
  886. }
  887. virtual void playProperties(IWuScopeVisitor & visitor) override
  888. {
  889. for (unsigned i=0; i < numStatistics; i++)
  890. {
  891. IConstWUStatistic & cur = statistics.item(curIndex + i);
  892. visitor.noteStatistic(cur.getKind(), cur.getValue(), cur);
  893. }
  894. }
  895. virtual bool getStat(StatisticKind kind, unsigned __int64 & value) const
  896. {
  897. for (unsigned i=0; i < numStatistics; i++)
  898. {
  899. IConstWUStatistic & cur = statistics.item(curIndex + i);
  900. if (cur.getKind() == kind)
  901. {
  902. value = cur.getValue();
  903. return true;
  904. }
  905. }
  906. return false;
  907. }
  908. virtual const char * queryAttribute(WuAttr attr) const
  909. {
  910. return nullptr;
  911. }
  912. virtual const char * queryHint(const char * kind) const
  913. {
  914. return nullptr;
  915. }
  916. protected:
  917. inline IConstWUStatistic & queryStatistic(unsigned i)
  918. {
  919. return statistics.item(curIndex + i);
  920. }
  921. bool initScope()
  922. {
  923. unsigned next = curIndex+1;
  924. while (next < statistics.ordinality())
  925. {
  926. if (compareStatisticScopes(statistics.item(curIndex), statistics.item(next)) != 0)
  927. break;
  928. next++;
  929. }
  930. numStatistics = (next - curIndex);
  931. return statistics.isItem(curIndex);
  932. }
  933. protected:
  934. IArrayOf<IConstWUStatistic> statistics;
  935. unsigned curIndex = 0;
  936. unsigned numStatistics = 1;
  937. };
  938. /*
  939. * An implementation of IConstWUScopeIterator for the query graphs.
  940. */
  941. class GraphScopeIterator : public CInterfaceOf<IConstWUScopeIterator>
  942. {
  943. private:
  944. //This uses a state machine - this enumeration contains the different states.
  945. enum State
  946. {
  947. SGraphBegin,
  948. SGraphFirstEdge,
  949. SGraphFirstSubGraph,
  950. SGraphEnd,
  951. SGraphNext,
  952. SSubGraphBegin,
  953. SSubGraphFirstEdge,
  954. SSubGraphFirstActivity,
  955. SSubGraphFirstSubGraph,
  956. SSubGraphEnd,
  957. SSubGraphNext,
  958. SEdgeBegin,
  959. SEdgeNext,
  960. SActivityBegin,
  961. SActivityFirstSubGraph,
  962. SActivityNext,
  963. SDone
  964. } state = SDone;
  965. public:
  966. GraphScopeIterator(const IConstWorkUnit * wu, const IStatisticsFilter * _filter) : graphIter(&wu->getGraphs(GraphTypeAny))
  967. {
  968. }
  969. virtual bool first() override
  970. {
  971. if (!graphIter->first())
  972. return false;
  973. state = SGraphBegin;
  974. return nextScope();
  975. }
  976. virtual bool next() override
  977. {
  978. return nextScope();
  979. }
  980. virtual bool isValid() override
  981. {
  982. return graphIter->isValid();
  983. }
  984. virtual const char * queryScope() const override
  985. {
  986. return curScopeName.str();
  987. }
  988. virtual StatisticScopeType getScopeType() const override
  989. {
  990. return scopeType;
  991. }
  992. virtual void playProperties(IWuScopeVisitor & visitor) override
  993. {
  994. switch (scopeType)
  995. {
  996. case SSTgraph:
  997. return;
  998. }
  999. IPropertyTree & cur = treeIters.tos().query();
  1000. switch (scopeType)
  1001. {
  1002. case SSTgraph:
  1003. break;
  1004. case SSTsubgraph:
  1005. break;
  1006. case SSTactivity:
  1007. {
  1008. playAttribute(visitor, WALabel);
  1009. Owned<IPropertyTreeIterator> attrs = cur.getElements("att");
  1010. ForEach(*attrs)
  1011. {
  1012. IPropertyTree & cur = attrs->query();
  1013. WuAttr attr = queryGraphChildAttToWuAttr(cur.queryProp("@name"));
  1014. if (attr != WANone)
  1015. visitor.noteAttribute(attr, cur.queryProp("@value"));
  1016. }
  1017. Owned<IPropertyTreeIterator> hints = cur.getElements("hint");
  1018. ForEach(*hints)
  1019. {
  1020. IPropertyTree & cur = hints->query();
  1021. visitor.noteHint(cur.queryProp("@name"), cur.queryProp("@value"));
  1022. }
  1023. break;
  1024. }
  1025. case SSTedge:
  1026. //MORE This will eventually need to walk the attributes and map the names.
  1027. //Need to be careful if they need to be mapped differently depending on the context.
  1028. playAttribute(visitor, WALabel);
  1029. playAttribute(visitor, WASource);
  1030. playAttribute(visitor, WATarget);
  1031. playAttribute(visitor, WASourceIndex);
  1032. playAttribute(visitor, WATargetIndex);
  1033. playAttribute(visitor, WAIsDependency);
  1034. break;
  1035. }
  1036. }
  1037. virtual bool getStat(StatisticKind kind, unsigned __int64 & value) const
  1038. {
  1039. return false;
  1040. }
  1041. virtual const char * queryAttribute(WuAttr attr) const
  1042. {
  1043. if (!treeIters.ordinality())
  1044. return nullptr;
  1045. //MORE - check that the attribute is value for the current scope type (to prevent defaults being returned)
  1046. return queryAttributeValue(treeIters.tos().query(), attr);
  1047. }
  1048. virtual const char * queryHint(const char * kind) const
  1049. {
  1050. //MORE: Needs to be implemented!
  1051. return nullptr;
  1052. }
  1053. private:
  1054. void playAttribute(IWuScopeVisitor & visitor, WuAttr kind)
  1055. {
  1056. const char * value = queryAttributeValue(treeIters.tos().query(), kind);
  1057. if (value)
  1058. visitor.noteAttribute(kind, value);
  1059. }
  1060. void pushIterator(IPropertyTreeIterator * iter, State state)
  1061. {
  1062. treeIters.append(*LINK(iter));
  1063. stateStack.append(state);
  1064. }
  1065. State popIterator()
  1066. {
  1067. treeIters.pop();
  1068. return (State)stateStack.popGet();
  1069. }
  1070. void pushScope(const char * id)
  1071. {
  1072. scopeLengths.append(curScopeName.length());
  1073. curScopeName.append(":").append(id);
  1074. }
  1075. void popScope()
  1076. {
  1077. curScopeName.setLength(scopeLengths.popGet());
  1078. }
  1079. bool nextScope()
  1080. {
  1081. for(;;)
  1082. {
  1083. switch (state)
  1084. {
  1085. case SGraphBegin:
  1086. graphIter->query().getName(StringBufferAdaptor(curScopeName.clear()));
  1087. scopeType = SSTgraph;
  1088. state = SGraphFirstEdge;
  1089. return true;
  1090. case SGraphFirstEdge:
  1091. {
  1092. //Walk dependencies - should possibly have a different SST e.g., SSTdependency since they do not
  1093. //share many characteristics with edges - e.g. no flowing records => few/no stats.
  1094. curGraph.setown(graphIter->query().getXGMMLTree(false));
  1095. Owned<IPropertyTreeIterator> treeIter = curGraph->getElements("edge");
  1096. if (treeIter && treeIter->first())
  1097. {
  1098. treeIter.setown(createSortedIterator(*treeIter, compareEdgeNode));
  1099. treeIter->first();
  1100. pushIterator(treeIter, SGraphFirstSubGraph);
  1101. state = SEdgeBegin;
  1102. }
  1103. else
  1104. state = SGraphFirstSubGraph;
  1105. break;
  1106. }
  1107. case SGraphFirstSubGraph:
  1108. {
  1109. Owned<IPropertyTreeIterator> treeIter = curGraph->getElements("node");
  1110. if (treeIter && treeIter->first())
  1111. {
  1112. treeIter.setown(createSortedIterator(*treeIter, compareSubGraphNode));
  1113. treeIter->first();
  1114. pushIterator(treeIter, SGraphNext);
  1115. state = SSubGraphBegin;
  1116. }
  1117. else
  1118. state = SGraphNext;
  1119. break;
  1120. }
  1121. case SGraphNext:
  1122. if (!graphIter->next())
  1123. return false;
  1124. state = SGraphBegin;
  1125. break;
  1126. case SSubGraphBegin:
  1127. scopeId.set(SubGraphScopePrefix).append(treeIters.tos().query().getPropInt("@id"));
  1128. pushScope(scopeId);
  1129. state = SSubGraphFirstEdge;
  1130. scopeType = SSTsubgraph;
  1131. return true;
  1132. case SSubGraphFirstEdge:
  1133. {
  1134. Owned<IPropertyTreeIterator> treeIter = treeIters.tos().query().getElements("att/graph/edge");
  1135. if (treeIter && treeIter->first())
  1136. {
  1137. treeIter.setown(createSortedIterator(*treeIter, compareEdgeNode));
  1138. pushIterator(treeIter, SSubGraphFirstActivity);
  1139. state = SEdgeBegin;
  1140. }
  1141. else
  1142. state = SSubGraphFirstActivity;
  1143. break;
  1144. }
  1145. case SSubGraphFirstActivity:
  1146. {
  1147. Owned<IPropertyTreeIterator> treeIter = treeIters.tos().query().getElements("att/graph/node");
  1148. if (treeIter && treeIter->first())
  1149. {
  1150. treeIter.setown(createSortedIterator(*treeIter, compareActivityNode));
  1151. pushIterator(treeIter, SSubGraphEnd);
  1152. state = SActivityBegin;
  1153. }
  1154. else
  1155. state = SSubGraphEnd;
  1156. break;
  1157. }
  1158. case SSubGraphEnd:
  1159. popScope();
  1160. state = SSubGraphNext;
  1161. break;
  1162. case SSubGraphNext:
  1163. if (treeIters.tos().next())
  1164. state = SSubGraphBegin;
  1165. else
  1166. state = popIterator();
  1167. break;
  1168. case SEdgeBegin:
  1169. scopeId.set(EdgeScopePrefix).append(treeIters.tos().query().queryProp("@id"));
  1170. pushScope(scopeId);
  1171. state = SEdgeNext;
  1172. scopeType = SSTedge;
  1173. return true;
  1174. case SEdgeNext:
  1175. popScope();
  1176. if (treeIters.tos().next())
  1177. state = SEdgeBegin;
  1178. else
  1179. state = popIterator();
  1180. break;
  1181. case SActivityBegin:
  1182. scopeId.set(ActivityScopePrefix).append(treeIters.tos().query().getPropInt("@id"));
  1183. pushScope(scopeId);
  1184. state = SActivityFirstSubGraph;
  1185. scopeType = SSTactivity;
  1186. return true;
  1187. case SActivityNext:
  1188. popScope();
  1189. if (treeIters.tos().next())
  1190. state = SActivityBegin;
  1191. else
  1192. state = popIterator();
  1193. break;
  1194. case SActivityFirstSubGraph:
  1195. {
  1196. Owned<IPropertyTreeIterator> treeIter = treeIters.tos().query().getElements("att/graph/node");
  1197. if (treeIter && treeIter->first())
  1198. {
  1199. treeIter.setown(createSortedIterator(*treeIter, compareSubGraphNode));
  1200. pushIterator(treeIter, SActivityNext);
  1201. state = SSubGraphBegin;
  1202. }
  1203. else
  1204. state = SActivityNext;
  1205. break;
  1206. }
  1207. }
  1208. }
  1209. //edge - next sibling
  1210. //activity - child subgraph; next sibling
  1211. //subgraph - child edges; child activities; other children? next sibling
  1212. //Check for a) edge b) activity c
  1213. //Either next edge
  1214. }
  1215. protected:
  1216. Owned<IConstWUGraphIterator> graphIter;
  1217. Owned<IPropertyTree> curGraph;
  1218. IArrayOf<IPropertyTreeIterator> treeIters;
  1219. UnsignedArray scopeLengths;
  1220. UnsignedArray stateStack;
  1221. StringBuffer curScopeName;
  1222. StringBuffer scopeId;
  1223. StatisticScopeType scopeType = SSTnone;
  1224. };
  1225. /*
  1226. * An implementation of IConstWUScopeIterator that combines results from multiple sources.
  1227. */
  1228. class CompoundStatisticsScopeIterator : public CInterfaceOf<IConstWUScopeIterator>
  1229. {
  1230. public:
  1231. CompoundStatisticsScopeIterator()
  1232. {
  1233. }
  1234. void addIter(IConstWUScopeIterator * iter)
  1235. {
  1236. if (iter)
  1237. {
  1238. iters.append(OLINK(*iter));
  1239. assertex(iters.ordinality() <= sizeof(activeIterMask)*8);
  1240. }
  1241. }
  1242. virtual bool first() override
  1243. {
  1244. activeIterMask = 0;
  1245. ForEachItemIn(i, iters)
  1246. {
  1247. if (iters.item(i).first())
  1248. activeIterMask |= (1U << i);
  1249. }
  1250. return findNextScope();
  1251. }
  1252. virtual bool next() override
  1253. {
  1254. ForEachItemIn(i, iters)
  1255. {
  1256. if (iterMatchesCurrentScope(i))
  1257. {
  1258. #ifdef _DEBUG
  1259. StringBuffer prevScope;
  1260. prevScope.append(iters.item(i).queryScope());
  1261. #endif
  1262. if (!iters.item(i).next())
  1263. activeIterMask &= ~(1U << i);
  1264. #ifdef _DEBUG
  1265. if (activeIterMask & (1U << i))
  1266. {
  1267. const char * curScope = iters.item(i).queryScope();
  1268. int compare = compareScopeName(prevScope, curScope);
  1269. if (compare >= 0)
  1270. throw MakeStringException(0, "Out of order scopes %s,%s = %d", prevScope.str(), curScope, compare);
  1271. }
  1272. #endif
  1273. }
  1274. }
  1275. return findNextScope();
  1276. }
  1277. virtual bool isValid() override
  1278. {
  1279. return (activeIterMask != 0);
  1280. }
  1281. virtual const char * queryScope() const override
  1282. {
  1283. return iters.item(firstMatchIter).queryScope();
  1284. }
  1285. virtual StatisticScopeType getScopeType() const override
  1286. {
  1287. return iters.item(firstMatchIter).getScopeType();
  1288. }
  1289. virtual void playProperties(IWuScopeVisitor & visitor) override
  1290. {
  1291. ForEachItemIn(i, iters)
  1292. {
  1293. if (iterMatchesCurrentScope(i))
  1294. iters.item(i).playProperties(visitor);
  1295. }
  1296. }
  1297. virtual bool getStat(StatisticKind kind, unsigned __int64 & value) const
  1298. {
  1299. ForEachItemIn(i, iters)
  1300. {
  1301. if (iterMatchesCurrentScope(i))
  1302. {
  1303. if (iters.item(i).getStat(kind, value))
  1304. return true;
  1305. }
  1306. }
  1307. return false;
  1308. }
  1309. virtual const char * queryAttribute(WuAttr attr) const
  1310. {
  1311. ForEachItemIn(i, iters)
  1312. {
  1313. if (iterMatchesCurrentScope(i))
  1314. {
  1315. const char * value = iters.item(i).queryAttribute(attr);
  1316. if (value)
  1317. return value;
  1318. }
  1319. }
  1320. return nullptr;
  1321. }
  1322. virtual const char * queryHint(const char * kind) const
  1323. {
  1324. ForEachItemIn(i, iters)
  1325. {
  1326. if (iterMatchesCurrentScope(i))
  1327. {
  1328. const char * value = iters.item(i).queryHint(kind);
  1329. if (value)
  1330. return value;
  1331. }
  1332. }
  1333. return nullptr;
  1334. }
  1335. inline bool iterMatchesCurrentScope(unsigned i) const { return ((1U << i) & matchIterMask) != 0; }
  1336. inline bool isAlive(unsigned i) const { return ((1U << i) & activeIterMask) != 0; }
  1337. protected:
  1338. //Calculate which iterators contain the scope that should come next
  1339. bool findNextScope()
  1340. {
  1341. if (activeIterMask == 0)
  1342. return false;
  1343. unsigned mask = 0;
  1344. const char * scope = nullptr;
  1345. ForEachItemIn(i, iters)
  1346. {
  1347. if (isAlive(i))
  1348. {
  1349. if (mask)
  1350. {
  1351. int compare = compareScopeName(scope, iters.item(i).queryScope());
  1352. if (compare == 0)
  1353. {
  1354. mask |= (1U << i);
  1355. }
  1356. else if (compare > 0)
  1357. {
  1358. scope = iters.item(i).queryScope();
  1359. mask = (1U << i);
  1360. firstMatchIter = i;
  1361. }
  1362. }
  1363. else
  1364. {
  1365. scope = iters.item(i).queryScope();
  1366. mask = (1U << i);
  1367. firstMatchIter = i;
  1368. }
  1369. }
  1370. }
  1371. matchIterMask = mask;
  1372. return true;
  1373. }
  1374. protected:
  1375. IArrayOf<IConstWUScopeIterator> iters;
  1376. unsigned curIter = 0;
  1377. unsigned firstMatchIter = 0;
  1378. unsigned matchIterMask = 0; // bit set of iterators which have a valid entry for the current scope
  1379. unsigned activeIterMask = 0; // bit set of iterators which are still active
  1380. };
  1381. class CConstGraphProgressStatisticsIterator : public CInterfaceOf<IConstWUStatisticIterator>
  1382. {
  1383. public:
  1384. CConstGraphProgressStatisticsIterator(const char * wuid, const IStatisticsFilter * _filter) : filter(_filter)
  1385. {
  1386. if (filter)
  1387. scopes.appendList(filter->queryScope(), ":");
  1388. const char * searchGraph = "*";
  1389. if (scopes.ordinality())
  1390. searchGraph = scopes.item(0);
  1391. rootPath.append("/GraphProgress/").append(wuid).append('/');
  1392. bool singleGraph = false;
  1393. if (!containsWildcard(searchGraph))
  1394. {
  1395. rootPath.append(searchGraph).append("/");
  1396. singleGraph = true;
  1397. }
  1398. //Don't lock the statistics while we iterate - any partial updates must not cause problems
  1399. if (daliClientActive())
  1400. conn.setown(querySDS().connect(rootPath.str(), myProcessSession(), RTM_NONE, SDS_LOCK_TIMEOUT));
  1401. if (conn && !singleGraph)
  1402. graphIter.setown(conn->queryRoot()->getElements("*"));
  1403. curStat.setown(new ExtractedStatistic);
  1404. //These are currently constant for all graph statistics instances
  1405. curStat->count = 1;
  1406. curStat->max = 0;
  1407. valid = false;
  1408. }
  1409. virtual IConstWUStatistic & query()
  1410. {
  1411. return *curStat;
  1412. }
  1413. virtual bool first()
  1414. {
  1415. valid = false;
  1416. if (!conn)
  1417. return false;
  1418. if (graphIter && !graphIter->first())
  1419. return false;
  1420. ensureUniqueStatistic();
  1421. if (!firstSubGraph())
  1422. {
  1423. if (!nextGraph())
  1424. return false;
  1425. }
  1426. valid = true;
  1427. return true;
  1428. }
  1429. virtual bool next()
  1430. {
  1431. ensureUniqueStatistic();
  1432. if (!nextStatistic())
  1433. {
  1434. if (!nextSubGraph())
  1435. {
  1436. if (!nextGraph())
  1437. {
  1438. valid = false;
  1439. return false;
  1440. }
  1441. }
  1442. }
  1443. return true;
  1444. }
  1445. virtual bool isValid()
  1446. {
  1447. return valid;
  1448. }
  1449. protected:
  1450. bool firstSubGraph()
  1451. {
  1452. IPropertyTree & graphNode = graphIter ? graphIter->query() : *conn->queryRoot();
  1453. const char * xpath = "sg*";
  1454. StringBuffer childXpath;
  1455. if (scopes.isItem(1))
  1456. {
  1457. const char * scope1 = scopes.item(1);
  1458. if (strnicmp(scope1, "sg", 2) == 0)
  1459. {
  1460. childXpath.append(scope1);
  1461. xpath = childXpath.str();
  1462. }
  1463. }
  1464. subgraphIter.setown(graphNode.getElements(xpath));
  1465. if (!subgraphIter)
  1466. subgraphIter.setown(graphNode.getElements("sg0"));
  1467. if (!subgraphIter->first())
  1468. return false;
  1469. if (firstStat())
  1470. return true;
  1471. return nextSubGraph();
  1472. }
  1473. bool nextSubGraph()
  1474. {
  1475. for (;;)
  1476. {
  1477. if (!subgraphIter->next())
  1478. return false;
  1479. if (firstStat())
  1480. return true;
  1481. }
  1482. }
  1483. bool nextGraph()
  1484. {
  1485. if (!graphIter)
  1486. return false;
  1487. for (;;)
  1488. {
  1489. if (!graphIter->next())
  1490. return false;
  1491. if (firstSubGraph())
  1492. return true;
  1493. }
  1494. }
  1495. bool firstStat()
  1496. {
  1497. IPropertyTree & curSubGraph = subgraphIter->query();
  1498. if (!checkSubGraph())
  1499. return false;
  1500. curSubGraph.getPropBin("Stats", compressed.clear());
  1501. //Don't crash on old format progress...
  1502. if (compressed.length() == 0)
  1503. return false;
  1504. decompressToBuffer(serialized.clear(), compressed);
  1505. Owned<IStatisticCollection> collection = createStatisticCollection(serialized);
  1506. curStat->timeStamp = collection->queryWhenCreated();
  1507. return beginCollection(*collection);
  1508. }
  1509. bool beginCollection(IStatisticCollection & collection)
  1510. {
  1511. collections.append(OLINK(collection));
  1512. numStats = collection.getNumStatistics();
  1513. curStatIndex = 0;
  1514. if (checkScope())
  1515. {
  1516. if (curStatIndex < numStats)
  1517. {
  1518. if (checkStatistic())
  1519. return true;
  1520. return nextStatistic();
  1521. }
  1522. }
  1523. return nextChildScope();
  1524. }
  1525. bool nextStatistic()
  1526. {
  1527. //Finish iterating the statistics at this level.
  1528. while (++curStatIndex < numStats)
  1529. {
  1530. if (checkStatistic())
  1531. return true;
  1532. }
  1533. return nextChildScope();
  1534. }
  1535. bool nextChildScope()
  1536. {
  1537. for (;;)
  1538. {
  1539. if (collections.ordinality() == 0)
  1540. return false;
  1541. IStatisticCollection * curCollection = &collections.tos();
  1542. if (childIterators.ordinality() < collections.ordinality())
  1543. {
  1544. if (!filter || filter->recurseChildScopes(curStat->scopeType, curStat->scope))
  1545. {
  1546. //Start iterating the children for the current collection
  1547. childIterators.append(curCollection->getScopes(NULL, false));
  1548. if (!childIterators.tos().first())
  1549. {
  1550. finishCollection();
  1551. continue;
  1552. }
  1553. }
  1554. else
  1555. {
  1556. //Don't walk the child scopes
  1557. collections.pop();
  1558. continue;
  1559. }
  1560. }
  1561. else if (!childIterators.tos().next())
  1562. {
  1563. finishCollection();
  1564. continue;
  1565. }
  1566. if (beginCollection(childIterators.tos().query()))
  1567. return true;
  1568. }
  1569. }
  1570. void finishCollection()
  1571. {
  1572. collections.pop();
  1573. childIterators.pop();
  1574. }
  1575. bool checkSubGraph()
  1576. {
  1577. if (!filter)
  1578. return true;
  1579. IPropertyTree & curSubGraph = subgraphIter->query();
  1580. curStat->creatorType = queryCreatorType(curSubGraph.queryProp("@c"));
  1581. curStat->creator.set(curSubGraph.queryProp("@creator"));
  1582. return filter->matches(curStat->creatorType, curStat->creator, SSTall, NULL, SMeasureAll, StKindAll, AnyStatisticValue);
  1583. }
  1584. bool checkScope()
  1585. {
  1586. if (!filter)
  1587. return true;
  1588. IStatisticCollection * collection = &collections.tos();
  1589. curStat->scopeType = collection->queryScopeType();
  1590. collection->getFullScope(curStat->scope.clear());
  1591. return filter->matches(SCTall, NULL, curStat->scopeType, curStat->scope, SMeasureAll, StKindAll, AnyStatisticValue);
  1592. }
  1593. bool checkStatistic()
  1594. {
  1595. IStatisticCollection & collection = collections.tos();
  1596. collection.getStatistic(curStat->kind, curStat->value, curStatIndex);
  1597. curStat->measure = queryMeasure(curStat->kind);
  1598. if (!filter)
  1599. return true;
  1600. if (!filter->matches(SCTall, NULL, SSTall, NULL, curStat->measure, curStat->kind, curStat->value))
  1601. return false;
  1602. return true;
  1603. }
  1604. void ensureUniqueStatistic()
  1605. {
  1606. //If something else has linked this statistic, clone a unique one.
  1607. if (curStat->IsShared())
  1608. curStat.setown(new ExtractedStatistic(*curStat));
  1609. }
  1610. private:
  1611. Owned<IRemoteConnection> conn;
  1612. Owned<ExtractedStatistic> curStat;
  1613. const IStatisticsFilter * filter;
  1614. StringArray scopes;
  1615. StringBuffer rootPath;
  1616. Owned<IPropertyTreeIterator> graphIter;
  1617. Owned<IPropertyTreeIterator> subgraphIter;
  1618. IArrayOf<IStatisticCollection> collections;
  1619. IArrayOf<IStatisticCollectionIterator> childIterators;
  1620. MemoryBuffer compressed;
  1621. MemoryBuffer serialized;
  1622. unsigned numStats;
  1623. unsigned curStatIndex;
  1624. bool valid;
  1625. };
  1626. //--------------------------------------------------------------------------------------------------------------------
  1627. EnumMapping states[] = {
  1628. { WUStateUnknown, "unknown" },
  1629. { WUStateCompiled, "compiled" },
  1630. { WUStateRunning, "running" },
  1631. { WUStateCompleted, "completed" },
  1632. { WUStateFailed, "failed" },
  1633. { WUStateArchived, "archived" },
  1634. { WUStateAborting, "aborting" },
  1635. { WUStateAborted, "aborted" },
  1636. { WUStateBlocked, "blocked" },
  1637. { WUStateSubmitted, "submitted" },
  1638. { WUStateScheduled, "scheduled" },
  1639. { WUStateCompiling, "compiling" },
  1640. { WUStateWait, "wait" },
  1641. { WUStateUploadingFiles, "uploading_files" },
  1642. { WUStateDebugPaused, "debugging" },
  1643. { WUStateDebugRunning, "debug_running" },
  1644. { WUStatePaused, "paused" },
  1645. { WUStateSize, NULL }
  1646. };
  1647. EnumMapping actions[] = {
  1648. { WUActionUnknown, "unknown" },
  1649. { WUActionCompile, "compile" },
  1650. { WUActionCheck, "check" },
  1651. { WUActionRun, "run" },
  1652. { WUActionExecuteExisting, "execute" },
  1653. { WUActionPause, "pause" },
  1654. { WUActionPauseNow, "pausenow" },
  1655. { WUActionResume, "resume" },
  1656. { WUActionSize, NULL },
  1657. };
  1658. EnumMapping priorityClasses[] = {
  1659. { PriorityClassUnknown, "unknown" },
  1660. { PriorityClassLow, "low" },
  1661. { PriorityClassNormal, "normal" },
  1662. { PriorityClassHigh, "high" },
  1663. { PriorityClassSize, NULL },
  1664. };
  1665. const char * getWorkunitStateStr(WUState state)
  1666. {
  1667. dbgassertex(state < WUStateSize);
  1668. return states[state].str; // MORE - should be using getEnumText, or need to take steps to ensure values remain contiguous and in order.
  1669. }
  1670. void setEnum(IPropertyTree *p, const char *propname, int value, const EnumMapping *map)
  1671. {
  1672. const char *defval = map->str;
  1673. while (map->str)
  1674. {
  1675. if (value==map->val)
  1676. {
  1677. p->setProp(propname, map->str);
  1678. return;
  1679. }
  1680. map++;
  1681. }
  1682. assertex(!"Unexpected value in setEnum");
  1683. p->setProp(propname, defval);
  1684. }
  1685. static int getEnum(const IPropertyTree *p, const char *propname, const EnumMapping *map)
  1686. {
  1687. return getEnum(p->queryProp(propname),map);
  1688. }
  1689. const char * getWorkunitActionStr(WUAction action)
  1690. {
  1691. return getEnumText(action, actions);
  1692. }
  1693. WUAction getWorkunitAction(const char *actionStr)
  1694. {
  1695. return (WUAction) getEnum(actionStr, actions);
  1696. }
  1697. //==========================================================================================
  1698. class CLightweightWorkunitInfo : public CInterfaceOf<IConstWorkUnitInfo>
  1699. {
  1700. public:
  1701. CLightweightWorkunitInfo(IPropertyTree &p)
  1702. {
  1703. wuid.set(p.queryName());
  1704. user.set(p.queryProp("@submitID"));
  1705. jobName.set(p.queryProp("@jobName"));
  1706. clusterName.set(p.queryProp("@clusterName"));
  1707. timeScheduled.set(p.queryProp("@timeScheduled"));
  1708. state = (WUState) getEnum(&p, "@state", states);
  1709. action = (WUAction) getEnum(&p, "Action", actions);
  1710. priority = (WUPriorityClass) getEnum(&p, "@priorityClass", priorityClasses);
  1711. priorityLevel = calcPriorityValue(&p);
  1712. wuscope.set(p.queryProp("@scope"));
  1713. appvalues.loadBranch(&p,"Application");
  1714. totalThorTime = (unsigned)nanoToMilli(extractTimeCollatable(p.queryProp("@totalThorTime"), false));
  1715. _isProtected = p.getPropBool("@protected", false);
  1716. }
  1717. virtual const char *queryWuid() const { return wuid.str(); }
  1718. virtual const char *queryUser() const { return user.str(); }
  1719. virtual const char *queryJobName() const { return jobName.str(); }
  1720. virtual const char *queryClusterName() const { return clusterName.str(); }
  1721. virtual const char *queryWuScope() const { return wuscope.str(); }
  1722. virtual WUState getState() const { return state; }
  1723. virtual const char *queryStateDesc() const { return getEnumText(state, states); }
  1724. virtual WUAction getAction() const { return action; }
  1725. virtual const char *queryActionDesc() const { return getEnumText(action, actions); }
  1726. virtual WUPriorityClass getPriority() const { return priority; }
  1727. virtual const char *queryPriorityDesc() const { return getEnumText(priority, priorityClasses); }
  1728. virtual int getPriorityLevel() const { return priorityLevel; }
  1729. virtual bool isProtected() const { return _isProtected; }
  1730. virtual IJlibDateTime & getTimeScheduled(IJlibDateTime & val) const
  1731. {
  1732. if (timeScheduled.length())
  1733. val.setGmtString(timeScheduled.str());
  1734. return val;
  1735. }
  1736. virtual unsigned getTotalThorTime() const { return totalThorTime; };
  1737. virtual IConstWUAppValueIterator & getApplicationValues() const { return *new CArrayIteratorOf<IConstWUAppValue,IConstWUAppValueIterator> (appvalues, 0, (IConstWorkUnitInfo *) this); };
  1738. protected:
  1739. StringAttr wuid, user, jobName, clusterName, timeScheduled, wuscope;
  1740. mutable CachedTags<CLocalWUAppValue,IConstWUAppValue> appvalues;
  1741. unsigned totalThorTime;
  1742. WUState state;
  1743. WUAction action;
  1744. WUPriorityClass priority;
  1745. int priorityLevel;
  1746. bool _isProtected;
  1747. };
  1748. extern IConstWorkUnitInfo *createConstWorkUnitInfo(IPropertyTree &p)
  1749. {
  1750. return new CLightweightWorkunitInfo(p);
  1751. }
  1752. class CDaliWuGraphStats : public CWuGraphStats
  1753. {
  1754. public:
  1755. CDaliWuGraphStats(IRemoteConnection *_conn, StatisticCreatorType _creatorType, const char * _creator, const char * _rootScope, unsigned _id)
  1756. : CWuGraphStats(LINK(_conn->queryRoot()), _creatorType, _creator, _rootScope, _id), conn(_conn)
  1757. {
  1758. }
  1759. protected:
  1760. Owned<IRemoteConnection> conn;
  1761. };
  1762. CWorkUnitWatcher::CWorkUnitWatcher(IWorkUnitSubscriber *_subscriber, WUSubscribeOptions flags, const char *wuid) : subscriber(_subscriber)
  1763. {
  1764. abortId = 0;
  1765. stateId = 0;
  1766. actionId = 0;
  1767. assertex((flags & ~SubscribeOptionAbort) == 0);
  1768. if (flags & SubscribeOptionAbort)
  1769. {
  1770. VStringBuffer xpath("/WorkUnitAborts/%s", wuid);
  1771. abortId = querySDS().subscribe(xpath.str(), *this);
  1772. }
  1773. }
  1774. CWorkUnitWatcher::~CWorkUnitWatcher()
  1775. {
  1776. assertex(abortId==0 && stateId==0 && actionId==0);
  1777. }
  1778. void CWorkUnitWatcher::unsubscribe()
  1779. {
  1780. CriticalBlock b(crit);
  1781. if (abortId)
  1782. querySDS().unsubscribe(abortId);
  1783. if (stateId)
  1784. querySDS().unsubscribe(stateId);
  1785. if (actionId)
  1786. querySDS().unsubscribe(actionId);
  1787. abortId = 0;
  1788. stateId = 0;
  1789. actionId = 0;
  1790. }
  1791. void CWorkUnitWatcher::notify(SubscriptionId id, const char *xpath, SDSNotifyFlags flags, unsigned valueLen, const void *valueData)
  1792. {
  1793. CriticalBlock b(crit);
  1794. if (id==stateId)
  1795. subscriber->notify(SubscribeOptionState);
  1796. else if (id==actionId)
  1797. subscriber->notify(SubscribeOptionAction);
  1798. else if (id==abortId)
  1799. subscriber->notify(SubscribeOptionAbort);
  1800. }
  1801. class CDaliWorkUnitWatcher : public CWorkUnitWatcher
  1802. {
  1803. public:
  1804. CDaliWorkUnitWatcher(IWorkUnitSubscriber *_subscriber, WUSubscribeOptions flags, const char *wuid)
  1805. : CWorkUnitWatcher(_subscriber, (WUSubscribeOptions) (flags & SubscribeOptionAbort), wuid)
  1806. {
  1807. if (flags & SubscribeOptionState)
  1808. {
  1809. VStringBuffer xpath("/WorkUnits/%s/State", wuid);
  1810. stateId = querySDS().subscribe(xpath.str(), *this);
  1811. }
  1812. if (flags & SubscribeOptionAction)
  1813. {
  1814. VStringBuffer xpath("/WorkUnits/%s/Action", wuid);
  1815. actionId = querySDS().subscribe(xpath.str(), *this);
  1816. }
  1817. }
  1818. };
  1819. void CPersistedWorkUnit::subscribe(WUSubscribeOptions options)
  1820. {
  1821. CriticalBlock block(crit);
  1822. assertex(options==SubscribeOptionAbort);
  1823. if (!abortWatcher)
  1824. {
  1825. abortWatcher.setown(new CWorkUnitWatcher(this, SubscribeOptionAbort, p->queryName()));
  1826. abortDirty = true;
  1827. }
  1828. }
  1829. void CPersistedWorkUnit::unsubscribe()
  1830. {
  1831. CriticalBlock block(crit);
  1832. if (abortWatcher)
  1833. {
  1834. abortWatcher->unsubscribe();
  1835. abortWatcher.clear();
  1836. }
  1837. }
  1838. bool CPersistedWorkUnit::aborting() const
  1839. {
  1840. CriticalBlock block(crit);
  1841. if (abortDirty)
  1842. {
  1843. StringBuffer apath;
  1844. apath.append("/WorkUnitAborts/").append(p->queryName());
  1845. Owned<IRemoteConnection> acon = querySDS().connect(apath.str(), myProcessSession(), 0, SDS_LOCK_TIMEOUT);
  1846. if (acon)
  1847. abortState = acon->queryRoot()->getPropInt(NULL) != 0;
  1848. else
  1849. abortState = false;
  1850. abortDirty = false;
  1851. }
  1852. return abortState;
  1853. }
  1854. class CDaliWorkUnit : public CPersistedWorkUnit
  1855. {
  1856. public:
  1857. CDaliWorkUnit(IRemoteConnection *_conn, ISecManager *secmgr, ISecUser *secuser)
  1858. : connection(_conn), CPersistedWorkUnit(secmgr, secuser)
  1859. {
  1860. loadPTree(connection->getRoot());
  1861. }
  1862. ~CDaliWorkUnit()
  1863. {
  1864. // NOTE - order is important - we need to construct connection before p and (especially) destroy after p
  1865. // We use the beforeDispose() in base class to help ensure this
  1866. p.clear();
  1867. }
  1868. IConstWUGraphProgress *getGraphProgress(const char *graphName) const
  1869. {
  1870. Owned<IRemoteConnection> conn = getProgressConnection();
  1871. if (conn)
  1872. {
  1873. IPTree *progress = conn->queryRoot()->queryPropTree(graphName);
  1874. if (progress)
  1875. return new CConstGraphProgress(p->queryName(), graphName, progress);
  1876. }
  1877. return NULL;
  1878. }
  1879. virtual WUGraphState queryGraphState(const char *graphName) const
  1880. {
  1881. Owned<IRemoteConnection> conn = getProgressConnection();
  1882. if (conn)
  1883. {
  1884. IPTree *progress = conn->queryRoot()->queryPropTree(graphName);
  1885. if (progress)
  1886. return (WUGraphState) progress->getPropInt("@_state", (unsigned) WUGraphUnknown);
  1887. }
  1888. return WUGraphUnknown;
  1889. }
  1890. virtual WUGraphState queryNodeState(const char *graphName, WUGraphIDType nodeId) const
  1891. {
  1892. Owned<IRemoteConnection> conn = getProgressConnection();
  1893. if (conn)
  1894. {
  1895. IPTree *progress = conn->queryRoot()->queryPropTree(graphName);
  1896. if (progress)
  1897. {
  1898. StringBuffer path;
  1899. // NOTE - the node state info still uses the old graph layout, even when the stats are using the new...
  1900. path.append("node[@id=\"").append(nodeId).append("\"]/@_state");
  1901. return (WUGraphState) progress->getPropInt(path, (unsigned) WUGraphUnknown);
  1902. }
  1903. }
  1904. return WUGraphUnknown;
  1905. }
  1906. virtual void clearGraphProgress() const
  1907. {
  1908. CriticalBlock block(crit);
  1909. progressConnection.clear(); // Make sure nothing is locking for read or we won't be able to lock for write
  1910. StringBuffer path("/GraphProgress/");
  1911. path.append(p->queryName());
  1912. Owned<IRemoteConnection> delconn = querySDS().connect(path.str(), myProcessSession(), RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT);
  1913. if (delconn)
  1914. delconn->close(true);
  1915. }
  1916. virtual bool getRunningGraph(IStringVal &graphName, WUGraphIDType &subId) const
  1917. {
  1918. Owned<IRemoteConnection> conn = getProgressConnection();
  1919. if (!conn)
  1920. return false;
  1921. const char *name = conn->queryRoot()->queryProp("Running/@graph");
  1922. if (name)
  1923. {
  1924. graphName.set(name);
  1925. subId = conn->queryRoot()->getPropInt64("Running/@subId");
  1926. return true;
  1927. }
  1928. else
  1929. return false;
  1930. }
  1931. virtual void forceReload()
  1932. {
  1933. synchronized sync(locked); // protect locked workunits (uncommitted writes) from reload
  1934. CriticalBlock block(crit);
  1935. clearCached(true);
  1936. connection->reload();
  1937. progressConnection.clear();
  1938. abortDirty = true;
  1939. p.setown(connection->getRoot());
  1940. }
  1941. virtual void cleanupAndDelete(bool deldll, bool deleteOwned, const StringArray *deleteExclusions)
  1942. {
  1943. CPersistedWorkUnit::cleanupAndDelete(deldll, deleteOwned, deleteExclusions);
  1944. clearGraphProgress();
  1945. connection->close(true);
  1946. connection.clear();
  1947. }
  1948. virtual void commit()
  1949. {
  1950. CPersistedWorkUnit::commit();
  1951. if (connection)
  1952. connection->commit();
  1953. }
  1954. virtual void _lockRemote()
  1955. {
  1956. StringBuffer wuRoot;
  1957. getXPath(wuRoot, p->queryName());
  1958. if (connection)
  1959. connection->changeMode(RTM_LOCK_WRITE,SDS_LOCK_TIMEOUT);
  1960. else
  1961. connection.setown(querySDS().connect(wuRoot.str(), myProcessSession(), RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT));
  1962. if (!connection)
  1963. throw MakeStringException(WUERR_LockFailed, "Failed to get connection for xpath %s", wuRoot.str());
  1964. clearCached(true);
  1965. p.setown(connection->getRoot());
  1966. }
  1967. virtual void _unlockRemote()
  1968. {
  1969. if (connection)
  1970. {
  1971. try
  1972. {
  1973. try
  1974. {
  1975. connection->commit();
  1976. }
  1977. catch (IException *e)
  1978. {
  1979. EXCLOG(e, "Error during workunit commit");
  1980. connection->rollback();
  1981. connection->changeMode(0, SDS_LOCK_TIMEOUT);
  1982. throw;
  1983. }
  1984. connection->changeMode(0, SDS_LOCK_TIMEOUT);
  1985. }
  1986. catch (IException *E)
  1987. {
  1988. StringBuffer s;
  1989. PrintLog("Failed to release write lock on workunit: %s", E->errorMessage(s).str());
  1990. throw;
  1991. }
  1992. }
  1993. }
  1994. virtual void setGraphState(const char *graphName, WUGraphState state) const
  1995. {
  1996. Owned<IRemoteConnection> conn = getWritableProgressConnection(graphName);
  1997. conn->queryRoot()->setPropInt("@_state", state);
  1998. }
  1999. virtual void setNodeState(const char *graphName, WUGraphIDType nodeId, WUGraphState state) const
  2000. {
  2001. CriticalBlock block(crit);
  2002. progressConnection.clear(); // Make sure nothing is locking for read or we won't be able to lock for write
  2003. VStringBuffer path("/GraphProgress/%s", queryWuid());
  2004. Owned<IRemoteConnection> conn = querySDS().connect(path, myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT);
  2005. IPTree *progress = ensurePTree(conn->queryRoot(), graphName);
  2006. // NOTE - the node state info still uses the old graph layout, even when the stats are using the new...
  2007. path.clear().append("node[@id=\"").append(nodeId).append("\"]");
  2008. IPropertyTree *node = progress->queryPropTree(path.str());
  2009. if (!node)
  2010. {
  2011. node = progress->addPropTree("node");
  2012. node->setPropInt64("@id", nodeId);
  2013. }
  2014. node->setPropInt("@_state", (unsigned)state);
  2015. switch (state)
  2016. {
  2017. case WUGraphRunning:
  2018. {
  2019. IPropertyTree *running = conn->queryRoot()->setPropTree("Running");
  2020. running->setProp("@graph", graphName);
  2021. running->setPropInt64("@subId", nodeId);
  2022. break;
  2023. }
  2024. case WUGraphComplete:
  2025. {
  2026. conn->queryRoot()->removeProp("Running"); // only one thing running at any given time and one thing with lockWrite access
  2027. break;
  2028. }
  2029. }
  2030. }
  2031. virtual IWUGraphStats *updateStats(const char *graphName, StatisticCreatorType creatorType, const char * creator, unsigned subgraph) const
  2032. {
  2033. return new CDaliWuGraphStats(getWritableProgressConnection(graphName), creatorType, creator, graphName, subgraph);
  2034. }
  2035. protected:
  2036. IRemoteConnection *getProgressConnection() const
  2037. {
  2038. CriticalBlock block(crit);
  2039. if (!progressConnection)
  2040. {
  2041. VStringBuffer path("/GraphProgress/%s", queryWuid());
  2042. progressConnection.setown(querySDS().connect(path, myProcessSession(), 0, SDS_LOCK_TIMEOUT)); // Note - we don't lock. The writes are atomic.
  2043. }
  2044. return progressConnection.getLink();
  2045. }
  2046. IRemoteConnection *getWritableProgressConnection(const char *graphName) const
  2047. {
  2048. CriticalBlock block(crit);
  2049. progressConnection.clear(); // Make sure subsequent reads from this workunit get the changes I am making
  2050. VStringBuffer path("/GraphProgress/%s/%s", queryWuid(), graphName);
  2051. return querySDS().connect(path, myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT);
  2052. }
  2053. IPropertyTree *getGraphProgressTree() const
  2054. {
  2055. Owned<IRemoteConnection> conn = getProgressConnection();
  2056. if (conn)
  2057. {
  2058. Owned<IPropertyTree> tmp = createPTree("GraphProgress");
  2059. mergePTree(tmp,conn->queryRoot());
  2060. return tmp.getClear();
  2061. }
  2062. return NULL;
  2063. }
  2064. Owned<IRemoteConnection> connection;
  2065. mutable Owned<IRemoteConnection> progressConnection;
  2066. };
  2067. class CLockedWorkUnit : implements ILocalWorkUnit, implements IExtendedWUInterface, public CInterface
  2068. {
  2069. public:
  2070. Owned<CLocalWorkUnit> c;
  2071. IMPLEMENT_IINTERFACE;
  2072. CLockedWorkUnit(CLocalWorkUnit *_c) : c(_c) {}
  2073. ~CLockedWorkUnit()
  2074. {
  2075. if (workUnitTraceLevel > 1)
  2076. PrintLog("Releasing locked workunit %s", queryWuid());
  2077. if (c)
  2078. c->unlockRemote();
  2079. }
  2080. virtual IConstWorkUnit * unlock()
  2081. {
  2082. c->unlockRemote();
  2083. return c.getClear();
  2084. }
  2085. virtual bool aborting() const
  2086. { return c->aborting(); }
  2087. virtual void forceReload()
  2088. { UNIMPLEMENTED; }
  2089. virtual WUAction getAction() const
  2090. { return c->getAction(); }
  2091. virtual const char *queryActionDesc() const
  2092. { return c->queryActionDesc(); }
  2093. virtual IStringVal & getApplicationValue(const char * application, const char * propname, IStringVal & str) const
  2094. { return c->getApplicationValue(application, propname, str); }
  2095. virtual int getApplicationValueInt(const char * application, const char * propname, int defVal) const
  2096. { return c->getApplicationValueInt(application, propname, defVal); }
  2097. virtual IConstWUAppValueIterator & getApplicationValues() const
  2098. { return c->getApplicationValues(); }
  2099. virtual bool hasWorkflow() const
  2100. { return c->hasWorkflow(); }
  2101. virtual unsigned queryEventScheduledCount() const
  2102. { return c->queryEventScheduledCount(); }
  2103. virtual IPropertyTree * queryWorkflowTree() const
  2104. { return c->queryWorkflowTree(); }
  2105. virtual IConstWorkflowItemIterator * getWorkflowItems() const
  2106. { return c->getWorkflowItems(); }
  2107. virtual IWorkflowItemArray * getWorkflowClone() const
  2108. { return c->getWorkflowClone(); }
  2109. virtual bool requiresLocalFileUpload() const
  2110. { return c->requiresLocalFileUpload(); }
  2111. virtual IConstLocalFileUploadIterator * getLocalFileUploads() const
  2112. { return c->getLocalFileUploads(); }
  2113. virtual bool getIsQueryService() const
  2114. { return c->getIsQueryService(); }
  2115. virtual bool getCloneable() const
  2116. { return c->getCloneable(); }
  2117. virtual IUserDescriptor * queryUserDescriptor() const
  2118. { return c->queryUserDescriptor(); }
  2119. virtual const char *queryClusterName() const
  2120. { return c->queryClusterName(); }
  2121. virtual unsigned getCodeVersion() const
  2122. { return c->getCodeVersion(); }
  2123. virtual unsigned getWuidVersion() const
  2124. { return c->getWuidVersion(); }
  2125. virtual void getBuildVersion(IStringVal & buildVersion, IStringVal & eclVersion) const
  2126. { c->getBuildVersion(buildVersion, eclVersion); }
  2127. virtual bool hasDebugValue(const char * propname) const
  2128. { return c->hasDebugValue(propname); }
  2129. virtual IStringVal & getDebugValue(const char * propname, IStringVal & str) const
  2130. { return c->getDebugValue(propname, str); }
  2131. virtual int getDebugValueInt(const char * propname, int defVal) const
  2132. { return c->getDebugValueInt(propname, defVal); }
  2133. virtual __int64 getDebugValueInt64(const char * propname, __int64 defVal) const
  2134. { return c->getDebugValueInt64(propname, defVal); }
  2135. virtual bool getDebugValueBool(const char * propname, bool defVal) const
  2136. { return c->getDebugValueBool(propname, defVal); }
  2137. virtual IStringIterator & getDebugValues() const
  2138. { return c->getDebugValues(NULL); }
  2139. virtual IStringIterator & getDebugValues(const char *prop) const
  2140. { return c->getDebugValues(prop); }
  2141. virtual unsigned getExceptionCount() const
  2142. { return c->getExceptionCount(); }
  2143. virtual IConstWUExceptionIterator & getExceptions() const
  2144. { return c->getExceptions(); }
  2145. virtual unsigned getGraphCount() const
  2146. { return c->getGraphCount(); }
  2147. virtual unsigned getSourceFileCount() const
  2148. { return c->getSourceFileCount(); }
  2149. virtual unsigned getResultCount() const
  2150. { return c->getResultCount(); }
  2151. virtual unsigned getVariableCount() const
  2152. { return c->getVariableCount(); }
  2153. virtual unsigned getApplicationValueCount() const
  2154. { return c->getApplicationValueCount(); }
  2155. virtual IConstWUGraphIterator & getGraphs(WUGraphType type) const
  2156. { return c->getGraphs(type); }
  2157. virtual IConstWUGraphMetaIterator & getGraphsMeta(WUGraphType type) const
  2158. { return c->getGraphsMeta(type); }
  2159. virtual IConstWUGraph * getGraph(const char *name) const
  2160. { return c->getGraph(name); }
  2161. virtual IConstWUGraphProgress * getGraphProgress(const char * name) const
  2162. { return c->getGraphProgress(name); }
  2163. virtual const char *queryJobName() const
  2164. { return c->queryJobName(); }
  2165. virtual IConstWUPlugin * getPluginByName(const char * name) const
  2166. { return c->getPluginByName(name); }
  2167. virtual IConstWUPluginIterator & getPlugins() const
  2168. { return c->getPlugins(); }
  2169. virtual IConstWULibrary* getLibraryByName(const char *name) const
  2170. { return c->getLibraryByName(name); }
  2171. virtual IConstWULibraryIterator & getLibraries() const
  2172. { return c->getLibraries(); }
  2173. virtual WUPriorityClass getPriority() const
  2174. { return c->getPriority(); }
  2175. virtual const char *queryPriorityDesc() const
  2176. { return c->queryPriorityDesc(); }
  2177. virtual int getPriorityLevel() const
  2178. { return c->getPriorityLevel(); }
  2179. virtual int getPriorityValue() const
  2180. { return c->getPriorityValue(); }
  2181. virtual IConstWUQuery * getQuery() const
  2182. { return c->getQuery(); }
  2183. virtual IConstWUWebServicesInfo * getWebServicesInfo() const
  2184. { return c->getWebServicesInfo(); }
  2185. virtual bool getRescheduleFlag() const
  2186. { return c->getRescheduleFlag(); }
  2187. virtual IConstWUResult * getResultByName(const char * name) const
  2188. { return c->getResultByName(name); }
  2189. virtual IConstWUResult * getResultBySequence(unsigned seq) const
  2190. { return c->getResultBySequence(seq); }
  2191. virtual unsigned getResultLimit() const
  2192. { return c->getResultLimit(); }
  2193. virtual IConstWUResultIterator & getResults() const
  2194. { return c->getResults(); }
  2195. virtual IStringVal & getScope(IStringVal & str) const
  2196. { return c->getScope(str); }
  2197. virtual IStringVal & getSecurityToken(IStringVal & str) const
  2198. { return c->getSecurityToken(str); }
  2199. virtual WUState getState() const
  2200. { return c->getState(); }
  2201. virtual IStringVal & getStateEx(IStringVal & str) const
  2202. { return c->getStateEx(str); }
  2203. virtual __int64 getAgentSession() const
  2204. { return c->getAgentSession(); }
  2205. virtual unsigned getAgentPID() const
  2206. { return c->getAgentPID(); }
  2207. virtual const char *queryStateDesc() const
  2208. { return c->queryStateDesc(); }
  2209. virtual bool getRunningGraph(IStringVal & graphName, WUGraphIDType & subId) const
  2210. { return c->getRunningGraph(graphName, subId); }
  2211. virtual IConstWUStatisticIterator & getStatistics(const IStatisticsFilter * filter) const
  2212. { return c->getStatistics(filter); }
  2213. virtual IConstWUStatistic * getStatistic(const char * creator, const char * scope, StatisticKind kind) const
  2214. { return c->getStatistic(creator, scope, kind); }
  2215. virtual IConstWUScopeIterator & getScopeIterator(const IStatisticsFilter * filter) const override
  2216. { return c->getScopeIterator(filter); }
  2217. virtual IStringVal & getSnapshot(IStringVal & str) const
  2218. { return c->getSnapshot(str); }
  2219. virtual const char *queryUser() const
  2220. { return c->queryUser(); }
  2221. virtual ErrorSeverity getWarningSeverity(unsigned code, ErrorSeverity defaultSeverity) const
  2222. { return c->getWarningSeverity(code, defaultSeverity); }
  2223. virtual const char *queryWuScope() const
  2224. { return c->queryWuScope(); }
  2225. virtual const char *queryWuid() const
  2226. { return c->queryWuid(); }
  2227. virtual IConstWUResult * getGlobalByName(const char * name) const
  2228. { return c->getGlobalByName(name); }
  2229. virtual IConstWUResult * getTemporaryByName(const char * name) const
  2230. { return c->getTemporaryByName(name); }
  2231. virtual IConstWUResultIterator & getTemporaries() const
  2232. { return c->getTemporaries(); }
  2233. virtual IConstWUResult * getVariableByName(const char * name) const
  2234. { return c->getVariableByName(name); }
  2235. virtual IConstWUResultIterator & getVariables() const
  2236. { return c->getVariables(); }
  2237. virtual bool isProtected() const
  2238. { return c->isProtected(); }
  2239. virtual bool isPausing() const
  2240. { return c->isPausing(); }
  2241. virtual IWorkUnit & lock()
  2242. { ((CInterface *)this)->Link(); return (IWorkUnit &) *this; }
  2243. virtual bool reload()
  2244. { UNIMPLEMENTED; }
  2245. virtual void subscribe(WUSubscribeOptions options)
  2246. { c->subscribe(options); }
  2247. virtual void requestAbort()
  2248. { c->requestAbort(); }
  2249. virtual unsigned calculateHash(unsigned prevHash)
  2250. { return queryExtendedWU(c)->calculateHash(prevHash); }
  2251. virtual void copyWorkUnit(IConstWorkUnit *cached, bool copyStats, bool all)
  2252. { queryExtendedWU(c)->copyWorkUnit(cached, copyStats, all); }
  2253. virtual IPropertyTree *queryPTree() const
  2254. { return queryExtendedWU(c)->queryPTree(); }
  2255. virtual IPropertyTree *getUnpackedTree(bool includeProgress) const
  2256. { return queryExtendedWU(c)->getUnpackedTree(includeProgress); }
  2257. virtual bool archiveWorkUnit(const char *base,bool del,bool deldll,bool deleteOwned,bool exportAssociatedFiles)
  2258. { return queryExtendedWU(c)->archiveWorkUnit(base,del,deldll,deleteOwned,exportAssociatedFiles); }
  2259. virtual unsigned queryFileUsage(const char *filename) const
  2260. { return c->queryFileUsage(filename); }
  2261. virtual IConstWUFileUsageIterator * getFieldUsage() const
  2262. { return c->getFieldUsage(); }
  2263. virtual bool getFieldUsageArray(StringArray & filenames, StringArray & columnnames, const char * clusterName) const
  2264. { return c->getFieldUsageArray(filenames, columnnames, clusterName); }
  2265. virtual IJlibDateTime & getTimeScheduled(IJlibDateTime &val) const
  2266. { return c->getTimeScheduled(val); }
  2267. virtual unsigned getDebugAgentListenerPort() const
  2268. { return c->getDebugAgentListenerPort(); }
  2269. virtual IStringVal & getDebugAgentListenerIP(IStringVal &ip) const
  2270. { return c->getDebugAgentListenerIP(ip); }
  2271. virtual IStringVal & getXmlParams(IStringVal & params, bool hidePasswords) const
  2272. { return c->getXmlParams(params, hidePasswords); }
  2273. virtual const IPropertyTree *getXmlParams() const
  2274. { return c->getXmlParams(); }
  2275. virtual unsigned __int64 getHash() const
  2276. { return c->getHash(); }
  2277. virtual IStringIterator *getLogs(const char *type, const char *instance) const
  2278. { return c->getLogs(type, instance); }
  2279. virtual IStringIterator *getProcesses(const char *type) const
  2280. { return c->getProcesses(type); }
  2281. virtual IPropertyTreeIterator* getProcesses(const char *type, const char *instance) const
  2282. { return c->getProcesses(type, instance); }
  2283. virtual unsigned getTotalThorTime() const
  2284. { return c->getTotalThorTime(); }
  2285. virtual WUGraphState queryGraphState(const char *graphName) const
  2286. { return c->queryGraphState(graphName); }
  2287. virtual WUGraphState queryNodeState(const char *graphName, WUGraphIDType nodeId) const
  2288. { return c->queryNodeState(graphName, nodeId); }
  2289. virtual void setGraphState(const char *graphName, WUGraphState state) const
  2290. { c->setGraphState(graphName, state); }
  2291. virtual void setNodeState(const char *graphName, WUGraphIDType nodeId, WUGraphState state) const
  2292. { c->setNodeState(graphName, nodeId, state); }
  2293. virtual IWUGraphStats *updateStats(const char *graphName, StatisticCreatorType creatorType, const char * creator, unsigned subgraph) const
  2294. { return c->updateStats(graphName, creatorType, creator, subgraph); }
  2295. virtual void clearGraphProgress() const
  2296. { c->clearGraphProgress(); }
  2297. virtual IStringVal & getAbortBy(IStringVal & str) const
  2298. { return c->getAbortBy(str); }
  2299. virtual unsigned __int64 getAbortTimeStamp() const
  2300. { return c->getAbortTimeStamp(); }
  2301. virtual void clearExceptions()
  2302. { c->clearExceptions(); }
  2303. virtual void commit()
  2304. { c->commit(); }
  2305. virtual IWUException * createException()
  2306. { return c->createException(); }
  2307. virtual void addProcess(const char *type, const char *instance, unsigned pid, const char *log)
  2308. { c->addProcess(type, instance, pid, log); }
  2309. virtual void protect(bool protectMode)
  2310. { c->protect(protectMode); }
  2311. virtual void setAction(WUAction action)
  2312. { c->setAction(action); }
  2313. virtual void setApplicationValue(const char * application, const char * propname, const char * value, bool overwrite)
  2314. { c->setApplicationValue(application, propname, value, overwrite); }
  2315. virtual void setApplicationValueInt(const char * application, const char * propname, int value, bool overwrite)
  2316. { c->setApplicationValueInt(application, propname, value, overwrite); }
  2317. virtual void incEventScheduledCount()
  2318. { c->incEventScheduledCount(); }
  2319. virtual void setIsQueryService(bool value)
  2320. { c->setIsQueryService(value); }
  2321. virtual void setCloneable(bool value)
  2322. { c->setCloneable(value); }
  2323. virtual void setIsClone(bool value)
  2324. { c->setIsClone(value); }
  2325. virtual void setClusterName(const char * value)
  2326. { c->setClusterName(value); }
  2327. virtual void setCodeVersion(unsigned version, const char * buildVersion, const char * eclVersion)
  2328. { c->setCodeVersion(version, buildVersion, eclVersion); }
  2329. virtual void setDebugValue(const char * propname, const char * value, bool overwrite)
  2330. { c->setDebugValue(propname, value, overwrite); }
  2331. virtual void setDebugValueInt(const char * propname, int value, bool overwrite)
  2332. { c->setDebugValueInt(propname, value, overwrite); }
  2333. virtual void setJobName(const char * value)
  2334. { c->setJobName(value); }
  2335. virtual void setPriority(WUPriorityClass cls)
  2336. { c->setPriority(cls); }
  2337. virtual void setPriorityLevel(int level)
  2338. { c->setPriorityLevel(level); }
  2339. virtual void setRescheduleFlag(bool value)
  2340. { c->setRescheduleFlag(value); }
  2341. virtual void setResultLimit(unsigned value)
  2342. { c->setResultLimit(value); }
  2343. virtual void setSecurityToken(const char *value)
  2344. { c->setSecurityToken(value); }
  2345. virtual void setState(WUState state)
  2346. { c->setState(state); }
  2347. virtual void setStateEx(const char * text)
  2348. { c->setStateEx(text); }
  2349. virtual void setAgentSession(__int64 sessionId)
  2350. { c->setAgentSession(sessionId); }
  2351. virtual void setStatistic(StatisticCreatorType creatorType, const char * creator, StatisticScopeType scopeType, const char * scope, StatisticKind kind, const char * optDescription, unsigned __int64 value, unsigned __int64 count, unsigned __int64 maxValue, StatsMergeAction mergeAction)
  2352. { c->setStatistic(creatorType, creator, scopeType, scope, kind, optDescription, value, count, maxValue, mergeAction); }
  2353. virtual void setTracingValue(const char * propname, const char * value)
  2354. { c->setTracingValue(propname, value); }
  2355. virtual void setTracingValueInt(const char * propname, int value)
  2356. { c->setTracingValueInt(propname, value); }
  2357. virtual void setTracingValueInt64(const char * propname, __int64 value)
  2358. { c->setTracingValueInt64(propname, value); }
  2359. virtual void setUser(const char * value)
  2360. { c->setUser(value); }
  2361. virtual void setWuScope(const char * value)
  2362. { c->setWuScope(value); }
  2363. virtual IWorkflowItem* addWorkflowItem(unsigned wfid, WFType type, WFMode mode, unsigned success, unsigned failure, unsigned recovery, unsigned retriesAllowed, unsigned contingencyFor)
  2364. { return c->addWorkflowItem(wfid, type, mode, success, failure, recovery, retriesAllowed, contingencyFor); }
  2365. virtual void syncRuntimeWorkflow(IWorkflowItemArray * array)
  2366. { c->syncRuntimeWorkflow(array); }
  2367. virtual IWorkflowItemIterator * updateWorkflowItems()
  2368. { return c->updateWorkflowItems(); }
  2369. virtual void resetWorkflow()
  2370. { c->resetWorkflow(); }
  2371. virtual void schedule()
  2372. { c->schedule(); }
  2373. virtual void deschedule()
  2374. { c->deschedule(); }
  2375. virtual unsigned addLocalFileUpload(LocalFileUploadType type, char const * source, char const * destination, char const * eventTag)
  2376. { return c->addLocalFileUpload(type, source, destination, eventTag); }
  2377. virtual IWUResult * updateGlobalByName(const char * name)
  2378. { return c->updateGlobalByName(name); }
  2379. virtual void createGraph(const char * name, const char *label, WUGraphType type, IPropertyTree *xgmml)
  2380. { c->createGraph(name, label, type, xgmml); }
  2381. virtual IWUQuery * updateQuery()
  2382. { return c->updateQuery(); }
  2383. virtual IWUWebServicesInfo * updateWebServicesInfo(bool create)
  2384. { return c->updateWebServicesInfo(create); }
  2385. virtual IWUPlugin * updatePluginByName(const char * name)
  2386. { return c->updatePluginByName(name); }
  2387. virtual IWULibrary * updateLibraryByName(const char * name)
  2388. { return c->updateLibraryByName(name); }
  2389. virtual IWUResult * updateResultByName(const char * name)
  2390. { return c->updateResultByName(name); }
  2391. virtual IWUResult * updateResultBySequence(unsigned seq)
  2392. { return c->updateResultBySequence(seq); }
  2393. virtual IWUResult * updateTemporaryByName(const char * name)
  2394. { return c->updateTemporaryByName(name); }
  2395. virtual IWUResult * updateVariableByName(const char * name)
  2396. { return c->updateVariableByName(name); }
  2397. virtual void addFile(const char *fileName, StringArray *clusters, unsigned usageCount, WUFileKind fileKind, const char *graphOwner)
  2398. { c->addFile(fileName, clusters, usageCount, fileKind, graphOwner); }
  2399. virtual void noteFileRead(IDistributedFile *file)
  2400. { c->noteFileRead(file); }
  2401. virtual void noteFieldUsage(IPropertyTree * usage)
  2402. { c->noteFieldUsage(usage); }
  2403. virtual void releaseFile(const char *fileName)
  2404. { c->releaseFile(fileName); }
  2405. virtual void resetBeforeGeneration()
  2406. { c->resetBeforeGeneration(); }
  2407. virtual void deleteTempFiles(const char *graph, bool deleteOwned, bool deleteJobOwned)
  2408. { c->deleteTempFiles(graph, deleteOwned, deleteJobOwned); }
  2409. virtual void deleteTemporaries()
  2410. { c->deleteTemporaries(); }
  2411. virtual void addDiskUsageStats(__int64 avgNodeUsage, unsigned minNode, __int64 minNodeUsage, unsigned maxNode, __int64 maxNodeUsage, __int64 graphId)
  2412. { c->addDiskUsageStats(avgNodeUsage, minNode, minNodeUsage, maxNode, maxNodeUsage, graphId); }
  2413. virtual IPropertyTree * getDiskUsageStats()
  2414. { return c->getDiskUsageStats(); }
  2415. virtual IPropertyTreeIterator & getFileIterator() const
  2416. { return c->getFileIterator(); }
  2417. virtual IPropertyTreeIterator & getFilesReadIterator() const
  2418. { return c->getFilesReadIterator(); }
  2419. virtual void setSnapshot(const char * value)
  2420. { c->setSnapshot(value); }
  2421. virtual void setWarningSeverity(unsigned code, ErrorSeverity severity)
  2422. { c->setWarningSeverity(code, severity); }
  2423. virtual void setTimeScheduled(const IJlibDateTime &val)
  2424. { c->setTimeScheduled(val); }
  2425. virtual void setDebugAgentListenerPort(unsigned port)
  2426. { c->setDebugAgentListenerPort(port); }
  2427. virtual void setDebugAgentListenerIP(const char * ip)
  2428. { c->setDebugAgentListenerIP(ip); }
  2429. virtual void setXmlParams(const char *params)
  2430. { c->setXmlParams(params); }
  2431. virtual void setXmlParams(IPropertyTree *tree)
  2432. { c->setXmlParams(tree); }
  2433. virtual void setHash(unsigned __int64 hash)
  2434. { c->setHash(hash); }
  2435. // ILocalWorkUnit - used for debugging etc
  2436. virtual void serialize(MemoryBuffer &tgt)
  2437. { c->serialize(tgt); }
  2438. virtual void deserialize(MemoryBuffer &src)
  2439. { c->deserialize(src); }
  2440. virtual bool switchThorQueue(const char *cluster, IQueueSwitcher *qs)
  2441. { return c->switchThorQueue(cluster,qs); }
  2442. virtual void setAllowedClusters(const char *value)
  2443. { c->setAllowedClusters(value); }
  2444. virtual IStringVal& getAllowedClusters(IStringVal &str) const
  2445. { return c->getAllowedClusters(str); }
  2446. virtual void remoteCheckAccess(IUserDescriptor *user, bool writeaccess) const
  2447. { c->remoteCheckAccess(user,writeaccess); }
  2448. virtual void setAllowAutoQueueSwitch(bool val)
  2449. { c->setAllowAutoQueueSwitch(val); }
  2450. virtual bool getAllowAutoQueueSwitch() const
  2451. { return c->getAllowAutoQueueSwitch(); }
  2452. virtual void setLibraryInformation(const char * name, unsigned interfaceHash, unsigned definitionHash)
  2453. { c->setLibraryInformation(name, interfaceHash, definitionHash); }
  2454. virtual void setResultInt(const char * name, unsigned sequence, __int64 val)
  2455. { c->setResultInt(name, sequence, val); }
  2456. virtual void setResultUInt(const char * name, unsigned sequence, unsigned __int64 val)
  2457. { c->setResultUInt(name, sequence, val); }
  2458. virtual void setResultReal(const char *name, unsigned sequence, double val)
  2459. { c->setResultReal(name, sequence, val); }
  2460. virtual void setResultVarString(const char * stepname, unsigned sequence, const char *val)
  2461. { c->setResultVarString(stepname, sequence, val); }
  2462. virtual void setResultVarUnicode(const char * stepname, unsigned sequence, UChar const *val)
  2463. { c->setResultVarUnicode(stepname, sequence, val); }
  2464. virtual void setResultString(const char * stepname, unsigned sequence, int len, const char *val)
  2465. { c->setResultString(stepname, sequence, len, val); }
  2466. virtual void setResultData(const char * stepname, unsigned sequence, int len, const void *val)
  2467. { c->setResultData(stepname, sequence, len, val); }
  2468. virtual void setResultRaw(const char * name, unsigned sequence, int len, const void *val)
  2469. { c->setResultRaw(name, sequence, len, val); }
  2470. virtual void setResultSet(const char * name, unsigned sequence, bool isAll, size32_t len, const void *val, ISetToXmlTransformer *xform)
  2471. { c->setResultSet(name, sequence, isAll, len, val, xform); }
  2472. virtual void setResultUnicode(const char * name, unsigned sequence, int len, UChar const * val)
  2473. { c->setResultUnicode(name, sequence, len, val); }
  2474. virtual void setResultBool(const char *name, unsigned sequence, bool val)
  2475. { c->setResultBool(name, sequence, val); }
  2476. virtual void setResultDecimal(const char *name, unsigned sequence, int len, int precision, bool isSigned, const void *val)
  2477. { c->setResultDecimal(name, sequence, len, precision, isSigned, val); }
  2478. virtual void setResultDataset(const char * name, unsigned sequence, size32_t len, const void *val, unsigned numRows, bool extend)
  2479. { c->setResultDataset(name, sequence, len, val, numRows, extend); }
  2480. };
  2481. class CLocalWUAssociated : implements IConstWUAssociatedFile, public CInterface
  2482. {
  2483. Owned<IPropertyTree> p;
  2484. public:
  2485. IMPLEMENT_IINTERFACE;
  2486. CLocalWUAssociated(IPropertyTree *p);
  2487. virtual WUFileType getType() const;
  2488. virtual IStringVal & getDescription(IStringVal & ret) const;
  2489. virtual IStringVal & getIp(IStringVal & ret) const;
  2490. virtual IStringVal & getName(IStringVal & ret) const;
  2491. virtual IStringVal & getNameTail(IStringVal & ret) const;
  2492. virtual unsigned getCrc() const;
  2493. virtual unsigned getMinActivityId() const;
  2494. virtual unsigned getMaxActivityId() const;
  2495. };
  2496. class CLocalWUQuery : implements IWUQuery, public CInterface
  2497. {
  2498. Owned<IPropertyTree> p;
  2499. mutable IArrayOf<IConstWUAssociatedFile> associated;
  2500. mutable CriticalSection crit;
  2501. mutable bool associatedCached;
  2502. private:
  2503. void addSpecialCaseAssociated(WUFileType type, const char * propname, unsigned crc) const;
  2504. void loadAssociated() const;
  2505. public:
  2506. IMPLEMENT_IINTERFACE;
  2507. CLocalWUQuery(IPropertyTree *p);
  2508. virtual WUQueryType getQueryType() const;
  2509. virtual IStringVal& getQueryText(IStringVal &str) const;
  2510. virtual IStringVal& getQueryShortText(IStringVal &str) const;
  2511. virtual IStringVal& getQueryName(IStringVal &str) const;
  2512. virtual IStringVal & getQueryMainDefinition(IStringVal & str) const;
  2513. virtual IStringVal& getQueryDllName(IStringVal &str) const;
  2514. virtual unsigned getQueryDllCrc() const;
  2515. virtual IStringVal& getQueryCppName(IStringVal &str) const;
  2516. virtual IStringVal& getQueryResTxtName(IStringVal &str) const;
  2517. virtual IConstWUAssociatedFile * getAssociatedFile(WUFileType type, unsigned index) const;
  2518. virtual IConstWUAssociatedFileIterator& getAssociatedFiles() const;
  2519. virtual bool isArchive() const;
  2520. virtual bool hasArchive() const
  2521. {
  2522. return p->getPropBool("@hasArchive");
  2523. }
  2524. virtual void setQueryType(WUQueryType qt);
  2525. virtual void setQueryText(const char *pstr);
  2526. virtual void setQueryName(const char *);
  2527. virtual void setQueryMainDefinition(const char * str);
  2528. virtual void addAssociatedFile(WUFileType type, const char * name, const char * ip, const char * desc, unsigned crc, unsigned minActivity, unsigned maxActivity);
  2529. virtual void removeAssociatedFiles();
  2530. virtual void removeAssociatedFile(WUFileType type, const char * name, const char * desc);
  2531. };
  2532. class CLocalWUWebServicesInfo : implements IWUWebServicesInfo, public CInterface
  2533. {
  2534. Owned<IPropertyTree> p;
  2535. mutable CriticalSection crit;
  2536. private:
  2537. public:
  2538. IMPLEMENT_IINTERFACE;
  2539. CLocalWUWebServicesInfo(IPropertyTree *p);
  2540. virtual IStringVal& getModuleName(IStringVal &str) const;
  2541. virtual IStringVal& getAttributeName(IStringVal &str) const;
  2542. virtual IStringVal& getDefaultName(IStringVal &str) const;
  2543. virtual IStringVal& getInfo(const char *name, IStringVal &str) const;
  2544. virtual IStringVal& getText(const char *name, IStringVal &str) const;
  2545. virtual unsigned getWebServicesCRC() const;
  2546. virtual void setModuleName(const char *);
  2547. virtual void setAttributeName(const char *);
  2548. virtual void setDefaultName(const char *);
  2549. virtual void setInfo(const char *name, const char *info);
  2550. virtual void setText(const char *name, const char *info);
  2551. virtual void setWebServicesCRC(unsigned);
  2552. };
  2553. class CLocalWUResult : implements IWUResult, public CInterface
  2554. {
  2555. friend class CLocalWorkUnit;
  2556. mutable CriticalSection crit;
  2557. Owned<IPropertyTree> p;
  2558. Owned<IProperties> xmlns;
  2559. public:
  2560. IMPLEMENT_IINTERFACE;
  2561. CLocalWUResult(IPropertyTree *props);
  2562. ~CLocalWUResult() { try { p.clear(); } catch (IException *E) {E->Release();}}
  2563. virtual WUResultStatus getResultStatus() const;
  2564. virtual IStringVal& getResultName(IStringVal &str) const;
  2565. virtual int getResultSequence() const;
  2566. virtual bool isResultScalar() const;
  2567. virtual IStringVal& getResultXml(IStringVal &str, bool hidePasswords) const;
  2568. virtual unsigned getResultFetchSize() const;
  2569. virtual __int64 getResultTotalRowCount() const;
  2570. virtual __int64 getResultRowCount() const;
  2571. virtual void getResultDataset(IStringVal & ecl, IStringVal & defs) const;
  2572. virtual IStringVal& getResultLogicalName(IStringVal &ecl) const;
  2573. virtual IStringVal& getResultKeyField(IStringVal& ecl) const;
  2574. virtual unsigned getResultRequestedRows() const;
  2575. virtual __int64 getResultInt() const;
  2576. virtual bool getResultBool() const;
  2577. virtual double getResultReal() const;
  2578. virtual IStringVal& getResultString(IStringVal & str, bool hidePassword) const;
  2579. virtual IDataVal& getResultRaw(IDataVal & data, IXmlToRawTransformer * xmlTransformer, ICsvToRawTransformer * csvTransformer) const;
  2580. virtual IDataVal& getResultUnicode(IDataVal & data) const;
  2581. virtual void getResultDecimal(void * val, unsigned length, unsigned precision, bool isSigned) const;
  2582. virtual IStringVal& getResultEclSchema(IStringVal & str) const;
  2583. virtual __int64 getResultRawSize(IXmlToRawTransformer * xmlTransformer, ICsvToRawTransformer * csvTransformer) const;
  2584. virtual IDataVal& getResultRaw(IDataVal & data, __int64 from, __int64 length, IXmlToRawTransformer * xmlTransformer, ICsvToRawTransformer * csvTransformer) const;
  2585. virtual IStringVal& getResultRecordSizeEntry(IStringVal & str) const;
  2586. virtual IStringVal& getResultTransformerEntry(IStringVal & str) const;
  2587. virtual __int64 getResultRowLimit() const;
  2588. virtual IStringVal& getResultFilename(IStringVal & str) const;
  2589. virtual WUResultFormat getResultFormat() const;
  2590. virtual unsigned getResultHash() const;
  2591. virtual bool getResultIsAll() const;
  2592. virtual IProperties *queryResultXmlns();
  2593. virtual IStringVal& getResultFieldOpt(const char *name, IStringVal &str) const;
  2594. virtual void getSchema(IArrayOf<ITypeInfo> &types, StringAttrArray &names, IStringVal * ecl=NULL) const;
  2595. virtual void getResultWriteLocation(IStringVal & _graph, unsigned & _activityId) const;
  2596. // interface IWUResult
  2597. virtual void setResultStatus(WUResultStatus status);
  2598. virtual void setResultName(const char *name);
  2599. virtual void setResultSequence(unsigned seq);
  2600. virtual void setResultSchemaRaw(unsigned len, const void *schema);
  2601. virtual void setResultScalar(bool isScalar);
  2602. virtual void setResultRaw(unsigned len, const void *xml, WUResultFormat format);
  2603. virtual void setResultFetchSize(unsigned rows); // 0 means file-loaded
  2604. virtual void setResultTotalRowCount(__int64 rows); // -1 means unknown
  2605. virtual void setResultRowCount(__int64 rows);
  2606. virtual void setResultDataset(const char *ecl, const char *defs);
  2607. virtual void setResultLogicalName(const char *logicalName);
  2608. virtual void setResultKeyField(const char * name);
  2609. virtual void setResultRequestedRows(unsigned req);
  2610. virtual void setResultRecordSizeEntry(const char * val);
  2611. virtual void setResultTransformerEntry(const char * val);
  2612. virtual void setResultInt(__int64 val);
  2613. virtual void setResultReal(double val);
  2614. virtual void setResultBool(bool val);
  2615. virtual void setResultString(const char * val, unsigned length);
  2616. virtual void setResultUnicode(const void * val, unsigned length);
  2617. virtual void setResultData(const void * val, unsigned length);
  2618. virtual void setResultDecimal(const void * val, unsigned length);
  2619. virtual void addResultRaw(unsigned len, const void * data, WUResultFormat format);
  2620. virtual void setResultRowLimit(__int64 value);
  2621. virtual void setResultFilename(const char * name);
  2622. virtual void setResultUInt(unsigned __int64 val);
  2623. virtual void setResultIsAll(bool value);
  2624. virtual void setResultFormat(WUResultFormat format);
  2625. virtual void setResultXML(const char *val);
  2626. virtual void setResultRow(unsigned len, const void * data);
  2627. virtual void setResultXmlns(const char *prefix, const char *uri);
  2628. virtual void setResultFieldOpt(const char *name, const char *value);
  2629. virtual void setResultWriteLocation(const char * _graph, unsigned _activityId);
  2630. virtual IPropertyTree *queryPTree() { return p; }
  2631. };
  2632. class CLocalWUPlugin : implements IWUPlugin, public CInterface
  2633. {
  2634. Owned<IPropertyTree> p;
  2635. public:
  2636. IMPLEMENT_IINTERFACE;
  2637. CLocalWUPlugin(IPropertyTree *p);
  2638. virtual IStringVal& getPluginName(IStringVal &str) const;
  2639. virtual IStringVal& getPluginVersion(IStringVal &str) const;
  2640. virtual void setPluginName(const char *str);
  2641. virtual void setPluginVersion(const char *str);
  2642. };
  2643. class CLocalWULibrary : implements IWULibrary, public CInterface
  2644. {
  2645. Owned<IPropertyTree> p;
  2646. public:
  2647. IMPLEMENT_IINTERFACE;
  2648. CLocalWULibrary(IPropertyTree *p);
  2649. virtual IStringVal & getName(IStringVal & str) const;
  2650. virtual void setName(const char * str);
  2651. };
  2652. class CLocalWUException : implements IWUException, public CInterface
  2653. {
  2654. Owned<IPropertyTree> p;
  2655. public:
  2656. IMPLEMENT_IINTERFACE;
  2657. CLocalWUException(IPropertyTree *p);
  2658. virtual IStringVal& getExceptionSource(IStringVal &str) const override;
  2659. virtual IStringVal& getExceptionMessage(IStringVal &str) const override;
  2660. virtual unsigned getExceptionCode() const override;
  2661. virtual ErrorSeverity getSeverity() const override;
  2662. virtual IStringVal & getTimeStamp(IStringVal & dt) const override;
  2663. virtual IStringVal & getExceptionFileName(IStringVal & str) const override;
  2664. virtual unsigned getExceptionLineNo() const override;
  2665. virtual unsigned getExceptionColumn() const override;
  2666. virtual unsigned getActivityId() const override;
  2667. virtual unsigned getSequence() const override;
  2668. virtual const char * queryScope() const override;
  2669. virtual unsigned getPriority() const override;
  2670. virtual void setExceptionSource(const char *str) override;
  2671. virtual void setExceptionMessage(const char *str) override;
  2672. virtual void setExceptionCode(unsigned code) override;
  2673. virtual void setSeverity(ErrorSeverity level) override;
  2674. virtual void setTimeStamp(const char * dt) override;
  2675. virtual void setExceptionFileName(const char *str) override;
  2676. virtual void setExceptionLineNo(unsigned r) override;
  2677. virtual void setExceptionColumn(unsigned c) override;
  2678. virtual void setActivityId(unsigned _id) override;
  2679. virtual void setScope(const char * _scope) override;
  2680. virtual void setPriority(unsigned _priority) override;
  2681. };
  2682. //==========================================================================================
  2683. extern WORKUNIT_API bool isSpecialResultSequence(unsigned sequence)
  2684. {
  2685. switch ((int) sequence)
  2686. {
  2687. case ResultSequenceInternal:
  2688. case ResultSequenceOnce:
  2689. case ResultSequencePersist:
  2690. case ResultSequenceStored:
  2691. return true;
  2692. default:
  2693. assertex(sequence <= INT_MAX);
  2694. return false;
  2695. }
  2696. }
  2697. class CConstWUArrayIterator : implements IConstWorkUnitIterator, public CInterface
  2698. {
  2699. unsigned curTreeNum;
  2700. IArrayOf<IPropertyTree> trees;
  2701. Owned<IConstWorkUnitInfo> cur;
  2702. void setCurrent()
  2703. {
  2704. cur.setown(new CLightweightWorkunitInfo(trees.item(curTreeNum)));
  2705. }
  2706. public:
  2707. IMPLEMENT_IINTERFACE;
  2708. CConstWUArrayIterator(IArrayOf<IPropertyTree> &_trees)
  2709. {
  2710. ForEachItemIn(t, _trees)
  2711. trees.append(*LINK(&_trees.item(t)));
  2712. curTreeNum = 0;
  2713. }
  2714. bool first()
  2715. {
  2716. curTreeNum = 0;
  2717. return next();
  2718. }
  2719. bool isValid()
  2720. {
  2721. return (NULL != cur.get());
  2722. }
  2723. bool next()
  2724. {
  2725. if (curTreeNum >= trees.ordinality())
  2726. {
  2727. cur.clear();
  2728. return false;
  2729. }
  2730. setCurrent();
  2731. ++curTreeNum;
  2732. return true;
  2733. }
  2734. IConstWorkUnitInfo & query() { return *cur; }
  2735. };
  2736. class CLocalWUFieldUsage : public CInterface, implements IConstWUFieldUsage
  2737. {
  2738. Owned<IPropertyTree> p;
  2739. public:
  2740. IMPLEMENT_IINTERFACE;
  2741. CLocalWUFieldUsage(IPropertyTree& _p) { p.setown(&_p); }
  2742. virtual const char * queryName() const { return p->queryProp("@name"); }
  2743. };
  2744. class CConstWUFieldUsageIterator : public CInterface, implements IConstWUFieldUsageIterator
  2745. {
  2746. public:
  2747. IMPLEMENT_IINTERFACE;
  2748. CConstWUFieldUsageIterator(IPropertyTreeIterator * tree) { iter.setown(tree); }
  2749. bool first() override { return iter->first(); }
  2750. bool isValid() override { return iter->isValid(); }
  2751. bool next() override { return iter->next(); }
  2752. IConstWUFieldUsage * get() const override { return new CLocalWUFieldUsage(iter->get()); }
  2753. private:
  2754. Owned<IPropertyTreeIterator> iter;
  2755. };
  2756. class CLocalWUFileUsage : public CInterface, implements IConstWUFileUsage
  2757. {
  2758. Owned<IPropertyTree> p;
  2759. public:
  2760. IMPLEMENT_IINTERFACE;
  2761. CLocalWUFileUsage(IPropertyTree& _p) { p.setown(&_p); }
  2762. virtual const char * queryName() const { return p->queryProp("@name"); }
  2763. virtual const char * queryType() const { return p->queryProp("@type"); }
  2764. virtual unsigned getNumFields() const { return p->getPropInt("@numFields"); }
  2765. virtual unsigned getNumFieldsUsed() const { return p->getPropInt("@numFieldsUsed"); }
  2766. virtual IConstWUFieldUsageIterator * getFields() const { return new CConstWUFieldUsageIterator(p->getElements("fields/field")); }
  2767. };
  2768. class CConstWUFileUsageIterator : public CInterface, implements IConstWUFileUsageIterator
  2769. {
  2770. public:
  2771. IMPLEMENT_IINTERFACE;
  2772. CConstWUFileUsageIterator(IPropertyTreeIterator * tree) { iter.setown(tree); }
  2773. bool first() override { return iter->first(); }
  2774. bool isValid() override { return iter->isValid(); }
  2775. bool next() override { return iter->next(); }
  2776. IConstWUFileUsage * get() const override { return new CLocalWUFileUsage(iter->get()); }
  2777. private:
  2778. Owned<IPropertyTreeIterator> iter;
  2779. };
  2780. //==========================================================================================
  2781. class CStringArrayIterator : implements IStringIterator, public CInterface
  2782. {
  2783. unsigned idx;
  2784. StringArray strings;
  2785. public:
  2786. IMPLEMENT_IINTERFACE;
  2787. CStringArrayIterator() { idx = 0; };
  2788. void append(const char *str) { strings.append(str); }
  2789. virtual bool first() { idx = 0; return strings.isItem(idx); }
  2790. virtual bool next() { idx ++; return strings.isItem(idx); }
  2791. virtual bool isValid() { return strings.isItem(idx); }
  2792. virtual IStringVal & str(IStringVal &s) { s.set(strings.item(idx)); return s; }
  2793. };
  2794. class CCachedJobNameIterator : implements IStringIterator, public CInterface
  2795. {
  2796. Owned<IPropertyTreeIterator> it;
  2797. public:
  2798. IMPLEMENT_IINTERFACE;
  2799. CCachedJobNameIterator(IPropertyTreeIterator *p) : it(p) {};
  2800. virtual bool first() { return it->first(); }
  2801. virtual bool next() { return it->next(); }
  2802. virtual bool isValid() { return it->isValid(); }
  2803. virtual IStringVal & str(IStringVal &s) { s.set(it->query().queryName()+1); return s; }
  2804. };
  2805. class CEmptyStringIterator : implements IStringIterator, public CInterface
  2806. {
  2807. public:
  2808. IMPLEMENT_IINTERFACE;
  2809. virtual bool first() { return false; }
  2810. virtual bool next() { return false; }
  2811. virtual bool isValid() { return false; }
  2812. virtual IStringVal & str(IStringVal &s) { s.clear(); return s; }
  2813. };
  2814. EnumMapping workunitSortFields[] =
  2815. {
  2816. { WUSFuser, "@submitID" },
  2817. { WUSFcluster, "@clusterName" },
  2818. { WUSFjob, "@jobName" },
  2819. { WUSFstate, "@state" },
  2820. { WUSFpriority, "@priorityClass" },
  2821. { WUSFprotected, "@protected" },
  2822. { WUSFwuid, "@" },
  2823. { WUSFecl, "Query/ShortText" },
  2824. { WUSFfileread, "FilesRead/File/@name" },
  2825. { WUSFtotalthortime, "@totalThorTime|"
  2826. "Statistics/Statistic[@c='summary'][@creator='thor'][@kind='TimeElapsed']/@value|"
  2827. "Statistics/Statistic[@c='summary'][@creator='hthor'][@kind='TimeElapsed']/@value|"
  2828. "Statistics/Statistic[@c='summary'][@creator='roxie'][@kind='TimeElapsed']/@value|"
  2829. "Statistics/Statistic[@desc='Total thor time']/@value|"
  2830. "Timings/Timing[@name='Total thor time']/@duration" //Use Statistics first. If not found, use Timings
  2831. },
  2832. { WUSFwuidhigh, "@" },
  2833. { WUSFwildwuid, "@" },
  2834. { WUSFappvalue, "Application" },
  2835. { WUSFfilewritten, "Files/File/@name" },
  2836. { WUSFterm, NULL }
  2837. };
  2838. extern const char *queryFilterXPath(WUSortField field)
  2839. {
  2840. return getEnumText(field, workunitSortFields);
  2841. }
  2842. EnumMapping querySortFields[] =
  2843. {
  2844. { WUQSFId, "@id" },
  2845. { WUQSFwuid, "@wuid" },
  2846. { WUQSFname, "@name" },
  2847. { WUQSFdll, "@dll" },
  2848. { WUQSFmemoryLimit, "@memoryLimit" },
  2849. { WUQSFmemoryLimitHi, "@memoryLimit" },
  2850. { WUQSFtimeLimit, "@timeLimit" },
  2851. { WUQSFtimeLimitHi, "@timeLimit" },
  2852. { WUQSFwarnTimeLimit, "@warnTimeLimit" },
  2853. { WUQSFwarnTimeLimitHi, "@warnTimeLimit" },
  2854. { WUQSFpriority, "@priority" },
  2855. { WUQSFpriorityHi, "@priority" },
  2856. { WUQSFQuerySet, "@querySetId" },
  2857. { WUQSFActivited, "@activated" },
  2858. { WUQSFSuspendedByUser, "@suspended" },
  2859. { WUQSFLibrary, "Library"},
  2860. { WUQSFPublishedBy, "@publishedBy" },
  2861. { WUQSFterm, NULL }
  2862. };
  2863. class asyncRemoveDllWorkItem: public CInterface, implements IWorkQueueItem // class only used in asyncRemoveDll
  2864. {
  2865. StringAttr name;
  2866. public:
  2867. IMPLEMENT_IINTERFACE;
  2868. asyncRemoveDllWorkItem(const char * _name) : name(_name)
  2869. {
  2870. }
  2871. void execute()
  2872. {
  2873. PROGLOG("WU removeDll %s", name.get());
  2874. queryDllServer().removeDll(name, true, true); // <name>, removeDlls=true, removeDirectory=true
  2875. }
  2876. };
  2877. class asyncRemoveRemoteFileWorkItem: public CInterface, implements IWorkQueueItem // class only used in asyncRemoveFile
  2878. {
  2879. RemoteFilename name;
  2880. public:
  2881. IMPLEMENT_IINTERFACE;
  2882. asyncRemoveRemoteFileWorkItem(const char * _ip, const char * _name)
  2883. {
  2884. SocketEndpoint ep(_ip);
  2885. name.setPath(ep, _name);
  2886. }
  2887. void execute()
  2888. {
  2889. Owned<IFile> file = createIFile(name);
  2890. PROGLOG("WU removeDll %s",file->queryFilename());
  2891. file->remove();
  2892. }
  2893. };
  2894. //==========================================================================================
  2895. class CConstQuerySetQueryIterator : implements IConstQuerySetQueryIterator, public CInterface
  2896. {
  2897. unsigned index;
  2898. IArrayOf<IPropertyTree> trees;
  2899. public:
  2900. IMPLEMENT_IINTERFACE;
  2901. CConstQuerySetQueryIterator(IArrayOf<IPropertyTree> &_trees)
  2902. {
  2903. ForEachItemIn(t, _trees)
  2904. trees.append(*LINK(&_trees.item(t)));
  2905. index = 0;
  2906. }
  2907. ~CConstQuerySetQueryIterator()
  2908. {
  2909. trees.kill();
  2910. }
  2911. bool first()
  2912. {
  2913. index = 0;
  2914. return (trees.ordinality()!=0);
  2915. }
  2916. bool next()
  2917. {
  2918. index++;
  2919. return (index<trees.ordinality());
  2920. }
  2921. bool isValid()
  2922. {
  2923. return (index<trees.ordinality());
  2924. }
  2925. IPropertyTree &query()
  2926. {
  2927. return trees.item(index);
  2928. }
  2929. };
  2930. class CSecurityCache
  2931. {
  2932. };
  2933. class CConstWUIterator : implements IConstWorkUnitIterator, public CInterface
  2934. {
  2935. public:
  2936. IMPLEMENT_IINTERFACE;
  2937. CConstWUIterator(IPropertyTreeIterator *_ptreeIter)
  2938. : ptreeIter(_ptreeIter)
  2939. {
  2940. }
  2941. bool first()
  2942. {
  2943. if (!ptreeIter->first())
  2944. {
  2945. cur.clear();
  2946. return false;
  2947. }
  2948. cur.setown(new CLightweightWorkunitInfo(ptreeIter->query()));
  2949. return true;
  2950. }
  2951. bool isValid()
  2952. {
  2953. return (NULL != cur.get());
  2954. }
  2955. bool next()
  2956. {
  2957. if (!ptreeIter->next())
  2958. {
  2959. cur.clear();
  2960. return false;
  2961. }
  2962. cur.setown(new CLightweightWorkunitInfo(ptreeIter->query()));
  2963. return true;
  2964. }
  2965. IConstWorkUnitInfo & query() { return *cur; }
  2966. private:
  2967. Owned<IConstWorkUnitInfo> cur;
  2968. Owned<IPropertyTreeIterator> ptreeIter;
  2969. };
  2970. class CSecureConstWUIterator : public CInterfaceOf<IConstWorkUnitIterator>
  2971. {
  2972. public:
  2973. CSecureConstWUIterator(IConstWorkUnitIterator *_parent, ISecManager *_secmgr=NULL, ISecUser *_secuser=NULL)
  2974. : parent(_parent), secmgr(_secmgr), secuser(_secuser)
  2975. {
  2976. assertex(_secuser && _secmgr);
  2977. }
  2978. bool first()
  2979. {
  2980. if (!parent->first())
  2981. return false;
  2982. return getNext();
  2983. }
  2984. bool next()
  2985. {
  2986. if (!parent->next())
  2987. return false;
  2988. return getNext();
  2989. }
  2990. virtual bool isValid()
  2991. {
  2992. return parent->isValid();
  2993. }
  2994. virtual IConstWorkUnitInfo &query()
  2995. {
  2996. return parent->query();
  2997. }
  2998. private:
  2999. Owned<IConstWorkUnitIterator> parent;
  3000. MapStringTo<int> scopePermissions;
  3001. Linked<ISecManager> secmgr;
  3002. Linked<ISecUser> secuser;
  3003. bool getNext() // scan for a workunit with permissions
  3004. {
  3005. do
  3006. {
  3007. const char *scopeName = parent->query().queryWuScope();
  3008. if (!scopeName || !*scopeName || checkScope(scopeName))
  3009. return true;
  3010. } while (parent->next());
  3011. return false;
  3012. }
  3013. bool checkScope(const char *scopeName)
  3014. {
  3015. int *perms = scopePermissions.getValue(scopeName);
  3016. SecAccessFlags perm;
  3017. if (!perms)
  3018. {
  3019. perm = secuser.get() ? secmgr->authorizeWorkunitScope(*secuser, scopeName) : SecAccess_Unavailable;
  3020. scopePermissions.setValue(scopeName, perm);
  3021. }
  3022. else
  3023. perm = (SecAccessFlags)*perms;
  3024. return perm >= SecAccess_Read;
  3025. }
  3026. };
  3027. CWorkUnitFactory::CWorkUnitFactory()
  3028. {
  3029. }
  3030. CWorkUnitFactory::~CWorkUnitFactory()
  3031. {
  3032. }
  3033. IWorkUnit* CWorkUnitFactory::createNamedWorkUnit(const char *wuid, const char *app, const char *scope, ISecManager *secmgr, ISecUser *secuser)
  3034. {
  3035. checkWuScopeSecAccess(scope, secmgr, secuser, SecAccess_Write, "Create", true, true);
  3036. Owned<CLocalWorkUnit> cw = _createWorkUnit(wuid, secmgr, secuser);
  3037. if (scope)
  3038. cw->setWuScope(scope); // Note - this may check access rights and throw exception. Is that correct? We might prefer to only check access once, and this will check on the lock too...
  3039. IWorkUnit* ret = &cw->lockRemote(false); // Note - this may throw exception if user does not have rights.
  3040. ret->setDebugValue("CREATED_BY", app, true);
  3041. ret->setDebugValue("CREATED_FOR", scope, true);
  3042. return ret;
  3043. }
  3044. IWorkUnit* CWorkUnitFactory::createWorkUnit(const char *app, const char *scope, ISecManager *secmgr, ISecUser *secuser)
  3045. {
  3046. StringBuffer wuid("W");
  3047. char result[32];
  3048. time_t ltime;
  3049. time( &ltime );
  3050. tm *today = localtime( &ltime ); // MORE - this is not threadsafe. But I probably don't care that much!
  3051. strftime(result, sizeof(result), "%Y%m%d-%H%M%S", today);
  3052. wuid.append(result);
  3053. if (workUnitTraceLevel > 1)
  3054. PrintLog("createWorkUnit created %s", wuid.str());
  3055. IWorkUnit* ret = createNamedWorkUnit(wuid.str(), app, scope, secmgr, secuser);
  3056. if (workUnitTraceLevel > 1)
  3057. PrintLog("createWorkUnit created %s", ret->queryWuid());
  3058. addTimeStamp(ret, SSTglobal, NULL, StWhenCreated);
  3059. return ret;
  3060. }
  3061. bool CWorkUnitFactory::deleteWorkUnit(const char * wuid, ISecManager *secmgr, ISecUser *secuser)
  3062. {
  3063. if (workUnitTraceLevel > 1)
  3064. PrintLog("deleteWorkUnit %s", wuid);
  3065. StringBuffer wuRoot;
  3066. getXPath(wuRoot, wuid);
  3067. Owned<CLocalWorkUnit> cw = _updateWorkUnit(wuid, secmgr, secuser);
  3068. if (!checkWuSecAccess(*cw.get(), secmgr, secuser, SecAccess_Full, "delete", true, true))
  3069. return false;
  3070. try
  3071. {
  3072. cw->cleanupAndDelete(true, true);
  3073. }
  3074. catch (IException *E)
  3075. {
  3076. StringBuffer s;
  3077. LOG(MCexception(E, MSGCLS_warning), E, s.append("Exception during deleteWorkUnit: ").append(wuid).str());
  3078. E->Release();
  3079. return false;
  3080. }
  3081. removeWorkUnitFromAllQueues(wuid); //known active workunits wouldn't make it this far
  3082. return true;
  3083. }
  3084. IConstWorkUnit* CWorkUnitFactory::openWorkUnit(const char *wuid, ISecManager *secmgr, ISecUser *secuser)
  3085. {
  3086. StringBuffer wuidStr(wuid);
  3087. wuidStr.trim();
  3088. if (wuidStr.length() && ('w' == wuidStr.charAt(0)))
  3089. wuidStr.setCharAt(0, 'W');
  3090. if (!wuidStr.length() || ('W' != wuidStr.charAt(0)))
  3091. {
  3092. if (workUnitTraceLevel > 1)
  3093. PrintLog("openWorkUnit %s invalid WUID", nullText(wuidStr.str()));
  3094. return NULL;
  3095. }
  3096. if (workUnitTraceLevel > 1)
  3097. PrintLog("openWorkUnit %s", wuidStr.str());
  3098. Owned<IConstWorkUnit> wu = _openWorkUnit(wuid, secmgr, secuser);
  3099. if (wu)
  3100. {
  3101. if (!checkWuSecAccess(*wu, secmgr, secuser, SecAccess_Read, "opening", true, true))
  3102. return NULL; // Actually throws exception on failure, so won't reach here
  3103. return wu.getClear();
  3104. }
  3105. else
  3106. {
  3107. if (workUnitTraceLevel > 0)
  3108. PrintLog("openWorkUnit %s not found", wuidStr.str());
  3109. return NULL;
  3110. }
  3111. }
  3112. IWorkUnit* CWorkUnitFactory::updateWorkUnit(const char *wuid, ISecManager *secmgr, ISecUser *secuser)
  3113. {
  3114. if (workUnitTraceLevel > 1)
  3115. PrintLog("updateWorkUnit %s", wuid);
  3116. Owned<CLocalWorkUnit> wu = _updateWorkUnit(wuid, secmgr, secuser);
  3117. if (wu)
  3118. {
  3119. if (!checkWuSecAccess(*wu.get(), secmgr, secuser, SecAccess_Write, "updating", true, true))
  3120. return NULL;
  3121. return &wu->lockRemote(false);
  3122. }
  3123. else
  3124. {
  3125. if (workUnitTraceLevel > 0)
  3126. PrintLog("updateWorkUnit %s not found", wuid);
  3127. return NULL;
  3128. }
  3129. }
  3130. IPropertyTree * pruneBranch(IPropertyTree * from, char const * xpath)
  3131. {
  3132. Owned<IPropertyTree> ret;
  3133. IPropertyTree * branch = from->queryPropTree(xpath);
  3134. if(branch)
  3135. {
  3136. ret.setown(createPTreeFromIPT(branch));
  3137. from->removeTree(branch);
  3138. }
  3139. return ret.getClear();
  3140. }
  3141. bool CWorkUnitFactory::restoreWorkUnit(const char *base, const char *wuid, bool restoreAssociated)
  3142. {
  3143. StringBuffer path(base);
  3144. addPathSepChar(path).append(wuid).append(".xml");
  3145. Owned<IPTree> pt = createPTreeFromXMLFile(path);
  3146. if (!pt)
  3147. return false;
  3148. CDateTime dt;
  3149. dt.setNow();
  3150. StringBuffer dts;
  3151. dt.getString(dts);
  3152. pt->setProp("@restoredDate", dts.str());
  3153. Owned<IPropertyTree> generatedDlls = pruneBranch(pt, "GeneratedDlls[1]");
  3154. Owned<IPropertyTree> associatedFiles;
  3155. IPropertyTree *srcAssociated = pt->queryPropTree("Query/Associated");
  3156. if (srcAssociated)
  3157. associatedFiles.setown(createPTreeFromIPT(srcAssociated));
  3158. // The updating of the repo is implementation specific...
  3159. if (!_restoreWorkUnit(pt.getClear(), wuid))
  3160. return false;
  3161. // now kludge back GeneratedDlls
  3162. if (generatedDlls)
  3163. {
  3164. Owned<IPropertyTreeIterator> dlls = generatedDlls->getElements("GeneratedDll");
  3165. for(dlls->first(); dlls->isValid(); dlls->next())
  3166. {
  3167. IPropertyTree & dll = dlls->query();
  3168. char const * name = dll.queryProp("@name");
  3169. char const * kind = dll.queryProp("@kind");
  3170. char const * location = dll.queryProp("@location");
  3171. Owned<IDllEntry> got = queryDllServer().getEntry(name);
  3172. if (!got)
  3173. {
  3174. RemoteFilename dstRfn;
  3175. dstRfn.setRemotePath(location);
  3176. StringBuffer srcPath(base);
  3177. addPathSepChar(srcPath);
  3178. dstRfn.getTail(srcPath);
  3179. OwnedIFile srcFile = createIFile(srcPath);
  3180. OwnedIFile dstFile = createIFile(dstRfn);
  3181. copyFile(dstFile, srcFile);
  3182. queryDllServer().registerDll(name, kind, location);
  3183. }
  3184. }
  3185. }
  3186. if (associatedFiles)
  3187. {
  3188. Owned<IPropertyTreeIterator> associated = associatedFiles->getElements("*");
  3189. ForEach(*associated)
  3190. {
  3191. IPropertyTree &file = associated->query();
  3192. const char *filename = file.queryProp("@filename");
  3193. SocketEndpoint ep(file.queryProp("@ip"));
  3194. RemoteFilename rfn;
  3195. rfn.setPath(ep, filename);
  3196. OwnedIFile dstFile = createIFile(rfn);
  3197. StringBuffer srcPath(base), name;
  3198. addPathSepChar(srcPath);
  3199. rfn.getTail(name);
  3200. srcPath.append(name);
  3201. if (generatedDlls)
  3202. {
  3203. VStringBuffer gDllPath("GeneratedDll[@name=\"%s\"]", name.str());
  3204. if (generatedDlls->hasProp(gDllPath))
  3205. continue; // generated dlls handled separately - see above
  3206. }
  3207. OwnedIFile srcFile = createIFile(srcPath);
  3208. if (srcFile->exists())
  3209. {
  3210. try
  3211. {
  3212. copyFile(dstFile, srcFile);
  3213. }
  3214. catch (IException *e)
  3215. {
  3216. VStringBuffer msg("Failed to restore associated file '%s' to destination '%s'", srcFile->queryFilename(), dstFile->queryFilename());
  3217. EXCLOG(e, msg.str());
  3218. e->Release();
  3219. }
  3220. }
  3221. }
  3222. }
  3223. return true;
  3224. }
  3225. int CWorkUnitFactory::setTracingLevel(int newLevel)
  3226. {
  3227. if (newLevel)
  3228. PrintLog("Setting workunit trace level to %d", newLevel);
  3229. int level = workUnitTraceLevel;
  3230. workUnitTraceLevel = newLevel;
  3231. return level;
  3232. }
  3233. void CWorkUnitFactory::descheduleAllWorkUnits(ISecManager *secmgr, ISecUser *secuser)
  3234. {
  3235. Owned<IRemoteConnection> conn = querySDS().connect("/Schedule", myProcessSession(), RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT);
  3236. if(!conn) return;
  3237. Owned<IPropertyTree> root(conn->queryRoot()->getBranch("."));
  3238. KeptAtomTable entries;
  3239. Owned<IPropertyTreeIterator> iter(root->getElements("*/*/*/*"));
  3240. StringBuffer wuid;
  3241. for(iter->first(); iter->isValid(); iter->next())
  3242. {
  3243. char const * entry = iter->query().queryName();
  3244. if(!entries.find(entry))
  3245. {
  3246. entries.addAtom(entry);
  3247. ncnameUnescape(entry, wuid.clear());
  3248. Owned<IWorkUnit> wu = updateWorkUnit(wuid, secmgr, secuser);
  3249. if(wu && (wu->getState() == WUStateWait))
  3250. wu->setState(WUStateCompleted);
  3251. }
  3252. }
  3253. bool more;
  3254. do more = root->removeProp("*"); while(more);
  3255. }
  3256. IConstQuerySetQueryIterator* CWorkUnitFactory::getQuerySetQueriesSorted( WUQuerySortField *sortorder, // list of fields to sort by (terminated by WUSFterm)
  3257. WUQuerySortField *filters, // NULL or list of fields to filter on (terminated by WUSFterm)
  3258. const void *filterbuf, // (appended) string values for filters
  3259. unsigned startoffset,
  3260. unsigned maxnum,
  3261. __int64 *cachehint,
  3262. unsigned *total,
  3263. const MapStringTo<bool> *_subset)
  3264. {
  3265. struct PostFilters
  3266. {
  3267. WUQueryFilterBoolean activatedFilter;
  3268. WUQueryFilterBoolean suspendedByUserFilter;
  3269. PostFilters()
  3270. {
  3271. activatedFilter = WUQFSAll;
  3272. suspendedByUserFilter = WUQFSAll;
  3273. };
  3274. } postFilters;
  3275. class CQuerySetQueriesPager : public CSimpleInterface, implements IElementsPager
  3276. {
  3277. StringAttr querySet;
  3278. StringAttr xPath;
  3279. StringAttr sortOrder;
  3280. PostFilters postFilters;
  3281. StringArray unknownAttributes;
  3282. const MapStringTo<bool> *subset;
  3283. void populateQueryTree(const IPropertyTree* querySetTree, IPropertyTree* queryTree)
  3284. {
  3285. const char* querySetId = querySetTree->queryProp("@id");
  3286. VStringBuffer path("Query%s", xPath.get());
  3287. Owned<IPropertyTreeIterator> iter = querySetTree->getElements(path.str());
  3288. ForEach(*iter)
  3289. {
  3290. IPropertyTree &query = iter->query();
  3291. bool activated = false;
  3292. const char* queryId = query.queryProp("@id");
  3293. if (queryId && *queryId)
  3294. {
  3295. if (subset)
  3296. {
  3297. VStringBuffer match("%s/%s", querySetId, queryId);
  3298. if (!subset->getValue(match))
  3299. continue;
  3300. }
  3301. VStringBuffer aliasXPath("Alias[@id='%s']", queryId);
  3302. IPropertyTree *alias = querySetTree->queryPropTree(aliasXPath.str());
  3303. if (alias)
  3304. activated = true;
  3305. }
  3306. if (activated && (postFilters.activatedFilter == WUQFSNo))
  3307. continue;
  3308. if (!activated && (postFilters.activatedFilter == WUQFSYes))
  3309. continue;
  3310. if ((postFilters.suspendedByUserFilter == WUQFSNo) && query.hasProp(getEnumText(WUQSFSuspendedByUser,querySortFields)))
  3311. continue;
  3312. if ((postFilters.suspendedByUserFilter == WUQFSYes) && !query.hasProp(getEnumText(WUQSFSuspendedByUser,querySortFields)))
  3313. continue;
  3314. IPropertyTree *queryWithSetId = queryTree->addPropTree("Query", createPTreeFromIPT(&query));
  3315. queryWithSetId->setProp("@querySetId", querySetId);
  3316. queryWithSetId->setPropBool("@activated", activated);
  3317. }
  3318. }
  3319. IRemoteConnection* populateQueryTree(IPropertyTree* queryTree)
  3320. {
  3321. StringBuffer querySetXPath("QuerySets");
  3322. if (!querySet.isEmpty())
  3323. querySetXPath.appendf("/QuerySet[@id=\"%s\"]", querySet.get());
  3324. Owned<IRemoteConnection> conn = querySDS().connect(querySetXPath.str(), myProcessSession(), 0, SDS_LOCK_TIMEOUT);
  3325. if (!conn)
  3326. return NULL;
  3327. if (querySet.isEmpty())
  3328. {
  3329. Owned<IPropertyTreeIterator> querySetIter = conn->queryRoot()->getElements("*");
  3330. ForEach(*querySetIter)
  3331. populateQueryTree(&querySetIter->query(), queryTree);
  3332. }
  3333. else
  3334. populateQueryTree(conn->queryRoot(), queryTree);
  3335. return conn.getClear();
  3336. }
  3337. public:
  3338. IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
  3339. CQuerySetQueriesPager(const char* _querySet, const char* _xPath, const char *_sortOrder, PostFilters& _postFilters, StringArray& _unknownAttributes, const MapStringTo<bool> *_subset)
  3340. : querySet(_querySet), xPath(_xPath), sortOrder(_sortOrder), subset(_subset)
  3341. {
  3342. postFilters.activatedFilter = _postFilters.activatedFilter;
  3343. postFilters.suspendedByUserFilter = _postFilters.suspendedByUserFilter;
  3344. ForEachItemIn(x, _unknownAttributes)
  3345. unknownAttributes.append(_unknownAttributes.item(x));
  3346. }
  3347. virtual IRemoteConnection* getElements(IArrayOf<IPropertyTree> &elements)
  3348. {
  3349. Owned<IPropertyTree> elementTree = createPTree("Queries");
  3350. Owned<IRemoteConnection> conn = populateQueryTree(elementTree);
  3351. if (!conn)
  3352. return NULL;
  3353. Owned<IPropertyTreeIterator> iter = elementTree->getElements("*");
  3354. if (!iter)
  3355. return NULL;
  3356. sortElements(iter, sortOrder.get(), NULL, NULL, unknownAttributes, elements);
  3357. return conn.getClear();
  3358. }
  3359. virtual bool allMatchingElementsReceived() { return true; } //For now, dali always returns all of matched Queries.
  3360. };
  3361. StringAttr querySet;
  3362. StringBuffer xPath;
  3363. StringBuffer so;
  3364. StringArray unknownAttributes;
  3365. if (filters)
  3366. {
  3367. const char *fv = (const char *)filterbuf;
  3368. for (unsigned i=0;filters[i]!=WUQSFterm;i++) {
  3369. int fmt = filters[i];
  3370. int subfmt = (fmt&0xff);
  3371. if (subfmt==WUQSFQuerySet)
  3372. querySet.set(fv);
  3373. else if ((subfmt==WUQSFmemoryLimit) || (subfmt==WUQSFtimeLimit) || (subfmt==WUQSFwarnTimeLimit) || (subfmt==WUQSFpriority))
  3374. xPath.append('[').append(getEnumText(subfmt,querySortFields)).append(">=").append(fv).append("]");
  3375. else if ((subfmt==WUQSFmemoryLimitHi) || (subfmt==WUQSFtimeLimitHi) || (subfmt==WUQSFwarnTimeLimitHi) || (subfmt==WUQSFpriorityHi))
  3376. xPath.append('[').append(getEnumText(subfmt,querySortFields)).append("<=").append(fv).append("]");
  3377. else if (subfmt==WUQSFActivited)
  3378. postFilters.activatedFilter = (WUQueryFilterBoolean) atoi(fv);
  3379. else if (subfmt==WUQSFSuspendedByUser)
  3380. postFilters.suspendedByUserFilter = (WUQueryFilterBoolean) atoi(fv);
  3381. else if (!fv || !*fv)
  3382. unknownAttributes.append(getEnumText(subfmt,querySortFields));
  3383. else {
  3384. xPath.append('[').append(getEnumText(subfmt,querySortFields)).append('=');
  3385. if (fmt&WUQSFnocase)
  3386. xPath.append('?');
  3387. if (fmt&WUQSFnumeric)
  3388. xPath.append('#');
  3389. if (fmt&WUQSFwild)
  3390. xPath.append('~');
  3391. xPath.append('"').append(fv).append("\"]");
  3392. }
  3393. fv = fv + strlen(fv)+1;
  3394. }
  3395. }
  3396. if (sortorder) {
  3397. for (unsigned i=0;sortorder[i]!=WUQSFterm;i++) {
  3398. if (so.length())
  3399. so.append(',');
  3400. int fmt = sortorder[i];
  3401. if (fmt&WUQSFreverse)
  3402. so.append('-');
  3403. if (fmt&WUQSFnocase)
  3404. so.append('?');
  3405. if (fmt&WUQSFnumeric)
  3406. so.append('#');
  3407. so.append(getEnumText(fmt&0xff,querySortFields));
  3408. }
  3409. }
  3410. IArrayOf<IPropertyTree> results;
  3411. Owned<IElementsPager> elementsPager = new CQuerySetQueriesPager(querySet.get(), xPath.str(), so.length()?so.str():NULL, postFilters, unknownAttributes, _subset);
  3412. Owned<IRemoteConnection> conn=getElementsPaged(elementsPager,startoffset,maxnum,NULL,"",cachehint,results,total,NULL);
  3413. return new CConstQuerySetQueryIterator(results);
  3414. }
  3415. bool CWorkUnitFactory::isAborting(const char *wuid) const
  3416. {
  3417. VStringBuffer apath("/WorkUnitAborts/%s", wuid);
  3418. try
  3419. {
  3420. Owned<IRemoteConnection> acon = querySDS().connect(apath.str(), myProcessSession(), 0, SDS_LOCK_TIMEOUT);
  3421. if (acon)
  3422. return acon->queryRoot()->getPropInt(NULL) != 0;
  3423. }
  3424. catch (IException *E)
  3425. {
  3426. EXCLOG(E);
  3427. E->Release();
  3428. }
  3429. return false;
  3430. }
  3431. void CWorkUnitFactory::clearAborting(const char *wuid)
  3432. {
  3433. VStringBuffer apath("/WorkUnitAborts/%s", wuid);
  3434. try
  3435. {
  3436. Owned<IRemoteConnection> acon = querySDS().connect(apath.str(), myProcessSession(), RTM_LOCK_WRITE|RTM_LOCK_SUB, SDS_LOCK_TIMEOUT);
  3437. if (acon)
  3438. acon->close(true);
  3439. }
  3440. catch (IException *E)
  3441. {
  3442. EXCLOG(E);
  3443. E->Release();
  3444. }
  3445. }
  3446. void CWorkUnitFactory::reportAbnormalTermination(const char *wuid, WUState &state, SessionId agent)
  3447. {
  3448. WARNLOG("reportAbnormalTermination: session stopped unexpectedly: %" I64F "d state: %d", (__int64) agent, (int) state);
  3449. bool isEcl = false;
  3450. switch (state)
  3451. {
  3452. case WUStateAborting:
  3453. state = WUStateAborted;
  3454. break;
  3455. case WUStateCompiling:
  3456. isEcl = true;
  3457. // drop into
  3458. default:
  3459. state = WUStateFailed;
  3460. }
  3461. Owned<IWorkUnit> wu = updateWorkUnit(wuid, NULL, NULL);
  3462. wu->setState(state);
  3463. Owned<IWUException> e = wu->createException();
  3464. e->setExceptionCode(isEcl ? 1001 : 1000);
  3465. e->setExceptionMessage(isEcl ? "EclServer terminated unexpectedly" : "Workunit terminated unexpectedly");
  3466. }
  3467. static CriticalSection deleteDllLock;
  3468. static IWorkQueueThread *deleteDllWorkQ = nullptr;
  3469. MODULE_INIT(INIT_PRIORITY_STANDARD)
  3470. {
  3471. return true;
  3472. }
  3473. MODULE_EXIT()
  3474. {
  3475. CriticalBlock b(deleteDllLock);
  3476. if (deleteDllWorkQ)
  3477. ::Release(deleteDllWorkQ);
  3478. deleteDllWorkQ = nullptr;
  3479. }
  3480. static void asyncRemoveDll(const char * name)
  3481. {
  3482. CriticalBlock b(deleteDllLock);
  3483. if (!deleteDllWorkQ)
  3484. deleteDllWorkQ = createWorkQueueThread();
  3485. deleteDllWorkQ->post(new asyncRemoveDllWorkItem(name));
  3486. }
  3487. static void asyncRemoveFile(const char * ip, const char * name)
  3488. {
  3489. CriticalBlock b(deleteDllLock);
  3490. if (!deleteDllWorkQ)
  3491. deleteDllWorkQ = createWorkQueueThread();
  3492. deleteDllWorkQ->post(new asyncRemoveRemoteFileWorkItem(ip, name));
  3493. }
  3494. class CDaliWorkUnitFactory : public CWorkUnitFactory, implements IDaliClientShutdown
  3495. {
  3496. public:
  3497. IMPLEMENT_IINTERFACE_USING(CWorkUnitFactory);
  3498. CDaliWorkUnitFactory()
  3499. {
  3500. // Assumes dali client configuration has already been done
  3501. sdsManager = &querySDS();
  3502. session = myProcessSession();
  3503. addShutdownHook(*this);
  3504. }
  3505. ~CDaliWorkUnitFactory()
  3506. {
  3507. removeShutdownHook(*this);
  3508. }
  3509. virtual bool initializeStore()
  3510. {
  3511. throwUnexpected(); // Used when loading a plugin factory - not applicable here
  3512. }
  3513. virtual IWorkUnitWatcher *getWatcher(IWorkUnitSubscriber *subscriber, WUSubscribeOptions options, const char *wuid) const
  3514. {
  3515. return new CDaliWorkUnitWatcher(subscriber, options, wuid);
  3516. }
  3517. virtual unsigned validateRepository(bool fixErrors)
  3518. {
  3519. return 0;
  3520. }
  3521. virtual void deleteRepository(bool recreate)
  3522. {
  3523. Owned<IRemoteConnection> conn = sdsManager->connect("/WorkUnits", session, RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT);
  3524. if (conn)
  3525. conn->close(true);
  3526. conn.setown(sdsManager->connect("/GraphProgress", session, RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT));
  3527. if (conn)
  3528. conn->close(true);
  3529. }
  3530. virtual void createRepository()
  3531. {
  3532. // Nothing to do
  3533. }
  3534. virtual const char *queryStoreType() const
  3535. {
  3536. return "Dali";
  3537. }
  3538. virtual CLocalWorkUnit *_createWorkUnit(const char *wuid, ISecManager *secmgr, ISecUser *secuser)
  3539. {
  3540. StringBuffer wuRoot;
  3541. getXPath(wuRoot, wuid);
  3542. IRemoteConnection *conn;
  3543. conn = sdsManager->connect(wuRoot.str(), session, RTM_LOCK_WRITE|RTM_CREATE_UNIQUE, SDS_LOCK_TIMEOUT);
  3544. conn->queryRoot()->setProp("@xmlns:xsi", "http://www.w3.org/1999/XMLSchema-instance");
  3545. conn->queryRoot()->setPropInt("@wuidVersion", WUID_VERSION);
  3546. return new CDaliWorkUnit(conn, secmgr, secuser);
  3547. }
  3548. virtual CLocalWorkUnit* _openWorkUnit(const char *wuid, ISecManager *secmgr, ISecUser *secuser)
  3549. {
  3550. StringBuffer wuRoot;
  3551. getXPath(wuRoot, wuid);
  3552. IRemoteConnection* conn = sdsManager->connect(wuRoot.str(), session, 0, SDS_LOCK_TIMEOUT);
  3553. if (conn)
  3554. return new CDaliWorkUnit(conn, secmgr, secuser);
  3555. else
  3556. return NULL;
  3557. }
  3558. virtual bool _restoreWorkUnit(IPTree *_pt, const char *wuid)
  3559. {
  3560. Owned<IPTree> pt(_pt);
  3561. Owned<IPropertyTree> gprogress = pruneBranch(pt, "GraphProgress[1]");
  3562. StringBuffer wuRoot;
  3563. getXPath(wuRoot, wuid);
  3564. Owned<IRemoteConnection> conn = sdsManager->connect(wuRoot.str(), myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT);
  3565. if (!conn)
  3566. {
  3567. ERRLOG("restoreWorkUnit could not create to %s", wuRoot.str());
  3568. return false;
  3569. }
  3570. IPropertyTree *root = conn->queryRoot();
  3571. if (root->hasChildren())
  3572. {
  3573. ERRLOG("restoreWorkUnit WUID %s already exists", wuid);
  3574. return false;
  3575. }
  3576. root->setPropTree(NULL, pt.getClear());
  3577. conn.clear();
  3578. // now kludge back GraphProgress
  3579. if (gprogress)
  3580. {
  3581. VStringBuffer xpath("/GraphProgress/%s", wuid);
  3582. conn.setown(querySDS().connect(xpath, myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT));
  3583. if (conn)
  3584. {
  3585. IPropertyTree *groot = conn->queryRoot();
  3586. if (groot->hasChildren())
  3587. WARNLOG("restoreWorkUnit WUID %s graphprogress already exists, replacing",wuid);
  3588. groot->setPropTree(NULL, gprogress.getClear());
  3589. }
  3590. }
  3591. return true;
  3592. }
  3593. virtual CLocalWorkUnit* _updateWorkUnit(const char *wuid, ISecManager *secmgr, ISecUser *secuser)
  3594. {
  3595. StringBuffer wuRoot;
  3596. getXPath(wuRoot, wuid);
  3597. IRemoteConnection* conn = sdsManager->connect(wuRoot.str(), session, RTM_LOCK_WRITE|RTM_LOCK_SUB, SDS_LOCK_TIMEOUT);
  3598. if (conn)
  3599. return new CDaliWorkUnit(conn, secmgr, secuser);
  3600. else
  3601. return NULL;
  3602. }
  3603. virtual IWorkUnit* getGlobalWorkUnit(ISecManager *secmgr, ISecUser *secuser)
  3604. {
  3605. // MORE - should it check security?
  3606. StringBuffer wuRoot;
  3607. getXPath(wuRoot, GLOBAL_WORKUNIT);
  3608. IRemoteConnection* conn = sdsManager->connect(wuRoot.str(), session, RTM_LOCK_WRITE|RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT);
  3609. conn->queryRoot()->setProp("@xmlns:xsi", "http://www.w3.org/1999/XMLSchema-instance");
  3610. Owned<CLocalWorkUnit> cw = new CDaliWorkUnit(conn, (ISecManager *) NULL, NULL);
  3611. return &cw->lockRemote(false);
  3612. }
  3613. virtual IConstWorkUnitIterator* getWorkUnitsByOwner(const char * owner, ISecManager *secmgr, ISecUser *secuser)
  3614. {
  3615. StringBuffer path("*");
  3616. if (owner && *owner)
  3617. path.append("[@submitID=?~\"").append(owner).append("\"]");
  3618. return _getWorkUnitsByXPath(path.str(), secmgr, secuser);
  3619. }
  3620. IConstWorkUnitIterator* getScheduledWorkUnits(ISecManager *secmgr, ISecUser *secuser)
  3621. {
  3622. StringBuffer path("*");
  3623. path.append("[@state=\"").append(getEnumText(WUStateScheduled, states)).append("\"]");
  3624. return _getWorkUnitsByXPath(path.str(), secmgr, secuser);
  3625. }
  3626. virtual void clientShutdown();
  3627. virtual unsigned numWorkUnits()
  3628. {
  3629. Owned<IRemoteConnection> conn = sdsManager->connect("/WorkUnits", session, 0, SDS_LOCK_TIMEOUT);
  3630. if (!conn)
  3631. return 0;
  3632. IPropertyTree *root = conn->queryRoot();
  3633. return root->numChildren();
  3634. }
  3635. /**
  3636. * Add a filter to an xpath query, with the appropriate filter flags
  3637. */
  3638. static void appendFilterToQueryString(StringBuffer& query, int flags, const char* name, const char* value)
  3639. {
  3640. query.append('[').append(name).append('=');
  3641. if (flags & WUSFnocase)
  3642. query.append('?');
  3643. if (flags & WUSFwild)
  3644. query.append('~');
  3645. query.append('"').append(value).append("\"]");
  3646. };
  3647. IConstWorkUnitIterator* getWorkUnitsSorted( WUSortField sortorder, // field to sort by (and flags for desc sort etc)
  3648. WUSortField *filters, // NULL or list of fields to filter on (terminated by WUSFterm)
  3649. const void *filterbuf, // (appended) string values for filters
  3650. unsigned startoffset,
  3651. unsigned maxnum,
  3652. __int64 *cachehint,
  3653. unsigned *total,
  3654. ISecManager *secmgr,
  3655. ISecUser *secuser)
  3656. {
  3657. class CQueryOrFilter : public CInterface
  3658. {
  3659. unsigned flags;
  3660. StringAttr name;
  3661. StringArray values;
  3662. public:
  3663. IMPLEMENT_IINTERFACE;
  3664. CQueryOrFilter(unsigned _flags, const char *_name, const char *_value)
  3665. : flags(_flags), name(_name)
  3666. {
  3667. values.appendListUniq(_value, "|");
  3668. };
  3669. const char* queryName() { return name.get(); };
  3670. unsigned querySearchFlags() { return flags; };
  3671. const StringArray& queryValues() const { return values; };
  3672. };
  3673. class CMultiPTreeIterator : public CInterfaceOf<IPropertyTreeIterator>
  3674. {
  3675. public:
  3676. virtual bool first() override
  3677. {
  3678. curSource = 0;
  3679. while (sources.isItem(curSource))
  3680. {
  3681. if (sources.item(curSource).first())
  3682. return true;
  3683. curSource++;
  3684. }
  3685. return false;
  3686. }
  3687. virtual bool next() override
  3688. {
  3689. if (sources.isItem(curSource))
  3690. {
  3691. if (sources.item(curSource).next())
  3692. return true;
  3693. curSource++;
  3694. while (sources.isItem(curSource))
  3695. {
  3696. if (sources.item(curSource).first())
  3697. return true;
  3698. curSource++;
  3699. }
  3700. }
  3701. return false;
  3702. }
  3703. virtual bool isValid() override
  3704. {
  3705. return sources.isItem(curSource);
  3706. }
  3707. virtual IPropertyTree & query() override
  3708. {
  3709. return sources.item(curSource).query();
  3710. }
  3711. void addSource(IPropertyTreeIterator &source)
  3712. {
  3713. sources.append(source);
  3714. }
  3715. private:
  3716. IArrayOf<IPropertyTreeIterator> sources;
  3717. unsigned curSource = 0;
  3718. };
  3719. class CWorkUnitsPager : public CSimpleInterface, implements IElementsPager
  3720. {
  3721. StringAttr xPath;
  3722. StringAttr sortOrder;
  3723. StringAttr nameFilterLo;
  3724. StringAttr nameFilterHi;
  3725. StringArray unknownAttributes;
  3726. Owned<CQueryOrFilter> orFilter;
  3727. public:
  3728. IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
  3729. CWorkUnitsPager(const char* _xPath, CQueryOrFilter* _orFilter, const char *_sortOrder, const char* _nameFilterLo, const char* _nameFilterHi, StringArray& _unknownAttributes)
  3730. : xPath(_xPath), orFilter(_orFilter), sortOrder(_sortOrder), nameFilterLo(_nameFilterLo), nameFilterHi(_nameFilterHi)
  3731. {
  3732. ForEachItemIn(x, _unknownAttributes)
  3733. unknownAttributes.append(_unknownAttributes.item(x));
  3734. }
  3735. virtual IRemoteConnection* getElements(IArrayOf<IPropertyTree> &elements)
  3736. {
  3737. Owned<IRemoteConnection> conn = querySDS().connect("WorkUnits", myProcessSession(), 0, SDS_LOCK_TIMEOUT);
  3738. if (!conn)
  3739. return NULL;
  3740. Owned<IPropertyTreeIterator> iter;
  3741. if (!orFilter)
  3742. {
  3743. iter.setown(conn->getElements(xPath.get()));
  3744. }
  3745. else
  3746. {
  3747. Owned <CMultiPTreeIterator> multi = new CMultiPTreeIterator;
  3748. bool added = false;
  3749. const char* fieldName = orFilter->queryName();
  3750. unsigned flags = orFilter->querySearchFlags();
  3751. const StringArray& values = orFilter->queryValues();
  3752. ForEachItemIn(i, values)
  3753. {
  3754. StringBuffer path = xPath.get();
  3755. const char* value = values.item(i);
  3756. if (!isEmptyString(value))
  3757. {
  3758. appendFilterToQueryString(path, flags, fieldName, value);
  3759. IPropertyTreeIterator *itr = conn->getElements(path.str());
  3760. if (itr)
  3761. {
  3762. multi->addSource(*itr);
  3763. added = true;
  3764. }
  3765. }
  3766. }
  3767. if (added)
  3768. iter.setown(multi.getClear());
  3769. }
  3770. if (!iter)
  3771. return NULL;
  3772. sortElements(iter, sortOrder.get(), nameFilterLo.get(), nameFilterHi.get(), unknownAttributes, elements);
  3773. return conn.getClear();
  3774. }
  3775. virtual bool allMatchingElementsReceived() { return true; }//For now, dali always returns all of matched WUs.
  3776. };
  3777. class CScopeChecker : public CSimpleInterface, implements ISortedElementsTreeFilter
  3778. {
  3779. UniqueScopes done;
  3780. ISecManager *secmgr;
  3781. ISecUser *secuser;
  3782. CriticalSection crit;
  3783. public:
  3784. IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
  3785. CScopeChecker(ISecManager *_secmgr,ISecUser *_secuser)
  3786. {
  3787. secmgr = _secmgr;
  3788. secuser = _secuser;
  3789. }
  3790. bool isOK(IPropertyTree &tree)
  3791. {
  3792. const char *scopename = tree.queryProp("@scope");
  3793. if (!scopename||!*scopename)
  3794. return true;
  3795. {
  3796. CriticalBlock block(crit);
  3797. const bool *b = done.getValue(scopename);
  3798. if (b)
  3799. return *b;
  3800. }
  3801. bool ret = checkWuScopeSecAccess(scopename,secmgr,secuser,SecAccess_Read,"iterating",false,false);
  3802. {
  3803. // conceivably could have already been checked and added, but ok.
  3804. CriticalBlock block(crit);
  3805. done.setValue(scopename,ret);
  3806. }
  3807. return ret;
  3808. }
  3809. };
  3810. Owned<CQueryOrFilter> orFilter;
  3811. Owned<ISortedElementsTreeFilter> sc = new CScopeChecker(secmgr,secuser);
  3812. StringBuffer query;
  3813. StringBuffer so;
  3814. StringAttr namefilter("*");
  3815. StringAttr namefilterlo;
  3816. StringAttr namefilterhi;
  3817. StringArray unknownAttributes;
  3818. if (filters)
  3819. {
  3820. const char *fv = (const char *) filterbuf;
  3821. for (unsigned i=0;filters[i]!=WUSFterm;i++)
  3822. {
  3823. assertex(fv);
  3824. int fmt = filters[i];
  3825. int subfmt = (fmt&0xff);
  3826. if (subfmt==WUSFwuid)
  3827. namefilterlo.set(fv);
  3828. else if (subfmt==WUSFwuidhigh)
  3829. namefilterhi.set(fv);
  3830. else if (subfmt==WUSFwildwuid)
  3831. namefilter.set(fv);
  3832. else if (subfmt==WUSFappvalue)
  3833. {
  3834. const char *app = fv;
  3835. fv = fv + strlen(fv)+1;
  3836. query.append("[Application/").append(app);
  3837. if (*fv)
  3838. query.append("=?~\"").append(fv).append('\"');
  3839. query.append("]");
  3840. }
  3841. else if (!*fv)
  3842. {
  3843. unknownAttributes.append(getEnumText(subfmt,workunitSortFields));
  3844. if (subfmt==WUSFtotalthortime)
  3845. sortorder = (WUSortField) (sortorder & ~WUSFnumeric);
  3846. }
  3847. else
  3848. {
  3849. const char* fieldName = getEnumText(subfmt,workunitSortFields);
  3850. if (!strchr(fv, '|'))
  3851. appendFilterToQueryString(query, fmt, fieldName, fv);
  3852. else if (orFilter)
  3853. throw MakeStringException(WUERR_InvalidUserInput, "Multiple OR filters not allowed");
  3854. else
  3855. {
  3856. if (!strieq(fieldName, getEnumText(WUSFstate,workunitSortFields)) &&
  3857. !strieq(fieldName, getEnumText(WUSFuser,workunitSortFields)) &&
  3858. !strieq(fieldName, getEnumText(WUSFcluster,workunitSortFields)))
  3859. throw MakeStringException(WUERR_InvalidUserInput, "OR filters not allowed for %s", fieldName);
  3860. orFilter.setown(new CQueryOrFilter(fmt, fieldName, fv));
  3861. }
  3862. }
  3863. fv = fv + strlen(fv)+1;
  3864. }
  3865. }
  3866. if ((sortorder&0xff)==WUSFtotalthortime)
  3867. sortorder = (WUSortField) (sortorder & ~WUSFnumeric);
  3868. query.insert(0, namefilter.get());
  3869. if (sortorder)
  3870. {
  3871. if (so.length())
  3872. so.append(',');
  3873. if (sortorder & WUSFreverse)
  3874. so.append('-');
  3875. if (sortorder & WUSFnocase)
  3876. so.append('?');
  3877. if (sortorder & WUSFnumeric)
  3878. so.append('#');
  3879. so.append(getEnumText(sortorder&0xff,workunitSortFields));
  3880. }
  3881. IArrayOf<IPropertyTree> results;
  3882. Owned<IElementsPager> elementsPager = new CWorkUnitsPager(query.str(), orFilter.getClear(), so.length()?so.str():NULL, namefilterlo.get(), namefilterhi.get(), unknownAttributes);
  3883. Owned<IRemoteConnection> conn=getElementsPaged(elementsPager,startoffset,maxnum,secmgr?sc:NULL,"",cachehint,results,total,NULL);
  3884. return new CConstWUArrayIterator(results);
  3885. }
  3886. virtual WUState waitForWorkUnit(const char * wuid, unsigned timeout, bool compiled, bool returnOnWaitState)
  3887. {
  3888. WUState ret = WUStateUnknown;
  3889. StringBuffer wuRoot;
  3890. getXPath(wuRoot, wuid);
  3891. Owned<IRemoteConnection> conn = sdsManager->connect(wuRoot.str(), session, 0, SDS_LOCK_TIMEOUT);
  3892. if (timeout == 0) //no need to subscribe
  3893. {
  3894. ret = (WUState) getEnum(conn->queryRoot(), "@state", states);
  3895. switch (ret)
  3896. {
  3897. case WUStateCompiled:
  3898. case WUStateUploadingFiles:
  3899. if (!compiled)
  3900. break;
  3901. //fall through
  3902. case WUStateCompleted:
  3903. case WUStateFailed:
  3904. case WUStateAborted:
  3905. return ret;
  3906. case WUStateWait:
  3907. if(returnOnWaitState)
  3908. return ret;
  3909. default:
  3910. break;
  3911. }
  3912. return WUStateUnknown;
  3913. }
  3914. Owned<WorkUnitWaiter> waiter = new WorkUnitWaiter(wuid, SubscribeOptionState);
  3915. LocalIAbortHandler abortHandler(*waiter);
  3916. if (conn)
  3917. {
  3918. SessionId agent = -1;
  3919. bool agentSessionStopped = false;
  3920. unsigned start = msTick();
  3921. for (;;)
  3922. {
  3923. ret = (WUState) getEnum(conn->queryRoot(), "@state", states);
  3924. switch (ret)
  3925. {
  3926. case WUStateCompiled:
  3927. case WUStateUploadingFiles:
  3928. if (!compiled)
  3929. break;
  3930. // fall into
  3931. case WUStateCompleted:
  3932. case WUStateFailed:
  3933. case WUStateAborted:
  3934. return ret;
  3935. case WUStateWait:
  3936. if(returnOnWaitState)
  3937. {
  3938. return ret;
  3939. }
  3940. break;
  3941. case WUStateCompiling:
  3942. case WUStateRunning:
  3943. case WUStateDebugPaused:
  3944. case WUStateDebugRunning:
  3945. case WUStateBlocked:
  3946. case WUStateAborting:
  3947. if (agentSessionStopped)
  3948. {
  3949. reportAbnormalTermination(wuid, ret, agent);
  3950. return ret;
  3951. }
  3952. if (queryDaliServerVersion().compare("2.1")>=0)
  3953. {
  3954. agent = conn->queryRoot()->getPropInt64("@agentSession", -1);
  3955. if((agent>0) && querySessionManager().sessionStopped(agent, 0))
  3956. {
  3957. agentSessionStopped = true;
  3958. conn->reload();
  3959. continue;
  3960. }
  3961. }
  3962. break;
  3963. }
  3964. agentSessionStopped = false; // reset for state changes such as WUStateWait then WUStateRunning again
  3965. unsigned waited = msTick() - start;
  3966. if (timeout==-1 || waited + 20000 < timeout)
  3967. {
  3968. waiter->wait(20000); // recheck state every 20 seconds, in case eclagent has crashed.
  3969. if (waiter->aborted)
  3970. {
  3971. ret = WUStateUnknown; // MORE - throw an exception?
  3972. break;
  3973. }
  3974. }
  3975. else if (waited > timeout || !waiter->wait(timeout-waited))
  3976. {
  3977. ret = WUStateUnknown; // MORE - throw an exception?
  3978. break;
  3979. }
  3980. conn->reload();
  3981. }
  3982. }
  3983. return ret;
  3984. }
  3985. virtual WUAction waitForWorkUnitAction(const char * wuid, WUAction original)
  3986. {
  3987. Owned<WorkUnitWaiter> waiter = new WorkUnitWaiter(wuid, SubscribeOptionAction);
  3988. LocalIAbortHandler abortHandler(*waiter);
  3989. WUAction ret = WUActionUnknown;
  3990. StringBuffer wuRoot;
  3991. getXPath(wuRoot, wuid);
  3992. Owned<IRemoteConnection> conn = sdsManager->connect(wuRoot.str(), session, 0, SDS_LOCK_TIMEOUT);
  3993. if (conn)
  3994. {
  3995. unsigned start = msTick();
  3996. for (;;)
  3997. {
  3998. ret = (WUAction) getEnum(conn->queryRoot(), "Action", actions);
  3999. if (ret != original)
  4000. break;
  4001. unsigned waited = msTick() - start;
  4002. waiter->wait(20000); // recheck state every 20 seconds even if no timeout, in case eclagent has crashed.
  4003. if (waiter->aborted)
  4004. {
  4005. ret = WUActionUnknown; // MORE - throw an exception?
  4006. break;
  4007. }
  4008. conn->reload();
  4009. }
  4010. }
  4011. waiter->unsubscribe();
  4012. return ret;
  4013. }
  4014. protected:
  4015. IConstWorkUnitIterator * _getWorkUnitsByXPath(const char *xpath, ISecManager *secmgr, ISecUser *secuser)
  4016. {
  4017. Owned<IRemoteConnection> conn = sdsManager->connect("/WorkUnits", session, 0, SDS_LOCK_TIMEOUT);
  4018. if (conn)
  4019. {
  4020. CDaliVersion serverVersionNeeded("3.2");
  4021. Owned<IPropertyTreeIterator> iter(queryDaliServerVersion().compare(serverVersionNeeded) < 0 ?
  4022. conn->queryRoot()->getElements(xpath) :
  4023. conn->getElements(xpath));
  4024. return createSecureConstWUIterator(iter.getClear(), secmgr, secuser);
  4025. }
  4026. else
  4027. return NULL;
  4028. }
  4029. ISDSManager *sdsManager;
  4030. SessionId session;
  4031. };
  4032. extern WORKUNIT_API IConstWorkUnitIterator *createSecureConstWUIterator(IConstWorkUnitIterator *iter, ISecManager *secmgr, ISecUser *secuser)
  4033. {
  4034. if (secmgr)
  4035. return new CSecureConstWUIterator(iter, secmgr, secuser);
  4036. else
  4037. return iter;
  4038. }
  4039. extern WORKUNIT_API IConstWorkUnitIterator *createSecureConstWUIterator(IPropertyTreeIterator *iter, ISecManager *secmgr, ISecUser *secuser)
  4040. {
  4041. if (secmgr)
  4042. return new CSecureConstWUIterator(new CConstWUIterator(iter), secmgr, secuser);
  4043. else
  4044. return new CConstWUIterator(iter);
  4045. }
  4046. static CriticalSection factoryCrit;
  4047. static Owned<IWorkUnitFactory> factory;
  4048. void CDaliWorkUnitFactory::clientShutdown()
  4049. {
  4050. CriticalBlock b(factoryCrit);
  4051. factory.clear();
  4052. }
  4053. void clientShutdownWorkUnit()
  4054. {
  4055. CriticalBlock b(factoryCrit);
  4056. factory.clear();
  4057. }
  4058. extern WORKUNIT_API void setWorkUnitFactory(IWorkUnitFactory * _factory)
  4059. {
  4060. CriticalBlock b(factoryCrit);
  4061. factory.setown(_factory);
  4062. }
  4063. extern WORKUNIT_API IWorkUnitFactory * getWorkUnitFactory()
  4064. {
  4065. if (!factory)
  4066. {
  4067. CriticalBlock b(factoryCrit);
  4068. if (!factory) // NOTE - this "double test" paradigm is not guaranteed threadsafe on modern systems/compilers - I think in this instance that is harmless even in the (extremely) unlikely event that it resulted in the setown being called twice.
  4069. {
  4070. const char *forceEnv = getenv("FORCE_DALI_WORKUNITS");
  4071. bool forceDali = forceEnv && !strieq(forceEnv, "off") && !strieq(forceEnv, "0");
  4072. Owned<IRemoteConnection> env = querySDS().connect("/Environment", myProcessSession(), 0, SDS_LOCK_TIMEOUT);
  4073. IPropertyTree *pluginInfo = NULL;
  4074. if (env)
  4075. {
  4076. SocketEndpoint targetDali = queryCoven().queryGroup().queryNode(0).endpoint();
  4077. IPropertyTree *daliInfo = findDaliProcess(env->queryRoot(), targetDali);
  4078. if (daliInfo)
  4079. {
  4080. const char *daliName = daliInfo->queryProp("@name");
  4081. if (daliName)
  4082. {
  4083. VStringBuffer xpath("Software/DaliServerPlugin[@type='WorkunitServer'][@daliServers='%s']", daliName);
  4084. pluginInfo = env->queryRoot()->queryPropTree(xpath);
  4085. }
  4086. if (!pluginInfo)
  4087. pluginInfo = daliInfo->queryPropTree("Plugin[@type='WorkunitServer']"); // Compatibility with early betas of 6.0 ...
  4088. }
  4089. }
  4090. if (pluginInfo && !forceDali)
  4091. factory.setown( (IWorkUnitFactory *) loadPlugin(pluginInfo));
  4092. else
  4093. factory.setown(new CDaliWorkUnitFactory());
  4094. }
  4095. }
  4096. return factory.getLink();
  4097. }
  4098. extern WORKUNIT_API IWorkUnitFactory * getDaliWorkUnitFactory()
  4099. {
  4100. if (!factory)
  4101. {
  4102. CriticalBlock b(factoryCrit);
  4103. if (!factory) // NOTE - this "double test" paradigm is not guaranteed threadsafe on modern systems/compilers - I think in this instance that is harmless even in the (extremely) unlikely event that it resulted in the setown being called twice.
  4104. factory.setown(new CDaliWorkUnitFactory());
  4105. }
  4106. return factory.getLink();
  4107. }
  4108. // A SecureWorkUnitFactory allows the security params to be supplied once to the factory rather than being supplied to each call.
  4109. // They can still be supplied if you want...
  4110. class CSecureWorkUnitFactory : implements IWorkUnitFactory, public CInterface
  4111. {
  4112. public:
  4113. IMPLEMENT_IINTERFACE;
  4114. CSecureWorkUnitFactory(IWorkUnitFactory *_baseFactory, ISecManager *_secMgr, ISecUser *_secUser)
  4115. : baseFactory(_baseFactory), defaultSecMgr(_secMgr), defaultSecUser(_secUser)
  4116. {
  4117. }
  4118. virtual bool initializeStore()
  4119. {
  4120. throwUnexpected(); // Used when loading a plugin factory - not applicable here
  4121. }
  4122. virtual IWorkUnitWatcher *getWatcher(IWorkUnitSubscriber *subscriber, WUSubscribeOptions options, const char *wuid) const
  4123. {
  4124. return baseFactory->getWatcher(subscriber, options, wuid);
  4125. }
  4126. virtual unsigned validateRepository(bool fix)
  4127. {
  4128. return baseFactory->validateRepository(fix);
  4129. }
  4130. virtual void deleteRepository(bool recreate)
  4131. {
  4132. return baseFactory->deleteRepository(recreate);
  4133. }
  4134. virtual void createRepository()
  4135. {
  4136. return baseFactory->createRepository();
  4137. }
  4138. virtual const char *queryStoreType() const
  4139. {
  4140. return baseFactory->queryStoreType();
  4141. }
  4142. virtual StringArray &getUniqueValues(WUSortField field, const char *prefix, StringArray &result) const
  4143. {
  4144. return baseFactory->getUniqueValues(field, prefix, result);
  4145. }
  4146. virtual IWorkUnit* createNamedWorkUnit(const char *wuid, const char *app, const char *user, ISecManager *secMgr, ISecUser *secUser)
  4147. {
  4148. if (!secMgr) secMgr = defaultSecMgr.get();
  4149. if (!secUser) secUser = defaultSecUser.get();
  4150. return baseFactory->createNamedWorkUnit(wuid, app, user, secMgr, secUser);
  4151. }
  4152. virtual IWorkUnit* createWorkUnit(const char *app, const char *user, ISecManager *secMgr, ISecUser *secUser)
  4153. {
  4154. if (!secMgr) secMgr = defaultSecMgr.get();
  4155. if (!secUser) secUser = defaultSecUser.get();
  4156. return baseFactory->createWorkUnit(app, user, secMgr, secUser);
  4157. }
  4158. virtual bool deleteWorkUnit(const char * wuid, ISecManager *secMgr, ISecUser *secUser)
  4159. {
  4160. if (!secMgr) secMgr = defaultSecMgr.get();
  4161. if (!secUser) secUser = defaultSecUser.get();
  4162. return baseFactory->deleteWorkUnit(wuid, secMgr, secUser);
  4163. }
  4164. virtual IConstWorkUnit* openWorkUnit(const char *wuid, ISecManager *secMgr, ISecUser *secUser)
  4165. {
  4166. if (!secMgr) secMgr = defaultSecMgr.get();
  4167. if (!secUser) secUser = defaultSecUser.get();
  4168. return baseFactory->openWorkUnit(wuid, secMgr, secUser);
  4169. }
  4170. virtual IWorkUnit* updateWorkUnit(const char *wuid, ISecManager *secMgr, ISecUser *secUser)
  4171. {
  4172. if (!secMgr) secMgr = defaultSecMgr.get();
  4173. if (!secUser) secUser = defaultSecUser.get();
  4174. return baseFactory->updateWorkUnit(wuid, secMgr, secUser);
  4175. }
  4176. virtual bool restoreWorkUnit(const char *base, const char *wuid, bool restoreAssociated)
  4177. {
  4178. return baseFactory->restoreWorkUnit(base, wuid, restoreAssociated);
  4179. }
  4180. virtual IWorkUnit * getGlobalWorkUnit(ISecManager *secMgr, ISecUser *secUser)
  4181. {
  4182. if (!secMgr) secMgr = defaultSecMgr.get();
  4183. if (!secUser) secUser = defaultSecUser.get();
  4184. return baseFactory->getGlobalWorkUnit(secMgr, secUser);
  4185. }
  4186. virtual IConstWorkUnitIterator * getWorkUnitsByOwner(const char * owner, ISecManager *secMgr, ISecUser *secUser)
  4187. {
  4188. if (!secMgr) secMgr = defaultSecMgr.get();
  4189. if (!secUser) secUser = defaultSecUser.get();
  4190. return baseFactory->getWorkUnitsByOwner(owner, secMgr, secUser);
  4191. }
  4192. virtual IConstWorkUnitIterator * getScheduledWorkUnits(ISecManager *secMgr, ISecUser *secUser)
  4193. {
  4194. if (!secMgr) secMgr = defaultSecMgr.get();
  4195. if (!secUser) secUser = defaultSecUser.get();
  4196. return baseFactory->getScheduledWorkUnits(secMgr, secUser);
  4197. }
  4198. virtual void descheduleAllWorkUnits(ISecManager *secMgr, ISecUser *secUser)
  4199. {
  4200. if (!secMgr) secMgr = defaultSecMgr.get();
  4201. if (!secUser) secUser = defaultSecUser.get();
  4202. baseFactory->descheduleAllWorkUnits(secMgr, secUser);
  4203. }
  4204. virtual int setTracingLevel(int newLevel)
  4205. {
  4206. return baseFactory->setTracingLevel(newLevel);
  4207. }
  4208. virtual IConstWorkUnitIterator* getWorkUnitsSorted( WUSortField sortorder, // field to sort by
  4209. WUSortField *filters, // NULL or list of fields to filter on (terminated by WUSFterm)
  4210. const void *filterbuf, // (appended) string values for filters
  4211. unsigned startoffset,
  4212. unsigned maxnum,
  4213. __int64 *cachehint,
  4214. unsigned *total,
  4215. ISecManager *secMgr, ISecUser *secUser)
  4216. {
  4217. if (!secMgr) secMgr = defaultSecMgr.get();
  4218. if (!secUser) secUser = defaultSecUser.get();
  4219. return baseFactory->getWorkUnitsSorted(sortorder,filters,filterbuf,startoffset,maxnum,cachehint, total, secMgr, secUser);
  4220. }
  4221. virtual IConstQuerySetQueryIterator* getQuerySetQueriesSorted( WUQuerySortField *sortorder,
  4222. WUQuerySortField *filters,
  4223. const void *filterbuf,
  4224. unsigned startoffset,
  4225. unsigned maxnum,
  4226. __int64 *cachehint,
  4227. unsigned *total,
  4228. const MapStringTo<bool> *subset)
  4229. {
  4230. // MORE - why no security?
  4231. return baseFactory->getQuerySetQueriesSorted(sortorder,filters,filterbuf,startoffset,maxnum,cachehint,total,subset);
  4232. }
  4233. virtual unsigned numWorkUnits()
  4234. {
  4235. return baseFactory->numWorkUnits();
  4236. }
  4237. virtual bool isAborting(const char *wuid) const
  4238. {
  4239. return baseFactory->isAborting(wuid);
  4240. }
  4241. virtual void clearAborting(const char *wuid)
  4242. {
  4243. baseFactory->clearAborting(wuid);
  4244. }
  4245. virtual WUState waitForWorkUnit(const char * wuid, unsigned timeout, bool compiled, bool returnOnWaitState)
  4246. {
  4247. return baseFactory->waitForWorkUnit(wuid, timeout, compiled, returnOnWaitState);
  4248. }
  4249. virtual WUAction waitForWorkUnitAction(const char * wuid, WUAction original)
  4250. {
  4251. return baseFactory->waitForWorkUnitAction(wuid, original);
  4252. }
  4253. private:
  4254. Owned<IWorkUnitFactory> baseFactory;
  4255. Linked<ISecManager> defaultSecMgr;
  4256. Linked<ISecUser> defaultSecUser;
  4257. };
  4258. extern WORKUNIT_API IWorkUnitFactory * getWorkUnitFactory(ISecManager *secmgr, ISecUser *secuser)
  4259. {
  4260. if (secmgr && secuser)
  4261. return new CSecureWorkUnitFactory(getWorkUnitFactory(), secmgr, secuser);
  4262. else
  4263. return getWorkUnitFactory();
  4264. }
  4265. //==========================================================================================
  4266. class CStringPTreeIterator : implements IStringIterator, public CInterface
  4267. {
  4268. Owned<IPropertyTreeIterator> it;
  4269. public:
  4270. IMPLEMENT_IINTERFACE;
  4271. CStringPTreeIterator(IPropertyTreeIterator *p) : it(p) {};
  4272. virtual bool first() { return it->first(); }
  4273. virtual bool next() { return it->next(); }
  4274. virtual bool isValid() { return it->isValid(); }
  4275. virtual IStringVal & str(IStringVal &s) { s.set(it->query().queryProp(NULL)); return s; }
  4276. };
  4277. class CStringPTreeTagIterator : implements IStringIterator, public CInterface
  4278. {
  4279. Owned<IPropertyTreeIterator> it;
  4280. public:
  4281. IMPLEMENT_IINTERFACE;
  4282. CStringPTreeTagIterator(IPropertyTreeIterator *p) : it(p) {};
  4283. virtual bool first() { return it->first(); }
  4284. virtual bool next() { return it->next(); }
  4285. virtual bool isValid() { return it->isValid(); }
  4286. virtual IStringVal & str(IStringVal &s) { s.set(it->query().queryName()); return s; }
  4287. };
  4288. class CStringPTreeAttrIterator : implements IStringIterator, public CInterface
  4289. {
  4290. Owned<IPropertyTreeIterator> it;
  4291. StringAttr name;
  4292. public:
  4293. IMPLEMENT_IINTERFACE;
  4294. CStringPTreeAttrIterator(IPropertyTreeIterator *p, const char *_name) : it(p), name(_name) {};
  4295. virtual bool first() { return it->first(); }
  4296. virtual bool next() { return it->next(); }
  4297. virtual bool isValid() { return it->isValid(); }
  4298. virtual IStringVal & str(IStringVal &s) { s.set(it->query().queryProp(name)); return s; }
  4299. };
  4300. //==========================================================================================
  4301. CLocalWorkUnit::CLocalWorkUnit(ISecManager *secmgr, ISecUser *secuser)
  4302. {
  4303. clearCached(false);
  4304. secMgr.set(secmgr);
  4305. secUser.set(secuser);
  4306. workflowIteratorCached = false;
  4307. resultsCached = false;
  4308. graphsCached = false;
  4309. temporariesCached = false;
  4310. variablesCached = false;
  4311. exceptionsCached = false;
  4312. pluginsCached = false;
  4313. librariesCached = false;
  4314. activitiesCached = false;
  4315. webServicesInfoCached = false;
  4316. roxieQueryInfoCached = false;
  4317. }
  4318. void CLocalWorkUnit::clearCached(bool clearTree)
  4319. {
  4320. query.clear();
  4321. webServicesInfo.clear();
  4322. workflowIterator.clear();
  4323. graphs.kill();
  4324. results.kill();
  4325. variables.kill();
  4326. plugins.kill();
  4327. libraries.kill();
  4328. exceptions.kill();
  4329. temporaries.kill();
  4330. statistics.kill();
  4331. appvalues.kill();
  4332. if (clearTree)
  4333. p.clear();
  4334. workflowIteratorCached = false;
  4335. resultsCached = false;
  4336. graphsCached = false;
  4337. temporariesCached = false;
  4338. variablesCached = false;
  4339. exceptionsCached = false;
  4340. pluginsCached = false;
  4341. librariesCached = false;
  4342. activitiesCached = false;
  4343. webServicesInfoCached = false;
  4344. roxieQueryInfoCached = false;
  4345. }
  4346. void CLocalWorkUnit::loadPTree(IPropertyTree *ptree)
  4347. {
  4348. clearCached(false);
  4349. p.setown(ptree);
  4350. }
  4351. void CLocalWorkUnit::beforeDispose()
  4352. {
  4353. try
  4354. {
  4355. unsubscribe();
  4356. clearCached(true);
  4357. userDesc.clear();
  4358. secMgr.clear();
  4359. secUser.clear();
  4360. }
  4361. catch (IException *E) { LOG(MCexception(E, MSGCLS_warning), E, "Exception during ~CLocalWorkUnit"); E->Release(); }
  4362. }
  4363. void CLocalWorkUnit::cleanupAndDelete(bool deldll, bool deleteOwned, const StringArray *deleteExclusions)
  4364. {
  4365. MTIME_SECTION(queryActiveTimer(), "WUDELETE cleanupAndDelete total");
  4366. // Delete any related things in SDS etc that might otherwise be forgotten
  4367. if (p->getPropBool("@protected", false))
  4368. throw MakeStringException(WUERR_WorkunitProtected, "%s: Workunit is protected",p->queryName());
  4369. switch (getState())
  4370. {
  4371. case WUStateAborted:
  4372. case WUStateCompleted:
  4373. case WUStateFailed:
  4374. case WUStateArchived:
  4375. break;
  4376. case WUStateCompiled:
  4377. if (getAction()==WUActionRun || getAction()==WUActionUnknown)
  4378. throw MakeStringException(WUERR_WorkunitActive, "%s: Workunit is active. Please abort before deleting this workunit.",p->queryName());
  4379. break;
  4380. case WUStateWait:
  4381. throw MakeStringException(WUERR_WorkunitScheduled, "%s: Workunit is scheduled",p->queryName());
  4382. default:
  4383. throw MakeStringException(WUERR_WorkunitActive, "%s: Workunit is active. Please abort before deleting this workunit.",p->queryName());
  4384. break;
  4385. }
  4386. if (getIsQueryService())
  4387. {
  4388. Owned<IPropertyTree> registry = getQueryRegistryRoot();
  4389. if (registry)
  4390. {
  4391. VStringBuffer xpath("QuerySet/Query[@wuid='%s']", p->queryName());
  4392. if (registry->hasProp(xpath.str()))
  4393. throw MakeStringException(WUERR_WorkunitPublished, "%s: Workunit is published",p->queryName());
  4394. }
  4395. }
  4396. try
  4397. {
  4398. if (deldll && !p->getPropBool("@isClone", false))
  4399. {
  4400. Owned<IConstWUQuery> q = getQuery();
  4401. if (q)
  4402. {
  4403. Owned<IConstWUAssociatedFileIterator> iter = &q->getAssociatedFiles();
  4404. SCMStringBuffer name;
  4405. ForEach(*iter)
  4406. {
  4407. IConstWUAssociatedFile & cur = iter->query();
  4408. cur.getNameTail(name);
  4409. if (!deleteExclusions || (NotFound == deleteExclusions->find(name.str())))
  4410. {
  4411. Owned<IDllEntry> entry = queryDllServer().getEntry(name.str());
  4412. if (entry.get())
  4413. asyncRemoveDll(name.str());
  4414. else
  4415. {
  4416. SCMStringBuffer ip, localPath;
  4417. cur.getName(localPath);
  4418. cur.getIp(ip);
  4419. asyncRemoveFile(ip.str(), localPath.str());
  4420. }
  4421. }
  4422. }
  4423. }
  4424. }
  4425. factory->clearAborting(queryWuid());
  4426. deleteTempFiles(NULL, deleteOwned, true); // all, any remaining.
  4427. }
  4428. catch(IException *E)
  4429. {
  4430. StringBuffer s;
  4431. LOG(MCexception(E, MSGCLS_warning), E, s.append("Exception during cleanupAndDelete: ").append(p->queryName()).str());
  4432. E->Release();
  4433. }
  4434. catch (...)
  4435. {
  4436. WARNLOG("Unknown exception during cleanupAndDelete: %s", p->queryName());
  4437. }
  4438. }
  4439. void CLocalWorkUnit::setTimeScheduled(const IJlibDateTime &val)
  4440. {
  4441. SCMStringBuffer strval;
  4442. val.getGmtString(strval);
  4443. p->setProp("@timescheduled",strval.str());
  4444. }
  4445. IJlibDateTime & CLocalWorkUnit::getTimeScheduled(IJlibDateTime &val) const
  4446. {
  4447. StringBuffer str;
  4448. p->getProp("@timescheduled",str);
  4449. if(str.length())
  4450. val.setGmtString(str.str());
  4451. return val;
  4452. }
  4453. bool modifyAndWriteWorkUnitXML(char const * wuid, StringBuffer & buf, StringBuffer & extra, IFileIO * fileio)
  4454. {
  4455. // kludge in extra chunks of XML such as GraphProgress and GeneratedDlls
  4456. if(extra.length())
  4457. {
  4458. size32_t l = (size32_t)strlen(wuid);
  4459. size32_t p = buf.length()-l-4; // bit of a kludge
  4460. assertex(memcmp(buf.str()+p+2,wuid,l)==0);
  4461. StringAttr tail(buf.str()+p);
  4462. buf.setLength(p);
  4463. buf.append(extra);
  4464. buf.append(tail);
  4465. }
  4466. return (fileio->write(0,buf.length(),buf.str()) == buf.length());
  4467. }
  4468. bool CLocalWorkUnit::archiveWorkUnit(const char *base, bool del, bool ignoredllerrors, bool deleteOwned, bool exportAssociatedFiles)
  4469. {
  4470. CriticalBlock block(crit);
  4471. StringBuffer path(base);
  4472. if (!p)
  4473. return false;
  4474. const char *wuid = p->queryName();
  4475. if (!wuid||!*wuid)
  4476. return false;
  4477. addPathSepChar(path).append(wuid).append(".xml");
  4478. Owned<IFile> file = createIFile(path.str());
  4479. if (!file)
  4480. return false;
  4481. Owned<IFileIO> fileio = file->open(IFOcreate);
  4482. if (!fileio)
  4483. return false;
  4484. StringBuffer buf;
  4485. exportWorkUnitToXML(this, buf, false, false, true);
  4486. StringBuffer extraWorkUnitXML;
  4487. Owned<IPTree> graphProgress = getGraphProgressTree();
  4488. if (graphProgress)
  4489. {
  4490. toXML(graphProgress,extraWorkUnitXML,1,XML_Format);
  4491. graphProgress.clear();
  4492. }
  4493. Owned<IConstWUQuery> q = getQuery();
  4494. if (!q)
  4495. {
  4496. if (!modifyAndWriteWorkUnitXML(wuid, buf, extraWorkUnitXML, fileio))
  4497. return false;
  4498. if (del)
  4499. {
  4500. if (getState()==WUStateUnknown)
  4501. setState(WUStateArchived); // to allow delete
  4502. cleanupAndDelete(false,deleteOwned); // no query, may as well delete
  4503. }
  4504. return false;
  4505. }
  4506. StringArray deleteExclusions; // associated files not to delete, added if failure to copy
  4507. Owned<IConstWUAssociatedFileIterator> iter = &q->getAssociatedFiles();
  4508. Owned<IPropertyTree> generatedDlls = createPTree("GeneratedDlls");
  4509. ForEach(*iter)
  4510. {
  4511. IConstWUAssociatedFile & cur = iter->query();
  4512. SCMStringBuffer name;
  4513. cur.getNameTail(name);
  4514. if (name.length())
  4515. {
  4516. Owned<IDllEntry> entry = queryDllServer().getEntry(name.str());
  4517. SCMStringBuffer curPath, curIp;
  4518. cur.getName(curPath);
  4519. cur.getIp(curIp);
  4520. SocketEndpoint curEp(curIp.str());
  4521. RemoteFilename curRfn;
  4522. curRfn.setPath(curEp, curPath.str());
  4523. StringBuffer dst(base);
  4524. addPathSepChar(dst);
  4525. curRfn.getTail(dst);
  4526. Owned<IFile> dstFile = createIFile(dst.str());
  4527. if (entry.get())
  4528. {
  4529. Owned<IException> exception;
  4530. Owned<IDllLocation> loc;
  4531. Owned<IPropertyTree> generatedDllBranch = createPTree();
  4532. generatedDllBranch->setProp("@name", entry->queryName());
  4533. generatedDllBranch->setProp("@kind", entry->queryKind());
  4534. if (exportAssociatedFiles)
  4535. {
  4536. try
  4537. {
  4538. loc.setown(entry->getBestLocation()); //throws exception if no readable locations
  4539. }
  4540. catch(IException * e)
  4541. {
  4542. exception.setown(e);
  4543. loc.setown(entry->getBestLocationCandidate()); //this will be closest of the unreadable locations
  4544. }
  4545. RemoteFilename filename;
  4546. loc->getDllFilename(filename);
  4547. if (!exception)
  4548. {
  4549. Owned<IFile> srcfile = createIFile(filename);
  4550. try
  4551. {
  4552. if (dstFile->exists())
  4553. {
  4554. if (streq(srcfile->queryFilename(), dstFile->queryFilename()))
  4555. deleteExclusions.append(name.str()); // restored workunit, referencing archive location for query dll (no longer true post HPCC-11191 fix)
  4556. // still want to delete if already archived but there are source file copies
  4557. }
  4558. else
  4559. copyFile(dstFile, srcfile);
  4560. }
  4561. catch(IException * e)
  4562. {
  4563. exception.setown(e);
  4564. }
  4565. }
  4566. if (exception)
  4567. {
  4568. if (ignoredllerrors)
  4569. {
  4570. EXCLOG(exception.get(), "archiveWorkUnit (copying associated file)");
  4571. //copy failed, so don't delete the registered dll files
  4572. deleteExclusions.append(name.str());
  4573. }
  4574. else
  4575. throw exception.getClear();
  4576. }
  4577. }
  4578. // Record Associated path to restore back to
  4579. StringBuffer restorePath;
  4580. curRfn.getRemotePath(restorePath);
  4581. generatedDllBranch->setProp("@location", restorePath.str());
  4582. generatedDlls->addPropTree("GeneratedDll", generatedDllBranch.getClear());
  4583. }
  4584. else if (exportAssociatedFiles) // no generated dll entry
  4585. {
  4586. Owned<IFile> srcFile = createIFile(curRfn);
  4587. try
  4588. {
  4589. copyFile(dstFile, srcFile);
  4590. }
  4591. catch (IException *e)
  4592. {
  4593. VStringBuffer msg("Failed to archive associated file '%s' to destination '%s'", srcFile->queryFilename(), dstFile->queryFilename());
  4594. EXCLOG(e, msg.str());
  4595. e->Release();
  4596. deleteExclusions.append(name.str());
  4597. }
  4598. }
  4599. }
  4600. }
  4601. iter.clear();
  4602. if (generatedDlls->numChildren())
  4603. toXML(generatedDlls, extraWorkUnitXML, 1, XML_Format);
  4604. if (!modifyAndWriteWorkUnitXML(wuid, buf, extraWorkUnitXML, fileio))
  4605. return false;
  4606. if (del)
  4607. {
  4608. //setState(WUStateArchived); // this isn't useful as about to delete it!
  4609. q.clear();
  4610. cleanupAndDelete(true, deleteOwned, &deleteExclusions);
  4611. }
  4612. return true;
  4613. }
  4614. void CLocalWorkUnit::loadXML(const char *xml)
  4615. {
  4616. CriticalBlock block(crit);
  4617. clearCached(true);
  4618. assertex(xml);
  4619. p.setown(createPTreeFromXMLString(xml,ipt_lowmem));
  4620. }
  4621. void CLocalWorkUnit::serialize(MemoryBuffer &tgt)
  4622. {
  4623. CriticalBlock block(crit);
  4624. StringBuffer x;
  4625. tgt.append(exportWorkUnitToXML(this, x, false, false, false).str());
  4626. }
  4627. void CLocalWorkUnit::deserialize(MemoryBuffer &src)
  4628. {
  4629. CriticalBlock block(crit);
  4630. StringAttr value;
  4631. src.read(value);
  4632. loadXML(value);
  4633. }
  4634. void CLocalWorkUnit::requestAbort()
  4635. {
  4636. CriticalBlock block(crit);
  4637. abortWorkUnit(p->queryName());
  4638. }
  4639. void CLocalWorkUnit::unlockRemote()
  4640. {
  4641. CriticalBlock block(crit);
  4642. locked.unlock();
  4643. _unlockRemote();
  4644. }
  4645. IWorkUnit &CLocalWorkUnit::lockRemote(bool commit)
  4646. {
  4647. if (secMgr)
  4648. checkWuSecAccess(*this, secMgr.get(), secUser.get(), SecAccess_Write, "write lock", true, true);
  4649. locked.lock();
  4650. CriticalBlock block(crit);
  4651. if (commit)
  4652. {
  4653. try
  4654. {
  4655. _lockRemote();
  4656. }
  4657. catch (IException *E)
  4658. {
  4659. StringBuffer s;
  4660. PrintLog("Failed to get write lock on workunit: %s", E->errorMessage(s).str());
  4661. locked.unlock();
  4662. throw;
  4663. }
  4664. }
  4665. return *new CLockedWorkUnit(LINK(this));
  4666. }
  4667. void CLocalWorkUnit::commit()
  4668. {
  4669. // Nothing to do if not backed by a persistent store
  4670. }
  4671. IWorkUnit& CLocalWorkUnit::lock()
  4672. {
  4673. return lockRemote(true);
  4674. }
  4675. const char *CLocalWorkUnit::queryWuid() const
  4676. {
  4677. CriticalBlock block(crit);
  4678. return p->queryName();
  4679. }
  4680. unsigned CLocalWorkUnit::getDebugAgentListenerPort() const
  4681. {
  4682. CriticalBlock block(crit);
  4683. return p->getPropInt("@DebugListenerPort", 0);
  4684. }
  4685. unsigned CLocalWorkUnit::getTotalThorTime() const
  4686. {
  4687. CriticalBlock block(crit);
  4688. return (unsigned)nanoToMilli(extractTimeCollatable(p->queryProp("@totalThorTime"), false));
  4689. }
  4690. void CLocalWorkUnit::setDebugAgentListenerPort(unsigned port)
  4691. {
  4692. CriticalBlock block(crit);
  4693. p->setPropInt("@DebugListenerPort", port);
  4694. }
  4695. IStringVal& CLocalWorkUnit::getDebugAgentListenerIP(IStringVal &ip) const
  4696. {
  4697. CriticalBlock block(crit);
  4698. ip.set(p->queryProp("@DebugListenerIP"));
  4699. return ip;
  4700. }
  4701. void CLocalWorkUnit::setDebugAgentListenerIP(const char * ip)
  4702. {
  4703. CriticalBlock block(crit);
  4704. p->setProp("@DebugListenerIP", ip);
  4705. }
  4706. IStringVal& CLocalWorkUnit::getSecurityToken(IStringVal &str) const
  4707. {
  4708. CriticalBlock block(crit);
  4709. str.set(p->queryProp("@token"));
  4710. return str;
  4711. }
  4712. void CLocalWorkUnit::setSecurityToken(const char *value)
  4713. {
  4714. CriticalBlock block(crit);
  4715. p->setProp("@token", value);
  4716. }
  4717. bool CLocalWorkUnit::getRunningGraph(IStringVal &graphName, WUGraphIDType &subId) const
  4718. {
  4719. // Only implemented in derived classes
  4720. return false;
  4721. }
  4722. void CLocalWorkUnit::setJobName(const char *value)
  4723. {
  4724. CriticalBlock block(crit);
  4725. p->setProp("@jobName", value);
  4726. }
  4727. const char *CLocalWorkUnit::queryJobName() const
  4728. {
  4729. CriticalBlock block(crit);
  4730. const char *ret = p->queryProp("@jobName");
  4731. if (!ret)
  4732. ret = "";
  4733. return ret;
  4734. }
  4735. void CLocalWorkUnit::setClusterName(const char *value)
  4736. {
  4737. CriticalBlock block(crit);
  4738. p->setProp("@clusterName", value);
  4739. }
  4740. const char *CLocalWorkUnit::queryClusterName() const
  4741. {
  4742. CriticalBlock block(crit);
  4743. const char *ret = p->queryProp("@clusterName");
  4744. if (!ret)
  4745. ret = "";
  4746. return ret;
  4747. }
  4748. void CLocalWorkUnit::setAllowedClusters(const char *value)
  4749. {
  4750. setDebugValue("allowedclusters",value, true);
  4751. }
  4752. IStringVal& CLocalWorkUnit::getAllowedClusters(IStringVal &str) const
  4753. {
  4754. CriticalBlock block(crit);
  4755. getDebugValue("allowedclusters",str);
  4756. if (str.length()!=0)
  4757. return str;
  4758. str.set(p->queryProp("@clusterName"));
  4759. return str;
  4760. }
  4761. void CLocalWorkUnit::setAllowAutoQueueSwitch(bool val)
  4762. {
  4763. setDebugValueInt("allowautoqueueswitch",val?1:0,true);
  4764. }
  4765. bool CLocalWorkUnit::getAllowAutoQueueSwitch() const
  4766. {
  4767. CriticalBlock block(crit);
  4768. return getDebugValueBool("allowautoqueueswitch",false);
  4769. }
  4770. void CLocalWorkUnit::setLibraryInformation(const char * name, unsigned interfaceHash, unsigned definitionHash)
  4771. {
  4772. StringBuffer suffix;
  4773. if (name && *name)
  4774. setApplicationValue("LibraryModule", "name", name, true);
  4775. setApplicationValueInt("LibraryModule", "interfaceHash", interfaceHash, true);
  4776. setApplicationValueInt("LibraryModule", "definitionHash", definitionHash, true);
  4777. setApplicationValue("LibraryModule", "platform", appendLibrarySuffix(suffix).str(), true);
  4778. }
  4779. void CLocalWorkUnit::remoteCheckAccess(IUserDescriptor *user, bool writeaccess) const
  4780. {
  4781. unsigned auditflags = DALI_LDAP_AUDIT_REPORT|DALI_LDAP_READ_WANTED;
  4782. if (writeaccess)
  4783. auditflags |= DALI_LDAP_WRITE_WANTED;
  4784. SecAccessFlags perm = SecAccess_Full;
  4785. const char *scopename = p->queryProp("@scope");
  4786. if (scopename&&*scopename) {
  4787. if (!user)
  4788. user = queryUserDescriptor();
  4789. perm = querySessionManager().getPermissionsLDAP("workunit",scopename,user,auditflags);
  4790. if (perm<0) {
  4791. if (perm == SecAccess_Unavailable)
  4792. perm = SecAccess_Full;
  4793. else
  4794. perm = SecAccess_None;
  4795. }
  4796. }
  4797. if (!HASREADPERMISSION(perm))
  4798. throw MakeStringException(WUERR_WorkunitAccessDenied, "Read access denied for workunit %s", queryWuid());
  4799. if (writeaccess && !HASWRITEPERMISSION(perm))
  4800. throw MakeStringException(WUERR_WorkunitAccessDenied, "Write access denied for workunit %s", queryWuid());
  4801. }
  4802. void CLocalWorkUnit::setUser(const char * value)
  4803. {
  4804. CriticalBlock block(crit);
  4805. p->setProp("@submitID", value);
  4806. }
  4807. const char *CLocalWorkUnit::queryUser() const
  4808. {
  4809. CriticalBlock block(crit);
  4810. const char *ret = p->queryProp("@submitID");
  4811. if (!ret)
  4812. ret = "";
  4813. return ret;
  4814. }
  4815. void CLocalWorkUnit::setWuScope(const char * value)
  4816. {
  4817. if (value && *value)
  4818. {
  4819. if (checkWuScopeSecAccess(value, secMgr.get(), secUser.get(), SecAccess_Write, "Change Scope", true, true))
  4820. {
  4821. CriticalBlock block(crit);
  4822. p->setProp("@scope", value);
  4823. }
  4824. }
  4825. }
  4826. const char *CLocalWorkUnit::queryWuScope() const
  4827. {
  4828. CriticalBlock block(crit);
  4829. const char *ret = p->queryProp("@scope");
  4830. if (!ret)
  4831. ret = "";
  4832. return ret;
  4833. }
  4834. void CLocalWorkUnit::setPriority(WUPriorityClass cls)
  4835. {
  4836. CriticalBlock block(crit);
  4837. setEnum(p, "@priorityClass", cls, priorityClasses);
  4838. }
  4839. WUPriorityClass CLocalWorkUnit::getPriority() const
  4840. {
  4841. CriticalBlock block(crit);
  4842. return (WUPriorityClass) getEnum(p, "@priorityClass", priorityClasses);
  4843. }
  4844. const char *CLocalWorkUnit::queryPriorityDesc() const
  4845. {
  4846. return getEnumText(getPriority(), priorityClasses);
  4847. }
  4848. void CLocalWorkUnit::setState(WUState value)
  4849. {
  4850. if (value==WUStateAborted || value==WUStatePaused || value==WUStateCompleted || value==WUStateFailed || value==WUStateSubmitted || value==WUStateWait)
  4851. {
  4852. if (factory)
  4853. factory->clearAborting(queryWuid());
  4854. }
  4855. CriticalBlock block(crit);
  4856. setEnum(p, "@state", value, states); // For historical reasons, we use state to store the state
  4857. setEnum(p, "State", value, states); // But we can only subscribe to elements, not attributes
  4858. if (getDebugValueBool("monitorWorkunit", false))
  4859. {
  4860. switch(value)
  4861. {
  4862. case WUStateAborted:
  4863. FLLOG(MCoperatorWarning, "Workunit %s aborted", p->queryName());
  4864. break;
  4865. case WUStateCompleted:
  4866. FLLOG(MCoperatorProgress, "Workunit %s completed", p->queryName());
  4867. break;
  4868. case WUStateFailed:
  4869. FLLOG(MCoperatorProgress, "Workunit %s failed", p->queryName());
  4870. break;
  4871. }
  4872. }
  4873. p->removeProp("@stateEx");
  4874. }
  4875. void CLocalWorkUnit::setStateEx(const char * text)
  4876. {
  4877. CriticalBlock block(crit);
  4878. p->setProp("@stateEx", text);
  4879. }
  4880. void CLocalWorkUnit::setAgentSession(__int64 sessionId)
  4881. {
  4882. CriticalBlock block(crit);
  4883. p->setPropInt64("@agentSession", sessionId);
  4884. }
  4885. bool CLocalWorkUnit::getIsQueryService() const
  4886. {
  4887. CriticalBlock block(crit);
  4888. return p->getPropBool("@isQueryService", false);
  4889. }
  4890. void CLocalWorkUnit::setIsQueryService(bool value)
  4891. {
  4892. CriticalBlock block(crit);
  4893. p->setPropBool("@isQueryService", value);
  4894. }
  4895. void CLocalWorkUnit::checkAgentRunning(WUState & state)
  4896. {
  4897. if (queryDaliServerVersion().compare("2.1")<0)
  4898. return;
  4899. switch(state)
  4900. {
  4901. case WUStateRunning:
  4902. case WUStateDebugPaused:
  4903. case WUStateDebugRunning:
  4904. case WUStateBlocked:
  4905. case WUStateAborting:
  4906. case WUStateCompiling:
  4907. case WUStatePaused:
  4908. {
  4909. SessionId agent = getAgentSession();
  4910. if((agent>0) && querySessionManager().sessionStopped(agent, 0))
  4911. {
  4912. forceReload();
  4913. state = (WUState) getEnum(p, "@state", states);
  4914. bool isecl=state==WUStateCompiling;
  4915. if (aborting())
  4916. state = WUStateAborted;
  4917. else if (state==WUStateRunning || state==WUStatePaused || state==WUStateDebugPaused || state==WUStateDebugRunning || state==WUStateBlocked || state==WUStateCompiling)
  4918. state = WUStateFailed;
  4919. else
  4920. return;
  4921. WARNLOG("checkAgentRunning terminated: %" I64F "d state = %d",(__int64)agent,(int)state);
  4922. Owned<IWorkUnit> w = &lock();
  4923. w->setState(state);
  4924. Owned<IWUException> e = w->createException();
  4925. WUAction action = w->getAction();
  4926. switch (action)
  4927. {
  4928. case WUActionPause:
  4929. case WUActionPauseNow:
  4930. case WUActionResume:
  4931. w->setAction(WUActionUnknown);
  4932. }
  4933. if(isecl)
  4934. {
  4935. e->setExceptionCode(1001);
  4936. e->setExceptionMessage("EclServer terminated unexpectedly");
  4937. }
  4938. else
  4939. {
  4940. e->setExceptionCode(1000);
  4941. e->setExceptionMessage("Workunit terminated unexpectedly");
  4942. }
  4943. }
  4944. }
  4945. }
  4946. }
  4947. WUState CLocalWorkUnit::getState() const
  4948. {
  4949. CriticalBlock block(crit);
  4950. WUState state = (WUState) getEnum(p, "@state", states);
  4951. switch (state)
  4952. {
  4953. case WUStateRunning:
  4954. case WUStateDebugPaused:
  4955. case WUStateDebugRunning:
  4956. case WUStateBlocked:
  4957. case WUStateCompiling:
  4958. if (aborting())
  4959. state = WUStateAborting;
  4960. break;
  4961. case WUStateSubmitted:
  4962. if (aborting())
  4963. state = WUStateAborted;
  4964. break;
  4965. }
  4966. const_cast<CLocalWorkUnit *>(this)->checkAgentRunning(state); //need const_cast as will change state if agent has died
  4967. return state;
  4968. }
  4969. IStringVal& CLocalWorkUnit::getStateEx(IStringVal & str) const
  4970. {
  4971. CriticalBlock block(crit);
  4972. str.set(p->queryProp("@stateEx"));
  4973. return str;
  4974. }
  4975. __int64 CLocalWorkUnit::getAgentSession() const
  4976. {
  4977. CriticalBlock block(crit);
  4978. return p->getPropInt64("@agentSession", -1);
  4979. }
  4980. unsigned CLocalWorkUnit::getAgentPID() const
  4981. {
  4982. CriticalBlock block(crit);
  4983. return p->getPropInt("@agentPID", -1);
  4984. }
  4985. const char * CLocalWorkUnit::queryStateDesc() const
  4986. {
  4987. // MORE - not sure about this - may prefer a separate interface
  4988. CriticalBlock block(crit);
  4989. try
  4990. {
  4991. return getEnumText(getState(), states);
  4992. }
  4993. catch (...)
  4994. {
  4995. return "???";
  4996. }
  4997. }
  4998. void CLocalWorkUnit::setAction(WUAction value)
  4999. {
  5000. CriticalBlock block(crit);
  5001. setEnum(p, "Action", value, actions);
  5002. }
  5003. WUAction CLocalWorkUnit::getAction() const
  5004. {
  5005. CriticalBlock block(crit);
  5006. return (WUAction) getEnum(p, "Action", actions);
  5007. }
  5008. const char *CLocalWorkUnit::queryActionDesc() const
  5009. {
  5010. CriticalBlock block(crit);
  5011. return p->queryProp("Action");
  5012. }
  5013. IStringVal& CLocalWorkUnit::getApplicationValue(const char *app, const char *propname, IStringVal &str) const
  5014. {
  5015. CriticalBlock block(crit);
  5016. StringBuffer prop("Application/");
  5017. prop.append(app).append('/').append(propname);
  5018. str.set(p->queryProp(prop.str()));
  5019. return str;
  5020. }
  5021. int CLocalWorkUnit::getApplicationValueInt(const char *app, const char *propname, int defVal) const
  5022. {
  5023. CriticalBlock block(crit);
  5024. StringBuffer prop("Application/");
  5025. prop.append(app).append('/').append(propname);
  5026. return p->getPropInt(prop.str(), defVal);
  5027. }
  5028. IConstWUAppValueIterator& CLocalWorkUnit::getApplicationValues() const
  5029. {
  5030. CriticalBlock block(crit);
  5031. appvalues.load(p,"Application/*");
  5032. return *new CArrayIteratorOf<IConstWUAppValue,IConstWUAppValueIterator> (appvalues, 0, (IConstWorkUnit *) this);
  5033. }
  5034. void CLocalWorkUnit::setApplicationValue(const char *app, const char *propname, const char *value, bool overwrite)
  5035. {
  5036. CriticalBlock block(crit);
  5037. StringBuffer prop("Application/");
  5038. prop.append(app).append('/').append(propname);
  5039. if (overwrite || !p->hasProp(prop.str()))
  5040. {
  5041. StringBuffer sp;
  5042. p->setProp(sp.append("Application").str(), "");
  5043. p->setProp(sp.append('/').append(app).str(), "");
  5044. p->setProp(prop.str(), value);
  5045. }
  5046. }
  5047. void CLocalWorkUnit::setApplicationValueInt(const char *app, const char *propname, int value, bool overwrite)
  5048. {
  5049. VStringBuffer s("%d", value);
  5050. setApplicationValue(app, propname, s, overwrite);
  5051. }
  5052. void CLocalWorkUnit::setPriorityLevel(int level)
  5053. {
  5054. CriticalBlock block(crit);
  5055. p->setPropInt("PriorityFlag", level);
  5056. }
  5057. int CLocalWorkUnit::getPriorityLevel() const
  5058. {
  5059. CriticalBlock block(crit);
  5060. return p->getPropInt("PriorityFlag");
  5061. }
  5062. int calcPriorityValue(const IPropertyTree * p)
  5063. {
  5064. int priority = p->getPropInt("PriorityFlag");
  5065. switch((WUPriorityClass) getEnum(p, "@priorityClass", priorityClasses))
  5066. {
  5067. case PriorityClassLow:
  5068. priority -= 100;
  5069. break;
  5070. case PriorityClassHigh:
  5071. priority += 100;
  5072. break;
  5073. }
  5074. return priority;
  5075. }
  5076. int CLocalWorkUnit::getPriorityValue() const
  5077. {
  5078. CriticalBlock block(crit);
  5079. return calcPriorityValue(p);
  5080. }
  5081. void CLocalWorkUnit::setRescheduleFlag(bool value)
  5082. {
  5083. CriticalBlock block(crit);
  5084. p->setPropInt("RescheduleFlag", (int) value);
  5085. }
  5086. bool CLocalWorkUnit::getRescheduleFlag() const
  5087. {
  5088. CriticalBlock block(crit);
  5089. return p->getPropInt("RescheduleFlag") != 0;
  5090. }
  5091. class NullIStringIterator : implements IStringIterator, public CInterface
  5092. {
  5093. public:
  5094. IMPLEMENT_IINTERFACE;
  5095. bool first() { return false; }
  5096. bool next() { return false; }
  5097. bool isValid() { return false; }
  5098. IStringVal & str(IStringVal & str) { return str; }
  5099. };
  5100. ClusterType getClusterType(const char * platform, ClusterType dft)
  5101. {
  5102. if (stricmp(platform, "thor") == 0)
  5103. return ThorLCRCluster;
  5104. if (stricmp(platform, "thorlcr") == 0)
  5105. return ThorLCRCluster;
  5106. if (stricmp(platform, "hthor") == 0)
  5107. return HThorCluster;
  5108. if (stricmp(platform, "roxie") == 0)
  5109. return RoxieCluster;
  5110. return dft;
  5111. }
  5112. const char *clusterTypeString(ClusterType clusterType, bool lcrSensitive)
  5113. {
  5114. switch (clusterType)
  5115. {
  5116. case ThorLCRCluster:
  5117. if (lcrSensitive)
  5118. return "thorlcr";
  5119. return "thor";
  5120. case RoxieCluster:
  5121. return "roxie";
  5122. case HThorCluster:
  5123. return "hthor";
  5124. }
  5125. throwUnexpected();
  5126. }
  5127. IPropertyTree *queryRoxieProcessTree(IPropertyTree *environment, const char *process)
  5128. {
  5129. if (!process || !*process)
  5130. return NULL;
  5131. VStringBuffer xpath("Software/RoxieCluster[@name=\"%s\"]", process);
  5132. return environment->queryPropTree(xpath.str());
  5133. }
  5134. void getRoxieProcessServers(IPropertyTree *roxie, SocketEndpointArray &endpoints)
  5135. {
  5136. if (!roxie)
  5137. return;
  5138. Owned<IPropertyTreeIterator> servers = roxie->getElements("RoxieServerProcess");
  5139. ForEach(*servers)
  5140. {
  5141. IPropertyTree &server = servers->query();
  5142. const char *netAddress = server.queryProp("@netAddress");
  5143. if (netAddress && *netAddress)
  5144. {
  5145. SocketEndpoint ep(netAddress, server.getPropInt("@port", 9876));
  5146. endpoints.append(ep);
  5147. }
  5148. }
  5149. }
  5150. void getRoxieProcessServers(const char *process, SocketEndpointArray &servers)
  5151. {
  5152. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  5153. Owned<IConstEnvironment> env = factory->openEnvironment();
  5154. if (!env)
  5155. return;
  5156. Owned<IPropertyTree> root = &env->getPTree();
  5157. getRoxieProcessServers(queryRoxieProcessTree(root, process), servers);
  5158. }
  5159. class CEnvironmentClusterInfo: implements IConstWUClusterInfo, public CInterface
  5160. {
  5161. StringAttr name;
  5162. StringAttr alias;
  5163. StringAttr serverQueue;
  5164. StringAttr agentQueue;
  5165. StringAttr roxieProcess;
  5166. SocketEndpointArray roxieServers;
  5167. StringAttr thorQueue;
  5168. StringArray thorProcesses;
  5169. StringArray primaryThorProcesses;
  5170. StringAttr prefix;
  5171. StringAttr ldapUser;
  5172. StringBuffer ldapPassword;
  5173. ClusterType platform;
  5174. unsigned clusterWidth;
  5175. unsigned roxieRedundancy;
  5176. unsigned channelsPerNode;
  5177. unsigned numberOfSlaveLogs;
  5178. int roxieReplicateOffset;
  5179. public:
  5180. IMPLEMENT_IINTERFACE;
  5181. CEnvironmentClusterInfo(const char *_name, const char *_prefix, const char *_alias, IPropertyTree *agent, IArrayOf<IPropertyTree> &thors, IPropertyTree *roxie)
  5182. : name(_name), prefix(_prefix), alias(_alias), roxieRedundancy(0), channelsPerNode(0), numberOfSlaveLogs(0), roxieReplicateOffset(1)
  5183. {
  5184. StringBuffer queue;
  5185. if (thors.ordinality())
  5186. {
  5187. thorQueue.set(getClusterThorQueueName(queue.clear(), name));
  5188. clusterWidth = 0;
  5189. bool isMultiThor = (thors.length() > 1);
  5190. ForEachItemIn(i,thors)
  5191. {
  5192. IPropertyTree &thor = thors.item(i);
  5193. const char* thorName = thor.queryProp("@name");
  5194. thorProcesses.append(thorName);
  5195. if (!isMultiThor)
  5196. primaryThorProcesses.append(thorName);
  5197. else
  5198. {
  5199. const char *nodeGroup = thor.queryProp("@nodeGroup");
  5200. if (!nodeGroup || strieq(nodeGroup, thorName))
  5201. primaryThorProcesses.append(thorName);
  5202. }
  5203. unsigned nodes = thor.getCount("ThorSlaveProcess");
  5204. if (!nodes)
  5205. throw MakeStringException(WUERR_MismatchClusterSize,"CEnvironmentClusterInfo: Thor cluster can not have 0 slave processes");
  5206. unsigned slavesPerNode = thor.getPropInt("@slavesPerNode", 1);
  5207. unsigned channelsPerSlave = thor.getPropInt("@channelsPerSlave", 1);
  5208. unsigned ts = nodes * slavesPerNode * channelsPerSlave;
  5209. numberOfSlaveLogs = nodes * slavesPerNode;
  5210. if (clusterWidth && (ts!=clusterWidth))
  5211. throw MakeStringException(WUERR_MismatchClusterSize,"CEnvironmentClusterInfo: mismatched thor sizes in cluster");
  5212. clusterWidth = ts;
  5213. bool islcr = !thor.getPropBool("@Legacy");
  5214. if (!islcr)
  5215. throw MakeStringException(WUERR_MismatchThorType,"CEnvironmentClusterInfo: Legacy Thor no longer supported");
  5216. }
  5217. platform = ThorLCRCluster;
  5218. }
  5219. else if (roxie)
  5220. {
  5221. roxieProcess.set(roxie->queryProp("@name"));
  5222. platform = RoxieCluster;
  5223. getRoxieProcessServers(roxie, roxieServers);
  5224. clusterWidth = roxieServers.length();
  5225. ldapUser.set(roxie->queryProp("@ldapUser"));
  5226. StringBuffer encPassword = roxie->queryProp("@ldapPassword");
  5227. if (encPassword.length())
  5228. decrypt(ldapPassword, encPassword);
  5229. const char *redundancyMode = roxie->queryProp("@slaveConfig");
  5230. if (redundancyMode && *redundancyMode)
  5231. {
  5232. unsigned dataCopies = roxie->getPropInt("@numDataCopies", 1);
  5233. if (strieq(redundancyMode, "overloaded"))
  5234. channelsPerNode = roxie->getPropInt("@channelsPernode", 1);
  5235. else if (strieq(redundancyMode, "full redundancy"))
  5236. {
  5237. roxieRedundancy = dataCopies-1;
  5238. roxieReplicateOffset = 0;
  5239. }
  5240. else if (strieq(redundancyMode, "cyclic redundancy"))
  5241. {
  5242. roxieRedundancy = dataCopies-1;
  5243. channelsPerNode = dataCopies;
  5244. roxieReplicateOffset = roxie->getPropInt("@cyclicOffset", 1);
  5245. }
  5246. }
  5247. }
  5248. else
  5249. {
  5250. clusterWidth = 1;
  5251. platform = HThorCluster;
  5252. }
  5253. if (agent)
  5254. {
  5255. assertex(!roxie);
  5256. agentQueue.set(getClusterEclAgentQueueName(queue.clear(), name));
  5257. }
  5258. else if (roxie)
  5259. agentQueue.set(getClusterRoxieQueueName(queue.clear(), name));
  5260. // MORE - does this need to be conditional?
  5261. serverQueue.set(getClusterEclCCServerQueueName(queue.clear(), name));
  5262. }
  5263. IStringVal & getName(IStringVal & str) const
  5264. {
  5265. str.set(name.get());
  5266. return str;
  5267. }
  5268. const char *getAlias() const
  5269. {
  5270. return alias;
  5271. }
  5272. IStringVal & getScope(IStringVal & str) const
  5273. {
  5274. str.set(prefix.get());
  5275. return str;
  5276. }
  5277. IStringVal & getAgentQueue(IStringVal & str) const
  5278. {
  5279. str.set(agentQueue);
  5280. return str;
  5281. }
  5282. virtual IStringVal & getServerQueue(IStringVal & str) const
  5283. {
  5284. str.set(serverQueue);
  5285. return str;
  5286. }
  5287. IStringVal & getThorQueue(IStringVal & str) const
  5288. {
  5289. str.set(thorQueue);
  5290. return str;
  5291. }
  5292. unsigned getSize() const
  5293. {
  5294. return clusterWidth;
  5295. }
  5296. unsigned getNumberOfSlaveLogs() const
  5297. {
  5298. return numberOfSlaveLogs;
  5299. }
  5300. virtual ClusterType getPlatform() const
  5301. {
  5302. return platform;
  5303. }
  5304. IStringVal & getRoxieProcess(IStringVal & str) const
  5305. {
  5306. str.set(roxieProcess.get());
  5307. return str;
  5308. }
  5309. const StringArray & getThorProcesses() const
  5310. {
  5311. return thorProcesses;
  5312. }
  5313. const StringArray & getPrimaryThorProcesses() const
  5314. {
  5315. return primaryThorProcesses;
  5316. }
  5317. const SocketEndpointArray & getRoxieServers() const
  5318. {
  5319. return roxieServers;
  5320. }
  5321. unsigned getRoxieRedundancy() const
  5322. {
  5323. return roxieRedundancy;
  5324. }
  5325. unsigned getChannelsPerNode() const
  5326. {
  5327. return channelsPerNode;
  5328. }
  5329. int getRoxieReplicateOffset() const
  5330. {
  5331. return roxieReplicateOffset;
  5332. }
  5333. const char *getLdapUser() const
  5334. {
  5335. return ldapUser.get();
  5336. }
  5337. virtual const char *getLdapPassword() const
  5338. {
  5339. return ldapPassword.str();
  5340. }
  5341. };
  5342. IStringVal &getProcessQueueNames(IStringVal &ret, const char *process, const char *type, const char *suffix)
  5343. {
  5344. if (process)
  5345. {
  5346. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  5347. Owned<IConstEnvironment> env = factory->openEnvironment();
  5348. if (env)
  5349. {
  5350. Owned<IPropertyTree> root = &env->getPTree();
  5351. StringBuffer queueNames;
  5352. StringBuffer xpath;
  5353. xpath.appendf("%s[@process=\"%s\"]", type, process);
  5354. Owned<IPropertyTreeIterator> targets = root->getElements("Software/Topology/Cluster");
  5355. ForEach(*targets)
  5356. {
  5357. IPropertyTree &target = targets->query();
  5358. if (target.hasProp(xpath))
  5359. {
  5360. if (queueNames.length())
  5361. queueNames.append(',');
  5362. queueNames.append(target.queryProp("@name")).append(suffix);
  5363. }
  5364. }
  5365. ret.set(queueNames);
  5366. }
  5367. }
  5368. return ret;
  5369. }
  5370. #define ROXIE_QUEUE_EXT ".roxie"
  5371. #define THOR_QUEUE_EXT ".thor"
  5372. #define ECLCCSERVER_QUEUE_EXT ".eclserver"
  5373. #define ECLSERVER_QUEUE_EXT ECLCCSERVER_QUEUE_EXT
  5374. #define ECLSCHEDULER_QUEUE_EXT ".eclscheduler"
  5375. #define ECLAGENT_QUEUE_EXT ".agent"
  5376. extern WORKUNIT_API void getDFUServerQueueNames(StringArray &ret, const char *process)
  5377. {
  5378. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  5379. Owned<IConstEnvironment> env = factory->openEnvironment();
  5380. if (!env)
  5381. return;
  5382. StringBuffer xpath = "Software/DfuServerProcess";
  5383. if (!isEmptyString(process))
  5384. xpath.appendf("[@name=\"%s\"]", process);
  5385. Owned<IPropertyTree> root = &env->getPTree();
  5386. Owned<IPropertyTreeIterator> targets = root->getElements(xpath.str());
  5387. ForEach(*targets)
  5388. {
  5389. IPropertyTree &target = targets->query();
  5390. if (target.hasProp("@queue"))
  5391. ret.appendListUniq(target.queryProp("@queue"), ",");
  5392. }
  5393. return;
  5394. }
  5395. extern WORKUNIT_API IStringVal &getEclCCServerQueueNames(IStringVal &ret, const char *process)
  5396. {
  5397. return getProcessQueueNames(ret, process, "EclCCServerProcess", ECLCCSERVER_QUEUE_EXT);
  5398. }
  5399. extern WORKUNIT_API IStringVal &getEclServerQueueNames(IStringVal &ret, const char *process)
  5400. {
  5401. return getProcessQueueNames(ret, process, "EclServerProcess", ECLSERVER_QUEUE_EXT); // shares queue name with EclCCServer
  5402. }
  5403. extern WORKUNIT_API IStringVal &getEclSchedulerQueueNames(IStringVal &ret, const char *process)
  5404. {
  5405. return getProcessQueueNames(ret, process, "EclSchedulerProcess", ECLSCHEDULER_QUEUE_EXT); // Shares deployment/config with EclCCServer
  5406. }
  5407. extern WORKUNIT_API IStringVal &getAgentQueueNames(IStringVal &ret, const char *process)
  5408. {
  5409. return getProcessQueueNames(ret, process, "EclAgentProcess", ECLAGENT_QUEUE_EXT);
  5410. }
  5411. extern WORKUNIT_API IStringVal &getRoxieQueueNames(IStringVal &ret, const char *process)
  5412. {
  5413. return getProcessQueueNames(ret, process, "RoxieCluster", ROXIE_QUEUE_EXT);
  5414. }
  5415. extern WORKUNIT_API IStringVal &getThorQueueNames(IStringVal &ret, const char *process)
  5416. {
  5417. return getProcessQueueNames(ret, process, "ThorCluster", THOR_QUEUE_EXT);
  5418. }
  5419. extern WORKUNIT_API StringBuffer &getClusterThorQueueName(StringBuffer &ret, const char *cluster)
  5420. {
  5421. return ret.append(cluster).append(THOR_QUEUE_EXT);
  5422. }
  5423. extern WORKUNIT_API StringBuffer &getClusterThorGroupName(StringBuffer &ret, const char *cluster)
  5424. {
  5425. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  5426. Owned<IConstEnvironment> env = factory->openEnvironment();
  5427. if (env)
  5428. {
  5429. Owned<IPropertyTree> root = &env->getPTree();
  5430. StringBuffer path;
  5431. path.append("Software/ThorCluster[@name=\"").append(cluster).append("\"]");
  5432. IPropertyTree * child = root->queryPropTree(path);
  5433. if (child)
  5434. getClusterGroupName(*child, ret);
  5435. }
  5436. return ret;
  5437. }
  5438. extern WORKUNIT_API StringBuffer &getClusterRoxieQueueName(StringBuffer &ret, const char *cluster)
  5439. {
  5440. return ret.append(cluster).append(ROXIE_QUEUE_EXT);
  5441. }
  5442. extern WORKUNIT_API StringBuffer &getClusterEclCCServerQueueName(StringBuffer &ret, const char *cluster)
  5443. {
  5444. return ret.append(cluster).append(ECLCCSERVER_QUEUE_EXT);
  5445. }
  5446. extern WORKUNIT_API StringBuffer &getClusterEclServerQueueName(StringBuffer &ret, const char *cluster)
  5447. {
  5448. return ret.append(cluster).append(ECLSERVER_QUEUE_EXT);
  5449. }
  5450. extern WORKUNIT_API StringBuffer &getClusterEclAgentQueueName(StringBuffer &ret, const char *cluster)
  5451. {
  5452. return ret.append(cluster).append(ECLAGENT_QUEUE_EXT);
  5453. }
  5454. extern WORKUNIT_API IStringIterator *getTargetClusters(const char *processType, const char *processName)
  5455. {
  5456. Owned<CStringArrayIterator> ret = new CStringArrayIterator;
  5457. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  5458. Owned<IConstEnvironment> env = factory->openEnvironment();
  5459. if (env)
  5460. {
  5461. Owned<IPropertyTree> root = &env->getPTree();
  5462. StringBuffer xpath;
  5463. xpath.appendf("%s", processType ? processType : "*");
  5464. if (processName && *processName)
  5465. xpath.appendf("[@process=\"%s\"]", processName);
  5466. Owned<IPropertyTreeIterator> targets = root->getElements("Software/Topology/Cluster");
  5467. ForEach(*targets)
  5468. {
  5469. IPropertyTree &target = targets->query();
  5470. if (target.hasProp(xpath))
  5471. {
  5472. ret->append(target.queryProp("@name"));
  5473. }
  5474. }
  5475. }
  5476. return ret.getClear();
  5477. }
  5478. extern WORKUNIT_API bool isProcessCluster(const char *process)
  5479. {
  5480. if (!process || !*process)
  5481. return false;
  5482. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  5483. Owned<IConstEnvironment> env = factory->openEnvironment();
  5484. if (!env)
  5485. return false;
  5486. Owned<IPropertyTree> root = &env->getPTree();
  5487. VStringBuffer xpath("Software/*Cluster[@name=\"%s\"]", process);
  5488. return root->hasProp(xpath.str());
  5489. }
  5490. extern WORKUNIT_API bool isProcessCluster(const char *remoteDali, const char *process)
  5491. {
  5492. if (!remoteDali || !*remoteDali)
  5493. return isProcessCluster(process);
  5494. if (!process || !*process)
  5495. return false;
  5496. Owned<INode> remote = createINode(remoteDali, 7070);
  5497. if (!remote)
  5498. return false;
  5499. //Cannot use getEnvironmentFactory() since it is using a remotedali
  5500. VStringBuffer xpath("Environment/Software/*Cluster[@name=\"%s\"]/@name", process);
  5501. try
  5502. {
  5503. Owned<IPropertyTreeIterator> clusters = querySDS().getElementsRaw(xpath, remote, 1000*60*1);
  5504. return clusters->first();
  5505. }
  5506. catch (IException *E)
  5507. {
  5508. StringBuffer msg;
  5509. E->errorMessage(msg);
  5510. DBGLOG("Exception validating cluster %s/%s: %s", remoteDali, xpath.str(), msg.str());
  5511. E->Release();
  5512. }
  5513. return true;
  5514. }
  5515. IConstWUClusterInfo* getTargetClusterInfo(IPropertyTree *environment, IPropertyTree *cluster)
  5516. {
  5517. const char *clustname = cluster->queryProp("@name");
  5518. // MORE - at the moment configenf specifies eclagent and thor queues by (in effect) placing an 'example' thor or eclagent in the topology
  5519. // that uses the queue that will be used.
  5520. // We should and I hope will change that, at which point the code below gets simpler
  5521. StringBuffer prefix(cluster->queryProp("@prefix"));
  5522. prefix.toLowerCase();
  5523. StringBuffer xpath;
  5524. StringBuffer querySetName;
  5525. IPropertyTree *agent = NULL;
  5526. const char *agentName = cluster->queryProp("EclAgentProcess/@process");
  5527. if (agentName)
  5528. {
  5529. xpath.clear().appendf("Software/EclAgentProcess[@name=\"%s\"]", agentName);
  5530. agent = environment->queryPropTree(xpath.str());
  5531. }
  5532. Owned<IPropertyTreeIterator> ti = cluster->getElements("ThorCluster");
  5533. IArrayOf<IPropertyTree> thors;
  5534. ForEach(*ti)
  5535. {
  5536. const char *thorName = ti->query().queryProp("@process");
  5537. if (thorName)
  5538. {
  5539. xpath.clear().appendf("Software/ThorCluster[@name=\"%s\"]", thorName);
  5540. thors.append(*environment->getPropTree(xpath.str()));
  5541. }
  5542. }
  5543. const char *roxieName = cluster->queryProp("RoxieCluster/@process");
  5544. return new CEnvironmentClusterInfo(clustname, prefix, cluster->queryProp("@alias"), agent, thors, queryRoxieProcessTree(environment, roxieName));
  5545. }
  5546. IPropertyTree* getTopologyCluster(Owned<IPropertyTree> &envRoot, const char *clustname)
  5547. {
  5548. if (!clustname || !*clustname)
  5549. return NULL;
  5550. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  5551. Owned<IConstEnvironment> env = factory->openEnvironment();
  5552. if (!env)
  5553. return NULL;
  5554. envRoot.setown(&env->getPTree());
  5555. StringBuffer xpath;
  5556. xpath.appendf("Software/Topology/Cluster[@name=\"%s\"]", clustname);
  5557. return envRoot->getPropTree(xpath.str());
  5558. }
  5559. bool validateTargetClusterName(const char *clustname)
  5560. {
  5561. Owned<IPropertyTree> envRoot;
  5562. Owned<IPropertyTree> cluster = getTopologyCluster(envRoot, clustname);
  5563. return (cluster.get()!=NULL);
  5564. }
  5565. IConstWUClusterInfo* getTargetClusterInfo(const char *clustname)
  5566. {
  5567. Owned<IPropertyTree> envRoot;
  5568. Owned<IPropertyTree> cluster = getTopologyCluster(envRoot, clustname);
  5569. if (!cluster)
  5570. return NULL;
  5571. return getTargetClusterInfo(envRoot, cluster);
  5572. }
  5573. unsigned getEnvironmentClusterInfo(CConstWUClusterInfoArray &clusters)
  5574. {
  5575. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  5576. Owned<IConstEnvironment> env = factory->openEnvironment();
  5577. if (!env)
  5578. return 0;
  5579. Owned<IPropertyTree> root = &env->getPTree();
  5580. return getEnvironmentClusterInfo(root, clusters);
  5581. }
  5582. unsigned getEnvironmentClusterInfo(IPropertyTree* environmentRoot, CConstWUClusterInfoArray &clusters)
  5583. {
  5584. if (!environmentRoot)
  5585. return 0;
  5586. Owned<IPropertyTreeIterator> clusterIter = environmentRoot->getElements("Software/Topology/Cluster");
  5587. ForEach(*clusterIter)
  5588. {
  5589. IPropertyTree &node = clusterIter->query();
  5590. Owned<IConstWUClusterInfo> cluster = getTargetClusterInfo(environmentRoot, &node);
  5591. clusters.append(*cluster.getClear());
  5592. }
  5593. return clusters.ordinality();
  5594. }
  5595. const char *getTargetClusterComponentName(const char *clustname, const char *processType, StringBuffer &name)
  5596. {
  5597. if (!clustname)
  5598. return NULL;
  5599. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  5600. Owned<IConstEnvironment> env = factory->openEnvironment();
  5601. if (!env)
  5602. return NULL;
  5603. Owned<IPropertyTree> root = &env->getPTree();
  5604. StringBuffer xpath;
  5605. xpath.appendf("Software/Topology/Cluster[@name=\"%s\"]", clustname);
  5606. Owned<IPropertyTree> cluster = root->getPropTree(xpath.str());
  5607. if (!cluster)
  5608. return NULL;
  5609. StringBuffer xpath1;
  5610. xpath1.appendf("%s/@process", processType);
  5611. name.append(cluster->queryProp(xpath1.str()));
  5612. return name.str();
  5613. }
  5614. unsigned getEnvironmentThorClusterNames(StringArray &thorNames, StringArray &groupNames, StringArray &targetNames, StringArray &queueNames)
  5615. {
  5616. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  5617. Owned<IConstEnvironment> env = factory->openEnvironment();
  5618. if (!env)
  5619. return 0;
  5620. Owned<IPropertyTree> root = &env->getPTree();
  5621. Owned<IPropertyTreeIterator> allTargets = root->getElements("Software/Topology/Cluster");
  5622. ForEach(*allTargets)
  5623. {
  5624. IPropertyTree &target = allTargets->query();
  5625. const char *targetName = target.queryProp("@name");
  5626. if (targetName && *targetName)
  5627. {
  5628. Owned<IPropertyTreeIterator> thorClusters = target.getElements("ThorCluster");
  5629. ForEach(*thorClusters)
  5630. {
  5631. const char *thorName = thorClusters->query().queryProp("@process");
  5632. VStringBuffer query("Software/ThorCluster[@name=\"%s\"]",thorName);
  5633. IPropertyTree *thorCluster = root->queryPropTree(query.str());
  5634. if (thorCluster)
  5635. {
  5636. const char *groupName = thorCluster->queryProp("@nodeGroup");
  5637. if (!groupName||!*groupName)
  5638. groupName = thorName;
  5639. thorNames.append(thorName);
  5640. groupNames.append(groupName);
  5641. targetNames.append(targetName);
  5642. StringBuffer queueName(targetName);
  5643. queueNames.append(queueName.append(THOR_QUEUE_EXT));
  5644. }
  5645. }
  5646. }
  5647. }
  5648. return thorNames.ordinality();
  5649. }
  5650. unsigned getEnvironmentHThorClusterNames(StringArray &eclAgentNames, StringArray &groupNames, StringArray &targetNames)
  5651. {
  5652. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  5653. Owned<IConstEnvironment> env = factory->openEnvironment();
  5654. if (!env)
  5655. return 0;
  5656. Owned<IPropertyTree> root = &env->getPTree();
  5657. Owned<IPropertyTreeIterator> allEclAgents = root->getElements("Software/EclAgentProcess");
  5658. ForEach(*allEclAgents)
  5659. {
  5660. IPropertyTree &eclAgent = allEclAgents->query();
  5661. const char *eclAgentName = eclAgent.queryProp("@name");
  5662. if (eclAgentName && *eclAgentName)
  5663. {
  5664. Owned<IPropertyTreeIterator> allTargets = root->getElements("Software/Topology/Cluster");
  5665. ForEach(*allTargets)
  5666. {
  5667. IPropertyTree &target = allTargets->query();
  5668. const char *targetName = target.queryProp("@name");
  5669. if (targetName && *targetName)
  5670. {
  5671. StringBuffer xpath;
  5672. xpath.appendf("EclAgentProcess[@process=\"%s\"]", eclAgentName);
  5673. if (target.hasProp(xpath) && !target.hasProp("ThorCluster"))
  5674. {
  5675. StringBuffer groupName("hthor__");
  5676. groupName.append(eclAgentName);
  5677. groupNames.append(groupName);
  5678. eclAgentNames.append(eclAgentName);
  5679. targetNames.append(targetName);
  5680. }
  5681. }
  5682. }
  5683. }
  5684. }
  5685. return eclAgentNames.ordinality();
  5686. }
  5687. IStringVal& CLocalWorkUnit::getScope(IStringVal &str) const
  5688. {
  5689. CriticalBlock block(crit);
  5690. if (p->hasProp("Debug/ForceScope"))
  5691. {
  5692. StringBuffer prefix(p->queryProp("Debug/ForceScope"));
  5693. str.set(prefix.toLowerCase().str());
  5694. }
  5695. else
  5696. {
  5697. Owned <IConstWUClusterInfo> ci = getTargetClusterInfo(p->queryProp("@clusterName"));
  5698. if (ci)
  5699. ci->getScope(str);
  5700. else
  5701. str.clear();
  5702. }
  5703. return str;
  5704. }
  5705. //Queries
  5706. void CLocalWorkUnit::setCodeVersion(unsigned codeVersion, const char * buildVersion, const char * eclVersion)
  5707. {
  5708. CriticalBlock block(crit);
  5709. p->setPropInt("@codeVersion", codeVersion);
  5710. p->setProp("@buildVersion", buildVersion);
  5711. p->setProp("@eclVersion", eclVersion);
  5712. }
  5713. unsigned CLocalWorkUnit::getCodeVersion() const
  5714. {
  5715. CriticalBlock block(crit);
  5716. return p->getPropInt("@codeVersion");
  5717. }
  5718. unsigned CLocalWorkUnit::getWuidVersion() const
  5719. {
  5720. CriticalBlock block(crit);
  5721. return p->getPropInt("@wuidVersion");
  5722. }
  5723. void CLocalWorkUnit::getBuildVersion(IStringVal & buildVersion, IStringVal & eclVersion) const
  5724. {
  5725. CriticalBlock block(crit);
  5726. buildVersion.set(p->queryProp("@buildVersion"));
  5727. eclVersion.set(p->queryProp("@eclVersion"));
  5728. }
  5729. void CLocalWorkUnit::setCloneable(bool value)
  5730. {
  5731. CriticalBlock block(crit);
  5732. p->setPropInt("@cloneable", value);
  5733. }
  5734. void CLocalWorkUnit::setIsClone(bool value)
  5735. {
  5736. CriticalBlock block(crit);
  5737. p->setPropInt("@isClone", value);
  5738. }
  5739. bool CLocalWorkUnit::getCloneable() const
  5740. {
  5741. CriticalBlock block(crit);
  5742. return p->getPropBool("@cloneable", false);
  5743. }
  5744. IUserDescriptor *CLocalWorkUnit::queryUserDescriptor() const
  5745. {
  5746. CriticalBlock block(crit);
  5747. if (!userDesc)
  5748. {
  5749. SCMStringBuffer token, user, password;
  5750. getSecurityToken(token);
  5751. extractToken(token.str(), queryWuid(), user, password);
  5752. userDesc.setown(createUserDescriptor());
  5753. userDesc->set(user.str(), password.str());
  5754. }
  5755. return userDesc;
  5756. }
  5757. bool CLocalWorkUnit::isProtected() const
  5758. {
  5759. CriticalBlock block(crit);
  5760. return p->getPropBool("@protected", false);
  5761. }
  5762. bool CLocalWorkUnit::isPausing() const
  5763. {
  5764. CriticalBlock block(crit);
  5765. if (WUActionPause == getAction())
  5766. {
  5767. switch (getState())
  5768. {
  5769. case WUStateRunning:
  5770. case WUStateAborting:
  5771. return true;
  5772. }
  5773. }
  5774. return false;
  5775. }
  5776. void CLocalWorkUnit::protect(bool protectMode)
  5777. {
  5778. CriticalBlock block(crit);
  5779. p->setPropBool("@protected", protectMode);
  5780. }
  5781. void CLocalWorkUnit::setResultLimit(unsigned value)
  5782. {
  5783. CriticalBlock block(crit);
  5784. p->setPropInt("resultLimit", value);
  5785. }
  5786. unsigned CLocalWorkUnit::getResultLimit() const
  5787. {
  5788. CriticalBlock block(crit);
  5789. return p->getPropInt("resultLimit");
  5790. }
  5791. IStringVal & CLocalWorkUnit::getSnapshot(IStringVal & str) const
  5792. {
  5793. CriticalBlock block(crit);
  5794. str.set(p->queryProp("SNAPSHOT"));
  5795. return str;
  5796. }
  5797. void CLocalWorkUnit::setSnapshot(const char * val)
  5798. {
  5799. CriticalBlock block(crit);
  5800. p->setProp("SNAPSHOT", val);
  5801. }
  5802. const static EnumMapping warningSeverityMap[] =
  5803. {
  5804. { SeverityInformation, "info" },
  5805. { SeverityWarning, "warning" },
  5806. { SeverityError, "error" },
  5807. { SeverityAlert, "alert" },
  5808. { SeverityIgnore, "ignore" },
  5809. { SeverityFatal, "fatal" },
  5810. { SeverityUnknown, NULL }
  5811. };
  5812. ErrorSeverity CLocalWorkUnit::getWarningSeverity(unsigned code, ErrorSeverity defaultSeverity) const
  5813. {
  5814. StringBuffer xpath;
  5815. xpath.append("OnWarnings/OnWarning[@code='").append(code).append("']");
  5816. CriticalBlock block(crit);
  5817. IPropertyTree * mapping = p->queryPropTree(xpath);
  5818. if (mapping)
  5819. return (ErrorSeverity) getEnum(mapping, "@severity", warningSeverityMap);
  5820. return defaultSeverity;
  5821. }
  5822. void CLocalWorkUnit::setWarningSeverity(unsigned code, ErrorSeverity severity)
  5823. {
  5824. StringBuffer xpath;
  5825. xpath.append("OnWarnings/OnWarning[@code='").append(code).append("']");
  5826. CriticalBlock block(crit);
  5827. IPropertyTree * mapping = p->queryPropTree(xpath);
  5828. if (!mapping)
  5829. {
  5830. IPropertyTree * onWarnings = ensurePTree(p, "OnWarnings");
  5831. mapping = onWarnings->addPropTree("OnWarning");
  5832. mapping->setPropInt("@code", code);
  5833. }
  5834. setEnum(mapping, "@severity", severity, warningSeverityMap);
  5835. }
  5836. static int comparePropTrees(IInterface * const *ll, IInterface * const *rr)
  5837. {
  5838. IPropertyTree *l = (IPropertyTree *) *ll;
  5839. IPropertyTree *r = (IPropertyTree *) *rr;
  5840. return stricmp(l->queryName(), r->queryName());
  5841. };
  5842. unsigned CLocalWorkUnit::calculateHash(unsigned crc)
  5843. {
  5844. // Any other values in the WU that could affect generated code should be crc'ed here
  5845. IPropertyTree *tree = p->queryBranch("Debug");
  5846. if (tree)
  5847. {
  5848. Owned<IPropertyTreeIterator> sub = tree->getElements("*");
  5849. ICopyArrayOf<IPropertyTree> subs;
  5850. for(sub->first(); sub->isValid(); sub->next())
  5851. subs.append(sub->query());
  5852. subs.sort(comparePropTrees);
  5853. ForEachItemIn(idx, subs)
  5854. {
  5855. const char *name = subs.item(idx).queryName();
  5856. const char *val = subs.item(idx).queryProp(NULL);
  5857. crc = crc32(name, (size32_t)strlen(name), crc);
  5858. if (val)
  5859. crc = crc32(val, (size32_t)strlen(val), crc);
  5860. }
  5861. }
  5862. Owned<IConstWUPluginIterator> plugins = &getPlugins();
  5863. for (plugins->first();plugins->isValid();plugins->next())
  5864. {
  5865. IConstWUPlugin &thisplugin = plugins->query();
  5866. SCMStringBuffer version;
  5867. thisplugin.getPluginVersion(version);
  5868. crc = crc32(version.str(), version.length(), crc);
  5869. }
  5870. return crc;
  5871. }
  5872. static void updateProp(IPropertyTree * to, const IPropertyTree * from, const char * xpath)
  5873. {
  5874. if (!to->hasProp(xpath) && from->hasProp(xpath))
  5875. to->setProp(xpath, from->queryProp(xpath));
  5876. }
  5877. static void setProp(IPropertyTree * to, const IPropertyTree * from, const char * xpath)
  5878. {
  5879. if (from->hasProp(xpath))
  5880. to->setProp(xpath, from->queryProp(xpath));
  5881. }
  5882. static void copyTree(IPropertyTree * to, const IPropertyTree * from, const char * xpath)
  5883. {
  5884. IPropertyTree * match = from->getBranch(xpath);
  5885. if (match)
  5886. to->setPropTree(xpath, match);
  5887. }
  5888. IPropertyTree *CLocalWorkUnit::queryPTree() const
  5889. {
  5890. return p;
  5891. }
  5892. void CLocalWorkUnit::copyWorkUnit(IConstWorkUnit *cached, bool copyStats, bool all)
  5893. {
  5894. CLocalWorkUnit *from = QUERYINTERFACE(cached, CLocalWorkUnit);
  5895. if (!from)
  5896. {
  5897. CLockedWorkUnit *fl = QUERYINTERFACE(cached, CLockedWorkUnit);
  5898. if (!fl)
  5899. throw MakeStringException(WUERR_InternalUnknownImplementation, "Cached workunit not created using workunit dll");
  5900. from = fl->c;
  5901. }
  5902. // Need to copy the query, the results, and the graphs from the cached query.
  5903. // The cache is made before the query is executed so there is no need to clear them.
  5904. if (!cached->getCloneable())
  5905. throw MakeStringException(WUERR_CannotCloneWorkunit, "Source work unit not marked as clonable");
  5906. const IPropertyTree * fromP = from->p;
  5907. IPropertyTree *pt;
  5908. CriticalBlock block(crit);
  5909. clearCached(false);
  5910. query.clear();
  5911. updateProp(p, fromP, "@jobName");
  5912. copyTree(p, fromP, "Query");
  5913. pt = fromP->getBranch("Application/LibraryModule");
  5914. if (pt)
  5915. {
  5916. ensurePTree(p, "Application");
  5917. p->setPropTree("Application/LibraryModule", pt);
  5918. }
  5919. pt = fromP->queryBranch("Debug");
  5920. if (pt)
  5921. {
  5922. IPropertyTree *curDebug = p->queryPropTree("Debug");
  5923. if (curDebug)
  5924. {
  5925. Owned<IPropertyTreeIterator> elems = pt->getElements("*");
  5926. ForEach(*elems)
  5927. {
  5928. IPropertyTree *elem = &elems->query();
  5929. if (!curDebug->hasProp(elem->queryName()))
  5930. curDebug->setPropTree(elem->queryName(),LINK(elem));
  5931. }
  5932. }
  5933. else
  5934. p->setPropTree("Debug", LINK(pt));
  5935. }
  5936. copyTree(p, fromP, "OnWarnings");
  5937. copyTree(p, fromP, "Plugins");
  5938. copyTree(p, fromP, "Libraries");
  5939. copyTree(p, fromP, "Results");
  5940. copyTree(p, fromP, "Graphs");
  5941. copyTree(p, fromP, "Workflow");
  5942. copyTree(p, fromP, "WebServicesInfo");
  5943. if (copyStats)
  5944. {
  5945. // Merge timing info from both branches
  5946. pt = fromP->getBranch("Statistics");
  5947. if (pt)
  5948. {
  5949. IPropertyTree *tgtStatistics = ensurePTree(p, "Statistics");
  5950. mergePTree(tgtStatistics, pt);
  5951. pt->Release();
  5952. }
  5953. }
  5954. updateProp(p, fromP, "@clusterName");
  5955. updateProp(p, fromP, "allowedclusters");
  5956. updateProp(p, fromP, "@submitID");
  5957. updateProp(p, fromP, "SNAPSHOT");
  5958. setProp(p, fromP, "@eventScheduledCount");
  5959. //MORE: This is very adhoc. All options that should be cloned should really be in a common branch
  5960. if (all)
  5961. {
  5962. setProp(p, fromP, "PriorityFlag");
  5963. setProp(p, fromP, "@priorityClass");
  5964. setProp(p, fromP, "@protected");
  5965. setProp(p, fromP, "@clusterName");
  5966. updateProp(p, fromP, "@scope");
  5967. }
  5968. //Variables may have been set up as parameters to the query - so need to preserve any values that were supplied.
  5969. pt = fromP->getBranch("Variables");
  5970. if (pt)
  5971. {
  5972. IPropertyTree *ptTgtVariables = ensurePTree(p, "Variables");
  5973. Owned<IPropertyTreeIterator> ptiVariable = pt->getElements("Variable");
  5974. for (ptiVariable->first(); ptiVariable->isValid(); ptiVariable->next())
  5975. {
  5976. IPropertyTree *ptSrcVariable = &ptiVariable->query();
  5977. const char *name = ptSrcVariable->queryProp("@name");
  5978. assertex(name);
  5979. StringBuffer xpath;
  5980. xpath.append("Variable[@name='").append(name).append("']");
  5981. IPropertyTree *ptTgtVariable = ptTgtVariables->queryPropTree(xpath.str());
  5982. IPropertyTree *merged = createPTreeFromIPT(ptSrcVariable); // clone entire source info...
  5983. merged->removeProp("Value"); // except value and status
  5984. merged->setProp("@status", "undefined");
  5985. if (!merged->getPropBool("@isScalar"))
  5986. merged->removeProp("totalRowCount");
  5987. merged->removeProp("rowCount");
  5988. // If there are any other fields that get set ONLY by eclagent, strip them out here...
  5989. if (ptTgtVariable)
  5990. {
  5991. // copy status and Value from what is already set in target
  5992. merged->setProp("@status", ptTgtVariable->queryProp("@status"));
  5993. MemoryBuffer value;
  5994. if (ptTgtVariable->getPropBin("Value", value))
  5995. merged->setPropBin("Value", value.length(), value.toByteArray());
  5996. ptTgtVariable->removeProp(xpath.str());
  5997. // If there are any other fields in a variable that get set by ws_ecl before submitting, copy them across here...
  5998. }
  5999. ptTgtVariables->addPropTree("Variable", merged);
  6000. }
  6001. pt->Release();
  6002. }
  6003. p->setProp("@codeVersion", fromP->queryProp("@codeVersion"));
  6004. p->setProp("@buildVersion", fromP->queryProp("@buildVersion"));
  6005. p->setProp("@eclVersion", fromP->queryProp("@eclVersion"));
  6006. p->setProp("@hash", fromP->queryProp("@hash"));
  6007. p->setPropBool("@cloneable", true);
  6008. p->setPropBool("@isClone", true);
  6009. resetWorkflow(); // the source Workflow section may have had some parts already executed...
  6010. Owned<IPropertyTreeIterator> results = p->getElements("Results/Result");
  6011. ForEach(*results)
  6012. {
  6013. CLocalWUResult result(LINK(&results->query()));
  6014. result.setResultStatus(ResultStatusUndefined);
  6015. }
  6016. copyTree(p, fromP, "usedsources"); // field usage
  6017. }
  6018. bool CLocalWorkUnit::hasDebugValue(const char *propname) const
  6019. {
  6020. StringBuffer lower;
  6021. lower.append(propname).toLowerCase();
  6022. CriticalBlock block(crit);
  6023. StringBuffer prop("Debug/");
  6024. return p->hasProp(prop.append(lower));
  6025. }
  6026. IStringVal& CLocalWorkUnit::getDebugValue(const char *propname, IStringVal &str) const
  6027. {
  6028. StringBuffer lower;
  6029. lower.append(propname).toLowerCase();
  6030. CriticalBlock block(crit);
  6031. StringBuffer prop("Debug/");
  6032. str.set(p->queryProp(prop.append(lower).str()));
  6033. return str;
  6034. }
  6035. IStringIterator& CLocalWorkUnit::getDebugValues() const
  6036. {
  6037. return getDebugValues(NULL);
  6038. }
  6039. IStringIterator& CLocalWorkUnit::getDebugValues(const char *prop) const
  6040. {
  6041. CriticalBlock block(crit);
  6042. StringBuffer path("Debug/");
  6043. if (prop)
  6044. {
  6045. StringBuffer lower;
  6046. lower.append(prop).toLowerCase();
  6047. path.append(lower);
  6048. }
  6049. else
  6050. path.append("*");
  6051. return *new CStringPTreeTagIterator(p->getElements(path.str()));
  6052. }
  6053. int CLocalWorkUnit::getDebugValueInt(const char *propname, int defVal) const
  6054. {
  6055. StringBuffer lower;
  6056. lower.append(propname).toLowerCase();
  6057. CriticalBlock block(crit);
  6058. StringBuffer prop("Debug/");
  6059. prop.append(lower);
  6060. return p->getPropInt(prop.str(), defVal);
  6061. }
  6062. __int64 CLocalWorkUnit::getDebugValueInt64(const char *propname, __int64 defVal) const
  6063. {
  6064. StringBuffer lower;
  6065. lower.append(propname).toLowerCase();
  6066. CriticalBlock block(crit);
  6067. StringBuffer prop("Debug/");
  6068. prop.append(lower);
  6069. return p->getPropInt64(prop.str(), defVal);
  6070. }
  6071. bool CLocalWorkUnit::getDebugValueBool(const char * propname, bool defVal) const
  6072. {
  6073. StringBuffer lower;
  6074. lower.append(propname).toLowerCase();
  6075. CriticalBlock block(crit);
  6076. StringBuffer prop("Debug/");
  6077. prop.append(lower);
  6078. return p->getPropBool(prop.str(), defVal);
  6079. }
  6080. IStringIterator *CLocalWorkUnit::getLogs(const char *type, const char *instance) const
  6081. {
  6082. VStringBuffer xpath("Process/%s/", type);
  6083. if (instance)
  6084. xpath.append(instance);
  6085. else
  6086. xpath.append("*");
  6087. CriticalBlock block(crit);
  6088. if (p->getPropInt("@wuidVersion") < 1) // legacy wuid
  6089. {
  6090. // NB: instance unused
  6091. if (streq("EclAgent", type))
  6092. return new CStringPTreeIterator(p->getElements("Debug/eclagentlog"));
  6093. else if (streq("Thor", type))
  6094. return new CStringPTreeIterator(p->getElements("Debug/thorlog*"));
  6095. VStringBuffer xpath("Debug/%s", type);
  6096. return new CStringPTreeIterator(p->getElements(xpath.str()));
  6097. }
  6098. else
  6099. return new CStringPTreeAttrIterator(p->getElements(xpath.str()), "@log");
  6100. }
  6101. IPropertyTreeIterator* CLocalWorkUnit::getProcesses(const char *type, const char *instance) const
  6102. {
  6103. VStringBuffer xpath("Process/%s/", type);
  6104. if (instance)
  6105. xpath.append(instance);
  6106. else
  6107. xpath.append("*");
  6108. CriticalBlock block(crit);
  6109. return p->getElements(xpath.str());
  6110. }
  6111. IStringIterator *CLocalWorkUnit::getProcesses(const char *type) const
  6112. {
  6113. VStringBuffer xpath("Process/%s/*", type);
  6114. CriticalBlock block(crit);
  6115. return new CStringPTreeTagIterator(p->getElements(xpath.str()));
  6116. }
  6117. void CLocalWorkUnit::addProcess(const char *type, const char *instance, unsigned pid, const char *log)
  6118. {
  6119. VStringBuffer processType("Process/%s", type);
  6120. VStringBuffer xpath("%s/%s", processType.str(), instance);
  6121. if (log)
  6122. xpath.appendf("[@log=\"%s\"]", log);
  6123. CriticalBlock block(crit);
  6124. if (!p->hasProp(xpath))
  6125. {
  6126. IPropertyTree *node = ensurePTree(p, processType.str());
  6127. node = node->addPropTree(instance);
  6128. node->setProp("@log", log);
  6129. node->setPropInt("@pid", pid);
  6130. }
  6131. }
  6132. void CLocalWorkUnit::setDebugValue(const char *propname, const char *value, bool overwrite)
  6133. {
  6134. StringBuffer lower;
  6135. lower.append(propname).toLowerCase();
  6136. CriticalBlock block(crit);
  6137. StringBuffer prop("Debug/");
  6138. prop.append(lower);
  6139. if (overwrite || !p->hasProp(prop.str()))
  6140. {
  6141. // MORE - not sure this line should be needed....
  6142. p->setProp("Debug", "");
  6143. p->setProp(prop.str(), value);
  6144. }
  6145. }
  6146. void CLocalWorkUnit::setDebugValueInt(const char *propname, int value, bool overwrite)
  6147. {
  6148. StringBuffer lower;
  6149. lower.append(propname).toLowerCase();
  6150. CriticalBlock block(crit);
  6151. StringBuffer prop("Debug/");
  6152. prop.append(lower);
  6153. if (overwrite || !p->hasProp(prop.str()))
  6154. {
  6155. // MORE - not sure this line should be needed....
  6156. p->setProp("Debug", "");
  6157. p->setPropInt(prop.str(), value);
  6158. }
  6159. }
  6160. void CLocalWorkUnit::setTracingValue(const char *propname, const char *value)
  6161. {
  6162. CriticalBlock block(crit);
  6163. // MORE - not sure this line should be needed....
  6164. p->setProp("Tracing", "");
  6165. StringBuffer prop("Tracing/");
  6166. p->setProp(prop.append(propname).str(), value);
  6167. }
  6168. void CLocalWorkUnit::setTracingValueInt(const char *propname, int value)
  6169. {
  6170. CriticalBlock block(crit);
  6171. StringBuffer prop("Tracing/");
  6172. p->setPropInt(prop.append(propname).str(), value);
  6173. }
  6174. void CLocalWorkUnit::setTracingValueInt64(const char *propname, __int64 value)
  6175. {
  6176. CriticalBlock block(crit);
  6177. VStringBuffer prop("Tracing/%s", propname);
  6178. p->setPropInt64(prop.str(), value);
  6179. }
  6180. IConstWUQuery* CLocalWorkUnit::getQuery() const
  6181. {
  6182. // For this to be legally called, we must have the read-able interface. So we are already locked for (at least) read.
  6183. CriticalBlock block(crit);
  6184. if (!query)
  6185. {
  6186. IPropertyTree *s = p->getPropTree("Query");
  6187. if (s)
  6188. query.setown(new CLocalWUQuery(s)); // NB takes ownership of 's'
  6189. }
  6190. return query.getLink();
  6191. }
  6192. IWUQuery* CLocalWorkUnit::updateQuery()
  6193. {
  6194. // For this to be legally called, we must have the write-able interface. So we are already locked for write.
  6195. CriticalBlock block(crit);
  6196. if (!query)
  6197. {
  6198. IPropertyTree *s = p->queryPropTree("Query");
  6199. if (!s)
  6200. s = p->addPropTree("Query", createPTreeFromXMLString("<Query fetchEntire='1'/>")); // Is this really desirable (the fetchEntire) ?
  6201. s->Link();
  6202. query.setown(new CLocalWUQuery(s));
  6203. }
  6204. return query.getLink();
  6205. }
  6206. void CLocalWorkUnit::loadPlugins() const
  6207. {
  6208. CriticalBlock block(crit);
  6209. if (!pluginsCached)
  6210. {
  6211. assertex(plugins.length() == 0);
  6212. Owned<IPropertyTreeIterator> r = p->getElements("Plugins/Plugin");
  6213. for (r->first(); r->isValid(); r->next())
  6214. {
  6215. IPropertyTree *rp = &r->query();
  6216. rp->Link();
  6217. plugins.append(*new CLocalWUPlugin(rp));
  6218. }
  6219. pluginsCached = true;
  6220. }
  6221. }
  6222. IConstWUPluginIterator& CLocalWorkUnit::getPlugins() const
  6223. {
  6224. CriticalBlock block(crit);
  6225. loadPlugins();
  6226. return *new CArrayIteratorOf<IConstWUPlugin,IConstWUPluginIterator> (plugins, 0, (IConstWorkUnit *) this);
  6227. }
  6228. void CLocalWorkUnit::loadLibraries() const
  6229. {
  6230. CriticalBlock block(crit);
  6231. if (!librariesCached)
  6232. {
  6233. assertex(libraries.length() == 0);
  6234. Owned<IPropertyTreeIterator> r = p->getElements("Libraries/Library");
  6235. ForEach(*r)
  6236. {
  6237. IPropertyTree *rp = &r->query();
  6238. rp->Link();
  6239. libraries.append(*new CLocalWULibrary(rp));
  6240. }
  6241. librariesCached = true;
  6242. }
  6243. }
  6244. IConstWULibraryIterator& CLocalWorkUnit::getLibraries() const
  6245. {
  6246. CriticalBlock block(crit);
  6247. loadLibraries();
  6248. return *new CArrayIteratorOf<IConstWULibrary,IConstWULibraryIterator> (libraries, 0, (IConstWorkUnit *) this);
  6249. }
  6250. IConstWULibrary * CLocalWorkUnit::getLibraryByName(const char * search) const
  6251. {
  6252. CriticalBlock block(crit);
  6253. loadLibraries();
  6254. ForEachItemIn(idx, libraries)
  6255. {
  6256. SCMStringBuffer name;
  6257. IConstWULibrary &cur = libraries.item(idx);
  6258. cur.getName(name);
  6259. if (stricmp(name.str(), search)==0)
  6260. return &OLINK(cur);
  6261. }
  6262. return NULL;
  6263. }
  6264. StringBuffer &formatGraphTimerLabel(StringBuffer &str, const char *graphName, unsigned subGraphNum, unsigned __int64 subId)
  6265. {
  6266. str.append("Graph ").append(graphName);
  6267. if (subGraphNum) str.append(" - ").append(subGraphNum).append(" (").append(subId).append(")");
  6268. else if (subId) str.append(" - id(").append(subId).append(")");
  6269. return str;
  6270. }
  6271. StringBuffer &formatGraphTimerScope(StringBuffer &str, const char *graphName, unsigned subGraphNum, unsigned __int64 subId)
  6272. {
  6273. str.append(graphName);
  6274. if (subId) str.append(":sg").append(subId);
  6275. return str;
  6276. }
  6277. bool parseGraphTimerLabel(const char *label, StringAttr &graphName, unsigned & graphNum, unsigned &subGraphNum, unsigned &subId)
  6278. {
  6279. // expects format: "Graph <graphname>[ - <subgraphnum> (<subgraphid>)]"
  6280. unsigned len = (size32_t)strlen(label);
  6281. if (len < 6 || (0 != memcmp(label, "Graph ", 6)))
  6282. return false;
  6283. graphNum = 0;
  6284. subGraphNum = 0;
  6285. subId = 0;
  6286. const char *finger = label+6;
  6287. const char *finger2 = strchr(finger, '-');
  6288. if (NULL == finger2) // just graphName
  6289. graphName.set(finger);
  6290. else
  6291. {
  6292. graphName.set(finger, (size32_t)((finger2-1)-finger));
  6293. finger = finger2+2; // skip '-' and space
  6294. finger2 = strchr(finger, ' ');
  6295. if (finger2)
  6296. {
  6297. subGraphNum = atoi_l(finger, (size32_t)(finger2-finger));
  6298. finger = finger2+2; // skip space and '('
  6299. finger2 = strchr(finger, ')');
  6300. if (finger2)
  6301. subId = atoi_l(finger, (size32_t)(finger2-finger));
  6302. }
  6303. else if (((len-(finger-label))>3) && 0 == memcmp(finger, "id(", 3)) // subgraph id only, new format.
  6304. {
  6305. finger += 3;
  6306. finger2 = strchr(finger, ')');
  6307. if (finger2)
  6308. subId = atoi_l(finger, (size32_t)(finger2-finger));
  6309. }
  6310. }
  6311. if (graphName && !memicmp(graphName, "graph", 5))
  6312. graphNum = atoi(graphName + 5);
  6313. return true;
  6314. }
  6315. bool parseGraphScope(const char *scope, StringAttr &graphName, unsigned & graphNum, unsigned &subGraphId)
  6316. {
  6317. if (!MATCHES_CONST_PREFIX(scope, GraphScopePrefix))
  6318. return false;
  6319. graphNum = atoi(scope + CONST_STRLEN(GraphScopePrefix));
  6320. subGraphId = 0;
  6321. const char * colon = strchr(scope, ':');
  6322. if (!colon)
  6323. {
  6324. graphName.set(scope);
  6325. return true;
  6326. }
  6327. const char * subgraph = colon+1;
  6328. graphName.set(scope, (size32_t)(colon - scope));
  6329. if (MATCHES_CONST_PREFIX(subgraph, SubGraphScopePrefix))
  6330. subGraphId = atoi(subgraph+CONST_STRLEN(SubGraphScopePrefix));
  6331. return true;
  6332. }
  6333. class WorkUnitStatisticsIterator : public CArrayIteratorOf<IConstWUStatistic,IConstWUStatisticIterator>
  6334. {
  6335. typedef CArrayIteratorOf<IConstWUStatistic,IConstWUStatisticIterator> PARENT;
  6336. public:
  6337. WorkUnitStatisticsIterator(const IArray &a, aindex_t start, IInterface *owner, const IStatisticsFilter * _filter)
  6338. : PARENT(a,start, owner), filter(_filter)
  6339. {
  6340. }
  6341. virtual bool first()
  6342. {
  6343. if (!PARENT::first())
  6344. return false;
  6345. if (matchesFilter())
  6346. return true;
  6347. return next();
  6348. }
  6349. virtual bool next()
  6350. {
  6351. for (;;)
  6352. {
  6353. if (!PARENT::next())
  6354. return false;
  6355. if (matchesFilter())
  6356. return true;
  6357. }
  6358. }
  6359. protected:
  6360. bool matchesFilter()
  6361. {
  6362. if (!filter)
  6363. return true;
  6364. return query().matches(filter);
  6365. }
  6366. protected:
  6367. Linked<const IStatisticsFilter> filter;
  6368. };
  6369. void CLocalWorkUnit::setStatistic(StatisticCreatorType creatorType, const char * creator, StatisticScopeType scopeType, const char * scope, StatisticKind kind, const char * optDescription, unsigned __int64 value, unsigned __int64 count, unsigned __int64 maxValue, StatsMergeAction mergeAction)
  6370. {
  6371. if (!scope) scope = GLOBAL_SCOPE;
  6372. const char * kindName = queryStatisticName(kind);
  6373. StatisticMeasure measure = queryMeasure(kind);
  6374. //creator. scope and name must all be present, and must not contain semi colons.
  6375. assertex(creator && scope);
  6376. CriticalBlock block(crit);
  6377. IPropertyTree * stats = p->queryPropTree("Statistics");
  6378. if (!stats)
  6379. stats = p->addPropTree("Statistics");
  6380. IPropertyTree * statTree = NULL;
  6381. if (mergeAction != StatsMergeAppend)
  6382. {
  6383. StringBuffer xpath;
  6384. xpath.append("Statistic[@creator='").append(creator).append("'][@scope='").append(scope).append("'][@kind='").append(kindName).append("']");
  6385. statTree = stats->queryPropTree(xpath.str());
  6386. }
  6387. if (!statTree)
  6388. {
  6389. statTree = stats->addPropTree("Statistic");
  6390. statTree->setProp("@creator", creator);
  6391. statTree->setProp("@scope", scope);
  6392. statTree->setProp("@kind", kindName);
  6393. //These items are primarily here to facilitate filtering.
  6394. statTree->setProp("@unit", queryMeasureName(measure));
  6395. statTree->setProp("@c", queryCreatorTypeName(creatorType));
  6396. statTree->setProp("@s", queryScopeTypeName(scopeType));
  6397. statTree->setPropInt64("@ts", getTimeStampNowValue());
  6398. if (optDescription)
  6399. statTree->setProp("@desc", optDescription);
  6400. if (statistics.cached)
  6401. statistics.append(LINK(statTree));
  6402. mergeAction = StatsMergeAppend;
  6403. }
  6404. if (mergeAction != StatsMergeAppend) // RKC->GH Is this right??
  6405. {
  6406. unsigned __int64 oldValue = statTree->getPropInt64("@value", 0);
  6407. unsigned __int64 oldCount = statTree->getPropInt64("@count", 0);
  6408. unsigned __int64 oldMax = statTree->getPropInt64("@max", 0);
  6409. if (oldMax < oldValue)
  6410. oldMax = oldValue;
  6411. statTree->setPropInt64("@value", mergeStatisticValue(oldValue, value, mergeAction));
  6412. statTree->setPropInt64("@count", count + oldCount);
  6413. if (maxValue > oldMax)
  6414. statTree->setPropInt64("@max", maxValue);
  6415. }
  6416. else
  6417. {
  6418. statTree->setPropInt64("@value", value);
  6419. statTree->setPropInt64("@count", count);
  6420. if (maxValue)
  6421. statTree->setPropInt64("@max", maxValue);
  6422. else
  6423. statTree->removeProp("@max");
  6424. }
  6425. if (creatorType==SCTsummary && kind==StTimeElapsed && isGlobalScope(scope))
  6426. {
  6427. StringBuffer t;
  6428. formatTimeCollatable(t, value, false);
  6429. p->setProp("@totalThorTime", t);
  6430. }
  6431. }
  6432. void CLocalWorkUnit::_loadStatistics() const
  6433. {
  6434. statistics.load(p,"Statistics/*");
  6435. }
  6436. IConstWUStatisticIterator& CLocalWorkUnit::getStatistics(const IStatisticsFilter * filter) const
  6437. {
  6438. CriticalBlock block(crit);
  6439. statistics.loadBranch(p,"Statistics");
  6440. Owned<IConstWUStatisticIterator> localStats = new WorkUnitStatisticsIterator(statistics, 0, (IConstWorkUnit *) this, filter);
  6441. if (filter && !filter->recurseChildScopes(SSTgraph, nullptr))
  6442. return *localStats.getClear();
  6443. const char * wuid = p->queryName();
  6444. Owned<IConstWUStatisticIterator> graphStats = new CConstGraphProgressStatisticsIterator(wuid, filter);
  6445. return * new CCompoundIteratorOf<IConstWUStatisticIterator, IConstWUStatistic>(localStats, graphStats);
  6446. }
  6447. IConstWUStatistic * CLocalWorkUnit::getStatistic(const char * creator, const char * scope, StatisticKind kind) const
  6448. {
  6449. //MORE: Optimize this....
  6450. StatisticsFilter filter;
  6451. filter.setCreator(creator);
  6452. filter.setScope(scope);
  6453. filter.setKind(kind);
  6454. Owned<IConstWUStatisticIterator> stats = &getStatistics(&filter);
  6455. if (stats->first())
  6456. return LINK(&stats->query());
  6457. return NULL;
  6458. }
  6459. IConstWUScopeIterator & CLocalWorkUnit::getScopeIterator(const IStatisticsFilter * filter) const
  6460. {
  6461. {
  6462. CriticalBlock block(crit);
  6463. statistics.loadBranch(p,"Statistics");
  6464. }
  6465. Owned<CompoundStatisticsScopeIterator> compoundIter = new CompoundStatisticsScopeIterator;
  6466. //MORE: These will need to be configurable in the filter. Can temporarily change to test the different elements
  6467. const bool includeGlobalStats = true;
  6468. const bool includeGraphStats = true;
  6469. const bool includeStaticGraph = true;
  6470. if (includeGlobalStats)
  6471. {
  6472. Owned<IConstWUScopeIterator> localStats(new WorkUnitStatisticsScopeIterator(statistics, filter));
  6473. compoundIter->addIter(localStats);
  6474. }
  6475. if (includeGraphStats && filter->recurseChildScopes(SSTgraph, nullptr))
  6476. {
  6477. const char * wuid = p->queryName();
  6478. Owned<IConstWUScopeIterator> scopeIter(new CConstGraphProgressScopeIterator(wuid, filter));
  6479. compoundIter->addIter(scopeIter);
  6480. }
  6481. if (includeStaticGraph)
  6482. {
  6483. Owned<IConstWUScopeIterator> graphIter(new GraphScopeIterator(this, filter));
  6484. compoundIter->addIter(graphIter);
  6485. }
  6486. return *compoundIter.getClear();
  6487. }
  6488. IWUPlugin* CLocalWorkUnit::updatePluginByName(const char *qname)
  6489. {
  6490. CriticalBlock block(crit);
  6491. IConstWUPlugin *existing = getPluginByName(qname);
  6492. if (existing)
  6493. return (IWUPlugin *) existing;
  6494. if (!plugins.length())
  6495. p->addPropTree("Plugins");
  6496. IPropertyTree *pl = p->queryPropTree("Plugins");
  6497. IPropertyTree *s = pl->addPropTree("Plugin");
  6498. s->Link();
  6499. IWUPlugin* q = new CLocalWUPlugin(s);
  6500. q->Link();
  6501. plugins.append(*q);
  6502. q->setPluginName(qname);
  6503. return q;
  6504. }
  6505. IConstWUPlugin* CLocalWorkUnit::getPluginByName(const char *qname) const
  6506. {
  6507. CriticalBlock block(crit);
  6508. loadPlugins();
  6509. ForEachItemIn(idx, plugins)
  6510. {
  6511. SCMStringBuffer name;
  6512. IConstWUPlugin &cur = plugins.item(idx);
  6513. cur.getPluginName(name);
  6514. if (stricmp(name.str(), qname)==0)
  6515. {
  6516. cur.Link();
  6517. return &cur;
  6518. }
  6519. }
  6520. return NULL;
  6521. }
  6522. IWULibrary* CLocalWorkUnit::updateLibraryByName(const char *qname)
  6523. {
  6524. CriticalBlock block(crit);
  6525. IConstWULibrary *existing = getLibraryByName(qname);
  6526. if (existing)
  6527. return (IWULibrary *) existing;
  6528. if (!libraries.length())
  6529. p->addPropTree("Libraries");
  6530. IPropertyTree *pl = p->queryPropTree("Libraries");
  6531. IPropertyTree *s = pl->addPropTree("Library");
  6532. s->Link();
  6533. IWULibrary* q = new CLocalWULibrary(s);
  6534. q->Link();
  6535. libraries.append(*q);
  6536. q->setName(qname);
  6537. return q;
  6538. }
  6539. void CLocalWorkUnit::_loadExceptions() const
  6540. {
  6541. assertex(exceptions.length() == 0);
  6542. Owned<IPropertyTreeIterator> r = p->getElements("Exceptions/Exception");
  6543. for (r->first(); r->isValid(); r->next())
  6544. {
  6545. IPropertyTree *rp = &r->query();
  6546. rp->Link();
  6547. exceptions.append(*new CLocalWUException(rp));
  6548. }
  6549. }
  6550. void CLocalWorkUnit::loadExceptions() const
  6551. {
  6552. CriticalBlock block(crit);
  6553. if (!exceptionsCached)
  6554. {
  6555. _loadExceptions();
  6556. exceptionsCached = true;
  6557. }
  6558. }
  6559. IConstWUExceptionIterator& CLocalWorkUnit::getExceptions() const
  6560. {
  6561. CriticalBlock block(crit);
  6562. loadExceptions();
  6563. return *new CArrayIteratorOf<IConstWUException,IConstWUExceptionIterator> (exceptions, 0, (IConstWorkUnit *) this);
  6564. }
  6565. unsigned CLocalWorkUnit::getExceptionCount() const
  6566. {
  6567. CriticalBlock block(crit);
  6568. loadExceptions();
  6569. return exceptions.length();
  6570. }
  6571. void CLocalWorkUnit::clearExceptions()
  6572. {
  6573. CriticalBlock block(crit);
  6574. // For this to be legally called, we must have the write-able interface. So we are already locked for write.
  6575. loadExceptions();
  6576. ForEachItemInRev(idx, exceptions)
  6577. {
  6578. IWUException &e = exceptions.item(idx);
  6579. SCMStringBuffer s;
  6580. e.getExceptionSource(s);
  6581. if (strieq(s.s, "eclcc") || strieq(s.s, "eclccserver") || strieq(s.s, "eclserver") )
  6582. break;
  6583. VStringBuffer xpath("Exceptions/Exception[@sequence='%d']", e.getSequence());
  6584. p->removeProp(xpath);
  6585. exceptions.remove(idx);
  6586. }
  6587. if (exceptions.length() == 0)
  6588. p->removeProp("Exceptions");
  6589. }
  6590. IWUException* CLocalWorkUnit::createException()
  6591. {
  6592. CriticalBlock block(crit);
  6593. // For this to be legally called, we must have the write-able interface. So we are already locked for write.
  6594. loadExceptions();
  6595. if (!exceptions.length())
  6596. p->addPropTree("Exceptions");
  6597. IPropertyTree *r = p->queryPropTree("Exceptions");
  6598. IPropertyTree *s = r->addPropTree("Exception");
  6599. s->setPropInt("@sequence", exceptions.ordinality());
  6600. IWUException* q = new CLocalWUException(LINK(s));
  6601. exceptions.append(*LINK(q));
  6602. Owned<IJlibDateTime> now = createDateTimeNow();
  6603. SCMStringBuffer temp;
  6604. now->getString(temp);
  6605. q->setTimeStamp(temp.str());
  6606. return q;
  6607. }
  6608. IConstWUWebServicesInfo* CLocalWorkUnit::getWebServicesInfo() const
  6609. {
  6610. // For this to be legally called, we must have the read-able interface. So we are already locked for (at least) read.
  6611. CriticalBlock block(crit);
  6612. if (!webServicesInfoCached)
  6613. {
  6614. assertex(!webServicesInfo);
  6615. IPropertyTree *s = p->getPropTree("WebServicesInfo");
  6616. if (s)
  6617. webServicesInfo.setown(new CLocalWUWebServicesInfo(s)); // NB takes ownership of 's'
  6618. webServicesInfoCached = true;
  6619. }
  6620. return webServicesInfo.getLink();
  6621. }
  6622. IWUWebServicesInfo* CLocalWorkUnit::updateWebServicesInfo(bool create)
  6623. {
  6624. // For this to be legally called, we must have the write-able interface. So we are already locked for write.
  6625. CriticalBlock block(crit);
  6626. if (!webServicesInfoCached)
  6627. {
  6628. IPropertyTree *s = p->queryPropTree("WebServicesInfo");
  6629. if (!s)
  6630. {
  6631. if (create)
  6632. s = p->addPropTree("WebServicesInfo");
  6633. else
  6634. return NULL;
  6635. }
  6636. s->Link();
  6637. webServicesInfo.setown(new CLocalWUWebServicesInfo(s));
  6638. webServicesInfoCached = true;
  6639. }
  6640. return webServicesInfo.getLink();
  6641. }
  6642. static int compareResults(IInterface * const *ll, IInterface * const *rr)
  6643. {
  6644. CLocalWUResult *l = (CLocalWUResult *) *ll;
  6645. CLocalWUResult *r = (CLocalWUResult *) *rr;
  6646. return l->getResultSequence() - r->getResultSequence();
  6647. }
  6648. void CLocalWorkUnit::_loadResults() const
  6649. {
  6650. Owned<IPropertyTreeIterator> r = p->getElements("Results/Result");
  6651. for (r->first(); r->isValid(); r->next())
  6652. {
  6653. IPropertyTree *rp = &r->query();
  6654. rp->Link();
  6655. results.append(*new CLocalWUResult(rp));
  6656. }
  6657. }
  6658. void CLocalWorkUnit::loadResults() const
  6659. {
  6660. if (!resultsCached)
  6661. {
  6662. assertex(results.length() == 0);
  6663. _loadResults();
  6664. results.sort(compareResults);
  6665. resultsCached = true;
  6666. }
  6667. }
  6668. void CLocalWorkUnit::_loadVariables() const
  6669. {
  6670. Owned<IPropertyTreeIterator> r = p->getElements("Variables/Variable");
  6671. for (r->first(); r->isValid(); r->next())
  6672. {
  6673. IPropertyTree *rp = &r->query();
  6674. rp->Link();
  6675. variables.append(*new CLocalWUResult(rp));
  6676. }
  6677. }
  6678. void CLocalWorkUnit::loadVariables() const
  6679. {
  6680. if (!variablesCached)
  6681. {
  6682. assertex(variables.length() == 0);
  6683. _loadVariables();
  6684. variablesCached = true;
  6685. }
  6686. }
  6687. void CLocalWorkUnit::_loadTemporaries() const
  6688. {
  6689. Owned<IPropertyTreeIterator> r = p->getElements("Temporaries/Variable");
  6690. for (r->first(); r->isValid(); r->next())
  6691. {
  6692. IPropertyTree *rp = &r->query();
  6693. rp->Link();
  6694. temporaries.append(*new CLocalWUResult(rp));
  6695. }
  6696. }
  6697. void CLocalWorkUnit::loadTemporaries() const
  6698. {
  6699. if (!temporariesCached)
  6700. {
  6701. assertex(temporaries.length() == 0);
  6702. _loadTemporaries();
  6703. temporariesCached = true;
  6704. }
  6705. }
  6706. void CLocalWorkUnit::deleteTemporaries()
  6707. {
  6708. CriticalBlock block(crit);
  6709. if (temporariesCached)
  6710. {
  6711. temporaries.kill();
  6712. temporariesCached = false;
  6713. }
  6714. p->removeProp("Temporaries");
  6715. }
  6716. IWUResult* CLocalWorkUnit::createResult()
  6717. {
  6718. CriticalBlock block(crit);
  6719. // For this to be legally called, we must have the write-able interface. So we are already locked for write.
  6720. loadResults();
  6721. if (!results.length())
  6722. p->addPropTree("Results");
  6723. IPropertyTree *r = p->queryPropTree("Results");
  6724. IPropertyTree *s = r->addPropTree("Result");
  6725. s->Link();
  6726. IWUResult* q = new CLocalWUResult(s);
  6727. q->Link();
  6728. results.append(*q);
  6729. return q;
  6730. }
  6731. IWUResult* CLocalWorkUnit::updateResultByName(const char *qname)
  6732. {
  6733. CriticalBlock block(crit);
  6734. IConstWUResult *existing = getResultByName(qname);
  6735. if (existing)
  6736. return (IWUResult *) existing;
  6737. IWUResult* q = createResult();
  6738. q->setResultName(qname);
  6739. return q;
  6740. }
  6741. IWUResult* CLocalWorkUnit::updateResultBySequence(unsigned seq)
  6742. {
  6743. CriticalBlock block(crit);
  6744. IConstWUResult *existing = getResultBySequence(seq);
  6745. if (existing)
  6746. return (IWUResult *) existing;
  6747. IWUResult* q = createResult();
  6748. q->setResultSequence(seq);
  6749. return q;
  6750. }
  6751. IConstWUResultIterator& CLocalWorkUnit::getResults() const
  6752. {
  6753. CriticalBlock block(crit);
  6754. loadResults();
  6755. return *new CArrayIteratorOf<IConstWUResult,IConstWUResultIterator> (results, 0, (IConstWorkUnit *) this);
  6756. }
  6757. IConstWUResult* CLocalWorkUnit::getResultByName(const char *qname) const
  6758. {
  6759. CriticalBlock block(crit);
  6760. loadResults();
  6761. ForEachItemIn(idx, results)
  6762. {
  6763. SCMStringBuffer name;
  6764. IConstWUResult &cur = results.item(idx);
  6765. cur.getResultName(name);
  6766. if (stricmp(name.str(), qname)==0)
  6767. {
  6768. cur.Link();
  6769. return &cur;
  6770. }
  6771. }
  6772. return NULL;
  6773. }
  6774. IConstWUResult* CLocalWorkUnit::getResultBySequence(unsigned seq) const
  6775. {
  6776. CriticalBlock block(crit);
  6777. loadResults();
  6778. ForEachItemIn(idx, results)
  6779. {
  6780. IConstWUResult &cur = results.item(idx);
  6781. if (cur.getResultSequence() == seq)
  6782. {
  6783. cur.Link();
  6784. return &cur;
  6785. }
  6786. }
  6787. return NULL;
  6788. }
  6789. IConstWUResultIterator& CLocalWorkUnit::getVariables() const
  6790. {
  6791. CriticalBlock block(crit);
  6792. loadVariables();
  6793. return *new CArrayIteratorOf<IConstWUResult,IConstWUResultIterator> (variables, 0, (IConstWorkUnit *) this);
  6794. }
  6795. IConstWUResult* CLocalWorkUnit::getGlobalByName(const char *qname) const
  6796. {
  6797. CriticalBlock block(crit);
  6798. if (strcmp(p->queryName(), GLOBAL_WORKUNIT)==0)
  6799. return getVariableByName(qname);
  6800. Owned <IWorkUnit> global = factory->getGlobalWorkUnit(secMgr, secUser);
  6801. return global->getVariableByName(qname);
  6802. }
  6803. IWUResult* CLocalWorkUnit::updateGlobalByName(const char *qname)
  6804. {
  6805. CriticalBlock block(crit);
  6806. if (strcmp(p->queryName(), GLOBAL_WORKUNIT)==0)
  6807. return updateVariableByName(qname);
  6808. Owned <IWorkUnit> global = factory->getGlobalWorkUnit(secMgr, secUser);
  6809. return global->updateVariableByName(qname);
  6810. }
  6811. IConstWUResult* CLocalWorkUnit::getVariableByName(const char *qname) const
  6812. {
  6813. CriticalBlock block(crit);
  6814. loadVariables();
  6815. ForEachItemIn(idx, variables)
  6816. {
  6817. SCMStringBuffer name;
  6818. IConstWUResult &cur = variables.item(idx);
  6819. cur.getResultName(name);
  6820. if (stricmp(name.str(), qname)==0)
  6821. {
  6822. cur.Link();
  6823. return &cur;
  6824. }
  6825. }
  6826. return NULL;
  6827. }
  6828. IConstWUResult* CLocalWorkUnit::getTemporaryByName(const char *qname) const
  6829. {
  6830. CriticalBlock block(crit);
  6831. loadTemporaries();
  6832. ForEachItemIn(idx, temporaries)
  6833. {
  6834. SCMStringBuffer name;
  6835. IConstWUResult &cur = temporaries.item(idx);
  6836. cur.getResultName(name);
  6837. if (stricmp(name.str(), qname)==0)
  6838. {
  6839. cur.Link();
  6840. return &cur;
  6841. }
  6842. }
  6843. return NULL;
  6844. }
  6845. IConstWUResultIterator& CLocalWorkUnit::getTemporaries() const
  6846. {
  6847. CriticalBlock block(crit);
  6848. loadTemporaries();
  6849. return *new CArrayIteratorOf<IConstWUResult,IConstWUResultIterator> (temporaries, 0, (IConstWorkUnit *) this);
  6850. }
  6851. IWUResult* CLocalWorkUnit::updateTemporaryByName(const char *qname)
  6852. {
  6853. CriticalBlock block(crit);
  6854. IConstWUResult *existing = getTemporaryByName(qname);
  6855. if (existing)
  6856. return (IWUResult *) existing;
  6857. IPropertyTree *vars = (temporaries.length()) ? p->queryPropTree("Temporaries") : p->addPropTree("Temporaries");
  6858. IPropertyTree *s = vars->addPropTree("Variable");
  6859. s->Link();
  6860. IWUResult* q = new CLocalWUResult(s);
  6861. q->Link();
  6862. temporaries.append(*q);
  6863. q->setResultName(qname);
  6864. q->setResultSequence(ResultSequenceInternal);
  6865. return q;
  6866. }
  6867. IWUResult* CLocalWorkUnit::updateVariableByName(const char *qname)
  6868. {
  6869. CriticalBlock block(crit);
  6870. IConstWUResult *existing = getVariableByName(qname);
  6871. if (existing)
  6872. return (IWUResult *) existing;
  6873. if (!variables.length())
  6874. p->addPropTree("Variables");
  6875. IPropertyTree *vars = p->queryPropTree("Variables");
  6876. IPropertyTree *s = vars->addPropTree("Variable");
  6877. s->Link();
  6878. IWUResult* q = new CLocalWUResult(s);
  6879. q->Link();
  6880. variables.append(*q);
  6881. q->setResultName(qname);
  6882. q->setResultSequence(ResultSequenceStored);
  6883. return q;
  6884. }
  6885. void CLocalWorkUnit::deleteTempFiles(const char *graph, bool deleteOwned, bool deleteJobOwned)
  6886. {
  6887. CriticalBlock block(crit);
  6888. IPropertyTree *files = p->queryPropTree("Files");
  6889. if (!files) return;
  6890. Owned<IPropertyTreeIterator> iter = files->getElements("File");
  6891. ICopyArrayOf<IPropertyTree> toRemove;
  6892. ForEach (*iter)
  6893. {
  6894. IPropertyTree &file = iter->query();
  6895. WUFileKind fileKind = (WUFileKind) file.getPropInt("@kind", WUFileStandard);
  6896. if(file.getPropBool("@temporary")) fileKind = WUFileTemporary; // @temporary, legacy check
  6897. bool needDelete;
  6898. switch(fileKind)
  6899. {
  6900. case WUFileTemporary:
  6901. if(graph==NULL)
  6902. needDelete = true;
  6903. else
  6904. {
  6905. const char *graphOwner = file.queryProp("@graph");
  6906. needDelete = ((graphOwner==NULL) || (strcmp(graph, graphOwner)==0));
  6907. }
  6908. break;
  6909. case WUFileJobOwned:
  6910. needDelete = ((graph==NULL) && deleteJobOwned);
  6911. break;
  6912. case WUFileOwned:
  6913. needDelete = ((graph==NULL) && deleteOwned);
  6914. break;
  6915. default:
  6916. needDelete = false;
  6917. }
  6918. if(needDelete)
  6919. {
  6920. const char *name = file.queryProp("@name");
  6921. LOG(MCdebugProgress, unknownJob, "Removing workunit file %s from DFS", name);
  6922. queryDistributedFileDirectory().removeEntry(name, queryUserDescriptor());
  6923. toRemove.append(file);
  6924. }
  6925. }
  6926. ForEachItemIn(r, toRemove) files->removeTree(&toRemove.item(r));
  6927. }
  6928. static void _noteFileRead(IDistributedFile *file, IPropertyTree *filesRead)
  6929. {
  6930. IDistributedSuperFile *super = file->querySuperFile();
  6931. StringBuffer fname;
  6932. file->getLogicalName(fname);
  6933. if (fname.length())
  6934. {
  6935. StringBuffer path("File[@name=\"");
  6936. path.append(fname).append("\"]");
  6937. IPropertyTree *fileTree = filesRead->queryPropTree(path.str());
  6938. if (fileTree)
  6939. fileTree->setPropInt("@useCount", fileTree->getPropInt("@useCount")+1);
  6940. else
  6941. {
  6942. StringBuffer cluster;
  6943. file->getClusterName(0,cluster);
  6944. fileTree = createPTree();
  6945. fileTree->setProp("@name", fname.str());
  6946. fileTree->setProp("@cluster", cluster.str());
  6947. fileTree->setPropInt("@useCount", 1);
  6948. fileTree = filesRead->addPropTree("File", fileTree);
  6949. }
  6950. if (super)
  6951. {
  6952. fileTree->setPropBool("@super", true);
  6953. Owned<IDistributedFileIterator> iter = super->getSubFileIterator(false);
  6954. ForEach (*iter)
  6955. {
  6956. IDistributedFile &file = iter->query();
  6957. StringBuffer fname;
  6958. file.getLogicalName(fname);
  6959. fileTree->addPropTree("Subfile")->setProp("@name", fname.str());
  6960. _noteFileRead(&file, filesRead);
  6961. }
  6962. }
  6963. }
  6964. }
  6965. void CLocalWorkUnit::_loadFilesRead() const
  6966. {
  6967. // Nothing to do
  6968. }
  6969. void CLocalWorkUnit::noteFileRead(IDistributedFile *file)
  6970. {
  6971. if (file)
  6972. {
  6973. CriticalBlock block(crit);
  6974. IPropertyTree *files = p->queryPropTree("FilesRead");
  6975. if (!files)
  6976. files = p->addPropTree("FilesRead");
  6977. _noteFileRead(file, files);
  6978. }
  6979. }
  6980. void CLocalWorkUnit::noteFieldUsage(IPropertyTree * fieldUsage)
  6981. {
  6982. if (fieldUsage)
  6983. {
  6984. CriticalBlock block(crit);
  6985. p->addPropTree("usedsources", fieldUsage);
  6986. }
  6987. }
  6988. void CLocalWorkUnit::_loadFilesWritten() const
  6989. {
  6990. // Nothing to do
  6991. }
  6992. static void addFile(IPropertyTree *files, const char *fileName, const char *cluster, unsigned usageCount, WUFileKind fileKind, const char *graphOwner)
  6993. {
  6994. StringBuffer path("File[@name=\"");
  6995. path.append(fileName).append("\"]");
  6996. if (cluster)
  6997. path.append("[@cluster=\"").append(cluster).append("\"]");
  6998. IPropertyTree *file = files->queryPropTree(path.str());
  6999. if (file) files->removeTree(file);
  7000. file = createPTree();
  7001. file->setProp("@name", fileName);
  7002. if (cluster)
  7003. file->setProp("@cluster", cluster);
  7004. if (graphOwner)
  7005. file->setProp("@graph", graphOwner);
  7006. file->setPropInt("@kind", (unsigned)fileKind);
  7007. if (WUFileTemporary == fileKind)
  7008. file->setPropInt("@usageCount", usageCount);
  7009. files->addPropTree("File", file);
  7010. }
  7011. void CLocalWorkUnit::addFile(const char *fileName, StringArray *clusters, unsigned usageCount, WUFileKind fileKind, const char *graphOwner)
  7012. {
  7013. CriticalBlock block(crit);
  7014. IPropertyTree *files = p->queryPropTree("Files");
  7015. if (!files)
  7016. files = p->addPropTree("Files");
  7017. if (!clusters)
  7018. ::addFile(files, fileName, NULL, usageCount, fileKind, graphOwner);
  7019. else
  7020. {
  7021. ForEachItemIn(c, *clusters)
  7022. ::addFile(files, fileName, clusters->item(c), usageCount, fileKind, graphOwner);
  7023. }
  7024. }
  7025. void CLocalWorkUnit::releaseFile(const char *fileName)
  7026. {
  7027. StringBuffer path("File[@name=\"");
  7028. path.append(fileName).append("\"]");
  7029. CriticalBlock block(crit);
  7030. IPropertyTree *files = p->queryPropTree("Files");
  7031. if (!files) return;
  7032. Owned<IPropertyTreeIterator> fiter = files->getElements(path.str());
  7033. ForEach (*fiter)
  7034. {
  7035. IPropertyTree *file = &fiter->query();
  7036. unsigned usageCount = file->getPropInt("@usageCount");
  7037. if (usageCount > 1)
  7038. file->setPropInt("@usageCount", usageCount-1);
  7039. else
  7040. {
  7041. StringAttr name(file->queryProp("@name"));
  7042. files->removeTree(file);
  7043. if (!name.isEmpty()&&(1 == usageCount))
  7044. {
  7045. if (queryDistributedFileDirectory().removeEntry(fileName, queryUserDescriptor()))
  7046. LOG(MCdebugProgress, unknownJob, "Removed (released) file %s from DFS", name.get());
  7047. }
  7048. }
  7049. }
  7050. }
  7051. void CLocalWorkUnit::clearGraphProgress() const
  7052. {
  7053. }
  7054. void CLocalWorkUnit::resetBeforeGeneration()
  7055. {
  7056. CriticalBlock block(crit);
  7057. //Remove all associated files
  7058. Owned<IWUQuery> q = updateQuery();
  7059. q->removeAssociatedFiles();
  7060. //Remove any pre-existing workflow information
  7061. workflowIterator.clear();
  7062. p->removeProp("Workflow");
  7063. }
  7064. unsigned CLocalWorkUnit::queryFileUsage(const char *fileName) const
  7065. {
  7066. StringBuffer path("Files/File[@name=\"");
  7067. path.append(fileName).append("\"]/@usageCount");
  7068. CriticalBlock block(crit);
  7069. return p->getPropInt(path.str());
  7070. }
  7071. IConstWUFileUsageIterator * CLocalWorkUnit::getFieldUsage() const
  7072. {
  7073. CriticalBlock block(crit);
  7074. IPropertyTree* fieldUsageTree = p->queryPropTree("usedsources");
  7075. if (!fieldUsageTree)
  7076. return NULL;
  7077. IPropertyTreeIterator* iter = fieldUsageTree->getElements("*");
  7078. return new CConstWUFileUsageIterator(iter);
  7079. }
  7080. bool isFilenameResolved(StringBuffer& filename)
  7081. {
  7082. size32_t length = filename.length();
  7083. // With current implementation, if filename is surrounded by single quotes, it means that the filename was resolved at compile time.
  7084. if (filename.length() >= 2 && filename.charAt(0) == '\'' && filename.charAt(length-1) == '\'')
  7085. return true;
  7086. else
  7087. return false;
  7088. }
  7089. bool CLocalWorkUnit::getFieldUsageArray(StringArray & filenames, StringArray & columnnames, const char * clusterName) const
  7090. {
  7091. bool scopeLoaded = false;
  7092. SCMStringBuffer defaultScope;
  7093. Owned<IConstWUFileUsageIterator> files = getFieldUsage();
  7094. if (!files)
  7095. return false; // this query was not compiled with recordFieldUsage option.
  7096. ForEach(*files)
  7097. {
  7098. Owned<IConstWUFileUsage> file = files->get();
  7099. StringBuffer filename = file->queryName();
  7100. size32_t length = filename.length();
  7101. if (length == 0)
  7102. throw MakeStringException(WUERR_InvalidFieldUsage, "Invalid FieldUsage found in WU. Cannot enforce view security.");
  7103. StringBuffer normalizedFilename;
  7104. // Two cases to handle:
  7105. // 1. Filename was known at compile time, and is surrounded in single quotes (i.e. 'filename').
  7106. // 2. Filename could not be resolved at compile time (i.e. filename is an input to a query),
  7107. // and is a raw expression WITHOUT surrounding single quotes (i.e. STORED('input_filename')).
  7108. if (isFilenameResolved(filename))
  7109. {
  7110. // filename cannot be empty (i.e. empty single quotes '')
  7111. if (length == 2)
  7112. throw MakeStringException(WUERR_InvalidFieldUsage, "Invalid FieldUsage found in WU. Cannot enforce view security.");
  7113. // Remove surrounding single quotes
  7114. StringAttr cleanFilename(filename.str()+1, length-2);
  7115. // When a filename doesn't start with a tilde (~), it means scope is omitted and is relying on a default scope.
  7116. // We need to load a default scope from config and prefix the filename with it.
  7117. if (cleanFilename.str()[0] != '~')
  7118. {
  7119. // loading a default scope from config is expensive, and should be only done once and be reused later.
  7120. if (!scopeLoaded)
  7121. {
  7122. Owned<IConstWUClusterInfo> clusterInfo = getTargetClusterInfo(clusterName);
  7123. if (!clusterInfo)
  7124. throw MakeStringException(WUERR_InvalidCluster, "Unknown cluster %s", clusterName);
  7125. clusterInfo->getScope(defaultScope);
  7126. scopeLoaded = true;
  7127. }
  7128. normalizedFilename.append(defaultScope.str());
  7129. normalizedFilename.append(cleanFilename.str());
  7130. }
  7131. else
  7132. {
  7133. normalizedFilename.append(cleanFilename);
  7134. }
  7135. }
  7136. else
  7137. {
  7138. // When filename is an unresolved expression, simply treat the expression as a "non-existent" filename.
  7139. // It will have an effect of this query accessing a non-existent filename, and will be denied access unconditionally.
  7140. normalizedFilename.append(filename.str());
  7141. }
  7142. Owned<IConstWUFieldUsageIterator> fields = file->getFields();
  7143. ForEach(*fields)
  7144. {
  7145. Owned<IConstWUFieldUsage> field = fields->get();
  7146. filenames.append(normalizedFilename.str());
  7147. columnnames.append(field->queryName());
  7148. }
  7149. }
  7150. return true;
  7151. }
  7152. IPropertyTree *CLocalWorkUnit::getDiskUsageStats()
  7153. {
  7154. return p->getPropTree("DiskUsageStats");
  7155. }
  7156. void CLocalWorkUnit::addDiskUsageStats(__int64 _avgNodeUsage, unsigned _minNode, __int64 _minNodeUsage, unsigned _maxNode, __int64 _maxNodeUsage, __int64 _graphId)
  7157. {
  7158. IPropertyTree *stats = p->queryPropTree("DiskUsageStats");
  7159. offset_t maxNodeUsage;
  7160. if (stats)
  7161. maxNodeUsage = stats->getPropInt64("@maxNodeUsage");
  7162. else
  7163. {
  7164. stats = p->addPropTree("DiskUsageStats");
  7165. maxNodeUsage = 0;
  7166. }
  7167. if ((offset_t)_maxNodeUsage > maxNodeUsage)
  7168. {
  7169. // record all details at time of max node usage.
  7170. stats->setPropInt("@minNode", _minNode);
  7171. stats->setPropInt("@maxNode", _maxNode);
  7172. stats->setPropInt64("@minNodeUsage", _minNodeUsage);
  7173. stats->setPropInt64("@maxNodeUsage", _maxNodeUsage);
  7174. stats->setPropInt64("@graphId", _graphId);
  7175. if (_avgNodeUsage)
  7176. {
  7177. unsigned _skewHi = (unsigned)((100 * (_maxNodeUsage-_avgNodeUsage))/_avgNodeUsage);
  7178. unsigned _skewLo = (unsigned)((100 * (_avgNodeUsage-_minNodeUsage))/_avgNodeUsage);
  7179. stats->setPropInt("@skewHi", _skewHi);
  7180. stats->setPropInt("@skewLo", _skewLo);
  7181. }
  7182. }
  7183. }
  7184. IPropertyTreeIterator & CLocalWorkUnit::getFileIterator() const
  7185. {
  7186. CriticalBlock block(crit);
  7187. _loadFilesWritten();
  7188. return * p->getElements("Files/File");
  7189. }
  7190. IPropertyTreeIterator & CLocalWorkUnit::getFilesReadIterator() const
  7191. {
  7192. CriticalBlock block(crit);
  7193. _loadFilesRead();
  7194. return * p->getElements("FilesRead/File");
  7195. }
  7196. //=================================================================================================
  7197. bool CLocalWorkUnit::switchThorQueue(const char *cluster, IQueueSwitcher *qs)
  7198. {
  7199. CriticalBlock block(crit);
  7200. if (qs->isAuto()&&!getAllowAutoQueueSwitch())
  7201. return false;
  7202. Owned<IConstWUClusterInfo> newci = getTargetClusterInfo(cluster);
  7203. if (!newci)
  7204. return false;
  7205. StringBuffer currentcluster;
  7206. if (!p->getProp("@clusterName",currentcluster))
  7207. return false;
  7208. Owned<IConstWUClusterInfo> curci = getTargetClusterInfo(currentcluster.str());
  7209. if (!curci)
  7210. return false;
  7211. SCMStringBuffer curqname;
  7212. curci->getThorQueue(curqname);
  7213. const char *wuid = p->queryName();
  7214. void *qi = qs->getQ(curqname.str(),wuid);
  7215. if (!qi)
  7216. return false;
  7217. setClusterName(cluster);
  7218. SCMStringBuffer newqname;
  7219. newci->getThorQueue(newqname);
  7220. qs->putQ(newqname.str(),wuid,qi);
  7221. return true;
  7222. }
  7223. //=================================================================================================
  7224. IPropertyTree *CLocalWorkUnit::getUnpackedTree(bool includeProgress) const
  7225. {
  7226. Owned<IPropertyTree> ret = createPTreeFromIPT(p);
  7227. Owned<IConstWUGraphIterator> graphIter = &getGraphs(GraphTypeAny);
  7228. ForEach(*graphIter)
  7229. {
  7230. IConstWUGraph &graph = graphIter->query();
  7231. Owned<IPropertyTree> graphTree = graph.getXGMMLTree(includeProgress);
  7232. SCMStringBuffer gName;
  7233. graph.getName(gName);
  7234. StringBuffer xpath("Graphs/Graph[@name=\"");
  7235. xpath.append(gName.s).append("\"]/xgmml");
  7236. IPropertyTree *xgmml = ret->queryPropTree(xpath.str());
  7237. if (xgmml) // don't know of any reason it shouldn't exist
  7238. {
  7239. xgmml->removeProp("graphBin");
  7240. xgmml->setPropTree("graph", graphTree.getClear());
  7241. }
  7242. }
  7243. return ret.getClear();
  7244. }
  7245. void CLocalWorkUnit::_loadGraphs(bool heavy) const
  7246. {
  7247. Owned<IPropertyTreeIterator> iter = p->getElements("Graphs/Graph");
  7248. ForEach(*iter)
  7249. {
  7250. IPropertyTree &graph = iter->query();
  7251. graphs.append(*new CLocalWUGraph(*this, LINK(&graph)));
  7252. }
  7253. }
  7254. void CLocalWorkUnit::loadGraphs(bool heavy) const
  7255. {
  7256. if (graphsCached < (heavy ? 2 : 1))
  7257. {
  7258. graphs.kill();
  7259. _loadGraphs(heavy);
  7260. graphsCached = (heavy ? 2 : 1);
  7261. }
  7262. }
  7263. EnumMapping graphTypes[] = {
  7264. { GraphTypeAny, "unknown" },
  7265. { GraphTypeProgress, "progress" },
  7266. { GraphTypeEcl, "ECL" },
  7267. { GraphTypeActivities, "activities" },
  7268. { GraphTypeSubProgress, "subgraph" },
  7269. { GraphTypeSize, NULL },
  7270. };
  7271. WUGraphType getGraphTypeFromString(const char* type)
  7272. {
  7273. return (WUGraphType) getEnum(type, graphTypes);
  7274. }
  7275. CLocalWUGraph::CLocalWUGraph(const CLocalWorkUnit &_owner, IPropertyTree *props) : p(props), owner(_owner)
  7276. {
  7277. wuidVersion = owner.getWuidVersion();
  7278. }
  7279. IStringVal& CLocalWUGraph::getName(IStringVal &str) const
  7280. {
  7281. str.set(p->queryProp("@name"));
  7282. return str;
  7283. }
  7284. IStringVal& CLocalWUGraph::getLabel(IStringVal &str) const
  7285. {
  7286. if (wuidVersion >= 2)
  7287. {
  7288. str.set(p->queryProp("@label"));
  7289. return str;
  7290. }
  7291. else
  7292. {
  7293. Owned<IPropertyTree> xgmml = getXGMMLTree(false);
  7294. str.set(xgmml->queryProp("@label"));
  7295. return str;
  7296. }
  7297. }
  7298. WUGraphState CLocalWUGraph::getState() const
  7299. {
  7300. return owner.queryGraphState(p->queryProp("@name"));
  7301. }
  7302. IStringVal& CLocalWUGraph::getXGMML(IStringVal &str, bool mergeProgress) const
  7303. {
  7304. Owned<IPropertyTree> xgmml = getXGMMLTree(mergeProgress);
  7305. if (xgmml)
  7306. {
  7307. StringBuffer x;
  7308. toXML(xgmml, x);
  7309. str.set(x.str());
  7310. }
  7311. return str;
  7312. }
  7313. unsigned CLocalWorkUnit::getGraphCount() const
  7314. {
  7315. CriticalBlock block(crit);
  7316. if (p->hasProp("Graphs"))
  7317. {
  7318. return p->queryPropTree("Graphs")->numChildren();
  7319. }
  7320. return 0;
  7321. }
  7322. unsigned CLocalWorkUnit::getSourceFileCount() const
  7323. {
  7324. CriticalBlock block(crit);
  7325. _loadFilesRead();
  7326. if (p->hasProp("FilesRead"))
  7327. {
  7328. return p->queryPropTree("FilesRead")->numChildren();
  7329. }
  7330. return 0;
  7331. }
  7332. unsigned CLocalWorkUnit::getResultCount() const
  7333. {
  7334. CriticalBlock block(crit);
  7335. if (p->hasProp("Results"))
  7336. {
  7337. return p->queryPropTree("Results")->numChildren();
  7338. }
  7339. return 0;
  7340. }
  7341. unsigned CLocalWorkUnit::getVariableCount() const
  7342. {
  7343. CriticalBlock block(crit);
  7344. if (p->hasProp("Variables"))
  7345. {
  7346. return p->queryPropTree("Variables")->numChildren();
  7347. }
  7348. return 0;
  7349. }
  7350. unsigned CLocalWorkUnit::getApplicationValueCount() const
  7351. {
  7352. CriticalBlock block(crit);
  7353. if (p->hasProp("Application"))
  7354. {
  7355. return p->queryPropTree("Application")->numChildren();
  7356. }
  7357. return 0;
  7358. }
  7359. StringBuffer &appendPTreeOpenTag(StringBuffer &s, IPropertyTree *tree, const char *name, unsigned indent, bool hidePasswords)
  7360. {
  7361. appendXMLOpenTag(s, name, NULL, false);
  7362. Owned<IAttributeIterator> attrs = tree->getAttributes(true);
  7363. if (attrs->first())
  7364. {
  7365. unsigned attributeindent = indent + (size32_t) strlen(name);
  7366. unsigned count = attrs->count();
  7367. bool doindent = false;
  7368. ForEach(*attrs)
  7369. {
  7370. if (hidePasswords && streq(attrs->queryName(), "@token"))
  7371. continue;
  7372. if (doindent)
  7373. s.append('\n').appendN(attributeindent, ' ');
  7374. else if (count > 3)
  7375. doindent = true;
  7376. appendXMLAttr(s, attrs->queryName()+1, attrs->queryValue());
  7377. }
  7378. }
  7379. s.append('>');
  7380. return s;
  7381. }
  7382. IStringVal &CLocalWorkUnit::getXmlParams(IStringVal &str, bool hidePasswords) const
  7383. {
  7384. CriticalBlock block(crit);
  7385. IPropertyTree *paramTree = p->queryPropTree("Parameters");
  7386. if (!paramTree)
  7387. return str;
  7388. StringBuffer xml;
  7389. if (!hidePasswords)
  7390. toXML(paramTree, xml);
  7391. else
  7392. {
  7393. appendPTreeOpenTag(xml.append(' '), paramTree, "Parameters", 0, false).append('\n');
  7394. Owned<IPropertyTreeIterator> elems = paramTree->getElements("*");
  7395. ForEach(*elems)
  7396. {
  7397. const char *paramname = elems->query().queryName();
  7398. VStringBuffer xpath("Variables/Variable[@name='%s']/Format/@password", paramname);
  7399. if (p->getPropBool(xpath))
  7400. appendXMLTag(xml.append(" "), paramname, "***").append('\n');
  7401. else
  7402. toXML(&elems->query(), xml, 2);
  7403. }
  7404. appendXMLCloseTag(xml.append(' '), "Parameters").append('\n');
  7405. }
  7406. str.set(xml);
  7407. return str;
  7408. }
  7409. const IPropertyTree *CLocalWorkUnit::getXmlParams() const
  7410. {
  7411. CriticalBlock block(crit);
  7412. return p->getPropTree("Parameters");
  7413. }
  7414. void CLocalWorkUnit::setXmlParams(const char *params)
  7415. {
  7416. CriticalBlock block(crit);
  7417. p->setPropTree("Parameters", createPTreeFromXMLString(params));
  7418. }
  7419. void CLocalWorkUnit::setXmlParams(IPropertyTree *tree)
  7420. {
  7421. CriticalBlock block(crit);
  7422. p->setPropTree("Parameters", tree);
  7423. }
  7424. unsigned __int64 CLocalWorkUnit::getHash() const
  7425. {
  7426. CriticalBlock block(crit);
  7427. return p->getPropInt64("@hash");
  7428. }
  7429. void CLocalWorkUnit::setHash(unsigned __int64 hash)
  7430. {
  7431. CriticalBlock block(crit);
  7432. p->setPropInt64("@hash", hash);
  7433. }
  7434. // getGraphs / getGraphsMeta
  7435. // These are basically the same except for the amount of preloading they do, and the type of the iterator they return...
  7436. // If a type other than any is requested, a postfilter is needed.
  7437. template <class T, class U> class CFilteredGraphIteratorOf : public CInterfaceOf<T>
  7438. {
  7439. WUGraphType type;
  7440. Owned<T> base;
  7441. bool match()
  7442. {
  7443. return base->query().getType()==type;
  7444. }
  7445. public:
  7446. CFilteredGraphIteratorOf<T,U>(T *_base, WUGraphType _type)
  7447. : base(_base), type(_type)
  7448. {
  7449. }
  7450. bool first()
  7451. {
  7452. if (!base->first())
  7453. return false;
  7454. if (match())
  7455. return true;
  7456. return next();
  7457. }
  7458. bool next()
  7459. {
  7460. while (base->next())
  7461. if (match())
  7462. return true;
  7463. return false;
  7464. }
  7465. virtual bool isValid()
  7466. {
  7467. return base->isValid();
  7468. }
  7469. U & query()
  7470. {
  7471. return base->query();
  7472. }
  7473. };
  7474. IConstWUGraphMetaIterator& CLocalWorkUnit::getGraphsMeta(WUGraphType type) const
  7475. {
  7476. /* NB: this method should be 'cheap', loadGraphs() creates IConstWUGraph interfaces to the graphs
  7477. * it does not actually pull the graph data. We only use IConstWUGraphMeta here, which never probes the xgmml.
  7478. */
  7479. CriticalBlock block(crit);
  7480. loadGraphs(false);
  7481. IConstWUGraphMetaIterator *giter = new CArrayIteratorOf<IConstWUGraph,IConstWUGraphMetaIterator> (graphs, 0, (IConstWorkUnit *) this);
  7482. if (type!=GraphTypeAny)
  7483. giter = new CFilteredGraphIteratorOf<IConstWUGraphMetaIterator, IConstWUGraphMeta>(giter,type);
  7484. return *giter;
  7485. }
  7486. IConstWUGraphIterator& CLocalWorkUnit::getGraphs(WUGraphType type) const
  7487. {
  7488. CriticalBlock block(crit);
  7489. loadGraphs(true);
  7490. IConstWUGraphIterator *giter = new CArrayIteratorOf<IConstWUGraph,IConstWUGraphIterator> (graphs, 0, (IConstWorkUnit *) this);
  7491. if (type!=GraphTypeAny)
  7492. giter = new CFilteredGraphIteratorOf<IConstWUGraphIterator, IConstWUGraph>(giter, type);
  7493. return *giter;
  7494. }
  7495. IConstWUGraph* CLocalWorkUnit::getGraph(const char *qname) const
  7496. {
  7497. CriticalBlock block(crit);
  7498. VStringBuffer xpath("Graphs/Graph[@name='%s']", qname);
  7499. // NOTE - this would go wrong if we had other graphs of same name but different type. Ignore for now.
  7500. IPTree *graph = p->queryPropTree(xpath);
  7501. if (graph)
  7502. return new CLocalWUGraph(*this, LINK(graph));
  7503. return NULL;
  7504. }
  7505. void CLocalWorkUnit::createGraph(const char * name, const char *label, WUGraphType type, IPropertyTree *xgmml)
  7506. {
  7507. CriticalBlock block(crit);
  7508. if (!graphs.length())
  7509. p->addPropTree("Graphs");
  7510. IPropertyTree *r = p->queryPropTree("Graphs");
  7511. IPropertyTree *s = r->addPropTree("Graph");
  7512. CLocalWUGraph *q = new CLocalWUGraph(*this, LINK(s));
  7513. q->setName(name);
  7514. q->setLabel(label);
  7515. q->setType(type);
  7516. q->setXGMMLTree(xgmml);
  7517. graphs.append(*q);
  7518. }
  7519. IConstWUGraphProgress *CLocalWorkUnit::getGraphProgress(const char *name) const
  7520. {
  7521. /* Owned<IRemoteConnection> conn = getProgressConnection();
  7522. if (conn)
  7523. {
  7524. IPTree *progress = conn->queryRoot()->queryPropTree(graphName);
  7525. if (progress)
  7526. return new CConstGraphProgress(p->queryName(), graphName, progress);
  7527. }
  7528. */
  7529. return NULL;
  7530. }
  7531. WUGraphState CLocalWorkUnit::queryGraphState(const char *graphName) const
  7532. {
  7533. throwUnexpected(); // Should only be used for persisted workunits
  7534. }
  7535. WUGraphState CLocalWorkUnit::queryNodeState(const char *graphName, WUGraphIDType nodeId) const
  7536. {
  7537. throwUnexpected(); // Should only be used for persisted workunits
  7538. }
  7539. void CLocalWorkUnit::setGraphState(const char *graphName, WUGraphState state) const
  7540. {
  7541. throwUnexpected(); // Should only be used for persisted workunits
  7542. }
  7543. void CLocalWorkUnit::setNodeState(const char *graphName, WUGraphIDType nodeId, WUGraphState state) const
  7544. {
  7545. throwUnexpected(); // Should only be used for persisted workunits
  7546. }
  7547. IWUGraphStats *CLocalWorkUnit::updateStats(const char *graphName, StatisticCreatorType creatorType, const char * creator, unsigned subgraph) const
  7548. {
  7549. return new CWuGraphStats(LINK(p), creatorType, creator, graphName, subgraph);
  7550. }
  7551. void CLocalWUGraph::setName(const char *str)
  7552. {
  7553. p->setProp("@name", str);
  7554. }
  7555. void CLocalWUGraph::setLabel(const char *str)
  7556. {
  7557. p->setProp("@label", str);
  7558. }
  7559. void CLocalWUGraph::setXGMML(const char *str)
  7560. {
  7561. setXGMMLTree(createPTreeFromXMLString(str,ipt_lowmem));
  7562. }
  7563. void CLocalWUGraph::setXGMMLTree(IPropertyTree *_graph)
  7564. {
  7565. assertex(strcmp(_graph->queryName(), "graph")==0);
  7566. IPropertyTree *xgmml = p->setPropTree("xgmml");
  7567. MemoryBuffer mb;
  7568. _graph->serialize(mb);
  7569. // Note - we could compress further but that would introduce compatibility concerns, so don't bother
  7570. // Cassandra workunit code actually lzw compresses the parent anyway
  7571. xgmml->setPropBin("graphBin", mb.length(), mb.toByteArray());
  7572. graph.setown(_graph);
  7573. }
  7574. static void expandAttributes(IPropertyTree & targetNode, IPropertyTree & progressNode)
  7575. {
  7576. Owned<IAttributeIterator> aIter = progressNode.getAttributes();
  7577. ForEach (*aIter)
  7578. {
  7579. const char *aName = aIter->queryName()+1;
  7580. if (0 != stricmp("id", aName)) // "id" reserved.
  7581. {
  7582. IPropertyTree *att = targetNode.addPropTree("att");
  7583. att->setProp("@name", aName);
  7584. att->setProp("@value", aIter->queryValue());
  7585. }
  7586. }
  7587. }
  7588. void CLocalWUGraph::mergeProgress(IPropertyTree &rootNode, IPropertyTree &progressTree, const unsigned &progressV) const
  7589. {
  7590. IPropertyTree *graphNode = rootNode.queryPropTree("att/graph");
  7591. if (!graphNode) return;
  7592. unsigned nodeId = rootNode.getPropInt("@id");
  7593. StringBuffer progressNodePath("node[@id=\"");
  7594. progressNodePath.append(nodeId).append("\"]");
  7595. IPropertyTree *progressNode = progressTree.queryPropTree(progressNodePath.str());
  7596. if (progressNode)
  7597. {
  7598. expandAttributes(*graphNode, *progressNode);
  7599. Owned<IPropertyTreeIterator> edges = progressNode->getElements("edge");
  7600. ForEach (*edges)
  7601. {
  7602. IPropertyTree &edge = edges->query();
  7603. StringBuffer edgePath("edge[@id=\"");
  7604. edgePath.append(edge.queryProp("@id")).append("\"]");
  7605. IPropertyTree *graphEdge = graphNode->queryPropTree(edgePath.str());
  7606. if (graphEdge)
  7607. {
  7608. if (progressV < 1)
  7609. mergePTree(graphEdge, &edge);
  7610. else
  7611. { // must translate to XGMML format
  7612. expandAttributes(*graphEdge, edge);
  7613. // This is really only here, so that our progress format can use non-attribute values, which have different efficiency qualifies (e.g. can be external by dali)
  7614. Owned<IPropertyTreeIterator> iter = edge.getElements("*");
  7615. ForEach (*iter)
  7616. {
  7617. IPropertyTree &t = iter->query();
  7618. IPropertyTree *att = graphEdge->addPropTree("att");
  7619. att->setProp("@name", t.queryName());
  7620. att->setProp("@value", t.queryProp(NULL));
  7621. }
  7622. }
  7623. }
  7624. }
  7625. Owned<IPropertyTreeIterator> nodes = progressNode->getElements("node");
  7626. ForEach (*nodes)
  7627. {
  7628. IPropertyTree &node = nodes->query();
  7629. StringBuffer nodePath("node[@id=\"");
  7630. nodePath.append(node.queryProp("@id")).append("\"]");
  7631. IPropertyTree *_node = graphNode->queryPropTree(nodePath.str());
  7632. if (_node)
  7633. {
  7634. if (progressV < 1)
  7635. mergePTree(_node, &node);
  7636. else
  7637. { // must translate to XGMML format
  7638. expandAttributes(*_node, node);
  7639. }
  7640. }
  7641. }
  7642. }
  7643. Owned<IPropertyTreeIterator> iter = graphNode->getElements("node");
  7644. ForEach (*iter)
  7645. mergeProgress(iter->query(), progressTree, progressV);
  7646. }
  7647. IPropertyTree * CLocalWUGraph::getXGMMLTreeRaw() const
  7648. {
  7649. return p->getPropTree("xgmml");
  7650. }
  7651. IPropertyTree * CLocalWUGraph::getXGMMLTree(bool doMergeProgress) const
  7652. {
  7653. if (!graph)
  7654. {
  7655. // NB: although graphBin introduced in wuidVersion==2,
  7656. // daliadmin can retrospectively compress existing graphs, so need to check for all versions
  7657. MemoryBuffer mb;
  7658. if (p->getPropBin("xgmml/graphBin", mb))
  7659. graph.setown(createPTree(mb, ipt_lowmem));
  7660. else
  7661. graph.setown(p->getBranch("xgmml/graph"));
  7662. if (!graph)
  7663. return NULL;
  7664. }
  7665. if (!doMergeProgress)
  7666. return graph.getLink();
  7667. else
  7668. {
  7669. Owned<IPropertyTree> copy = createPTreeFromIPT(graph, ipt_lowmem);
  7670. Owned<IConstWUGraphProgress> progress = owner.getGraphProgress(p->queryProp("@name"));
  7671. if (progress)
  7672. {
  7673. //MORE: Eventually this should directly access the new stats structure
  7674. unsigned progressV = progress->queryFormatVersion();
  7675. Owned<IPropertyTree> progressTree = progress->getProgressTree();
  7676. Owned<IPropertyTreeIterator> nodeIterator = copy->getElements("node");
  7677. ForEach (*nodeIterator)
  7678. mergeProgress(nodeIterator->query(), *progressTree, progressV);
  7679. }
  7680. return copy.getClear();
  7681. }
  7682. }
  7683. WUGraphType CLocalWUGraph::getType() const
  7684. {
  7685. return (WUGraphType) getEnum(p, "@type", graphTypes);
  7686. }
  7687. IStringVal & CLocalWUGraph::getTypeName(IStringVal &str) const
  7688. {
  7689. str.set(p->queryProp("@type"));
  7690. if (!str.length())
  7691. str.set("unknown");
  7692. return str;
  7693. }
  7694. void CLocalWUGraph::setType(WUGraphType _type)
  7695. {
  7696. setEnum(p, "@type", _type, graphTypes);
  7697. }
  7698. //=================================================================================================
  7699. EnumMapping queryFileTypes[] = {
  7700. { FileTypeCpp, "cpp" },
  7701. { FileTypeDll, "dll" },
  7702. { FileTypeResText, "res" },
  7703. { FileTypeHintXml, "hint" },
  7704. { FileTypeXml, "xml" },
  7705. { FileTypeSize, NULL },
  7706. };
  7707. CLocalWUAssociated::CLocalWUAssociated(IPropertyTree *props) : p(props)
  7708. {
  7709. }
  7710. WUFileType CLocalWUAssociated::getType() const
  7711. {
  7712. return (WUFileType)getEnum(p, "@type", queryFileTypes);
  7713. }
  7714. IStringVal & CLocalWUAssociated::getDescription(IStringVal & str) const
  7715. {
  7716. str.set(p->queryProp("@desc"));
  7717. return str;
  7718. }
  7719. IStringVal & CLocalWUAssociated::getIp(IStringVal & str) const
  7720. {
  7721. str.set(p->queryProp("@ip"));
  7722. return str;
  7723. }
  7724. IStringVal & CLocalWUAssociated::getName(IStringVal & str) const
  7725. {
  7726. str.set(p->queryProp("@filename"));
  7727. return str;
  7728. }
  7729. IStringVal & CLocalWUAssociated::getNameTail(IStringVal & str) const
  7730. {
  7731. str.set(pathTail(p->queryProp("@filename")));
  7732. return str;
  7733. }
  7734. unsigned CLocalWUAssociated::getCrc() const
  7735. {
  7736. return p->getPropInt("@crc", 0);
  7737. }
  7738. unsigned CLocalWUAssociated::getMinActivityId() const
  7739. {
  7740. return p->getPropInt("@minActivity", 0);
  7741. }
  7742. unsigned CLocalWUAssociated::getMaxActivityId() const
  7743. {
  7744. return p->getPropInt("@maxActivity", 0);
  7745. }
  7746. //=================================================================================================
  7747. CLocalWUQuery::CLocalWUQuery(IPropertyTree *props) : p(props)
  7748. {
  7749. associatedCached = false;
  7750. }
  7751. EnumMapping queryTypes[] = {
  7752. { QueryTypeUnknown, "unknown" },
  7753. { QueryTypeEcl, "ECL" },
  7754. { QueryTypeSql, "SQL" },
  7755. { QueryTypeXml, "XML" },
  7756. { QueryTypeAttribute, "Attribute" },
  7757. { QueryTypeSize, NULL },
  7758. };
  7759. WUQueryType CLocalWUQuery::getQueryType() const
  7760. {
  7761. return (WUQueryType) getEnum(p, "@type", queryTypes);
  7762. }
  7763. void CLocalWUQuery::setQueryType(WUQueryType qt)
  7764. {
  7765. setEnum(p, "@type", qt, queryTypes);
  7766. }
  7767. IStringVal& CLocalWUQuery::getQueryText(IStringVal &str) const
  7768. {
  7769. const char *text = p->queryProp("Text");
  7770. if (!text)
  7771. text = p->queryProp("ShortText");
  7772. str.set(text);
  7773. return str;
  7774. }
  7775. IStringVal& CLocalWUQuery::getQueryShortText(IStringVal &str) const
  7776. {
  7777. const char * text = p->queryProp("ShortText");
  7778. if (text)
  7779. str.set(text);
  7780. else
  7781. {
  7782. text = p->queryProp("Text");
  7783. if (isArchiveQuery(text))
  7784. {
  7785. Owned<IPropertyTree> xml = createPTreeFromXMLString(text, ipt_caseInsensitive|ipt_lowmem);
  7786. const char * path = xml->queryProp("Query/@attributePath");
  7787. if (path)
  7788. {
  7789. IPropertyTree * resolved = resolveDefinitionInArchive(xml, path);
  7790. if (resolved)
  7791. str.set(resolved->queryProp(NULL));
  7792. }
  7793. else
  7794. str.set(xml->queryProp("Query"));
  7795. }
  7796. else
  7797. str.set(text);
  7798. }
  7799. return str;
  7800. }
  7801. bool CLocalWUQuery::isArchive() const
  7802. {
  7803. if (p->hasProp("@isArchive"))
  7804. return p->getPropBool("@isArchive");
  7805. const char *text = p->queryProp("Text");
  7806. return isArchiveQuery(text);
  7807. }
  7808. IStringVal& CLocalWUQuery::getQueryName(IStringVal &str) const
  7809. {
  7810. str.set(p->queryProp("@name"));
  7811. return str;
  7812. }
  7813. IStringVal & CLocalWUQuery::getQueryMainDefinition(IStringVal & str) const
  7814. {
  7815. str.set(p->queryProp("@main"));
  7816. return str;
  7817. }
  7818. IStringVal& CLocalWUQuery::getQueryDllName(IStringVal &str) const
  7819. {
  7820. Owned<IConstWUAssociatedFile> entry = getAssociatedFile(FileTypeDll, 0);
  7821. if (entry)
  7822. entry->getNameTail(str);
  7823. return str;
  7824. }
  7825. IStringVal& CLocalWUQuery::getQueryCppName(IStringVal &str) const
  7826. {
  7827. Owned<IConstWUAssociatedFile> entry = getAssociatedFile(FileTypeCpp, 0);
  7828. if (entry)
  7829. entry->getName(str);
  7830. return str;
  7831. }
  7832. IStringVal& CLocalWUQuery::getQueryResTxtName(IStringVal &str) const
  7833. {
  7834. Owned<IConstWUAssociatedFile> entry = getAssociatedFile(FileTypeResText, 0);
  7835. if (entry)
  7836. entry->getName(str);
  7837. return str;
  7838. }
  7839. unsigned CLocalWUQuery::getQueryDllCrc() const
  7840. {
  7841. Owned<IConstWUAssociatedFile> entry = getAssociatedFile(FileTypeDll, 0);
  7842. if (entry)
  7843. return entry->getCrc();
  7844. return 0;
  7845. }
  7846. void CLocalWUQuery::setQueryText(const char *text)
  7847. {
  7848. bool isArchive = isArchiveQuery(text);
  7849. if (isArchive)
  7850. {
  7851. p->setProp("Text", text);
  7852. Owned<IPropertyTree> xml = createPTreeFromXMLString(text, ipt_caseInsensitive|ipt_lowmem);
  7853. const char * path = xml->queryProp("Query/@attributePath");
  7854. if (path)
  7855. {
  7856. IPropertyTree * resolved = resolveDefinitionInArchive(xml, path);
  7857. if (resolved)
  7858. p->setProp("ShortText", resolved->queryProp(NULL));
  7859. }
  7860. else
  7861. p->setProp("ShortText", xml->queryProp("Query"));
  7862. }
  7863. else
  7864. {
  7865. p->setProp("Text", text); // At some point in the future we may be able to remove this,
  7866. // but as long as there may be new workunits compiled by old systems, we can't
  7867. p->setProp("ShortText", text);
  7868. }
  7869. p->setPropBool("@isArchive", isArchive);
  7870. if (isArchive)
  7871. p->setPropBool("@hasArchive", true); //preserved if setQueryText is called multiple times. Should setting this be more explicit?
  7872. }
  7873. void CLocalWUQuery::setQueryName(const char *qname)
  7874. {
  7875. p->setProp("@name", qname);
  7876. }
  7877. void CLocalWUQuery::setQueryMainDefinition(const char * str)
  7878. {
  7879. p->setProp("@main", str);
  7880. }
  7881. void CLocalWUQuery::addAssociatedFile(WUFileType type, const char * name, const char * ip, const char * desc, unsigned crc, unsigned minActivity, unsigned maxActivity)
  7882. {
  7883. CriticalBlock block(crit);
  7884. loadAssociated();
  7885. if (!associated.length())
  7886. p->addPropTree("Associated");
  7887. IPropertyTree *pl = p->queryPropTree("Associated");
  7888. IPropertyTree *s = pl->addPropTree("File");
  7889. setEnum(s, "@type", type, queryFileTypes);
  7890. s->setProp("@filename", name);
  7891. s->setProp("@ip", ip);
  7892. s->setProp("@desc", desc);
  7893. if (crc)
  7894. s->setPropInt("@crc", crc);
  7895. if (minActivity)
  7896. s->setPropInt("@minActivity", minActivity);
  7897. if (maxActivity)
  7898. s->setPropInt("@maxActivity", maxActivity);
  7899. IConstWUAssociatedFile * q = new CLocalWUAssociated(LINK(s));
  7900. associated.append(*q);
  7901. }
  7902. void CLocalWUQuery::removeAssociatedFile(WUFileType type, const char * name, const char * desc)
  7903. {
  7904. CriticalBlock block(crit);
  7905. associatedCached = false;
  7906. associated.kill();
  7907. StringBuffer xpath;
  7908. xpath.append("Associated/File");
  7909. if (type)
  7910. xpath.append("[@type=\"").append(getEnumText(type, queryFileTypes)).append("\"]");
  7911. if (name)
  7912. xpath.append("[@filename=\"").append(name).append("\"]");
  7913. if (desc)
  7914. xpath.append("[@desc=\"").append(desc).append("\"]");
  7915. p->removeProp(xpath.str());
  7916. }
  7917. void CLocalWUQuery::removeAssociatedFiles()
  7918. {
  7919. associatedCached = false;
  7920. associated.kill();
  7921. p->removeProp("Associated");
  7922. }
  7923. IConstWUAssociatedFile * CLocalWUQuery::getAssociatedFile(WUFileType type, unsigned index) const
  7924. {
  7925. CriticalBlock block(crit);
  7926. loadAssociated();
  7927. ForEachItemIn(idx, associated)
  7928. {
  7929. CLocalWUAssociated &cur = static_cast<CLocalWUAssociated &>(associated.item(idx));
  7930. if (cur.getType() == type)
  7931. {
  7932. if (index-- == 0)
  7933. return &OLINK(cur);
  7934. }
  7935. }
  7936. return NULL;
  7937. }
  7938. void CLocalWUQuery::addSpecialCaseAssociated(WUFileType type, const char * propname, unsigned crc) const
  7939. {
  7940. const char * name = p->queryProp(propname);
  7941. if (name)
  7942. {
  7943. IPropertyTree *s = createPTree("File");
  7944. setEnum(s, "@type", type, queryFileTypes);
  7945. s->setProp("@filename", name);
  7946. if (crc)
  7947. s->setPropInt("@crc", crc);
  7948. associated.append(*new CLocalWUAssociated(s));
  7949. }
  7950. }
  7951. void CLocalWUQuery::loadAssociated() const
  7952. {
  7953. CriticalBlock block(crit);
  7954. if (!associatedCached)
  7955. {
  7956. assertex(associated.length() == 0);
  7957. addSpecialCaseAssociated(FileTypeDll, "DllName", p->getPropInt("DllCrc", 0));
  7958. addSpecialCaseAssociated(FileTypeCpp, "CppName", 0);
  7959. addSpecialCaseAssociated(FileTypeResText, "ResTxtName", 0);
  7960. Owned<IPropertyTreeIterator> r = p->getElements("Associated/File");
  7961. for (r->first(); r->isValid(); r->next())
  7962. {
  7963. IPropertyTree *rp = &r->query();
  7964. rp->Link();
  7965. associated.append(*new CLocalWUAssociated(rp));
  7966. }
  7967. associatedCached = true;
  7968. }
  7969. }
  7970. IConstWUAssociatedFileIterator& CLocalWUQuery::getAssociatedFiles() const
  7971. {
  7972. CriticalBlock block(crit);
  7973. loadAssociated();
  7974. return *new CArrayIteratorOf<IConstWUAssociatedFile,IConstWUAssociatedFileIterator> (associated, 0, (IConstWUQuery *) this);
  7975. }
  7976. //========================================================================================
  7977. CLocalWUWebServicesInfo::CLocalWUWebServicesInfo(IPropertyTree *props) : p(props)
  7978. {
  7979. }
  7980. IStringVal& CLocalWUWebServicesInfo::getModuleName(IStringVal &str) const
  7981. {
  7982. str.set(p->queryProp("@module"));
  7983. return str;
  7984. }
  7985. IStringVal& CLocalWUWebServicesInfo::getAttributeName(IStringVal &str) const
  7986. {
  7987. str.set(p->queryProp("@attribute"));
  7988. return str;
  7989. }
  7990. IStringVal& CLocalWUWebServicesInfo::getDefaultName(IStringVal &str) const
  7991. {
  7992. str.set(p->queryProp("@defaultName"));
  7993. return str;
  7994. }
  7995. unsigned CLocalWUWebServicesInfo::getWebServicesCRC() const
  7996. {
  7997. return (unsigned) p->getPropInt("@crc");
  7998. }
  7999. IStringVal& CLocalWUWebServicesInfo::getInfo(const char *name, IStringVal &str) const
  8000. {
  8001. if (!name)
  8002. {
  8003. StringBuffer ws_info;
  8004. ws_info.appendf("<%s ", p->queryName());
  8005. Owned<IAttributeIterator> attrs = p->getAttributes();
  8006. for(attrs->first(); attrs->isValid(); attrs->next())
  8007. {
  8008. const char *name = attrs->queryName()+1;
  8009. const char *value = attrs->queryValue();
  8010. ws_info.appendf("%s='%s' ", name, value);
  8011. }
  8012. ws_info.append("> \n");
  8013. Owned<IPropertyTreeIterator> info = p->getElements("*");
  8014. ForEach(*info)
  8015. {
  8016. IPropertyTree &item = info->query();
  8017. const char *name = item.queryName();
  8018. if (name)
  8019. {
  8020. MemoryBuffer mb;
  8021. bool isbin = p->isBinary(name);
  8022. if (isbin)
  8023. {
  8024. p->getPropBin(name,mb);
  8025. if (mb.length())
  8026. {
  8027. unsigned len = 0;
  8028. mb.read(len);
  8029. StringBuffer encodedString;
  8030. StringBuffer val(len, (const char *) mb.readDirect(len));
  8031. encodeXML(val, encodedString);
  8032. ws_info.appendf("<%s>%s</%s>", name, encodedString.str(), name);
  8033. }
  8034. }
  8035. else
  8036. {
  8037. StringBuffer tmp;
  8038. toXML(&item, tmp);
  8039. ws_info.append(tmp.str());
  8040. }
  8041. }
  8042. }
  8043. ws_info.appendf("</%s>", p->queryName());
  8044. str.setLen(ws_info.str(), ws_info.length());
  8045. }
  8046. else
  8047. {
  8048. MemoryBuffer mb;
  8049. p->getPropBin(name,mb);
  8050. if (mb.length())
  8051. {
  8052. unsigned len;
  8053. mb.read(len);
  8054. str.setLen((const char *) mb.readDirect(len), len);
  8055. }
  8056. }
  8057. return str;
  8058. }
  8059. IStringVal& CLocalWUWebServicesInfo::getText(const char *name, IStringVal &str) const
  8060. {
  8061. str.set(p->queryProp(name));
  8062. return str;
  8063. }
  8064. void CLocalWUWebServicesInfo::setModuleName(const char *mname)
  8065. {
  8066. p->setProp("@module", mname);
  8067. }
  8068. void CLocalWUWebServicesInfo::setAttributeName(const char *aname)
  8069. {
  8070. p->setProp("@attribute", aname);
  8071. }
  8072. void CLocalWUWebServicesInfo::setDefaultName(const char *dname)
  8073. {
  8074. p->setProp("@defaultName", dname);
  8075. }
  8076. void CLocalWUWebServicesInfo::setWebServicesCRC(unsigned crc)
  8077. {
  8078. p->setPropInt("@crc", crc);
  8079. }
  8080. void CLocalWUWebServicesInfo::setInfo(const char *name, const char *info)
  8081. {
  8082. MemoryBuffer m;
  8083. unsigned len = (size32_t)strlen(info);
  8084. serializeLPString(len, info, m);
  8085. p->setPropBin(name, m.length(), m.toByteArray());
  8086. }
  8087. void CLocalWUWebServicesInfo::setText(const char *name, const char *info)
  8088. {
  8089. p->setProp(name, info);
  8090. }
  8091. //========================================================================================
  8092. CLocalWUResult::CLocalWUResult(IPropertyTree *props) : p(props)
  8093. {
  8094. }
  8095. EnumMapping resultStatuses[] = {
  8096. { ResultStatusUndefined, "undefined" },
  8097. { ResultStatusCalculated, "calculated" },
  8098. { ResultStatusSupplied, "supplied" },
  8099. { ResultStatusFailed, "failed" },
  8100. { ResultStatusPartial, "partial" },
  8101. { ResultStatusSize, NULL }
  8102. };
  8103. WUResultStatus CLocalWUResult::getResultStatus() const
  8104. {
  8105. return (WUResultStatus ) getEnum(p, "@status", resultStatuses);
  8106. }
  8107. IStringVal& CLocalWUResult::getResultName(IStringVal &str) const
  8108. {
  8109. str.set(p->queryProp("@name"));
  8110. return str;
  8111. }
  8112. int CLocalWUResult::getResultSequence() const
  8113. {
  8114. return p->getPropInt("@sequence", -1);
  8115. }
  8116. bool CLocalWUResult::isResultScalar() const
  8117. {
  8118. return p->getPropInt("@isScalar", 1) != 0;
  8119. }
  8120. bool findSize(int size, IntArray &sizes)
  8121. {
  8122. ForEachItemIn(idx, sizes)
  8123. {
  8124. if (sizes.item(idx)==size)
  8125. return true;
  8126. }
  8127. return false;
  8128. }
  8129. void CLocalWUResult::getSchema(IArrayOf<ITypeInfo> &types, StringAttrArray &names, IStringVal * eclText) const
  8130. {
  8131. MemoryBuffer schema;
  8132. p->getPropBin("SchemaRaw", schema);
  8133. if (schema.length())
  8134. {
  8135. for (;;)
  8136. {
  8137. StringAttr name;
  8138. schema.read(name);
  8139. if (*schema.readDirect(0)==type_void)
  8140. break;
  8141. names.append(*new StringAttrItem(name));
  8142. types.append(*deserializeType(schema)); // MORE - nested records!
  8143. }
  8144. schema.skip(1);
  8145. if (schema.length() != schema.getPos())
  8146. {
  8147. unsigned eclLen;
  8148. schema.read(eclLen);
  8149. const char * schemaData = (const char *)schema.readDirect(eclLen);
  8150. if (eclText)
  8151. {
  8152. eclText->setLen(schemaData, eclLen);
  8153. if ((eclLen == 0) && names.ordinality())
  8154. {
  8155. const char * firstName = names.item(0).text;
  8156. StringBuffer temp;
  8157. temp.append("RECORD ");
  8158. types.item(0).getECLType(temp);
  8159. temp.append(" value{NAMED('").append(firstName).append("')}").append("; END;");
  8160. eclText->set(temp.str());
  8161. }
  8162. }
  8163. }
  8164. }
  8165. }
  8166. void readRow(StringBuffer &out, MemoryBuffer &in, TypeInfoArray &types, StringAttrArray &names)
  8167. {
  8168. ForEachItemIn(idx, types)
  8169. {
  8170. StringAttrItem &name = names.item(idx);
  8171. ITypeInfo &type = types.item(idx);
  8172. unsigned size = type.getSize();
  8173. switch(type.getTypeCode())
  8174. {
  8175. case type_data:
  8176. if (size==UNKNOWN_LENGTH)
  8177. {
  8178. if (in.remaining() < sizeof(int))
  8179. throw MakeStringException(WUERR_CorruptResult, "corrupt workunit information");
  8180. in.read(size);
  8181. }
  8182. outputXmlData(size, in.readDirect(size), name.text, out);
  8183. break;
  8184. case type_string:
  8185. if (size==UNKNOWN_LENGTH)
  8186. {
  8187. if (in.remaining() < sizeof(int))
  8188. throw MakeStringException(WUERR_CorruptResult, "corrupt workunit information");
  8189. in.read(size);
  8190. }
  8191. outputXmlString(size, (const char *) in.readDirect(size), name.text, out);
  8192. break;
  8193. case type_varstring:
  8194. {
  8195. if (size == UNKNOWN_LENGTH)
  8196. size = (size32_t)strlen((const char *) in.readDirect(0))+1;
  8197. const char * text = (const char *) in.readDirect(size);
  8198. outputXmlString((size32_t)strlen(text), text, name.text, out);
  8199. break;
  8200. }
  8201. case type_unicode:
  8202. {
  8203. unsigned len = type.getStringLen();
  8204. if (size==UNKNOWN_LENGTH)
  8205. in.read(len);
  8206. outputXmlUnicode(len, (UChar const *) in.readDirect(len*2), name.text, out);
  8207. }
  8208. break;
  8209. case type_utf8:
  8210. {
  8211. unsigned len = type.getStringLen();
  8212. if (size==UNKNOWN_LENGTH)
  8213. {
  8214. in.read(len);
  8215. size = rtlUtf8Size(len, in.readDirect(0));
  8216. }
  8217. outputXmlUtf8(len, (const char *) in.readDirect(size), name.text, out);
  8218. }
  8219. break;
  8220. case type_qstring:
  8221. {
  8222. unsigned len = type.getStringLen();
  8223. if (size==UNKNOWN_LENGTH)
  8224. in.read(len);
  8225. unsigned outlen;
  8226. char *outstr;
  8227. rtlQStrToStrX(outlen, outstr, len, (const char *) in.readDirect(rtlQStrSize(len)));
  8228. outputXmlString(outlen, outstr, name.text, out);
  8229. free(outstr);
  8230. break;
  8231. }
  8232. case type_int:
  8233. case type_swapint:
  8234. if (type.isSigned())
  8235. {
  8236. const unsigned char *raw = (const unsigned char *) in.readDirect(size);
  8237. unsigned __int64 cval8 = 0;
  8238. //MORE: I think this is wrong - swapped doesn't mean little/big/
  8239. if (type.isSwappedEndian())
  8240. {
  8241. unsigned idx = 0;
  8242. if (raw[idx] & 0x80)
  8243. cval8 = (__int64)-1;
  8244. while (size--)
  8245. cval8 = (cval8 << 8) | raw[idx++];
  8246. }
  8247. else
  8248. {
  8249. if (raw[size-1] & 0x80)
  8250. cval8 = (__int64)-1;
  8251. while (size--)
  8252. cval8 = (cval8 << 8) | raw[size];
  8253. }
  8254. outputXmlInt((__int64) cval8, name.text, out);
  8255. }
  8256. else
  8257. {
  8258. const unsigned char *raw = (const unsigned char *) in.readDirect(size);
  8259. unsigned __int64 cval8 = 0;
  8260. if (type.isSwappedEndian())
  8261. {
  8262. unsigned idx = 0;
  8263. while (size--)
  8264. cval8 = (cval8 << 8) | raw[idx++];
  8265. }
  8266. else
  8267. {
  8268. while (size--)
  8269. cval8 = (cval8 << 8) | raw[size];
  8270. }
  8271. outputXmlUInt(cval8, name.text, out);
  8272. }
  8273. break;
  8274. case type_boolean:
  8275. bool cvalb;
  8276. in.read(cvalb);
  8277. outputXmlBool(cvalb, name.text, out);
  8278. break;
  8279. case type_decimal:
  8280. if (type.isSigned())
  8281. outputXmlDecimal(in.readDirect(size), size, type.getPrecision(), name.text, out);
  8282. else
  8283. outputXmlUDecimal(in.readDirect(size), size, type.getPrecision(), name.text, out);
  8284. break;
  8285. case type_real:
  8286. double cvald;
  8287. switch(size)
  8288. {
  8289. case 4:
  8290. float cvalf;
  8291. in.read(cvalf);
  8292. cvald = cvalf;
  8293. break;
  8294. case 8:
  8295. in.read(cvald);
  8296. break;
  8297. }
  8298. outputXmlReal(cvald, name.text, out);
  8299. break;
  8300. default:
  8301. assertex(!"unexpected type in raw record");
  8302. break;
  8303. }
  8304. }
  8305. }
  8306. IStringVal& CLocalWUResult::getResultXml(IStringVal &str, bool hidePassword) const
  8307. {
  8308. TypeInfoArray types;
  8309. StringAttrArray names;
  8310. getSchema(types, names);
  8311. StringBuffer xml;
  8312. const char * name = p->queryProp("@name");
  8313. if (name)
  8314. xml.appendf("<Dataset name=\'%s\'>\n", name);
  8315. else
  8316. xml.append("<Dataset>\n");
  8317. if (hidePassword && p->getPropBool("Format/@password"))
  8318. {
  8319. xml.append(" <Row>");
  8320. appendXMLTag(xml, name, "****");
  8321. xml.append("</Row>\n");
  8322. }
  8323. else if (p->hasProp("Value"))
  8324. {
  8325. MemoryBuffer raw;
  8326. p->getPropBin("Value", raw);
  8327. unsigned __int64 numrows = getResultRowCount();
  8328. while (numrows--)
  8329. {
  8330. xml.append(" <Row>");
  8331. readRow(xml, raw, types, names);
  8332. xml.append("</Row>\n");
  8333. }
  8334. }
  8335. else if (p->hasProp("xmlValue"))
  8336. {
  8337. xml.append(" <Row>");
  8338. appendXMLTag(xml, name, p->queryProp("xmlValue"));
  8339. xml.append("</Row>\n");
  8340. }
  8341. xml.append("</Dataset>\n");
  8342. str.set(xml.str());
  8343. return str;
  8344. }
  8345. IProperties *CLocalWUResult::queryResultXmlns()
  8346. {
  8347. CriticalBlock block(crit);
  8348. if (xmlns)
  8349. return xmlns;
  8350. xmlns.setown(createProperties());
  8351. Owned<IAttributeIterator> it = p->getAttributes();
  8352. unsigned prefixLen = strlen("@xmlns");
  8353. ForEach(*it)
  8354. {
  8355. const char *name = it->queryName();
  8356. if (!strncmp("@xmlns", name, prefixLen))
  8357. {
  8358. if (name[prefixLen]==':') //normal case
  8359. xmlns->setProp(name+prefixLen+1, it->queryValue());
  8360. else if (!name[prefixLen]) //special case, unprefixed namespace
  8361. xmlns->setProp("xmlns", it->queryValue());
  8362. }
  8363. }
  8364. return xmlns;
  8365. }
  8366. unsigned CLocalWUResult::getResultFetchSize() const
  8367. {
  8368. return p->getPropInt("fetchSize", 100);
  8369. }
  8370. __int64 CLocalWUResult::getResultTotalRowCount() const
  8371. {
  8372. return p->getPropInt64("totalRowCount", -1);
  8373. }
  8374. __int64 CLocalWUResult::getResultRowCount() const
  8375. {
  8376. return p->getPropInt64("rowCount", 0);
  8377. }
  8378. void CLocalWUResult::getResultDataset(IStringVal & ecl, IStringVal & defs) const
  8379. {
  8380. ecl.set(p->queryProp("datasetEcl"));
  8381. defs.set(p->queryProp("datasetEclDefs"));
  8382. }
  8383. IStringVal& CLocalWUResult::getResultLogicalName(IStringVal & val) const
  8384. {
  8385. val.set(p->queryProp("logicalName"));
  8386. return val;
  8387. }
  8388. IStringVal& CLocalWUResult::getResultKeyField(IStringVal & ecl) const
  8389. {
  8390. ecl.set(p->queryProp("keyField"));
  8391. return ecl;
  8392. }
  8393. unsigned CLocalWUResult::getResultRequestedRows() const
  8394. {
  8395. return p->getPropInt("requestedRows", 1);
  8396. }
  8397. IStringVal& CLocalWUResult::getResultEclSchema(IStringVal & str) const
  8398. {
  8399. TypeInfoArray types;
  8400. StringAttrArray names;
  8401. getSchema(types, names, &str);
  8402. return str;
  8403. }
  8404. IStringVal& CLocalWUResult::getResultRecordSizeEntry(IStringVal & str) const
  8405. {
  8406. str.set(p->queryProp("@recordSizeEntry"));
  8407. return str;
  8408. }
  8409. IStringVal& CLocalWUResult::getResultTransformerEntry(IStringVal & str) const
  8410. {
  8411. str.set(p->queryProp("@transformerEntry"));
  8412. return str;
  8413. }
  8414. __int64 CLocalWUResult::getResultRowLimit() const
  8415. {
  8416. return p->getPropInt64("@rowLimit");
  8417. }
  8418. IStringVal& CLocalWUResult::getResultFilename(IStringVal & str) const
  8419. {
  8420. str.set(p->queryProp("@tempFilename"));
  8421. return str;
  8422. }
  8423. IStringVal& CLocalWUResult::getResultFieldOpt(const char *name, IStringVal &str) const
  8424. {
  8425. str.clear();
  8426. if (!name || !*name)
  8427. return str;
  8428. IPropertyTree *format = p->queryPropTree("Format");
  8429. if (!format)
  8430. return str;
  8431. VStringBuffer xpath("@%s", name);
  8432. str.set(format->queryProp(xpath));
  8433. return str;
  8434. }
  8435. void CLocalWUResult::getResultWriteLocation(IStringVal & _graph, unsigned & _activityId) const
  8436. {
  8437. _graph.set(p->queryProp("@graph"));
  8438. _activityId = p->getPropInt("@activity", 0);
  8439. }
  8440. void CLocalWUResult::setResultStatus(WUResultStatus status)
  8441. {
  8442. setEnum(p, "@status", status, resultStatuses);
  8443. if (status==ResultStatusUndefined)
  8444. {
  8445. p->removeProp("Value");
  8446. p->removeProp("totalRowCount");
  8447. p->removeProp("rowCount");
  8448. p->removeProp("@format");
  8449. p->removeProp("@tempFileNmae");
  8450. p->removeProp("logicalName");
  8451. }
  8452. }
  8453. void CLocalWUResult::setResultName(const char *s)
  8454. {
  8455. p->setProp("@name", s);
  8456. }
  8457. void CLocalWUResult::setResultSequence(unsigned seq)
  8458. {
  8459. p->setPropInt("@sequence", seq);
  8460. }
  8461. void CLocalWUResult::setResultSchemaRaw(unsigned size, const void *schema)
  8462. {
  8463. p->setPropBin("SchemaRaw", size, schema);
  8464. }
  8465. void CLocalWUResult::setResultXmlns(const char *prefix, const char *uri)
  8466. {
  8467. StringBuffer xpath("@xmlns");
  8468. if (prefix && *prefix)
  8469. xpath.append(':').append(prefix);
  8470. p->setProp(xpath, uri);
  8471. }
  8472. void CLocalWUResult::setResultFieldOpt(const char *name, const char *value)
  8473. {
  8474. if (!name || !*name)
  8475. return;
  8476. IPropertyTree *format = ensurePTree(p, "Format");
  8477. VStringBuffer xpath("@%s", name);
  8478. format->setProp(xpath, value);
  8479. }
  8480. void CLocalWUResult::setResultWriteLocation(const char * _graph, unsigned _activityId)
  8481. {
  8482. p->setProp("@graph", _graph);
  8483. p->setPropInt("@activity", _activityId);
  8484. }
  8485. void CLocalWUResult::setResultScalar(bool isScalar)
  8486. {
  8487. p->setPropInt("@isScalar", (int) isScalar);
  8488. if (isScalar)
  8489. setResultTotalRowCount(1);
  8490. }
  8491. void CLocalWUResult::setResultRaw(unsigned len, const void *data, WUResultFormat format)
  8492. {
  8493. p->setPropBin("Value", len, data);
  8494. setResultStatus(ResultStatusSupplied);
  8495. setResultFormat(format);
  8496. }
  8497. void CLocalWUResult::setResultFormat(WUResultFormat format)
  8498. {
  8499. switch (format)
  8500. {
  8501. case ResultFormatXml:
  8502. p->setProp("@format","xml");
  8503. break;
  8504. case ResultFormatXmlSet:
  8505. p->setProp("@format","xmlSet");
  8506. break;
  8507. case ResultFormatCsv:
  8508. p->setProp("@format","csv");
  8509. break;
  8510. default:
  8511. p->removeProp("@format");
  8512. break;
  8513. }
  8514. }
  8515. void CLocalWUResult::setResultXML(const char *val)
  8516. {
  8517. p->setProp("xmlValue", val);
  8518. }
  8519. void CLocalWUResult::addResultRaw(unsigned len, const void *data, WUResultFormat format)
  8520. {
  8521. p->appendPropBin("Value", len, data);
  8522. setResultStatus(ResultStatusPartial);
  8523. const char *existingFormat = p->queryProp("@format");
  8524. const char *formatStr = NULL;
  8525. switch (format)
  8526. {
  8527. case ResultFormatXml:
  8528. formatStr = "xml";
  8529. break;
  8530. case ResultFormatXmlSet:
  8531. formatStr = "xmlSet";
  8532. break;
  8533. case ResultFormatCsv:
  8534. formatStr = "csv";
  8535. break;
  8536. default:
  8537. p->removeProp("@format");
  8538. break;
  8539. }
  8540. if (format)
  8541. {
  8542. if (existingFormat)
  8543. {
  8544. if (0 != stricmp(formatStr, existingFormat))
  8545. throw MakeStringException(WUERR_ResultFormatMismatch, "addResult format %s, does not match existing format %s", formatStr, existingFormat);
  8546. }
  8547. else
  8548. p->setProp("@format", formatStr);
  8549. }
  8550. }
  8551. void CLocalWUResult::setResultFetchSize(unsigned rows)
  8552. {
  8553. p->setPropInt("fetchSize", rows);
  8554. }
  8555. void CLocalWUResult::setResultTotalRowCount(__int64 rows)
  8556. {
  8557. p->setPropInt64("totalRowCount", rows);
  8558. }
  8559. void CLocalWUResult::setResultRowCount(__int64 rows)
  8560. {
  8561. p->setPropInt64("rowCount", rows);
  8562. }
  8563. void CLocalWUResult::setResultDataset(const char *ecl, const char *defs)
  8564. {
  8565. p->setProp("datasetEcl", ecl);
  8566. p->setProp("datasetEclDefs", defs);
  8567. }
  8568. void CLocalWUResult::setResultLogicalName(const char *logicalName)
  8569. {
  8570. p->setProp("logicalName", logicalName);
  8571. }
  8572. void CLocalWUResult::setResultKeyField(const char *ecl)
  8573. {
  8574. p->setProp("keyField", ecl);
  8575. }
  8576. void CLocalWUResult::setResultRequestedRows(unsigned rows)
  8577. {
  8578. p->setPropInt("requestedRows", rows);
  8579. }
  8580. void CLocalWUResult::setResultRecordSizeEntry(const char * entry)
  8581. {
  8582. p->setProp("@recordSizeEntry", entry);
  8583. }
  8584. void CLocalWUResult::setResultTransformerEntry(const char * entry)
  8585. {
  8586. p->setProp("@transformerEntry", entry);
  8587. }
  8588. void CLocalWUResult::setResultRowLimit(__int64 value)
  8589. {
  8590. p->setPropInt64("@rowLimit", value);
  8591. }
  8592. void CLocalWUResult::setResultFilename(const char * name)
  8593. {
  8594. p->setProp("@tempFilename", name);
  8595. }
  8596. // MORE - it's an undetected error if we call getResult... of a type that does not match schema
  8597. __int64 CLocalWUResult::getResultInt() const
  8598. {
  8599. __int64 result = 0;
  8600. MemoryBuffer s;
  8601. p->getPropBin("Value", s);
  8602. if (s.length())
  8603. s.read(result);
  8604. else
  8605. result = p->getPropInt64("xmlValue");
  8606. return result;
  8607. }
  8608. bool CLocalWUResult::getResultBool() const
  8609. {
  8610. bool result = false;
  8611. MemoryBuffer s;
  8612. p->getPropBin("Value", s);
  8613. if (s.length())
  8614. s.read(result);
  8615. else
  8616. result = p->getPropBool("xmlValue");
  8617. return result;
  8618. }
  8619. double CLocalWUResult::getResultReal() const
  8620. {
  8621. double result = 0;
  8622. MemoryBuffer s;
  8623. p->getPropBin("Value", s);
  8624. if (s.length())
  8625. s.read(result);
  8626. else
  8627. {
  8628. const char *xmlVal = p->queryProp("xmlValue");
  8629. if (xmlVal)
  8630. result = atof(xmlVal);
  8631. }
  8632. return result;
  8633. }
  8634. void CLocalWUResult::getResultDecimal(void * val, unsigned len, unsigned precision, bool isSigned) const
  8635. {
  8636. MemoryBuffer s;
  8637. p->getPropBin("Value", s);
  8638. if (s.length())
  8639. {
  8640. assertex(s.length() == len);
  8641. s.read(len, val);
  8642. }
  8643. else
  8644. {
  8645. const char *xmlVal = p->queryProp("xmlValue");
  8646. if (xmlVal)
  8647. {
  8648. Decimal d;
  8649. d.setString(strlen(xmlVal), xmlVal);
  8650. if (isSigned)
  8651. d.getDecimal(len, precision, val);
  8652. else
  8653. d.getUDecimal(len, precision, val);
  8654. }
  8655. else
  8656. memset(val, 0, len);
  8657. }
  8658. }
  8659. IStringVal& CLocalWUResult::getResultString(IStringVal & str, bool hidePassword) const
  8660. {
  8661. if (hidePassword && p->getPropBool("@password"))
  8662. {
  8663. str.set("****");
  8664. return str;
  8665. }
  8666. MemoryBuffer s;
  8667. p->getPropBin("Value", s);
  8668. if (s.length())
  8669. {
  8670. unsigned len;
  8671. s.read(len);
  8672. str.setLen((const char *) s.readDirect(len), len);
  8673. }
  8674. else
  8675. {
  8676. p->getPropBin("xmlValue", s);
  8677. if (p->isBinary("xmlValue"))
  8678. str.setLen(s.toByteArray(), s.length());
  8679. else
  8680. {
  8681. char *ascii = rtlUtf8ToVStr(rtlUtf8Length(s.length(), s.toByteArray()), s.toByteArray());
  8682. str.set(ascii);
  8683. rtlFree(ascii);
  8684. }
  8685. }
  8686. return str;
  8687. }
  8688. WUResultFormat CLocalWUResult::getResultFormat() const
  8689. {
  8690. const char * format = p->queryProp("@format");
  8691. if (!format)
  8692. return ResultFormatRaw;
  8693. else if (strcmp(format, "xml") == 0)
  8694. return ResultFormatXml;
  8695. else if (strcmp(format, "xmlSet") == 0)
  8696. return ResultFormatXmlSet;
  8697. else if (strcmp(format, "csv") == 0)
  8698. return ResultFormatCsv;
  8699. else
  8700. throw MakeStringException(WUERR_InvalidResultFormat, "Unrecognised result format %s", format);
  8701. }
  8702. IDataVal& CLocalWUResult::getResultRaw(IDataVal & data, IXmlToRawTransformer * xmlTransformer, ICsvToRawTransformer * csvTransformer) const
  8703. {
  8704. MemoryBuffer s;
  8705. p->getPropBin("Value", s);
  8706. unsigned len = s.length();
  8707. if (len)
  8708. {
  8709. WUResultFormat format = getResultFormat();
  8710. if (format == ResultFormatXml || format == ResultFormatXmlSet)
  8711. {
  8712. if (!xmlTransformer)
  8713. throw MakeStringException(WUERR_MissingFormatTranslator, "No transformer supplied to translate XML format result");
  8714. xmlTransformer->transform(data, len, s.readDirect(len), format == ResultFormatXml);
  8715. }
  8716. else if (format == ResultFormatCsv)
  8717. {
  8718. if (!csvTransformer)
  8719. throw MakeStringException(WUERR_MissingFormatTranslator, "No transformer supplied to translate Csv format result");
  8720. csvTransformer->transform(data, len, s.readDirect(len), true);
  8721. }
  8722. else
  8723. data.setLen(s.readDirect(len), len);
  8724. }
  8725. else
  8726. data.clear();
  8727. return data;
  8728. }
  8729. unsigned CLocalWUResult::getResultHash() const
  8730. {
  8731. MemoryBuffer s;
  8732. p->getPropBin("Value", s);
  8733. unsigned len = s.length();
  8734. const byte * data = (const byte *)s.toByteArray();
  8735. return ~hashc(data, len, ~0);
  8736. }
  8737. IDataVal& CLocalWUResult::getResultUnicode(IDataVal & data) const
  8738. {
  8739. MemoryBuffer s;
  8740. p->getPropBin("Value", s);
  8741. if (s.length())
  8742. {
  8743. unsigned len;
  8744. s.read(len);
  8745. data.setLen(s.readDirect(len*2), len*2);
  8746. }
  8747. else
  8748. {
  8749. StringBuffer utf8;
  8750. if (p->getProp("xmlValue", utf8))
  8751. {
  8752. unsigned outlen;
  8753. UChar *out;
  8754. rtlUtf8ToUnicodeX(outlen, out, utf8.length(), utf8.str());
  8755. data.setLen(out, outlen*2);
  8756. rtlFree(out);
  8757. }
  8758. else
  8759. data.clear();
  8760. }
  8761. return data;
  8762. }
  8763. __int64 CLocalWUResult::getResultRawSize(IXmlToRawTransformer * xmlTransformer, ICsvToRawTransformer * csvTransformer) const
  8764. {
  8765. WUResultFormat format = getResultFormat();
  8766. if (format == ResultFormatRaw)
  8767. {
  8768. //MORE: This should not load the whole property...
  8769. MemoryBuffer s;
  8770. p->getPropBin("Value", s);
  8771. return s.length();
  8772. }
  8773. else
  8774. {
  8775. MemoryBuffer temp;
  8776. MemoryBuffer2IDataVal adaptor(temp);
  8777. getResultRaw(adaptor, xmlTransformer, csvTransformer);
  8778. return temp.length();
  8779. }
  8780. }
  8781. IDataVal& CLocalWUResult::getResultRaw(IDataVal & data, __int64 from, __int64 length, IXmlToRawTransformer * xmlTransformer, ICsvToRawTransformer * csvTransformer) const
  8782. {
  8783. WUResultFormat format = getResultFormat();
  8784. if (format != ResultFormatRaw)
  8785. {
  8786. MemoryBuffer temp;
  8787. MemoryBuffer2IDataVal adaptor(temp);
  8788. getResultRaw(adaptor, xmlTransformer, csvTransformer);
  8789. unsigned len = temp.length();
  8790. if (from > len) from = len;
  8791. if (from + length > len) length = len - from;
  8792. data.setLen(temp.readDirect(len) + from, (size32_t)length);
  8793. return data;
  8794. }
  8795. else
  8796. {
  8797. //MORE: This should not load the whole property, and should be different from the code above...
  8798. MemoryBuffer s;
  8799. p->getPropBin("Value", s);
  8800. unsigned len = s.length();
  8801. if (from > len) from = len;
  8802. if (from + length > len) length = len - from;
  8803. data.setLen(s.readDirect(len) + from, (size32_t)length);
  8804. return data;
  8805. }
  8806. }
  8807. bool CLocalWUResult::getResultIsAll() const
  8808. {
  8809. return p->getPropBool("@isAll", false);
  8810. }
  8811. // MORE - it's an undetected error if we call setResult... of a type that does not match schema
  8812. void CLocalWUResult::setResultInt(__int64 val)
  8813. {
  8814. // Note: we always serialize scalar integer results as int8, and schema must reflect this
  8815. MemoryBuffer m;
  8816. serializeInt8(val, m);
  8817. p->setPropBin("Value", m.length(), m.toByteArray());
  8818. setResultRowCount(1);
  8819. setResultTotalRowCount(1);
  8820. }
  8821. void CLocalWUResult::setResultUInt(unsigned __int64 val)
  8822. {
  8823. setResultInt((__int64) val);
  8824. }
  8825. void CLocalWUResult::setResultReal(double val)
  8826. {
  8827. // Note: we always serialize scalar real results as real8, and schema must reflect this
  8828. MemoryBuffer m;
  8829. serializeReal8(val, m);
  8830. p->setPropBin("Value", m.length(), m.toByteArray());
  8831. setResultRowCount(1);
  8832. setResultTotalRowCount(1);
  8833. }
  8834. void CLocalWUResult::setResultBool(bool val)
  8835. {
  8836. MemoryBuffer m;
  8837. serializeBool(val, m);
  8838. p->setPropBin("Value", m.length(), m.toByteArray());
  8839. setResultRowCount(1);
  8840. setResultTotalRowCount(1);
  8841. }
  8842. void CLocalWUResult::setResultString(const char *val, unsigned len)
  8843. {
  8844. // Note: we always serialize scalar strings with length prefix, and schema must reflect this
  8845. MemoryBuffer m;
  8846. serializeLPString(len, val, m);
  8847. p->setPropBin("Value", m.length(), m.toByteArray());
  8848. setResultRowCount(1);
  8849. setResultTotalRowCount(1);
  8850. }
  8851. void CLocalWUResult::setResultUnicode(const void *val, unsigned len)
  8852. {
  8853. // Note: we always serialize scalar strings with length prefix, and schema must reflect this
  8854. MemoryBuffer m;
  8855. m.append(len).append(len*2, val);
  8856. p->setPropBin("Value", m.length(), m.toByteArray());
  8857. setResultRowCount(1);
  8858. setResultTotalRowCount(1);
  8859. }
  8860. void CLocalWUResult::setResultData(const void *val, unsigned len)
  8861. {
  8862. // Note: we always serialize scalar data with length prefix, and schema must reflect this
  8863. MemoryBuffer m;
  8864. serializeLPString(len, (const char *)val, m);
  8865. p->setPropBin("Value", m.length(), m.toByteArray());
  8866. setResultRowCount(1);
  8867. setResultTotalRowCount(1);
  8868. }
  8869. void CLocalWUResult::setResultDecimal(const void *val, unsigned len)
  8870. {
  8871. // Note: serialized as data but with length known from schema
  8872. MemoryBuffer m;
  8873. serializeFixedData(len, val, m);
  8874. p->setPropBin("Value", m.length(), m.toByteArray());
  8875. setResultRowCount(1);
  8876. setResultTotalRowCount(1);
  8877. }
  8878. void CLocalWUResult::setResultRow(unsigned len, const void * data)
  8879. {
  8880. p->setPropBin("Value", len, data);
  8881. setResultRowCount(1);
  8882. setResultTotalRowCount(1);
  8883. setResultFormat(ResultFormatRaw);
  8884. }
  8885. void CLocalWUResult::setResultIsAll(bool value)
  8886. {
  8887. p->setPropBool("@isAll", value);
  8888. }
  8889. //==========================================================================================
  8890. CLocalWUPlugin::CLocalWUPlugin(IPropertyTree *props) : p(props)
  8891. {
  8892. }
  8893. IStringVal& CLocalWUPlugin::getPluginName(IStringVal &str) const
  8894. {
  8895. str.set(p->queryProp("@dllname"));
  8896. return str;
  8897. }
  8898. IStringVal& CLocalWUPlugin::getPluginVersion(IStringVal &str) const
  8899. {
  8900. str.set(p->queryProp("@version"));
  8901. return str;
  8902. }
  8903. void CLocalWUPlugin::setPluginName(const char *str)
  8904. {
  8905. p->setProp("@dllname", str);
  8906. }
  8907. void CLocalWUPlugin::setPluginVersion(const char *str)
  8908. {
  8909. p->setProp("@version", str);
  8910. }
  8911. //==========================================================================================
  8912. CLocalWULibrary::CLocalWULibrary(IPropertyTree *props) : p(props)
  8913. {
  8914. }
  8915. IStringVal& CLocalWULibrary::getName(IStringVal &str) const
  8916. {
  8917. str.set(p->queryProp("@name"));
  8918. return str;
  8919. }
  8920. void CLocalWULibrary::setName(const char *str)
  8921. {
  8922. p->setProp("@name", str);
  8923. }
  8924. //==========================================================================================
  8925. CLocalWUException::CLocalWUException(IPropertyTree *props) : p(props)
  8926. {
  8927. }
  8928. IStringVal& CLocalWUException::getExceptionSource(IStringVal &str) const
  8929. {
  8930. str.set(p->queryProp("@source"));
  8931. return str;
  8932. }
  8933. IStringVal& CLocalWUException::getExceptionMessage(IStringVal &str) const
  8934. {
  8935. str.set(p->queryProp(NULL));
  8936. return str;
  8937. }
  8938. unsigned CLocalWUException::getExceptionCode() const
  8939. {
  8940. return p->getPropInt("@code", 0);
  8941. }
  8942. ErrorSeverity CLocalWUException::getSeverity() const
  8943. {
  8944. return (ErrorSeverity)p->getPropInt("@severity", SeverityError);
  8945. }
  8946. IStringVal & CLocalWUException::getTimeStamp(IStringVal & dt) const
  8947. {
  8948. dt.set(p->queryProp("@time"));
  8949. return dt;
  8950. }
  8951. IStringVal & CLocalWUException::getExceptionFileName(IStringVal & str) const
  8952. {
  8953. str.set(p->queryProp("@filename"));
  8954. return str;
  8955. }
  8956. unsigned CLocalWUException::getExceptionLineNo() const
  8957. {
  8958. return p->getPropInt("@row", 0);
  8959. }
  8960. unsigned CLocalWUException::getExceptionColumn() const
  8961. {
  8962. return p->getPropInt("@col", 0);
  8963. }
  8964. unsigned CLocalWUException::getActivityId() const
  8965. {
  8966. const char * scope = queryScope();
  8967. if (scope)
  8968. {
  8969. const char * colon = strrchr(scope, ':');
  8970. if (colon && hasPrefix(colon+1, ActivityScopePrefix, true))
  8971. return atoi(colon+1+strlen(ActivityScopePrefix));
  8972. }
  8973. return p->getPropInt("@activity", 0);
  8974. }
  8975. unsigned CLocalWUException::getSequence() const
  8976. {
  8977. return p->getPropInt("@sequence", 0);
  8978. }
  8979. const char * CLocalWUException::queryScope() const
  8980. {
  8981. return p->queryProp("@scope");
  8982. }
  8983. unsigned CLocalWUException::getPriority() const
  8984. {
  8985. return p->getPropInt("@prio", 0);
  8986. }
  8987. void CLocalWUException::setExceptionSource(const char *str)
  8988. {
  8989. p->setProp("@source", str);
  8990. }
  8991. void CLocalWUException::setExceptionMessage(const char *str)
  8992. {
  8993. p->setProp(NULL, str);
  8994. }
  8995. void CLocalWUException::setExceptionCode(unsigned code)
  8996. {
  8997. p->setPropInt("@code", code);
  8998. }
  8999. void CLocalWUException::setSeverity(ErrorSeverity level)
  9000. {
  9001. p->setPropInt("@severity", level);
  9002. }
  9003. void CLocalWUException::setTimeStamp(const char *str)
  9004. {
  9005. p->setProp("@time", str);
  9006. }
  9007. void CLocalWUException::setExceptionFileName(const char *str)
  9008. {
  9009. p->setProp("@filename", str);
  9010. }
  9011. void CLocalWUException::setExceptionLineNo(unsigned r)
  9012. {
  9013. p->setPropInt("@row", r);
  9014. }
  9015. void CLocalWUException::setExceptionColumn(unsigned c)
  9016. {
  9017. p->setPropInt("@col", c);
  9018. }
  9019. void CLocalWUException::setActivityId(unsigned _id)
  9020. {
  9021. p->setPropInt("@activity", _id);
  9022. }
  9023. void CLocalWUException::setScope(const char * _scope)
  9024. {
  9025. p->setProp("@scope", _scope);
  9026. }
  9027. void CLocalWUException::setPriority(unsigned _priority)
  9028. {
  9029. p->setPropInt("@prio", _priority);
  9030. }
  9031. //==========================================================================================
  9032. CLocalWUAppValue::CLocalWUAppValue(IPropertyTree *props, unsigned child) : p(props)
  9033. {
  9034. StringAttrBuilder propPath(prop);
  9035. propPath.append("*[").append(child).append("]");
  9036. }
  9037. const char * CLocalWUAppValue::queryApplication() const
  9038. {
  9039. return p->queryName();
  9040. }
  9041. const char * CLocalWUAppValue::queryName() const
  9042. {
  9043. IPropertyTree* val=p->queryPropTree(prop.str());
  9044. if(val)
  9045. return val->queryName();
  9046. return ""; // Should not happen in normal usage
  9047. }
  9048. const char * CLocalWUAppValue::queryValue() const
  9049. {
  9050. return p->queryProp(prop.str());
  9051. }
  9052. //==========================================================================================
  9053. CLocalWUStatistic::CLocalWUStatistic(IPropertyTree *props) : p(props)
  9054. {
  9055. }
  9056. IStringVal & CLocalWUStatistic::getCreator(IStringVal & str) const
  9057. {
  9058. const char * creator = p->queryProp("@creator");
  9059. str.set(creator);
  9060. return str;
  9061. }
  9062. IStringVal & CLocalWUStatistic::getDescription(IStringVal & str, bool createDefault) const
  9063. {
  9064. const char * desc = p->queryProp("@desc");
  9065. if (desc)
  9066. {
  9067. str.set(desc); // legacy and in case it is overridden
  9068. }
  9069. else if (createDefault)
  9070. {
  9071. StatisticKind kind = getKind();
  9072. assertex(kind != StKindNone);
  9073. const char * scope = p->queryProp("@scope");
  9074. assertex(scope);
  9075. //Clean up the format of the scope when converting it to a description
  9076. StringBuffer descriptionText;
  9077. if (isGlobalScope(scope))
  9078. {
  9079. const char * creator = p->queryProp("@creator");
  9080. descriptionText.append(creator).append(":");
  9081. queryLongStatisticName(descriptionText, kind);
  9082. }
  9083. else
  9084. {
  9085. for (;;)
  9086. {
  9087. char c = *scope++;
  9088. if (!c)
  9089. break;
  9090. if (c == ':')
  9091. descriptionText.append(": ");
  9092. else
  9093. descriptionText.append(c);
  9094. }
  9095. if (kind != StTimeElapsed)
  9096. queryLongStatisticName(descriptionText.append(": "), kind);
  9097. }
  9098. str.set(descriptionText);
  9099. }
  9100. else
  9101. str.clear();
  9102. return str;
  9103. }
  9104. IStringVal & CLocalWUStatistic::getFormattedValue(IStringVal & str) const
  9105. {
  9106. StringBuffer formatted;
  9107. formatStatistic(formatted, getValue(), getMeasure());
  9108. str.set(formatted);
  9109. return str;
  9110. }
  9111. StatisticCreatorType CLocalWUStatistic::getCreatorType() const
  9112. {
  9113. return queryCreatorType(p->queryProp("@c"));
  9114. }
  9115. StatisticScopeType CLocalWUStatistic::getScopeType() const
  9116. {
  9117. return queryScopeType(p->queryProp("@s"));
  9118. }
  9119. StatisticKind CLocalWUStatistic::getKind() const
  9120. {
  9121. return queryStatisticKind(p->queryProp("@kind"));
  9122. }
  9123. const char * CLocalWUStatistic::queryScope() const
  9124. {
  9125. return p->queryProp("@scope");
  9126. }
  9127. StatisticMeasure CLocalWUStatistic::getMeasure() const
  9128. {
  9129. return queryMeasure(p->queryProp("@unit"));
  9130. }
  9131. unsigned __int64 CLocalWUStatistic::getValue() const
  9132. {
  9133. return p->getPropInt64("@value", 0);
  9134. }
  9135. unsigned __int64 CLocalWUStatistic::getCount() const
  9136. {
  9137. return p->getPropInt64("@count", 0);
  9138. }
  9139. unsigned __int64 CLocalWUStatistic::getMax() const
  9140. {
  9141. return p->getPropInt64("@max", 0);
  9142. }
  9143. unsigned __int64 CLocalWUStatistic::getTimestamp() const
  9144. {
  9145. return p->getPropInt64("@ts", 0);
  9146. }
  9147. bool CLocalWUStatistic::matches(const IStatisticsFilter * filter) const
  9148. {
  9149. if (!filter)
  9150. return true;
  9151. const char * creator = p->queryProp("@creator");
  9152. const char * scope = p->queryProp("@scope");
  9153. return filter->matches(getCreatorType(), creator, getScopeType(), scope, getMeasure(), getKind(), getValue());
  9154. }
  9155. //==========================================================================================
  9156. extern WORKUNIT_API ILocalWorkUnit * createLocalWorkUnit(const char *xml)
  9157. {
  9158. Owned<CLocalWorkUnit> cw = new CLocalWorkUnit((ISecManager *) NULL, NULL);
  9159. if (xml)
  9160. cw->loadPTree(createPTreeFromXMLString(xml, ipt_lowmem));
  9161. else
  9162. {
  9163. Owned<IPropertyTree> p = createPTree("W_LOCAL", ipt_lowmem);
  9164. p->setProp("@xmlns:xsi", "http://www.w3.org/1999/XMLSchema-instance");
  9165. cw->loadPTree(p.getClear());
  9166. }
  9167. ILocalWorkUnit* ret = QUERYINTERFACE(&cw->lockRemote(false), ILocalWorkUnit);
  9168. return ret;
  9169. }
  9170. void exportWorkUnitToXMLWithHiddenPasswords(IPropertyTree *p, IIOStream &out, unsigned extraXmlFlags)
  9171. {
  9172. const char *name = p->queryName();
  9173. if (!name)
  9174. name = "__unnamed__";
  9175. StringBuffer temp;
  9176. writeStringToStream(out, appendPTreeOpenTag(temp, p, name, 1, true));
  9177. Owned<IPropertyTreeIterator> elems = p->getElements("*", iptiter_sort);
  9178. ForEach(*elems)
  9179. {
  9180. IPropertyTree &elem = elems->query();
  9181. if (streq(elem.queryName(), "Parameters"))
  9182. {
  9183. writeStringToStream(out, appendPTreeOpenTag(temp.clear().append(' '), &elem, "Parameters", 2, false).append('\n'));
  9184. Owned<IPropertyTreeIterator> params = elem.getElements("*", iptiter_sort);
  9185. ForEach(*params)
  9186. {
  9187. IPropertyTree &param = params->query();
  9188. const char *paramname = param.queryName();
  9189. VStringBuffer xpath("Variables/Variable[@name='%s']/Format/@password", paramname);
  9190. if (p->getPropBool(xpath))
  9191. writeStringToStream(out, appendXMLTag(temp.clear().append(" "), paramname, "****").append('\n'));
  9192. else
  9193. {
  9194. toXML(&param, out, 2, XML_Format|XML_SortTags|extraXmlFlags);
  9195. }
  9196. }
  9197. writeStringToStream(out, appendXMLCloseTag(temp.clear().append(' '), "Parameters").append('\n'));
  9198. }
  9199. else if (streq(elem.queryName(), "Variables"))
  9200. {
  9201. writeStringToStream(out, appendPTreeOpenTag(temp.clear().append(' '), &elem, "Variables", 2, false).append('\n'));
  9202. Owned<IPropertyTreeIterator> vars = elem.getElements("*", iptiter_sort);
  9203. ForEach(*vars)
  9204. {
  9205. Owned<IPropertyTree> var = LINK(&vars->query());
  9206. if (var->getPropBool("Format/@password"))
  9207. {
  9208. var.setown(createPTreeFromIPT(var)); //copy and remove password values
  9209. var->removeProp("Value");
  9210. var->removeProp("xmlValue");
  9211. }
  9212. toXML(var, out, 2, XML_Format|XML_SortTags|extraXmlFlags);
  9213. }
  9214. writeStringToStream(out, appendXMLCloseTag(temp.clear().append(' '), "Variables").append('\n'));
  9215. }
  9216. else
  9217. toXML(&elem, out, 1, XML_Format|XML_SortTags|extraXmlFlags);
  9218. }
  9219. writeStringToStream(out, appendXMLCloseTag(temp.clear(), name));
  9220. }
  9221. StringBuffer &exportWorkUnitToXMLWithHiddenPasswords(IPropertyTree *p, StringBuffer &str)
  9222. {
  9223. class CAdapter : public CInterface, implements IIOStream
  9224. {
  9225. StringBuffer &out;
  9226. public:
  9227. IMPLEMENT_IINTERFACE;
  9228. CAdapter(StringBuffer &_out) : out(_out) { }
  9229. virtual void flush() { }
  9230. virtual size32_t read(size32_t len, void * data) { UNIMPLEMENTED; return 0; }
  9231. virtual size32_t write(size32_t len, const void * data) { out.append(len, (const char *)data); return len; }
  9232. } adapter(str);
  9233. exportWorkUnitToXMLWithHiddenPasswords(p->queryBranch(NULL), adapter, 0);
  9234. return str;
  9235. }
  9236. void exportWorkUnitToXMLFileWithHiddenPasswords(IPropertyTree *p, const char *filename, unsigned extraXmlFlags)
  9237. {
  9238. OwnedIFile ifile = createIFile(filename);
  9239. OwnedIFileIO ifileio = ifile->open(IFOcreate);
  9240. Owned<IIOStream> stream = createIOStream(ifileio);
  9241. exportWorkUnitToXMLWithHiddenPasswords(p->queryBranch(NULL), *stream, extraXmlFlags);
  9242. }
  9243. extern WORKUNIT_API StringBuffer &exportWorkUnitToXML(const IConstWorkUnit *wu, StringBuffer &str, bool unpack, bool includeProgress, bool hidePasswords)
  9244. {
  9245. // MORE - queryPTree isn't really safe without holding CLocalWorkUnit::crit - really need to move these functions into CLocalWorkunit
  9246. const IExtendedWUInterface *ewu = queryExtendedWU(wu);
  9247. if (ewu)
  9248. {
  9249. Linked<IPropertyTree> p;
  9250. if (unpack||includeProgress)
  9251. p.setown(ewu->getUnpackedTree(includeProgress));
  9252. else
  9253. p.set(ewu->queryPTree());
  9254. if (hidePasswords)
  9255. return exportWorkUnitToXMLWithHiddenPasswords(p, str);
  9256. else
  9257. return toXML(p, str, 0, XML_Format|XML_SortTags);
  9258. }
  9259. else
  9260. return str.append("Unrecognized workunit format");
  9261. }
  9262. extern WORKUNIT_API void exportWorkUnitToXMLFile(const IConstWorkUnit *wu, const char * filename, unsigned extraXmlFlags, bool unpack, bool includeProgress, bool hidePasswords, bool splitStats)
  9263. {
  9264. const IExtendedWUInterface *ewu = queryExtendedWU(wu);
  9265. if (ewu)
  9266. {
  9267. Linked<IPropertyTree> p;
  9268. if (unpack||includeProgress)
  9269. p.setown(ewu->getUnpackedTree(includeProgress));
  9270. else
  9271. p.set(ewu->queryPTree());
  9272. if (hidePasswords)
  9273. return exportWorkUnitToXMLFileWithHiddenPasswords(p, filename, extraXmlFlags);
  9274. if (splitStats)
  9275. {
  9276. StringBuffer statsFilename;
  9277. statsFilename.append(filename).append(".stats");
  9278. IPropertyTree * stats = p->queryPropTree("Statistics");
  9279. if (stats)
  9280. {
  9281. saveXML(statsFilename, stats, 0, (XML_Format|XML_SortTags|extraXmlFlags) & ~XML_LineBreakAttributes);
  9282. p->removeProp("Statistics");
  9283. }
  9284. }
  9285. saveXML(filename, p, 0, XML_Format|XML_SortTags|extraXmlFlags);
  9286. }
  9287. else
  9288. throw makeStringException(0, "Unrecognized workunit format");
  9289. }
  9290. extern WORKUNIT_API void submitWorkUnit(const char *wuid, const char *username, const char *password)
  9291. {
  9292. MemoryBuffer buffer;
  9293. Owned<INamedQueueConnection> conn = createNamedQueueConnection(0); // MORE - security token?
  9294. Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
  9295. Owned<IWorkUnit> workunit = factory->updateWorkUnit(wuid);
  9296. assertex(workunit);
  9297. SCMStringBuffer token;
  9298. createToken(wuid, username, password, token);
  9299. workunit->setSecurityToken(token.str());
  9300. StringAttr clusterName(workunit->queryClusterName());
  9301. if (!clusterName.length())
  9302. throw MakeStringException(WUERR_InvalidCluster, "No target cluster specified");
  9303. workunit->commit();
  9304. workunit.clear();
  9305. Owned<IConstWUClusterInfo> clusterInfo = getTargetClusterInfo(clusterName.str());
  9306. if (!clusterInfo)
  9307. throw MakeStringException(WUERR_InvalidCluster, "Unknown cluster %s", clusterName.str());
  9308. SCMStringBuffer serverQueue;
  9309. clusterInfo->getServerQueue(serverQueue);
  9310. assertex(serverQueue.length());
  9311. Owned<IJobQueue> queue = createJobQueue(serverQueue.str());
  9312. if (!queue.get())
  9313. throw MakeStringException(WUERR_InvalidQueue, "Could not create workunit queue");
  9314. IJobQueueItem *item = createJobQueueItem(wuid);
  9315. queue->enqueue(item);
  9316. }
  9317. extern WORKUNIT_API void abortWorkUnit(const char *wuid)
  9318. {
  9319. StringBuffer xpath("/WorkUnitAborts/");
  9320. xpath.append(wuid);
  9321. Owned<IRemoteConnection> acon = querySDS().connect(xpath.str(), myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE, SDS_LOCK_TIMEOUT);
  9322. acon->queryRoot()->setPropInt(NULL, 1);
  9323. }
  9324. extern WORKUNIT_API void secSubmitWorkUnit(const char *wuid, ISecManager &secmgr, ISecUser &secuser)
  9325. {
  9326. if (checkWuSecAccess(wuid, &secmgr, &secuser, SecAccess_Write, "Submit", true, true))
  9327. submitWorkUnit(wuid, secuser.getName(), secuser.credentials().getPassword());
  9328. }
  9329. extern WORKUNIT_API void secAbortWorkUnit(const char *wuid, ISecManager &secmgr, ISecUser &secuser)
  9330. {
  9331. if (!checkWuSecAccess(wuid, &secmgr, &secuser, SecAccess_Write, "Submit", true, true))
  9332. return;
  9333. abortWorkUnit(wuid);
  9334. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid);
  9335. if(!cw)
  9336. return;
  9337. WorkunitUpdate wu(&cw->lock());
  9338. const char *abortBy = secuser.getName();
  9339. if (abortBy && *abortBy)
  9340. wu->setTracingValue("AbortBy", abortBy);
  9341. wu->setTracingValueInt64("AbortTimeStamp", getTimeStampNowValue());
  9342. }
  9343. extern WORKUNIT_API void submitWorkUnit(const char *wuid, ISecManager *secmgr, ISecUser *secuser)
  9344. {
  9345. if (secmgr && secuser)
  9346. return secSubmitWorkUnit(wuid, *secmgr, *secuser);
  9347. if (secuser)
  9348. return submitWorkUnit(wuid, secuser->getName(), secuser->credentials().getPassword());
  9349. submitWorkUnit(wuid, "", "");
  9350. }
  9351. extern WORKUNIT_API void abortWorkUnit(const char *wuid, ISecManager *secmgr, ISecUser *secuser)
  9352. {
  9353. if (secmgr && secuser)
  9354. return secAbortWorkUnit(wuid, *secmgr, *secuser);
  9355. abortWorkUnit(wuid);
  9356. }
  9357. bool CLocalWorkUnit::hasWorkflow() const
  9358. {
  9359. return p->hasProp("Workflow");
  9360. }
  9361. unsigned CLocalWorkUnit::queryEventScheduledCount() const
  9362. {
  9363. CriticalBlock block(crit);
  9364. if (p->hasProp("@eventScheduledCount"))
  9365. return p->getPropInt("@eventScheduledCount", 0);
  9366. else
  9367. return p->getPropInt("Workflow/@eventScheduledCount", 0); // Legacy location for this setting
  9368. }
  9369. void CLocalWorkUnit::incEventScheduledCount()
  9370. {
  9371. CriticalBlock block(crit);
  9372. p->setPropInt("@eventScheduledCount", queryEventScheduledCount()+1);
  9373. }
  9374. IPropertyTree * CLocalWorkUnit::queryWorkflowTree() const
  9375. {
  9376. CriticalBlock block(crit);
  9377. return p->queryPropTree("Workflow");
  9378. }
  9379. IConstWorkflowItemIterator* CLocalWorkUnit::getWorkflowItems() const
  9380. {
  9381. // For this to be legally called, we must have the read-able interface. So we are already locked for (at least) read.
  9382. CriticalBlock block(crit);
  9383. if(!workflowIteratorCached)
  9384. {
  9385. assertex(!workflowIterator);
  9386. Owned<IPropertyTree> s = p->getPropTree("Workflow");
  9387. if(s)
  9388. workflowIterator.setown(createWorkflowItemIterator(s));
  9389. workflowIteratorCached = true;
  9390. }
  9391. return workflowIterator.getLink();
  9392. }
  9393. IWorkflowItemArray * CLocalWorkUnit::getWorkflowClone() const
  9394. {
  9395. unsigned count = 0;
  9396. Owned<IConstWorkflowItemIterator> iter = getWorkflowItems();
  9397. for(iter->first(); iter->isValid(); iter->next())
  9398. count++;
  9399. Owned<IWorkflowItemArray> array = createWorkflowItemArray(count);
  9400. for(iter->first(); iter->isValid(); iter->next())
  9401. array->addClone(iter->query());
  9402. return array.getLink();
  9403. }
  9404. IWorkflowItem * CLocalWorkUnit::addWorkflowItem(unsigned wfid, WFType type, WFMode mode, unsigned success, unsigned failure, unsigned recovery, unsigned retriesAllowed, unsigned contingencyFor)
  9405. {
  9406. // For this to be legally called, we must have the write-able interface. So we are already locked for write.
  9407. CriticalBlock block(crit);
  9408. workflowIterator.clear();
  9409. workflowIteratorCached = false;
  9410. IPropertyTree * s = p->queryPropTree("Workflow");
  9411. if(!s)
  9412. s = p->addPropTree("Workflow");
  9413. return createWorkflowItem(s, wfid, type, mode, success, failure, recovery, retriesAllowed, contingencyFor);
  9414. }
  9415. IWorkflowItemIterator * CLocalWorkUnit::updateWorkflowItems()
  9416. {
  9417. // For this to be legally called, we must have the write-able interface. So we are already locked for write.
  9418. CriticalBlock block(crit);
  9419. if(!workflowIterator)
  9420. {
  9421. IPropertyTree * s = p->queryPropTree("Workflow");
  9422. if(!s)
  9423. s = p->addPropTree("Workflow");
  9424. workflowIterator.setown(createWorkflowItemIterator(s));
  9425. workflowIteratorCached = true;
  9426. }
  9427. return workflowIterator.getLink();
  9428. }
  9429. void CLocalWorkUnit::syncRuntimeWorkflow(IWorkflowItemArray * array)
  9430. {
  9431. Owned<IWorkflowItemIterator> iter = updateWorkflowItems();
  9432. Owned<IWorkflowItem> item;
  9433. for(iter->first(); iter->isValid(); iter->next())
  9434. {
  9435. item.setown(iter->get());
  9436. item->syncRuntimeData(array->queryWfid(item->queryWfid()));
  9437. }
  9438. workflowIterator.clear();
  9439. workflowIteratorCached = false;
  9440. }
  9441. void CLocalWorkUnit::resetWorkflow()
  9442. {
  9443. if (hasWorkflow())
  9444. {
  9445. Owned<IWorkflowItemIterator> iter = updateWorkflowItems();
  9446. Owned<IWorkflowItem> wf;
  9447. for(iter->first(); iter->isValid(); iter->next())
  9448. {
  9449. wf.setown(iter->get());
  9450. wf->reset();
  9451. }
  9452. workflowIterator.clear();
  9453. workflowIteratorCached = false;
  9454. }
  9455. }
  9456. void CLocalWorkUnit::schedule()
  9457. {
  9458. CriticalBlock block(crit);
  9459. if(queryEventScheduledCount() == 0) return;
  9460. switch(getState())
  9461. {
  9462. case WUStateCompleted:
  9463. setState(WUStateWait);
  9464. break;
  9465. case WUStateFailed:
  9466. case WUStateArchived:
  9467. case WUStateAborting:
  9468. case WUStateAborted:
  9469. case WUStateScheduled:
  9470. throw MakeStringException(WUERR_CannotSchedule, "Cannot schedule workunit in this state");
  9471. }
  9472. StringBuffer rootPath;
  9473. rootPath.append("/Schedule/").append(queryClusterName());
  9474. Owned<IRemoteConnection> conn = querySDS().connect(rootPath.str(), myProcessSession(), RTM_LOCK_WRITE | RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT);
  9475. Owned<IPropertyTree> root = conn->getRoot();
  9476. if(!root->hasChildren())
  9477. {
  9478. StringBuffer addPath;
  9479. addPath.append("/Schedulers/").append(queryClusterName());
  9480. Owned<IRemoteConnection> addConn = querySDS().connect(addPath.str(), myProcessSession(), RTM_LOCK_WRITE | RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT);
  9481. }
  9482. char const * wuid = p->queryName();
  9483. StringBuffer xpath("*/*/");
  9484. ncnameEscape(wuid, xpath);
  9485. bool more;
  9486. do more = root->removeProp(xpath.str()); while(more);
  9487. Owned<IConstWorkflowItemIterator> iter = getWorkflowItems();
  9488. Owned<IWorkflowEvent> event;
  9489. Owned<IPropertyTree> branch1, branch2;
  9490. for(iter->first(); iter->isValid(); iter->next())
  9491. {
  9492. event.setown(iter->query()->getScheduleEvent());
  9493. if(!event) continue;
  9494. ncnameEscape(event->queryName(), xpath.clear());
  9495. ensurePTree(root, xpath.str());
  9496. branch1.setown(root->getPropTree(xpath.str()));
  9497. ncnameEscape(event->queryText(), xpath.clear());
  9498. ensurePTree(branch1, xpath.str());
  9499. branch2.setown(branch1->getPropTree(xpath.str()));
  9500. ncnameEscape(wuid, xpath.clear());
  9501. ensurePTree(branch2, xpath.str());
  9502. }
  9503. }
  9504. void CLocalWorkUnit::deschedule()
  9505. {
  9506. if(queryEventScheduledCount() == 0) return;
  9507. if(getState() == WUStateWait)
  9508. setState(WUStateCompleted);
  9509. doDescheduleWorkkunit(p->queryName());
  9510. }
  9511. EnumMapping localFileUploadTypes[] = {
  9512. { UploadTypeFileSpray, "FileSpray" },
  9513. { UploadTypeWUResult, "WUResult" },
  9514. { UploadTypeWUResultCsv, "WUResultCsv" },
  9515. { UploadTypeWUResultXml, "WUResultXml" },
  9516. { UploadTypeSize, NULL }
  9517. };
  9518. class CLocalFileUpload : public CInterface, implements IConstLocalFileUpload
  9519. {
  9520. public:
  9521. CLocalFileUpload(IPropertyTree * _tree) : tree(_tree) {}
  9522. CLocalFileUpload(unsigned id, LocalFileUploadType type, char const * source, char const * destination, char const * eventTag)
  9523. {
  9524. tree.setown(createPTree());
  9525. tree->setPropInt("@id", id);
  9526. setEnum(tree, "@type", type, localFileUploadTypes);
  9527. tree->setProp("@source", source);
  9528. tree->setProp("@destination", destination);
  9529. if (eventTag)
  9530. tree->setProp("@eventTag", eventTag);
  9531. }
  9532. IMPLEMENT_IINTERFACE;
  9533. IPropertyTree * getTree() { return tree.getLink(); }
  9534. virtual unsigned queryID() const { return tree->getPropInt("@id"); }
  9535. virtual LocalFileUploadType queryType() const { return (LocalFileUploadType)getEnum(tree, "@type", localFileUploadTypes); }
  9536. virtual IStringVal & getSource(IStringVal & ret) const { ret.set(tree->queryProp("@source")); return ret; }
  9537. virtual IStringVal & getDestination(IStringVal & ret) const { ret.set(tree->queryProp("@destination")); return ret; }
  9538. virtual IStringVal & getEventTag(IStringVal & ret) const { if(tree->hasProp("@eventTag")) ret.set(tree->queryProp("@eventTag")); else ret.clear(); return ret; }
  9539. private:
  9540. Owned<IPropertyTree> tree;
  9541. };
  9542. class CLocalFileUploadIterator : public CInterface, implements IConstLocalFileUploadIterator
  9543. {
  9544. public:
  9545. CLocalFileUploadIterator(IPropertyTree * _tree) : tree(_tree), iter(tree->getElements("LocalFileUpload")) {}
  9546. IMPLEMENT_IINTERFACE;
  9547. bool first() { return iter->first(); }
  9548. bool isValid() { return iter->isValid(); }
  9549. bool next() { return iter->next(); }
  9550. IConstLocalFileUpload * get() { return new CLocalFileUpload(&iter->get()); }
  9551. private:
  9552. Owned<IPropertyTree> tree;
  9553. Owned<IPropertyTreeIterator> iter;
  9554. };
  9555. IConstLocalFileUploadIterator * CLocalWorkUnit::getLocalFileUploads() const
  9556. {
  9557. // For this to be legally called, we must have the read-able interface. So we are already locked for (at least) read.
  9558. CriticalBlock block(crit);
  9559. Owned<IPropertyTree> s = p->getPropTree("LocalFileUploads");
  9560. if(s)
  9561. return new CLocalFileUploadIterator(s.getClear());
  9562. else
  9563. return NULL;
  9564. }
  9565. bool CLocalWorkUnit::requiresLocalFileUpload() const
  9566. {
  9567. SCMStringBuffer dest;
  9568. Owned<IConstWUResult> result;
  9569. Owned<IConstLocalFileUploadIterator> iter(getLocalFileUploads());
  9570. if(!iter)
  9571. return false;
  9572. for(iter->first(); iter->isValid(); iter->next())
  9573. {
  9574. Owned<IConstLocalFileUpload> upload(iter->get());
  9575. switch(upload->queryType())
  9576. {
  9577. case UploadTypeWUResult:
  9578. case UploadTypeWUResultCsv:
  9579. case UploadTypeWUResultXml:
  9580. upload->getDestination(dest);
  9581. result.setown(getResultByName(dest.str()));
  9582. if(!result)
  9583. return true;
  9584. break;
  9585. default:
  9586. throw MakeStringException(WUERR_InvalidUploadFormat, "Unsupported local file upload type %s", getEnumText(upload->queryType(), localFileUploadTypes));
  9587. }
  9588. }
  9589. return false;
  9590. }
  9591. unsigned CLocalWorkUnit::addLocalFileUpload(LocalFileUploadType type, char const * source, char const * destination, char const * eventTag)
  9592. {
  9593. // For this to be legally called, we must have the write-able interface. So we are already locked for write.
  9594. CriticalBlock block(crit);
  9595. IPropertyTree * s = p->queryPropTree("LocalFileUploads");
  9596. if(!s)
  9597. s = p->addPropTree("LocalFileUploads");
  9598. unsigned id = s->numChildren();
  9599. Owned<CLocalFileUpload> upload = new CLocalFileUpload(id, type, source, destination, eventTag);
  9600. s->addPropTree("LocalFileUpload", upload->getTree());
  9601. return id;
  9602. }
  9603. IStringVal & CLocalWorkUnit::getAbortBy(IStringVal & str) const
  9604. {
  9605. CriticalBlock block(crit);
  9606. str.set(p->queryProp("Tracing/AbortBy"));
  9607. return str;
  9608. }
  9609. unsigned __int64 CLocalWorkUnit::getAbortTimeStamp() const
  9610. {
  9611. CriticalBlock block(crit);
  9612. return p->getPropInt64("Tracing/AbortTimeStamp", 0);
  9613. }
  9614. #if 0
  9615. void testConstWorkflow(IConstWorkflowItem * cwf, bool * okay, bool * dep)
  9616. {
  9617. DBGLOG("Test workflow const iface %u", cwf->queryWfid());
  9618. unsigned deps = 0;
  9619. Owned<IWorkflowDependencyIterator> diter;
  9620. switch(cwf->queryWfid())
  9621. {
  9622. case 1:
  9623. assertex(!cwf->isScheduled());
  9624. assertex(cwf->queryType() == WFTypeNormal);
  9625. assertex(cwf->queryState() == WFStateNull);
  9626. diter.setown(cwf->getDependencies());
  9627. for(diter->first(); diter->isValid(); diter->next())
  9628. deps++;
  9629. assertex(deps==0);
  9630. okay[0] = true;
  9631. break;
  9632. case 2:
  9633. assertex(!cwf->isScheduled());
  9634. assertex(cwf->queryType() == WFTypeRecovery);
  9635. assertex(cwf->queryState() == WFStateSkip);
  9636. okay[1] = true;
  9637. break;
  9638. case 3:
  9639. assertex(cwf->queryContingencyFor() == 4);
  9640. okay[2] = true;
  9641. break;
  9642. case 4:
  9643. assertex(cwf->isScheduled());
  9644. assertex(cwf->queryType() == WFTypeNormal);
  9645. assertex(cwf->queryState() == WFStateReqd);
  9646. assertex(cwf->querySuccess() == 0);
  9647. assertex(cwf->queryFailure() == 3);
  9648. assertex(cwf->queryRecovery() == 2);
  9649. assertex(cwf->queryRetriesAllowed() == 10);
  9650. assertex(cwf->queryRetriesRemaining() == 10);
  9651. diter.setown(cwf->getDependencies());
  9652. for(diter->first(); diter->isValid(); diter->next())
  9653. {
  9654. dep[diter->query()-1] = true;
  9655. deps++;
  9656. }
  9657. assertex(deps==2);
  9658. assertex(dep[0]);
  9659. assertex(dep[1]);
  9660. okay[3] = true;
  9661. break;
  9662. case 5:
  9663. assertex(cwf->isScheduled());
  9664. assertex(!cwf->isScheduledNow());
  9665. assertex(cwf->querySchedulePriority() == 75);
  9666. assertex(cwf->queryScheduleCount() == 5);
  9667. assertex(cwf->queryScheduleCountRemaining() == 5);
  9668. okay[4] = true;
  9669. break;
  9670. case 6:
  9671. assertex(cwf->isScheduled());
  9672. assertex(!cwf->isScheduledNow());
  9673. assertex(cwf->querySchedulePriority() == 25);
  9674. assertex(!cwf->hasScheduleCount());
  9675. okay[5] = true;
  9676. break;
  9677. default:
  9678. assertex(!"unknown wfid in test");
  9679. }
  9680. }
  9681. void testRuntimeWorkflow(IRuntimeWorkflowItem * rwf, bool * okay)
  9682. {
  9683. DBGLOG("Test workflow runtime iface %u", rwf->queryWfid());
  9684. switch(rwf->queryWfid())
  9685. {
  9686. case 1:
  9687. case 2:
  9688. case 3:
  9689. okay[rwf->queryWfid()-1] = true;
  9690. break;
  9691. case 4:
  9692. {
  9693. unsigned tries = 0;
  9694. while(rwf->testAndDecRetries())
  9695. tries++;
  9696. assertex(tries == 10);
  9697. assertex(rwf->queryRetriesRemaining() == 0);
  9698. rwf->setState(WFStateFail);
  9699. assertex(rwf->queryState() == WFStateFail);
  9700. rwf->reset();
  9701. assertex(rwf->queryRetriesRemaining() == 10);
  9702. assertex(rwf->queryState() == WFStateReqd);
  9703. }
  9704. okay[3] = true;
  9705. break;
  9706. case 5:
  9707. {
  9708. assertex(rwf->queryScheduleCountRemaining() == 5);
  9709. unsigned count = 0;
  9710. do count++; while(rwf->decAndTestScheduleCountRemaining());
  9711. assertex(count == 5);
  9712. assertex(rwf->queryScheduleCountRemaining() == 0);
  9713. rwf->reset();
  9714. assertex(rwf->queryScheduleCountRemaining() == 5);
  9715. }
  9716. okay[4] = true;
  9717. break;
  9718. case 6:
  9719. {
  9720. assertex(!rwf->hasScheduleCount());
  9721. unsigned count;
  9722. for(count=0; count<20; count++)
  9723. assertex(rwf->decAndTestScheduleCountRemaining());
  9724. }
  9725. okay[5] = true;
  9726. break;
  9727. default:
  9728. assertex(!"unknown wfid in test");
  9729. }
  9730. }
  9731. void testWorkflow()
  9732. {
  9733. DBGLOG("workunit.cpp : testWorkflow");
  9734. CLocalWorkUnit wu("W-WF-TEST", 0, 0, 0);
  9735. Owned<IWorkflowItem> wf;
  9736. wf.setown(wu.addWorkflowItem(1, WFTypeNormal, 0, 0, 0, 0, 0));
  9737. wf.setown(wu.addWorkflowItem(2, WFTypeRecovery, 0, 0, 0, 0, 0));
  9738. wf.setown(wu.addWorkflowItem(3, WFTypeFailure, 0, 0, 0, 0, 4));
  9739. wf.setown(wu.addWorkflowItem(4, WFTypeNormal, 0, 3, 2, 10, 0));
  9740. wf->setScheduledNow();
  9741. wf->addDependency(1);
  9742. wf.setown(wu.addWorkflowItem(5, WFTypeNormal, 0, 0, 0, 0, 0));
  9743. wf->setScheduledOn("test", "foo*");
  9744. wf->setSchedulePriority(75);
  9745. wf->setScheduleCount(5);
  9746. wf.setown(wu.addWorkflowItem(6, WFTypeNormal, 0, 0, 0, 0, 0));
  9747. wf->setScheduledOn("test", "bar*");
  9748. wf->setSchedulePriority(25);
  9749. unsigned const n = 6;
  9750. bool okay[n];
  9751. bool dep[n];
  9752. unsigned i;
  9753. for(i=0; i<n; i++)
  9754. okay[i] = dep[i] = 0;
  9755. Owned<IConstWorkflowItemIterator> citer(wu.getWorkflowItems());
  9756. for(citer->first(); citer->isValid(); citer->next())
  9757. testConstWorkflow(citer->query(), okay, dep);
  9758. for(i=0; i<n; i++)
  9759. {
  9760. assertex(okay[i]);
  9761. okay[i] = false;
  9762. }
  9763. Owned<IWorkflowItemIterator> miter(wu.updateWorkflowItems());
  9764. for(miter->first(); miter->isValid(); miter->next())
  9765. {
  9766. Owned<IRuntimeWorkflowItem> rwf(miter->get());
  9767. testRuntimeWorkflow(rwf, okay);
  9768. }
  9769. for(i=0; i<n; i++)
  9770. {
  9771. assertex(okay[i]);
  9772. okay[i] = dep[i] = false;
  9773. }
  9774. Owned<IWorkflowItemArray> array(wu.getWorkflowClone());
  9775. unsigned wfid;
  9776. for(wfid = 1; array->isValid(wfid); wfid++)
  9777. testConstWorkflow(&array->queryWfid(wfid), okay, dep);
  9778. for(i=0; i<n; i++)
  9779. {
  9780. assertex(okay[i]);
  9781. okay[i] = false;
  9782. }
  9783. for(wfid = 1; array->isValid(wfid); wfid++)
  9784. testRuntimeWorkflow(&array->queryWfid(wfid), okay);
  9785. for(i=0; i<n; i++)
  9786. {
  9787. assertex(okay[i]);
  9788. okay[i] = false;
  9789. }
  9790. }
  9791. #endif
  9792. //------------------------------------------------------------------------------------------
  9793. extern WUState waitForWorkUnitToComplete(const char * wuid, int timeout, bool returnOnWaitState)
  9794. {
  9795. return factory->waitForWorkUnit(wuid, (unsigned) timeout, false, returnOnWaitState);
  9796. }
  9797. extern WORKUNIT_API WUState secWaitForWorkUnitToComplete(const char * wuid, ISecManager &secmgr, ISecUser &secuser, int timeout, bool returnOnWaitState)
  9798. {
  9799. if (checkWuSecAccess(wuid, &secmgr, &secuser, SecAccess_Read, "Wait for Complete", false, true))
  9800. return waitForWorkUnitToComplete(wuid, timeout, returnOnWaitState);
  9801. return WUStateUnknown;
  9802. }
  9803. extern bool waitForWorkUnitToCompile(const char * wuid, int timeout)
  9804. {
  9805. switch(factory->waitForWorkUnit(wuid, (unsigned) timeout, true, true))
  9806. {
  9807. case WUStateCompiled:
  9808. case WUStateCompleted:
  9809. case WUStateWait:
  9810. case WUStateUploadingFiles:
  9811. return true;
  9812. default:
  9813. return false;
  9814. }
  9815. }
  9816. extern WORKUNIT_API bool secWaitForWorkUnitToCompile(const char * wuid, ISecManager &secmgr, ISecUser &secuser, int timeout)
  9817. {
  9818. if (checkWuSecAccess(wuid, &secmgr, &secuser, SecAccess_Read, "Wait for Compile", false, true))
  9819. return waitForWorkUnitToCompile(wuid, timeout);
  9820. return false;
  9821. }
  9822. extern WORKUNIT_API bool secDebugWorkunit(const char * wuid, ISecManager &secmgr, ISecUser &secuser, const char *command, StringBuffer &response)
  9823. {
  9824. if (strnicmp(command, "<debug:", 7) == 0 && checkWuSecAccess(wuid, &secmgr, &secuser, SecAccess_Read, "Debug", false, true))
  9825. {
  9826. Owned<IConstWorkUnit> wu = factory->openWorkUnit(wuid, &secmgr, &secuser);
  9827. SCMStringBuffer ip;
  9828. unsigned port;
  9829. port = wu->getDebugAgentListenerPort();
  9830. wu->getDebugAgentListenerIP(ip);
  9831. SocketEndpoint debugEP(ip.str(), port);
  9832. Owned<ISocket> socket = ISocket::connect_timeout(debugEP, 1000);
  9833. unsigned len = (size32_t)strlen(command);
  9834. unsigned revlen = len;
  9835. _WINREV(revlen);
  9836. socket->write(&revlen, sizeof(revlen));
  9837. socket->write(command, len);
  9838. for (;;)
  9839. {
  9840. socket->read(&len, sizeof(len));
  9841. _WINREV(len);
  9842. if (len == 0)
  9843. break;
  9844. if (len & 0x80000000)
  9845. {
  9846. throwUnexpected();
  9847. }
  9848. char * mem = (char*) response.reserve(len);
  9849. socket->read(mem, len);
  9850. }
  9851. return true;
  9852. }
  9853. return false;
  9854. }
  9855. void getSimpleResultType(IWUResult *r, Owned<ITypeInfo> &type)
  9856. {
  9857. TypeInfoArray types;
  9858. StringAttrArray names;
  9859. r->getSchema(types, names, NULL);
  9860. if (types.ordinality()==1)
  9861. type.set(&types.item(0));
  9862. }
  9863. bool isSuppliedParamScalar(IWUResult *r, IPropertyTree &curVal, Owned<ITypeInfo> &type)
  9864. {
  9865. if (!r->isResultScalar())
  9866. return false;
  9867. if (!curVal.hasChildren())
  9868. return true;
  9869. getSimpleResultType(r, type);
  9870. return type && type->isScalar();
  9871. }
  9872. void updateSuppliedXmlParams(IWorkUnit * w)
  9873. {
  9874. Owned<const IPropertyTree> params = w->getXmlParams();
  9875. if (!params)
  9876. return;
  9877. Owned<IPropertyTreeIterator> elems = params->getElements("*");
  9878. ForEach(*elems)
  9879. {
  9880. IPropertyTree & curVal = elems->query();
  9881. const char *name = curVal.queryName();
  9882. Owned<IWUResult> r = updateWorkUnitResult(w, name, -1);
  9883. if (r)
  9884. {
  9885. Owned<ITypeInfo> type;
  9886. StringBuffer s;
  9887. if (isSuppliedParamScalar(r, curVal, type))
  9888. {
  9889. curVal.getProp(".", s);
  9890. r->setResultXML(s);
  9891. r->setResultStatus(ResultStatusSupplied);
  9892. }
  9893. else
  9894. {
  9895. toXML(&curVal, s);
  9896. if (!type)
  9897. getSimpleResultType(r, type);
  9898. bool isSet = (type && type->getTypeCode()==type_set);
  9899. r->setResultRaw(s.length(), s.str(), isSet ? ResultFormatXmlSet : ResultFormatXml);
  9900. }
  9901. }
  9902. else
  9903. DBGLOG("WARNING: no matching variable in workunit for input parameter %s", name);
  9904. }
  9905. }
  9906. IWUResult * updateWorkUnitResult(IWorkUnit * w, const char *name, unsigned sequence)
  9907. {
  9908. switch ((int)sequence)
  9909. {
  9910. case ResultSequenceStored:
  9911. return w->updateVariableByName(name);
  9912. case ResultSequencePersist:
  9913. return w->updateGlobalByName(name);
  9914. case ResultSequenceInternal:
  9915. case ResultSequenceOnce:
  9916. return w->updateTemporaryByName(name);
  9917. default:
  9918. return w->updateResultBySequence(sequence);
  9919. }
  9920. }
  9921. IConstWUResult * getWorkUnitResult(IConstWorkUnit * w, const char *name, unsigned sequence)
  9922. {
  9923. switch ((int)sequence)
  9924. {
  9925. case ResultSequenceStored:
  9926. return w->getVariableByName(name);
  9927. case ResultSequencePersist:
  9928. return w->getGlobalByName(name);
  9929. case ResultSequenceInternal:
  9930. case ResultSequenceOnce:
  9931. return w->getTemporaryByName(name);
  9932. default:
  9933. if (name && name[0])
  9934. return w->getResultByName(name);//name takes precedence over sequence
  9935. else
  9936. return w->getResultBySequence(sequence);
  9937. }
  9938. }
  9939. extern WORKUNIT_API bool getWorkUnitCreateTime(const char *wuid,CDateTime &time)
  9940. {
  9941. if (wuid) {
  9942. char prefchar;
  9943. unsigned year,month,day,hour,min,sec;
  9944. if (sscanf(wuid, "%c%4u%2u%2u-%2u%2u%2u", &prefchar, &year, &month, &day, &hour, &min, &sec)==7) {
  9945. time.set(year, month, day, hour, min, sec, 0, true);
  9946. // time.setDate(year, month, day);
  9947. // time.setTime(hour, min, sec, 0, true); // for some reason time is local
  9948. return true;
  9949. }
  9950. }
  9951. return false;
  9952. }
  9953. extern WORKUNIT_API IStringVal& createToken(const char *wuid, const char *user, const char *password, IStringVal &str)
  9954. {
  9955. StringBuffer wu, token("X");
  9956. wu.append(wuid).append(';').append(user).append(';').append(password);
  9957. encrypt(token,wu.str());
  9958. str.set(token.str());
  9959. return str;
  9960. }
  9961. // This will be replaced by something more secure!
  9962. extern WORKUNIT_API void extractToken(const char *token, const char *wuid, IStringVal &user, IStringVal &password)
  9963. {
  9964. if (token && *token)
  9965. {
  9966. StringBuffer wu;
  9967. decrypt(wu, token+1);
  9968. const char *finger = strchr(wu.str(),';');
  9969. if (finger && strnicmp(wuid, wu.str(), finger-wu.str())==0)
  9970. {
  9971. const char *finger1 = strchr(++finger,';');
  9972. if(finger1)
  9973. {
  9974. user.setLen(finger, (size32_t)(finger1-finger));
  9975. finger1++;
  9976. password.setLen(finger1, (size32_t)(wu.str() + wu.length() - finger1));
  9977. return;
  9978. }
  9979. }
  9980. throw MakeStringException(WUERR_InvalidSecurityToken, "Invalid call to extractToken");
  9981. }
  9982. }
  9983. extern WORKUNIT_API WUState getWorkUnitState(const char* state)
  9984. {
  9985. return (WUState) getEnum(state, states);
  9986. }
  9987. const LogMsgCategory MCschedconn = MCprogress(1000); // Category used to inform about schedule synchronization
  9988. class CWorkflowScheduleConnection : implements IWorkflowScheduleConnection, public CInterface
  9989. {
  9990. public:
  9991. CWorkflowScheduleConnection(char const * wuid)
  9992. {
  9993. basexpath.append("/WorkflowSchedule/").append(wuid);
  9994. flagxpath.append(basexpath.str()).append("/Active");
  9995. }
  9996. IMPLEMENT_IINTERFACE;
  9997. virtual void lock()
  9998. {
  9999. LOG(MCschedconn, "Locking base schedule connection");
  10000. baseconn.setown(querySDS().connect(basexpath.str(), myProcessSession(), RTM_CREATE_QUERY | RTM_LOCK_WRITE, INFINITE));
  10001. if(!baseconn)
  10002. throw MakeStringException(WUERR_ScheduleLockFailed, "Could not get base workflow schedule lock");
  10003. }
  10004. virtual void unlock()
  10005. {
  10006. LOG(MCschedconn, "Unlocking base schedule connection");
  10007. baseconn.clear();
  10008. }
  10009. virtual void setActive()
  10010. {
  10011. LOG(MCschedconn, "Setting active flag in schedule connection");
  10012. flagconn.setown(querySDS().connect(flagxpath.str(), myProcessSession(), RTM_CREATE | RTM_LOCK_WRITE | RTM_DELETE_ON_DISCONNECT, INFINITE));
  10013. if(!flagconn)
  10014. throw MakeStringException(WUERR_ScheduleLockFailed, "Could not get active workflow schedule lock");
  10015. }
  10016. virtual void resetActive()
  10017. {
  10018. LOG(MCschedconn, "Resetting active flag in schedule connection");
  10019. flagconn.clear();
  10020. }
  10021. virtual bool queryActive()
  10022. {
  10023. return baseconn->queryRoot()->hasProp("Active");
  10024. }
  10025. virtual bool pull(IWorkflowItemArray * workflow)
  10026. {
  10027. assertex(baseconn);
  10028. Owned<IPropertyTree> root = baseconn->getRoot();
  10029. Owned<IPropertyTree> eventQueue = root->getPropTree("EventQueue");
  10030. if(!eventQueue) return false;
  10031. if(!eventQueue->hasProp("Item")) return false;
  10032. {
  10033. Owned<IPropertyTreeIterator> eventItems = eventQueue->getElements("Item");
  10034. Owned<IPropertyTree> eventItem;
  10035. Owned<IRuntimeWorkflowItemIterator> wfItems = workflow->getSequenceIterator();
  10036. Owned<IRuntimeWorkflowItem> wfItem;
  10037. for(eventItems->first(); eventItems->isValid(); eventItems->next())
  10038. {
  10039. eventItem.setown(&eventItems->get());
  10040. const char * eventName = eventItem->queryProp("@name");
  10041. const char * eventText = eventItem->queryProp("@text");
  10042. for(wfItems->first(); wfItems->isValid(); wfItems->next())
  10043. {
  10044. wfItem.setown(wfItems->get());
  10045. if(wfItem->queryState() != WFStateWait)
  10046. continue;
  10047. Owned<IWorkflowEvent> targetEvent = wfItem->getScheduleEvent();
  10048. if(!targetEvent || !targetEvent->matches(eventName, eventText))
  10049. continue;
  10050. wfItem->setEvent(eventName, eventText);
  10051. wfItem->setState(WFStateReqd);
  10052. resetDependentsState(workflow, *wfItem);
  10053. }
  10054. }
  10055. }
  10056. bool more;
  10057. do
  10058. more = eventQueue->removeProp("Item");
  10059. while(more);
  10060. return true;
  10061. }
  10062. virtual void push(char const * name, char const * text)
  10063. {
  10064. assertex(baseconn);
  10065. Owned<IPropertyTree> root = baseconn->getRoot();
  10066. IPropertyTree *eventQueue = ensurePTree(root, "EventQueue");
  10067. IPropertyTree *eventItem = eventQueue->addPropTree("Item");
  10068. eventItem->setProp("@name", name);
  10069. eventItem->setProp("@text", text);
  10070. }
  10071. virtual void remove()
  10072. {
  10073. if (baseconn)
  10074. {
  10075. baseconn->close(true);
  10076. baseconn.clear();
  10077. }
  10078. }
  10079. private:
  10080. void resetItemStateAndDependents(IWorkflowItemArray * workflow, unsigned wfid) const
  10081. {
  10082. if (wfid)
  10083. resetItemStateAndDependents(workflow, workflow->queryWfid(wfid));
  10084. }
  10085. void resetItemStateAndDependents(IWorkflowItemArray * workflow, IRuntimeWorkflowItem & item) const
  10086. {
  10087. switch(item.queryState())
  10088. {
  10089. case WFStateDone:
  10090. case WFStateFail:
  10091. {
  10092. item.setState(WFStateNull);
  10093. resetItemStateAndDependents(workflow, item.queryPersistWfid());
  10094. resetDependentsState(workflow, item);
  10095. break;
  10096. }
  10097. }
  10098. }
  10099. void resetDependentsState(IWorkflowItemArray * workflow, IRuntimeWorkflowItem & item) const
  10100. {
  10101. Owned<IWorkflowDependencyIterator> iter(item.getDependencies());
  10102. for(iter->first(); iter->isValid(); iter->next())
  10103. {
  10104. IRuntimeWorkflowItem & dep = workflow->queryWfid(iter->query());
  10105. resetItemStateAndDependents(workflow, dep);
  10106. }
  10107. }
  10108. private:
  10109. StringBuffer basexpath;
  10110. StringBuffer flagxpath;
  10111. Owned<IRemoteConnection> baseconn;
  10112. Owned<IRemoteConnection> flagconn;
  10113. };
  10114. extern WORKUNIT_API IWorkflowScheduleConnection * getWorkflowScheduleConnection(char const * wuid)
  10115. {
  10116. return new CWorkflowScheduleConnection(wuid);
  10117. }
  10118. extern WORKUNIT_API IExtendedWUInterface * queryExtendedWU(IConstWorkUnit * wu)
  10119. {
  10120. return QUERYINTERFACE(wu, IExtendedWUInterface);
  10121. }
  10122. extern WORKUNIT_API const IExtendedWUInterface * queryExtendedWU(const IConstWorkUnit * wu)
  10123. {
  10124. return QUERYINTERFACE(wu, const IExtendedWUInterface);
  10125. }
  10126. extern WORKUNIT_API void addExceptionToWorkunit(IWorkUnit * wu, ErrorSeverity severity, const char * source, unsigned code, const char * text, const char * filename, unsigned lineno, unsigned column, unsigned activity)
  10127. {
  10128. Owned<IWUException> we = wu->createException();
  10129. we->setSeverity(severity);
  10130. we->setExceptionMessage(text);
  10131. if (source)
  10132. we->setExceptionSource(source);
  10133. if (code)
  10134. we->setExceptionCode(code);
  10135. if (filename)
  10136. we->setExceptionFileName(filename);
  10137. if (lineno)
  10138. {
  10139. we->setExceptionLineNo(lineno);
  10140. if (column)
  10141. we->setExceptionColumn(lineno);
  10142. }
  10143. if (activity)
  10144. we->setActivityId(activity);
  10145. }
  10146. const char * skipLeadingXml(const char * text)
  10147. {
  10148. if (!text)
  10149. return NULL;
  10150. //skip utf8 BOM, probably excessive
  10151. if (memcmp(text, UTF8_BOM, 3) == 0)
  10152. text += 3;
  10153. for (;;)
  10154. {
  10155. if (isspace(*text))
  10156. text++;
  10157. else if (text[0] == '<' && text[1] == '?')
  10158. {
  10159. text += 2;
  10160. for (;;)
  10161. {
  10162. if (!*text) break;
  10163. if (text[0] == '?' && text[1] == '>')
  10164. {
  10165. text += 2;
  10166. break;
  10167. }
  10168. text++;
  10169. }
  10170. }
  10171. else if (text[0] == '<' && text[1] == '!' && text[2] == '-' && text[3] == '-')
  10172. {
  10173. text += 4;
  10174. for (;;)
  10175. {
  10176. if (!*text) break;
  10177. if (text[0] == '-' && text[1] == '-' && text[2] == '>')
  10178. {
  10179. text += 3;
  10180. break;
  10181. }
  10182. text++;
  10183. }
  10184. }
  10185. else
  10186. break;
  10187. }
  10188. return text;
  10189. }
  10190. extern WORKUNIT_API bool isArchiveQuery(const char * text)
  10191. {
  10192. text = skipLeadingXml(text);
  10193. if (!text)
  10194. return false;
  10195. const char * archivePrefix = "<Archive";
  10196. return memicmp(text, archivePrefix, strlen(archivePrefix)) == 0;
  10197. }
  10198. extern WORKUNIT_API bool isQueryManifest(const char * text)
  10199. {
  10200. text = skipLeadingXml(text);
  10201. if (!text)
  10202. return false;
  10203. const char * manifestPrefix = "<Manifest";
  10204. return memicmp(text, manifestPrefix, strlen(manifestPrefix)) == 0;
  10205. }
  10206. //------------------------------------------------------------------------------
  10207. // Named Alias helper function
  10208. static IPropertyTree * resolveQueryByDll(IPropertyTree * queryRegistry, const char * dll)
  10209. {
  10210. StringBuffer xpath;
  10211. xpath.append("Query[@dll=\"").append(dll).append("\"]");
  10212. return queryRegistry->getPropTree(xpath);
  10213. }
  10214. static IPropertyTree * resolveQueryByWuid(IPropertyTree * queryRegistry, const char * wuid)
  10215. {
  10216. StringBuffer xpath;
  10217. xpath.append("Query[@wuid=\"").append(wuid).append("\"]");
  10218. return queryRegistry->getPropTree(xpath);
  10219. }
  10220. static void clearAliases(IPropertyTree * queryRegistry, const char * id)
  10221. {
  10222. StringBuffer lcId(id);
  10223. lcId.toLowerCase();
  10224. StringBuffer xpath;
  10225. xpath.append("Alias[@id=\"").append(lcId).append("\"]");
  10226. Owned<IPropertyTreeIterator> iter = queryRegistry->getElements(xpath);
  10227. ForEach(*iter)
  10228. {
  10229. queryRegistry->removeProp(xpath.str());
  10230. }
  10231. }
  10232. IPropertyTree * addNamedQuery(IPropertyTree * queryRegistry, const char * name, const char * wuid, const char * dll, bool library, const char *userid, const char *snapshot)
  10233. {
  10234. StringBuffer lcName(name);
  10235. lcName.toLowerCase();
  10236. StringBuffer xpath;
  10237. xpath.append("Query[@name=\"").append(lcName.str()).append("\"]");
  10238. Owned<IPropertyTreeIterator> iter = queryRegistry->getElements(xpath);
  10239. unsigned seq = 1;
  10240. ForEach(*iter)
  10241. {
  10242. IPropertyTree &item = iter->query();
  10243. const char *thisWuid = item.queryProp("@wuid");
  10244. if (strieq(wuid, thisWuid))
  10245. return &item;
  10246. unsigned thisSeq = item.getPropInt("@seq");
  10247. if (thisSeq >= seq)
  10248. seq = thisSeq + 1;
  10249. }
  10250. StringBuffer id;
  10251. id.append(lcName).append(".").append(seq);
  10252. IPropertyTree * newEntry = createPTree("Query", ipt_caseInsensitive|ipt_lowmem);
  10253. newEntry->setProp("@name", lcName);
  10254. newEntry->setProp("@wuid", wuid);
  10255. newEntry->setProp("@dll", dll);
  10256. newEntry->setProp("@id", id);
  10257. newEntry->setPropInt("@seq", seq);
  10258. if (library)
  10259. newEntry->setPropBool("@isLibrary", true);
  10260. if (userid && *userid)
  10261. newEntry->setProp("@publishedBy", userid);
  10262. if (snapshot && *snapshot)
  10263. newEntry->setProp("@snapshot", snapshot);
  10264. return queryRegistry->addPropTree("Query", newEntry);
  10265. }
  10266. void removeNamedQuery(IPropertyTree * queryRegistry, const char * id)
  10267. {
  10268. StringBuffer lcId(id);
  10269. lcId.toLowerCase();
  10270. clearAliases(queryRegistry, lcId);
  10271. StringBuffer xpath;
  10272. xpath.append("Query[@id=\"").append(lcId).append("\"]");
  10273. queryRegistry->removeProp(xpath);
  10274. }
  10275. void removeDllFromNamedQueries(IPropertyTree * queryRegistry, const char * dll)
  10276. {
  10277. Owned<IPropertyTree> match = resolveQueryByDll(queryRegistry, dll);
  10278. if (!match)
  10279. return;
  10280. clearAliases(queryRegistry, match->queryProp("@id"));
  10281. queryRegistry->removeTree(match);
  10282. }
  10283. void removeWuidFromNamedQueries(IPropertyTree * queryRegistry, const char * wuid)
  10284. {
  10285. Owned<IPropertyTree> match = resolveQueryByWuid(queryRegistry, wuid);
  10286. if (!match)
  10287. return;
  10288. clearAliases(queryRegistry, match->queryProp("@id"));
  10289. queryRegistry->removeTree(match);
  10290. }
  10291. void removeAliasesFromNamedQuery(IPropertyTree * queryRegistry, const char * id)
  10292. {
  10293. clearAliases(queryRegistry, id);
  10294. }
  10295. void setQueryAlias(IPropertyTree * queryRegistry, const char * name, const char * value)
  10296. {
  10297. StringBuffer lcName(name);
  10298. lcName.toLowerCase();
  10299. StringBuffer xpath;
  10300. xpath.append("Alias[@name=\"").append(lcName).append("\"]");
  10301. IPropertyTree * match = queryRegistry->queryPropTree(xpath);
  10302. if (!match)
  10303. {
  10304. match = queryRegistry->addPropTree("Alias");
  10305. match->setProp("@name", lcName);
  10306. }
  10307. match->setProp("@id", value);
  10308. }
  10309. extern WORKUNIT_API IPropertyTree * getQueryById(IPropertyTree * queryRegistry, const char *queryid)
  10310. {
  10311. if (!queryRegistry || !queryid)
  10312. return NULL;
  10313. StringBuffer xpath;
  10314. xpath.append("Query[@id=\"").append(queryid).append("\"]");
  10315. return queryRegistry->getPropTree(xpath);
  10316. }
  10317. extern WORKUNIT_API IPropertyTree * getQueryById(const char *queryset, const char *queryid, bool readonly)
  10318. {
  10319. Owned<IPropertyTree> queryRegistry = getQueryRegistry(queryset, readonly);
  10320. return getQueryById(queryRegistry, queryid);
  10321. }
  10322. extern WORKUNIT_API IPropertyTree * resolveQueryAlias(IPropertyTree * queryRegistry, const char * alias)
  10323. {
  10324. if (!queryRegistry || !alias)
  10325. return NULL;
  10326. StringBuffer xpath;
  10327. unsigned cnt = 0;
  10328. StringBuffer lc(alias);
  10329. const char * search = lc.toLowerCase().str();
  10330. for (;;)
  10331. {
  10332. xpath.set("Alias[@name='").append(search).append("']/@id");
  10333. const char * queryId = queryRegistry->queryProp(xpath);
  10334. if (!queryId)
  10335. break;
  10336. //Check for too many alias indirections.
  10337. if (cnt++ > 10)
  10338. return NULL;
  10339. search = lc.set(queryId).toLowerCase().str();
  10340. }
  10341. return getQueryById(queryRegistry, search);
  10342. }
  10343. extern WORKUNIT_API IPropertyTree * resolveQueryAlias(const char *queryset, const char *alias, bool readonly)
  10344. {
  10345. Owned<IPropertyTree> queryRegistry = getQueryRegistry(queryset, readonly);
  10346. return resolveQueryAlias(queryRegistry, alias);
  10347. }
  10348. void setQuerySuspendedState(IPropertyTree * queryRegistry, const char *id, bool suspend, const char *userid)
  10349. {
  10350. StringBuffer lcId(id);
  10351. lcId.toLowerCase();
  10352. StringBuffer xpath;
  10353. xpath.append("Query[@id=\"").append(lcId).append("\"]");
  10354. IPropertyTree *tree = queryRegistry->queryPropTree(xpath);
  10355. if (tree)
  10356. {
  10357. if (tree->getPropBool("@suspended", false) == suspend)
  10358. return;
  10359. if (suspend)
  10360. {
  10361. tree->addPropBool("@suspended", true);
  10362. if (userid && *userid)
  10363. tree->addProp("@suspendedBy", userid);
  10364. }
  10365. else
  10366. {
  10367. tree->removeProp("@suspended");
  10368. tree->removeProp("@suspendedBy");
  10369. }
  10370. }
  10371. else
  10372. throw MakeStringException((suspend)? QUERRREG_SUSPEND : QUERRREG_UNSUSPEND, "Modifying query suspended state failed. Could not find query %s", id);
  10373. }
  10374. void setQueryCommentForNamedQuery(IPropertyTree * queryRegistry, const char *id, const char *queryComment)
  10375. {
  10376. if (queryComment)
  10377. {
  10378. StringBuffer lcId(id);
  10379. lcId.toLowerCase();
  10380. StringBuffer xpath;
  10381. xpath.append("Query[@id=\"").append(lcId).append("\"]");
  10382. IPropertyTree *tree = queryRegistry->queryPropTree(xpath);
  10383. if (tree)
  10384. tree->setProp("@queryComment", queryComment);
  10385. else
  10386. throw MakeStringException(QUERRREG_COMMENT, "Could not find query %s", id);
  10387. }
  10388. }
  10389. extern WORKUNIT_API IPropertyTree * getQueryRegistryRoot()
  10390. {
  10391. Owned<IRemoteConnection> conn = querySDS().connect("/QuerySets", myProcessSession(), RTM_LOCK_READ, SDS_LOCK_TIMEOUT);
  10392. if (conn)
  10393. return conn->getRoot();
  10394. else
  10395. return NULL;
  10396. }
  10397. extern WORKUNIT_API void checkAddLibrariesToQueryEntry(IPropertyTree *queryTree, IConstWULibraryIterator *libraries)
  10398. {
  10399. if (!queryTree || !libraries)
  10400. return;
  10401. if (queryTree->hasProp("@libCount")) //already added
  10402. return;
  10403. unsigned libCount=0;
  10404. ForEach(*libraries)
  10405. {
  10406. IConstWULibrary &library = libraries->query();
  10407. SCMStringBuffer libname;
  10408. if (!library.getName(libname).length())
  10409. continue;
  10410. queryTree->addProp("Library", libname.str());
  10411. libCount++;
  10412. }
  10413. queryTree->setPropInt("@libCount", libCount);
  10414. }
  10415. extern WORKUNIT_API void checkAddLibrariesToQueryEntry(IPropertyTree *queryTree, IConstWorkUnit *cw)
  10416. {
  10417. Owned<IConstWULibraryIterator> libraries = &cw->getLibraries();
  10418. checkAddLibrariesToQueryEntry(queryTree, libraries);
  10419. }
  10420. extern WORKUNIT_API IPropertyTree * getQueryRegistry(const char * wsEclId, bool readonly)
  10421. {
  10422. //Only lock the branch for the target we're interested in.
  10423. StringBuffer xpath;
  10424. xpath.append("/QuerySets/QuerySet[@id=\"").append(wsEclId).append("\"]");
  10425. Owned<IRemoteConnection> conn = querySDS().connect(xpath.str(), myProcessSession(), readonly ? RTM_LOCK_READ : RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT);
  10426. if (conn)
  10427. return conn->getRoot();
  10428. if (readonly)
  10429. return NULL;
  10430. //Lock the QuerySets in case another thread/client wants to check/add the same QuerySet.
  10431. Owned<IRemoteConnection> globalLock = querySDS().connect("/QuerySets/", myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT);
  10432. //Re-check if the QuerySet has been added between checking the 1st time and gaining the globalLock.
  10433. conn.setown(querySDS().connect(xpath.str(), myProcessSession(), RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT));
  10434. if (conn)
  10435. return conn->getRoot();
  10436. conn.setown(querySDS().connect("/QuerySets/QuerySet", myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_ADD, SDS_LOCK_TIMEOUT));
  10437. if (!conn)
  10438. throwUnexpected();
  10439. IPropertyTree * root = conn->queryRoot();
  10440. root->setProp("@id",wsEclId);
  10441. conn->commit();
  10442. return LINK(root);
  10443. }
  10444. IPropertyTree * addNamedPackageSet(IPropertyTree * packageRegistry, const char * name, IPropertyTree *packageInfo, bool overWrite)
  10445. {
  10446. StringBuffer xpath;
  10447. StringBuffer lcName(name);
  10448. lcName.toLowerCase();
  10449. // see if "name" already exists
  10450. xpath.append("Package[@id='").append(name).append("']");
  10451. IPropertyTree *pkgTree = packageRegistry->queryPropTree(xpath.str());
  10452. if (pkgTree)
  10453. {
  10454. if (overWrite)
  10455. packageRegistry->removeTree(pkgTree);
  10456. else
  10457. throw MakeStringException(WUERR_PackageAlreadyExists, "Package name %s already exists, either delete it or specify overwrite",name);
  10458. }
  10459. IPropertyTree *tree = packageRegistry->addPropTree("Package", packageInfo);
  10460. tree->setProp("@id", lcName);
  10461. return tree;
  10462. }
  10463. void removeNamedPackage(IPropertyTree * packageRegistry, const char * id)
  10464. {
  10465. StringBuffer lcId(id);
  10466. lcId.toLowerCase();
  10467. StringBuffer xpath;
  10468. xpath.append("Package[@id=\"").append(lcId).append("\"]");
  10469. packageRegistry->removeProp(xpath);
  10470. }
  10471. extern WORKUNIT_API IPropertyTree * getPackageSetRegistry(const char * wsEclId, bool readonly)
  10472. {
  10473. //Only lock the branch for the target we're interested in.
  10474. StringBuffer xpath;
  10475. xpath.append("/PackageSets/PackageSet[@id=\"").append(wsEclId).append("\"]");
  10476. Owned<IRemoteConnection> conn = querySDS().connect(xpath.str(), myProcessSession(), readonly ? RTM_LOCK_READ : RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT);
  10477. if (conn)
  10478. return conn->getRoot();
  10479. if (readonly)
  10480. return NULL;
  10481. //Lock the PackageSets in case another thread/client wants to check/add the same PackageSet.
  10482. Owned<IRemoteConnection> globalLock = querySDS().connect("/PackageSets/", myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT);
  10483. //Re-check if the PackageSet has been added between checking the 1st time and gaining the globalLock.
  10484. conn.setown(querySDS().connect(xpath.str(), myProcessSession(), RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT));
  10485. if (conn)
  10486. return conn->getRoot();
  10487. conn.setown(querySDS().connect("/PackageSets/PackageSet", myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_ADD, SDS_LOCK_TIMEOUT));
  10488. if (!conn)
  10489. throwUnexpected();
  10490. IPropertyTree* root = conn->queryRoot();
  10491. root->setProp("@id",wsEclId);
  10492. conn->commit();
  10493. return LINK(root);
  10494. }
  10495. void addQueryToQuerySet(IWorkUnit *workunit, IPropertyTree *queryRegistry, const char *queryName, WUQueryActivationOptions activateOption, StringBuffer &newQueryId, const char *userid)
  10496. {
  10497. StringBuffer cleanQueryName;
  10498. appendUtf8XmlName(cleanQueryName, strlen(queryName), queryName);
  10499. SCMStringBuffer dllName;
  10500. Owned<IConstWUQuery> q = workunit->getQuery();
  10501. q->getQueryDllName(dllName);
  10502. if (!dllName.length())
  10503. throw MakeStringException(WUERR_InvalidDll, "Cannot deploy query - no associated dll.");
  10504. StringBuffer currentTargetClusterType;
  10505. queryRegistry->getProp("@targetclustertype", currentTargetClusterType);
  10506. SCMStringBuffer targetClusterType;
  10507. workunit->getDebugValue("targetclustertype", targetClusterType);
  10508. SCMStringBuffer snapshot;
  10509. workunit->getSnapshot(snapshot);
  10510. if (currentTargetClusterType.length() < 1)
  10511. {
  10512. queryRegistry->setProp("@targetclustertype", targetClusterType.str());
  10513. }
  10514. else
  10515. {
  10516. if (strcmp(currentTargetClusterType.str(), "roxie") == 0 && strcmp(currentTargetClusterType.str(), targetClusterType.str())!=0)
  10517. {
  10518. throw MakeStringException(WUERR_MismatchClusterType, "TargetClusterTypes of workunit and queryset do not match.");
  10519. }
  10520. }
  10521. IPropertyTree *newEntry = addNamedQuery(queryRegistry, cleanQueryName, workunit->queryWuid(), dllName.str(), isLibrary(workunit), userid, snapshot.str());
  10522. Owned<IConstWULibraryIterator> libraries = &workunit->getLibraries();
  10523. checkAddLibrariesToQueryEntry(newEntry, libraries);
  10524. newQueryId.append(newEntry->queryProp("@id"));
  10525. workunit->setIsQueryService(true); //will check querysets before delete
  10526. workunit->commit();
  10527. activateQuery(queryRegistry, activateOption, queryName, newQueryId, userid);
  10528. }
  10529. void activateQuery(IPropertyTree *queryRegistry, WUQueryActivationOptions activateOption, const char *queryName, const char *queryId, const char *userid)
  10530. {
  10531. StringBuffer cleanQueryName;
  10532. appendUtf8XmlName(cleanQueryName, strlen(queryName), queryName);
  10533. if (activateOption == ACTIVATE_SUSPEND_PREVIOUS|| activateOption == ACTIVATE_DELETE_PREVIOUS)
  10534. {
  10535. Owned<IPropertyTree> prevQuery = resolveQueryAlias(queryRegistry, cleanQueryName);
  10536. setQueryAlias(queryRegistry, cleanQueryName, queryId);
  10537. if (prevQuery && !streq(queryId, prevQuery->queryProp("@id")))
  10538. {
  10539. if (activateOption == ACTIVATE_SUSPEND_PREVIOUS)
  10540. setQuerySuspendedState(queryRegistry, prevQuery->queryProp("@id"), true, userid);
  10541. else
  10542. removeNamedQuery(queryRegistry, prevQuery->queryProp("@id"));
  10543. }
  10544. }
  10545. else if (activateOption == MAKE_ACTIVATE || activateOption == MAKE_ACTIVATE_LOAD_DATA_ONLY)
  10546. setQueryAlias(queryRegistry, cleanQueryName, queryId);
  10547. }
  10548. void addQueryToQuerySet(IWorkUnit *workunit, const char *querySetName, const char *queryName, WUQueryActivationOptions activateOption, StringBuffer &newQueryId, const char *userid)
  10549. {
  10550. Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySetName, false);
  10551. addQueryToQuerySet(workunit, queryRegistry, queryName, activateOption, newQueryId, userid);
  10552. }
  10553. bool removeQuerySetAlias(const char *querySetName, const char *alias)
  10554. {
  10555. Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySetName, true);
  10556. StringBuffer xpath;
  10557. xpath.appendf("Alias[@name='%s']", alias);
  10558. IPropertyTree *t = queryRegistry->queryPropTree(xpath);
  10559. return queryRegistry->removeTree(t);
  10560. }
  10561. void addQuerySetAlias(const char *querySetName, const char *alias, const char *id)
  10562. {
  10563. Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySetName, false);
  10564. setQueryAlias(queryRegistry, alias, id);
  10565. }
  10566. void setSuspendQuerySetQuery(const char *querySetName, const char *id, bool suspend, const char *userid)
  10567. {
  10568. Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySetName, true);
  10569. setQuerySuspendedState(queryRegistry, id, suspend, userid);
  10570. }
  10571. void deleteQuerySetQuery(const char *querySetName, const char *id)
  10572. {
  10573. Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySetName, true);
  10574. removeNamedQuery(queryRegistry, id);
  10575. }
  10576. void removeQuerySetAliasesFromNamedQuery(const char *querySetName, const char * id)
  10577. {
  10578. Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySetName, true);
  10579. clearAliases(queryRegistry, id);
  10580. }
  10581. void setQueryCommentForNamedQuery(const char *querySetName, const char *id, const char *queryComment)
  10582. {
  10583. Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySetName, true);
  10584. setQueryCommentForNamedQuery(queryRegistry, id, queryComment);
  10585. }
  10586. const char *queryIdFromQuerySetWuid(IPropertyTree *queryRegistry, const char *wuid, const char *queryName, IStringVal &id)
  10587. {
  10588. if (!queryRegistry)
  10589. return NULL;
  10590. StringBuffer xpath;
  10591. xpath.appendf("Query[@wuid='%s']", wuid);
  10592. if (queryName && *queryName)
  10593. xpath.appendf("[@name='%s']", queryName);
  10594. IPropertyTree *q = queryRegistry->queryPropTree(xpath.str());
  10595. if (q)
  10596. {
  10597. id.set(q->queryProp("@id"));
  10598. }
  10599. return id.str();
  10600. }
  10601. const char *queryIdFromQuerySetWuid(const char *querySetName, const char *wuid, const char *queryName, IStringVal &id)
  10602. {
  10603. Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySetName, true);
  10604. return queryIdFromQuerySetWuid(queryRegistry, wuid, queryName, id);
  10605. }
  10606. extern WORKUNIT_API void gatherLibraryNames(StringArray &names, StringArray &unresolved, IWorkUnitFactory &workunitFactory, IConstWorkUnit &cw, IPropertyTree *queryset)
  10607. {
  10608. Owned<IConstWULibraryIterator> wulibraries = &cw.getLibraries();
  10609. ForEach(*wulibraries)
  10610. {
  10611. SCMStringBuffer libname;
  10612. IConstWULibrary &wulibrary = wulibraries->query();
  10613. wulibrary.getName(libname);
  10614. if (names.contains(libname.str()) || unresolved.contains(libname.str()))
  10615. continue;
  10616. Owned<IPropertyTree> query = resolveQueryAlias(queryset, libname.str());
  10617. if (query && query->getPropBool("@isLibrary"))
  10618. {
  10619. const char *wuid = query->queryProp("@wuid");
  10620. Owned<IConstWorkUnit> libcw = workunitFactory.openWorkUnit(wuid);
  10621. if (libcw)
  10622. {
  10623. names.appendUniq(libname.str());
  10624. gatherLibraryNames(names, unresolved, workunitFactory, *libcw, queryset);
  10625. continue;
  10626. }
  10627. }
  10628. unresolved.appendUniq(libname.str());
  10629. }
  10630. }
  10631. bool looksLikeAWuid(const char * wuid, const char firstChar)
  10632. {
  10633. if (!wuid)
  10634. return false;
  10635. if (wuid[0] != firstChar)
  10636. return false;
  10637. if (!isdigit(wuid[1]) || !isdigit(wuid[2]) || !isdigit(wuid[3]) || !isdigit(wuid[4]))
  10638. return false;
  10639. if (!isdigit(wuid[5]) || !isdigit(wuid[6]) || !isdigit(wuid[7]) || !isdigit(wuid[8]))
  10640. return false;
  10641. return (wuid[9]=='-');
  10642. }
  10643. IPropertyTree * resolveDefinitionInArchive(IPropertyTree * archive, const char * path)
  10644. {
  10645. IPropertyTree * module = archive;
  10646. const char * dot = strrchr(path, '.');
  10647. StringBuffer xpath;
  10648. if (dot)
  10649. {
  10650. xpath.clear().append("Module[@key='").appendLower(dot-path, path).append("']");
  10651. module = archive->queryPropTree(xpath);
  10652. path = dot+1;
  10653. }
  10654. else
  10655. module = archive->queryPropTree("Module[@key='']");
  10656. if (!module)
  10657. return NULL;
  10658. xpath.clear().append("Attribute[@key='").appendLower(strlen(path), path).append("']");
  10659. return module->queryPropTree(xpath);
  10660. }
  10661. extern WORKUNIT_API void associateLocalFile(IWUQuery * query, WUFileType type, const char * name, const char * description, unsigned crc, unsigned minActivity, unsigned maxActivity)
  10662. {
  10663. StringBuffer hostname;
  10664. queryHostIP().getIpText(hostname);
  10665. StringBuffer fullPathname;
  10666. makeAbsolutePath(name, fullPathname);
  10667. query->addAssociatedFile(type, fullPathname, hostname, description, crc, minActivity, maxActivity);
  10668. }
  10669. extern WORKUNIT_API void descheduleWorkunit(char const * wuid)
  10670. {
  10671. Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
  10672. Owned<IWorkUnit> workunit = factory->updateWorkUnit(wuid);
  10673. if(workunit)
  10674. workunit->deschedule();
  10675. else
  10676. doDescheduleWorkkunit(wuid);
  10677. }
  10678. extern WORKUNIT_API void updateWorkunitTimeStat(IWorkUnit * wu, StatisticScopeType scopeType, const char * scope, StatisticKind kind, const char * description, unsigned __int64 value)
  10679. {
  10680. wu->setStatistic(queryStatisticsComponentType(), queryStatisticsComponentName(), scopeType, scope, kind, description, value, 1, 0, StatsMergeReplace);
  10681. }
  10682. class WuTimingUpdater : implements ITimeReportInfo
  10683. {
  10684. public:
  10685. WuTimingUpdater(IWorkUnit * _wu, StatisticScopeType _scopeType, StatisticKind _kind)
  10686. : wu(_wu), scopeType(_scopeType), kind(_kind)
  10687. { }
  10688. virtual void report(const char * scope, const __int64 totaltime, const __int64 maxtime, const unsigned count)
  10689. {
  10690. wu->setStatistic(queryStatisticsComponentType(), queryStatisticsComponentName(), scopeType, scope, kind, nullptr, totaltime, count, maxtime, StatsMergeReplace);
  10691. }
  10692. protected:
  10693. IWorkUnit * wu;
  10694. StatisticScopeType scopeType;
  10695. StatisticKind kind;
  10696. };
  10697. extern WORKUNIT_API void updateWorkunitTimings(IWorkUnit * wu, ITimeReporter *timer)
  10698. {
  10699. WuTimingUpdater target(wu, SSTsection, StTimeTotalExecute);
  10700. timer->report(target);
  10701. }
  10702. extern WORKUNIT_API void updateWorkunitTimings(IWorkUnit * wu, StatisticScopeType scopeType, StatisticKind kind, ITimeReporter *timer)
  10703. {
  10704. WuTimingUpdater target(wu, scopeType, kind);
  10705. timer->report(target);
  10706. }
  10707. extern WORKUNIT_API void getWorkunitTotalTime(IConstWorkUnit* workunit, const char* creator, unsigned __int64 & totalTimeNs, unsigned __int64 & totalThisTimeNs)
  10708. {
  10709. StatisticsFilter summaryTimeFilter(SCTsummary, creator, SSTglobal, GLOBAL_SCOPE, SMeasureTimeNs, StTimeElapsed);
  10710. Owned<IConstWUStatistic> totalThorTime = getStatistic(workunit, summaryTimeFilter);
  10711. if (!totalThorTime)
  10712. {
  10713. StatisticsFilter legacySummaryTimeFilter(SCTsummary, creator, SSTglobal, LEGACY_GLOBAL_SCOPE, SMeasureTimeNs, StTimeElapsed);
  10714. totalThorTime.setown(getStatistic(workunit, legacySummaryTimeFilter));
  10715. }
  10716. Owned<IConstWUStatistic> totalThisThorTime = workunit->getStatistic(queryStatisticsComponentName(), GLOBAL_SCOPE, StTimeElapsed);
  10717. if (!totalThisThorTime)
  10718. totalThisThorTime.setown(workunit->getStatistic(queryStatisticsComponentName(), LEGACY_GLOBAL_SCOPE, StTimeElapsed));
  10719. if (totalThorTime)
  10720. totalTimeNs = totalThorTime->getValue();
  10721. else
  10722. totalTimeNs = 0;
  10723. if (totalThisThorTime)
  10724. totalThisTimeNs = totalThisThorTime->getValue();
  10725. else
  10726. totalThisTimeNs = 0;
  10727. }
  10728. extern WORKUNIT_API void addTimeStamp(IWorkUnit * wu, StatisticScopeType scopeType, const char * scope, StatisticKind kind)
  10729. {
  10730. wu->setStatistic(queryStatisticsComponentType(), queryStatisticsComponentName(), scopeType, scope, kind, NULL, getTimeStampNowValue(), 1, 0, StatsMergeAppend);
  10731. }
  10732. IConstWUStatistic * getStatistic(IConstWorkUnit * wu, const IStatisticsFilter & filter)
  10733. {
  10734. Owned<IConstWUStatisticIterator> iter = &wu->getStatistics(&filter);
  10735. if (iter->first())
  10736. return &OLINK(iter->query());
  10737. return NULL;
  10738. }
  10739. class GlobalStatisticGatherer : public CInterfaceOf<IStatisticGatherer>
  10740. {
  10741. public:
  10742. GlobalStatisticGatherer(IWorkUnit * _wu) : wu(_wu) {}
  10743. virtual void beginScope(const StatsScopeId & id)
  10744. {
  10745. prevLenStack.append(scope.length());
  10746. if (scope.length())
  10747. scope.append(":");
  10748. id.getScopeText(scope);
  10749. scopeTypeStack.append(id.queryScopeType());
  10750. }
  10751. virtual void beginSubGraphScope(unsigned id)
  10752. {
  10753. StatsScopeId scopeId(SSTsubgraph, id);
  10754. beginScope(scopeId);
  10755. }
  10756. virtual void beginActivityScope(unsigned id)
  10757. {
  10758. StatsScopeId scopeId(SSTactivity, id);
  10759. beginScope(scopeId);
  10760. }
  10761. virtual void beginEdgeScope(unsigned id, unsigned oid)
  10762. {
  10763. StatsScopeId scopeId(SSTedge, id, oid);
  10764. beginScope(scopeId);
  10765. }
  10766. virtual void endScope()
  10767. {
  10768. scope.setLength(prevLenStack.popGet());
  10769. scopeTypeStack.pop();
  10770. }
  10771. virtual void addStatistic(StatisticKind kind, unsigned __int64 value)
  10772. {
  10773. StatisticScopeType scopeType = scopeTypeStack.ordinality() ? (StatisticScopeType)scopeTypeStack.tos() : SSTglobal;
  10774. wu->setStatistic(queryStatisticsComponentType(), queryStatisticsComponentName(), scopeType, scope, kind, NULL, value, 1, 0, StatsMergeAppend);
  10775. }
  10776. virtual void updateStatistic(StatisticKind kind, unsigned __int64 value, StatsMergeAction mergeAction)
  10777. {
  10778. StatisticScopeType scopeType = scopeTypeStack.ordinality() ? (StatisticScopeType)scopeTypeStack.tos() : SSTglobal;
  10779. wu->setStatistic(queryStatisticsComponentType(), queryStatisticsComponentName(), scopeType, scope, kind, NULL, value, 1, 0, mergeAction);
  10780. }
  10781. virtual IStatisticCollection * getResult()
  10782. {
  10783. return NULL;
  10784. }
  10785. protected:
  10786. Linked<IWorkUnit> wu;
  10787. StringBuffer scope;
  10788. UnsignedArray prevLenStack;
  10789. UnsignedArray scopeTypeStack;
  10790. };
  10791. IStatisticGatherer * createGlobalStatisticGatherer(IWorkUnit * wu)
  10792. {
  10793. return new GlobalStatisticGatherer(wu);
  10794. }
  10795. extern WORKUNIT_API IPropertyTree * getWUGraphProgress(const char * wuid, bool readonly)
  10796. {
  10797. if (!wuid || !*wuid)
  10798. return NULL;
  10799. VStringBuffer path("/GraphProgress/%s", wuid);
  10800. Owned<IRemoteConnection> conn = querySDS().connect(path.str(),myProcessSession(),readonly ? RTM_LOCK_READ : RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT);
  10801. if (conn)
  10802. return conn->getRoot();
  10803. else
  10804. return NULL;
  10805. }
  10806. void addWorkunitException(IWorkUnit * wu, IError * error, bool removeTimeStamp)
  10807. {
  10808. ErrorSeverity wuSeverity = SeverityInformation;
  10809. ErrorSeverity severity = error->getSeverity();
  10810. switch (severity)
  10811. {
  10812. case SeverityIgnore:
  10813. return;
  10814. case SeverityInformation:
  10815. break;
  10816. case SeverityWarning:
  10817. wuSeverity = SeverityWarning;
  10818. break;
  10819. case SeverityError:
  10820. case SeverityFatal:
  10821. wuSeverity = SeverityError;
  10822. break;
  10823. }
  10824. Owned<IWUException> exception = wu->createException();
  10825. exception->setSeverity(wuSeverity);
  10826. StringBuffer msg;
  10827. exception->setExceptionCode(error->errorCode());
  10828. exception->setExceptionMessage(error->errorMessage(msg).str());
  10829. const char * source = queryCreatorTypeName(queryStatisticsComponentType());
  10830. exception->setExceptionSource(source);
  10831. exception->setExceptionFileName(error->getFilename());
  10832. exception->setExceptionLineNo(error->getLine());
  10833. exception->setExceptionColumn(error->getColumn());
  10834. if (removeTimeStamp)
  10835. exception->setTimeStamp(nullptr);
  10836. if (error->getActivity())
  10837. exception->setActivityId(error->getActivity());
  10838. if (error->queryScope())
  10839. exception->setScope(error->queryScope());
  10840. }
  10841. IError * WorkUnitErrorReceiver::mapError(IError * error)
  10842. {
  10843. return LINK(error);
  10844. }
  10845. void WorkUnitErrorReceiver::report(IError* eclError)
  10846. {
  10847. addWorkunitException(wu, eclError, removeTimeStamp);
  10848. }
  10849. size32_t WorkUnitErrorReceiver::errCount()
  10850. {
  10851. unsigned count = 0;
  10852. Owned<IConstWUExceptionIterator> exceptions = &wu->getExceptions();
  10853. ForEach(*exceptions)
  10854. if (exceptions->query().getSeverity() == SeverityError)
  10855. count++;
  10856. return count;
  10857. }
  10858. size32_t WorkUnitErrorReceiver::warnCount()
  10859. {
  10860. unsigned count = 0;
  10861. Owned<IConstWUExceptionIterator> exceptions = &wu->getExceptions();
  10862. ForEach(*exceptions)
  10863. if (exceptions->query().getSeverity() == SeverityWarning)
  10864. count++;
  10865. return count;
  10866. }