workunit.cpp 345 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603
  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. #define GLOBAL_WORKUNIT "global"
  46. #define SDS_LOCK_TIMEOUT (5*60*1000) // 5mins, 30s a bit short
  47. static int workUnitTraceLevel = 1;
  48. static StringBuffer &getXPath(StringBuffer &wuRoot, const char *wuid)
  49. {
  50. // MORE - can fold in the date
  51. return wuRoot.append("/WorkUnits/").append(wuid);
  52. }
  53. //To be called by eclserver, but esp etc. won't know, so we need to store it.
  54. static StringBuffer & appendLibrarySuffix(StringBuffer & suffix)
  55. {
  56. #ifdef _WIN32
  57. suffix.append("W");
  58. #else
  59. suffix.append("L");
  60. #endif
  61. #ifdef __64BIT__
  62. suffix.append("64");
  63. #else
  64. suffix.append("32");
  65. #endif
  66. return suffix;
  67. }
  68. typedef MapStringTo<bool> UniqueScopes;
  69. static void wuAccessError(const char *username, const char *action, const char *wuscope, const char *wuid, bool excpt, bool log)
  70. {
  71. StringBuffer err;
  72. err.append("Workunit Access Denied - action: ").append(action).append(" user:").append(username ? username : "<Unknown>");
  73. if (wuid)
  74. err.append(" workunit:").append(wuid);
  75. if (wuscope)
  76. err.append(" scope:").append(wuscope);
  77. //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
  78. SYSLOG(AUDIT_TYPE_ACCESS_FAILURE, err.str());
  79. if (log)
  80. LOG(MCuserError, "%s", err.str());
  81. if (excpt)
  82. throw MakeStringException(WUERR_AccessError, "%s", err.str());
  83. }
  84. static bool checkWuScopeSecAccess(const char *wuscope, ISecManager *secmgr, ISecUser *secuser, int required, const char *action, bool excpt, bool log)
  85. {
  86. if (!secmgr || !secuser)
  87. return true;
  88. bool ret = secmgr->authorizeEx(RT_WORKUNIT_SCOPE, *secuser, wuscope)>=required;
  89. if (!ret && (log || excpt))
  90. wuAccessError(secuser->getName(), action, wuscope, NULL, excpt, log);
  91. return ret;
  92. }
  93. static bool checkWuScopeListSecAccess(const char *wuscope, ISecResourceList *scopes, int required, const char *action, bool excpt, bool log)
  94. {
  95. if (!scopes)
  96. return true;
  97. bool ret=true;
  98. if (wuscope)
  99. {
  100. Owned<ISecResource> res=scopes->getResource(wuscope);
  101. if (!res || res->getAccessFlags()<required)
  102. ret=false;
  103. }
  104. else
  105. {
  106. for (int seq=0; ret && seq<scopes->count(); seq++)
  107. {
  108. ISecResource *res=scopes->queryResource(seq);
  109. if (res && res->getAccessFlags()<required)
  110. return false;
  111. }
  112. }
  113. if (!ret && (log || excpt))
  114. wuAccessError(NULL, action, wuscope, NULL, excpt, log);
  115. return ret;
  116. }
  117. static bool checkWuSecAccess(IConstWorkUnit &cw, ISecManager *secmgr, ISecUser *secuser, int required, const char *action, bool excpt, bool log)
  118. {
  119. if (!secmgr || !secuser)
  120. return true;
  121. SCMStringBuffer wuscope;
  122. bool ret=secmgr->authorizeEx(RT_WORKUNIT_SCOPE, *secuser, cw.getWuScope(wuscope).str())>=required;
  123. if (!ret && (log || excpt))
  124. {
  125. wuAccessError(secuser->getName(), action, wuscope.str(), cw.queryWuid(), excpt, log);
  126. }
  127. return ret;
  128. }
  129. static bool checkWuSecAccess(const char *wuid, ISecManager *secmgr, ISecUser *secuser, int required, const char *action, bool excpt, bool log)
  130. {
  131. StringBuffer wuRoot;
  132. Owned<IRemoteConnection> conn = querySDS().connect(getXPath(wuRoot, wuid).str(), myProcessSession(), 0, SDS_LOCK_TIMEOUT);
  133. if (conn)
  134. {
  135. Owned<IPropertyTree> ptree=conn->getRoot();
  136. return checkWuScopeSecAccess(ptree->queryProp("@scope"), secmgr, secuser, required, action, excpt, log);
  137. }
  138. if (log || excpt)
  139. wuAccessError(secuser ? secuser->getName() : NULL, action, "Unknown", NULL, excpt, log);
  140. return false;
  141. }
  142. void doDescheduleWorkkunit(char const * wuid)
  143. {
  144. StringBuffer xpath;
  145. xpath.append("*/*/*/");
  146. ncnameEscape(wuid, xpath);
  147. Owned<IRemoteConnection> conn = querySDS().connect("/Schedule", myProcessSession(), RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT);
  148. if(!conn) return;
  149. Owned<IPropertyTree> root = conn->getRoot();
  150. bool more;
  151. do more = root->removeProp(xpath.str()); while(more);
  152. }
  153. #define PROGRESS_FORMAT_V 2
  154. class CConstGraphProgress : public CInterface, implements IConstWUGraphProgress
  155. {
  156. class CWuGraphStats : public CInterfaceOf<IWUGraphStats>
  157. {
  158. public:
  159. CWuGraphStats(CConstGraphProgress &_parent, StatisticCreatorType _creatorType, const char * _creator, const char * _rootScope, unsigned _id)
  160. : parent(_parent), creatorType(_creatorType), creator(_creator), id(_id)
  161. {
  162. StringBuffer subgraphScopeName;
  163. subgraphScopeName.append(_rootScope);
  164. StatisticScopeType scopeType = SSTgraph;
  165. StatsScopeId rootScopeId;
  166. verifyex(rootScopeId.setScopeText(_rootScope));
  167. collector.setown(createStatisticsGatherer(_creatorType, _creator, rootScopeId));
  168. }
  169. virtual void beforeDispose()
  170. {
  171. Owned<IStatisticCollection> stats = collector->getResult();
  172. MemoryBuffer compressed;
  173. {
  174. MemoryBuffer serialized;
  175. serializeStatisticCollection(serialized, stats);
  176. compressToBuffer(compressed, serialized.length(), serialized.toByteArray());
  177. }
  178. unsigned minActivity = 0;
  179. unsigned maxActivity = 0;
  180. stats->getMinMaxActivity(minActivity, maxActivity);
  181. parent.setSubgraphStats(creatorType, creator, id, compressed, minActivity, maxActivity);
  182. }
  183. virtual IStatisticGatherer & queryStatsBuilder()
  184. {
  185. return *collector;
  186. }
  187. protected:
  188. CConstGraphProgress &parent;
  189. Owned<IStatisticGatherer> collector;
  190. StringAttr creator;
  191. StatisticCreatorType creatorType;
  192. unsigned id;
  193. };
  194. class CGraphProgress : public CInterface, implements IWUGraphProgress
  195. {
  196. CConstGraphProgress &parent;
  197. public:
  198. IMPLEMENT_IINTERFACE;
  199. CGraphProgress(CConstGraphProgress &_parent) : parent(_parent)
  200. {
  201. parent.lockWrite();
  202. }
  203. ~CGraphProgress()
  204. {
  205. parent.unlock();
  206. }
  207. virtual IPropertyTree * getProgressTree() { return parent.getProgressTree(); }
  208. virtual WUGraphState queryGraphState() { return parent.queryGraphState(); }
  209. virtual WUGraphState queryNodeState(WUGraphIDType nodeId) { return parent.queryNodeState(nodeId); }
  210. virtual IWUGraphProgress * update() { throwUnexpected(); }
  211. virtual IWUGraphStats * update(StatisticCreatorType creatorType, const char * creator, unsigned subgraph) { throwUnexpected(); }
  212. virtual unsigned queryFormatVersion() { return parent.queryFormatVersion(); }
  213. virtual void setGraphState(WUGraphState state)
  214. {
  215. parent.setGraphState(state);
  216. }
  217. virtual void setNodeState(WUGraphIDType nodeId, WUGraphState state)
  218. {
  219. parent.setNodeState(nodeId, state);
  220. }
  221. };
  222. void clearConnection()
  223. {
  224. conn.clear();
  225. progress.clear();
  226. }
  227. public:
  228. IMPLEMENT_IINTERFACE;
  229. static void deleteWuidProgress(const char *wuid)
  230. {
  231. StringBuffer path("/GraphProgress/");
  232. path.append(wuid);
  233. Owned<IRemoteConnection> conn = querySDS().connect(path.str(), myProcessSession(), RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT);
  234. if (conn)
  235. conn->close(true);
  236. }
  237. CConstGraphProgress(const char *_wuid, const char *_graphName) : wuid(_wuid), graphName(_graphName)
  238. {
  239. rootPath.append("/GraphProgress/").append(wuid).append('/').append(graphName).append('/');
  240. connected = connectedWrite = false;
  241. formatVersion = 0;
  242. }
  243. CConstGraphProgress(const char *_wuid, const char *_graphName, IPropertyTree *_progress) : wuid(_wuid), graphName(_graphName), progress(_progress)
  244. {
  245. formatVersion = progress->getPropInt("@format");
  246. connectedWrite = false; // should never be
  247. connected = true;
  248. }
  249. void connect()
  250. {
  251. clearConnection();
  252. packProgress(wuid,false);
  253. conn.setown(querySDS().connect(rootPath.str(), myProcessSession(), RTM_LOCK_READ|RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT));
  254. progress.set(conn->queryRoot());
  255. formatVersion = progress->getPropInt("@format");
  256. connected = true;
  257. }
  258. void lockWrite()
  259. {
  260. if (connectedWrite) return;
  261. if (!rootPath.length())
  262. throw MakeStringException(WUERR_GraphProgressWriteUnsupported, "Writing to graph progress unsupported in this context");
  263. // JCSMORE - look at using changeMode here.
  264. if (conn)
  265. clearConnection();
  266. else
  267. packProgress(wuid,false);
  268. conn.setown(querySDS().connect(rootPath.str(), myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT));
  269. progress.set(conn->queryRoot());
  270. if (!progress->hasChildren()) // i.e. blank.
  271. {
  272. formatVersion = PROGRESS_FORMAT_V;
  273. progress->setPropInt("@format", PROGRESS_FORMAT_V);
  274. }
  275. else
  276. formatVersion = progress->getPropInt("@format");
  277. connected = connectedWrite = true;
  278. }
  279. void unlock()
  280. {
  281. connected = false;
  282. connectedWrite = false;
  283. clearConnection();
  284. }
  285. static bool getRunningGraph(const char *wuid, IStringVal &graphName, WUGraphIDType &subId)
  286. {
  287. StringBuffer path;
  288. Owned<IRemoteConnection> conn = querySDS().connect(path.append("/GraphProgress/").append(wuid).str(), myProcessSession(), RTM_LOCK_READ, SDS_LOCK_TIMEOUT);
  289. if (!conn) return false;
  290. const char *name = conn->queryRoot()->queryProp("Running/@graph");
  291. if (name)
  292. {
  293. graphName.set(name);
  294. subId = conn->queryRoot()->getPropInt64("Running/@subId");
  295. return true;
  296. }
  297. else
  298. return false;
  299. }
  300. void setGraphState(WUGraphState state)
  301. {
  302. progress->setPropInt("@_state", (unsigned)state);
  303. }
  304. void setNodeState(WUGraphIDType nodeId, WUGraphState state)
  305. {
  306. if (!connectedWrite) lockWrite();
  307. StringBuffer path;
  308. path.append("node[@id=\"").append(nodeId).append("\"]");
  309. IPropertyTree *node = progress->queryPropTree(path.str());
  310. if (!node)
  311. {
  312. node = progress->addPropTree("node", createPTree());
  313. node->setPropInt("@id", (int)nodeId);
  314. }
  315. node->setPropInt("@_state", (unsigned)state);
  316. switch (state)
  317. {
  318. case WUGraphRunning:
  319. {
  320. StringBuffer path;
  321. Owned<IRemoteConnection> conn = querySDS().connect(path.append("/GraphProgress/").append(wuid).str(), myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT);
  322. IPropertyTree *running = conn->queryRoot()->setPropTree("Running", createPTree());
  323. running->setProp("@graph", graphName);
  324. running->setPropInt64("@subId", nodeId);
  325. break;
  326. }
  327. case WUGraphComplete:
  328. {
  329. StringBuffer path;
  330. Owned<IRemoteConnection> conn = querySDS().connect(path.append("/GraphProgress/").append(wuid).str(), myProcessSession(), RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT);
  331. conn->queryRoot()->removeProp("Running"); // only one thing running at any given time and one thing with lockWrite access
  332. break;
  333. }
  334. }
  335. }
  336. virtual IPropertyTree * getProgressTree()
  337. {
  338. if (!connected) connect();
  339. if (progress->getPropBool("@stats"))
  340. return createProcessTreeFromStats();
  341. return LINK(progress);
  342. }
  343. virtual WUGraphState queryGraphState()
  344. {
  345. return (WUGraphState)queryProgressStateTree()->getPropInt("@_state", (unsigned)WUGraphUnknown);
  346. }
  347. virtual WUGraphState queryNodeState(WUGraphIDType nodeId)
  348. {
  349. StringBuffer path;
  350. path.append("node[@id=\"").append(nodeId).append("\"]/@_state");
  351. return (WUGraphState)queryProgressStateTree()->getPropInt(path.str(), (unsigned)WUGraphUnknown);
  352. }
  353. virtual IWUGraphProgress * update()
  354. {
  355. return new CGraphProgress(*this);
  356. }
  357. virtual IWUGraphStats * update(StatisticCreatorType creatorType, const char * creator, unsigned subgraph)
  358. {
  359. return new CWuGraphStats(*this, creatorType, creator, graphName, subgraph);
  360. }
  361. virtual unsigned queryFormatVersion()
  362. {
  363. if (!connected) connect();
  364. return formatVersion;
  365. }
  366. static bool packProgress(const char *wuid,bool pack)
  367. {
  368. //MORE: This function could be deleted, because progress information is never actually packed
  369. StringBuffer path;
  370. path.append("/GraphProgress/").append(wuid);
  371. Owned<IRemoteConnection> conn(querySDS().connect(path.str(), myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT));
  372. if (!conn)
  373. return false;
  374. Owned<IPropertyTree> newt;
  375. MemoryBuffer buf;
  376. IPropertyTree *root = conn->queryRoot();
  377. if (root->getPropBin("Packed",buf)) {
  378. if (pack)
  379. return true;
  380. newt.setown(createPTree(buf));
  381. IPropertyTree *running = root->queryPropTree("Running");
  382. if (running)
  383. newt->setPropTree("Running",createPTreeFromIPT(running));
  384. }
  385. else {
  386. if (!pack)
  387. return true;
  388. newt.setown(createPTree(wuid));
  389. IPropertyTree *running = root->queryPropTree("Running");
  390. if (running) {
  391. newt->setPropTree("Running",createPTreeFromIPT(running));
  392. root->removeTree(running);
  393. }
  394. root->serialize(buf);
  395. newt->setPropBin("Packed",buf.length(),buf.bufferBase());
  396. }
  397. root->setPropTree(NULL,newt.getClear());
  398. return true;
  399. }
  400. private:
  401. IPropertyTree * queryProgressStateTree()
  402. {
  403. if (!connected) connect();
  404. return progress;
  405. }
  406. static void expandStats(IPropertyTree * target, IStatisticCollection & collection)
  407. {
  408. StringBuffer formattedValue;
  409. unsigned numStats = collection.getNumStatistics();
  410. for (unsigned i=0; i < numStats; i++)
  411. {
  412. StatisticKind kind;
  413. unsigned __int64 value;
  414. collection.getStatistic(kind, value, i);
  415. formatStatistic(formattedValue.clear(), value, kind);
  416. //Until 6.0 generate the backward compatible tag name
  417. const char * legacyTreeTag = queryLegacyTreeTag(kind);
  418. if (legacyTreeTag)
  419. {
  420. StatisticMeasure measure = queryMeasure(kind);
  421. if (measure == SMeasureSkew)
  422. {
  423. //Minimum stats were always output as +ve numbers
  424. if (queryStatsVariant(kind) == StSkewMin)
  425. value = -value;
  426. target->setPropInt64(legacyTreeTag, value/100);
  427. }
  428. else if (measure == SMeasureTimeNs)
  429. {
  430. //Legacy timings are in ms => scale
  431. target->setPropInt64(legacyTreeTag, value/1000000);
  432. }
  433. else
  434. target->setProp(legacyTreeTag, formattedValue);
  435. }
  436. //Unconditionally output in the new format.
  437. target->setProp(queryTreeTag(kind), formattedValue);
  438. }
  439. }
  440. void expandProcessTreeFromStats(IPropertyTree * rootTarget, IPropertyTree * target, IStatisticCollection * collection)
  441. {
  442. expandStats(target, *collection);
  443. StringBuffer scopeName;
  444. Owned<IStatisticCollectionIterator> activityIter = &collection->getScopes(NULL);
  445. ForEach(*activityIter)
  446. {
  447. IStatisticCollection & cur = activityIter->query();
  448. cur.getScope(scopeName.clear());
  449. const char * id = scopeName.str();
  450. const char * tag;
  451. IPropertyTree * curTarget = target;
  452. switch (cur.queryScopeType())
  453. {
  454. case SSTedge:
  455. tag = "edge";
  456. id += strlen(EdgeScopePrefix);
  457. break;
  458. case SSTactivity:
  459. tag = "node";
  460. id += strlen(ActivityScopePrefix);
  461. break;
  462. case SSTsubgraph:
  463. //All subgraphs are added a root elements in the progress tree
  464. curTarget = rootTarget;
  465. tag = "node";
  466. id += strlen(SubGraphScopePrefix);
  467. break;
  468. default:
  469. throwUnexpected();
  470. }
  471. IPropertyTree * next = curTarget->addPropTree(tag, createPTree());
  472. next->setProp("@id", id);
  473. expandProcessTreeFromStats(rootTarget, next, &cur);
  474. }
  475. }
  476. IPropertyTree * createProcessTreeFromStats()
  477. {
  478. MemoryBuffer compressed;
  479. MemoryBuffer serialized;
  480. Owned<IPropertyTree> progressTree = createPTree();
  481. Owned<IPropertyTreeIterator> iter = progress->getElements("sg*");
  482. ForEach(*iter)
  483. {
  484. IPropertyTree & curSubGraph = iter->query();
  485. curSubGraph.getPropBin("Stats", compressed.clear());
  486. //Protect against updates that delete the stats while we are iterating
  487. if (compressed.length())
  488. {
  489. decompressToBuffer(serialized.clear(), compressed);
  490. Owned<IStatisticCollection> collection = createStatisticCollection(serialized);
  491. expandProcessTreeFromStats(progressTree, progressTree, collection);
  492. }
  493. }
  494. return progressTree.getClear();
  495. }
  496. void setSubgraphStats(StatisticCreatorType creatorType, const char * creator, unsigned id, const MemoryBuffer & compressed, unsigned minActivity, unsigned maxActivity)
  497. {
  498. StringBuffer tag;
  499. tag.append("sg").append(id);
  500. IPropertyTree * subgraph = createPTree(tag);
  501. subgraph->setProp("@c", queryCreatorTypeName(creatorType));
  502. subgraph->setProp("@creator", creator);
  503. subgraph->setPropInt("@minActivity", minActivity);
  504. subgraph->setPropInt("@maxActivity", maxActivity);
  505. //Replace the particular subgraph statistics added by this creator
  506. tag.append("[@creator='").append(creator).append("']");
  507. lockWrite();
  508. subgraph = progress->setPropTree(tag, subgraph);
  509. subgraph->setPropBin("Stats", compressed.length(), compressed.toByteArray());
  510. if (!progress->getPropBool("@stats", false))
  511. progress->setPropBool("@stats", true);
  512. unlock();
  513. }
  514. private:
  515. Owned<IRemoteConnection> conn;
  516. Linked<IPropertyTree> progress;
  517. StringAttr wuid, graphName;
  518. StringBuffer rootPath;
  519. bool connected, connectedWrite;
  520. unsigned formatVersion;
  521. };
  522. //--------------------------------------------------------------------------------------------------------------------
  523. class ExtractedStatistic : public CInterfaceOf<IConstWUStatistic>
  524. {
  525. public:
  526. virtual IStringVal & getDescription(IStringVal & str, bool createDefault) const
  527. {
  528. if (!description && createDefault)
  529. {
  530. switch (kind)
  531. {
  532. case StTimeElapsed:
  533. {
  534. if (scopeType != SSTsubgraph)
  535. break;
  536. //Create a default description for a root subgraph
  537. const char * colon = strchr(scope, ':');
  538. if (!colon)
  539. break;
  540. const char * subgraph = colon+1;
  541. //Check for nested subgraph
  542. if (strchr(subgraph, ':'))
  543. break;
  544. assertex(strncmp(subgraph, SubGraphScopePrefix, strlen(SubGraphScopePrefix)) == 0);
  545. StringAttr graphname;
  546. graphname.set(scope, colon - scope);
  547. unsigned subId = atoi(subgraph + strlen(SubGraphScopePrefix));
  548. StringBuffer desc;
  549. formatGraphTimerLabel(desc, graphname, 0, subId);
  550. str.set(desc);
  551. return str;
  552. }
  553. }
  554. }
  555. str.set(description);
  556. return str;
  557. }
  558. virtual IStringVal & getCreator(IStringVal & str) const
  559. {
  560. str.set(creator);
  561. return str;
  562. }
  563. virtual IStringVal & getScope(IStringVal & str) const
  564. {
  565. str.set(scope);
  566. return str;
  567. }
  568. virtual IStringVal & getFormattedValue(IStringVal & str) const
  569. {
  570. StringBuffer formatted;
  571. formatStatistic(formatted, value, measure);
  572. str.set(formatted);
  573. return str;
  574. }
  575. virtual StatisticMeasure getMeasure() const
  576. {
  577. return measure;
  578. }
  579. virtual StatisticKind getKind() const
  580. {
  581. return kind;
  582. }
  583. virtual StatisticCreatorType getCreatorType() const
  584. {
  585. return creatorType;
  586. }
  587. virtual StatisticScopeType getScopeType() const
  588. {
  589. return scopeType;
  590. }
  591. virtual unsigned __int64 getValue() const
  592. {
  593. return value;
  594. }
  595. virtual unsigned __int64 getCount() const
  596. {
  597. return count;
  598. }
  599. virtual unsigned __int64 getMax() const
  600. {
  601. return max;
  602. }
  603. virtual unsigned __int64 getTimestamp() const
  604. {
  605. return timeStamp;
  606. }
  607. virtual bool matches(const IStatisticsFilter * filter) const
  608. {
  609. return filter->matches(creatorType, creator, scopeType, scope, measure, kind);
  610. }
  611. public:
  612. StringAttr creator;
  613. StringAttr description;
  614. StringBuffer scope;
  615. StatisticMeasure measure;
  616. StatisticKind kind;
  617. StatisticCreatorType creatorType;
  618. StatisticScopeType scopeType;
  619. unsigned __int64 value;
  620. unsigned __int64 count;
  621. unsigned __int64 max;
  622. unsigned __int64 timeStamp;
  623. };
  624. class CConstGraphProgressStatisticsIterator : public CInterfaceOf<IConstWUStatisticIterator>
  625. {
  626. public:
  627. CConstGraphProgressStatisticsIterator(const char * wuid, const IStatisticsFilter * _filter) : filter(_filter)
  628. {
  629. if (filter)
  630. scopes.appendList(filter->queryScope(), ":");
  631. const char * searchGraph = "*";
  632. if (scopes.ordinality())
  633. searchGraph = scopes.item(0);
  634. rootPath.append("/GraphProgress/").append(wuid).append('/');
  635. bool singleGraph = false;
  636. if (!containsWildcard(searchGraph))
  637. {
  638. rootPath.append(searchGraph).append("/");
  639. singleGraph = true;
  640. }
  641. //Don't lock the statistics while we iterate - any partial updates must not cause problems
  642. if (daliClientActive())
  643. conn.setown(querySDS().connect(rootPath.str(), myProcessSession(), RTM_NONE, SDS_LOCK_TIMEOUT));
  644. if (conn && !singleGraph)
  645. graphIter.setown(conn->queryRoot()->getElements("*"));
  646. curStat.setown(new ExtractedStatistic);
  647. //These are currently constant for all graph statistics instances
  648. curStat->count = 1;
  649. curStat->max = 0;
  650. valid = false;
  651. }
  652. virtual IConstWUStatistic & query()
  653. {
  654. return *curStat;
  655. }
  656. virtual bool first()
  657. {
  658. valid = false;
  659. if (!conn)
  660. return false;
  661. if (graphIter && !graphIter->first())
  662. return false;
  663. ensureUniqueStatistic();
  664. if (!firstSubGraph())
  665. return false;
  666. valid = true;
  667. return true;
  668. }
  669. virtual bool next()
  670. {
  671. ensureUniqueStatistic();
  672. if (!nextStatistic())
  673. {
  674. if (!nextSubGraph())
  675. {
  676. if (!nextGraph())
  677. {
  678. valid = false;
  679. return false;
  680. }
  681. }
  682. }
  683. return true;
  684. }
  685. virtual bool isValid()
  686. {
  687. return valid;
  688. }
  689. protected:
  690. bool firstSubGraph()
  691. {
  692. IPropertyTree & graphNode = graphIter ? graphIter->query() : *conn->queryRoot();
  693. const char * xpath = "sg*";
  694. StringBuffer childXpath;
  695. if (scopes.isItem(1))
  696. {
  697. const char * scope1 = scopes.item(1);
  698. if (strnicmp(scope1, "sg", 2) == 0)
  699. {
  700. childXpath.append(scope1);
  701. xpath = childXpath.str();
  702. }
  703. }
  704. subgraphIter.setown(graphNode.getElements(xpath));
  705. if (!subgraphIter)
  706. subgraphIter.setown(graphNode.getElements("sg0"));
  707. if (!subgraphIter->first())
  708. return false;
  709. if (firstStat())
  710. return true;
  711. return nextSubGraph();
  712. }
  713. bool nextSubGraph()
  714. {
  715. loop
  716. {
  717. if (!subgraphIter->next())
  718. return false;
  719. if (firstStat())
  720. return true;
  721. }
  722. }
  723. bool nextGraph()
  724. {
  725. if (!graphIter)
  726. return false;
  727. loop
  728. {
  729. if (!graphIter->next())
  730. return false;
  731. if (firstSubGraph())
  732. return true;
  733. }
  734. }
  735. bool firstStat()
  736. {
  737. IPropertyTree & curSubGraph = subgraphIter->query();
  738. if (!checkSubGraph())
  739. return false;
  740. curSubGraph.getPropBin("Stats", compressed.clear());
  741. //Don't crash on old format progress...
  742. if (compressed.length() == 0)
  743. return false;
  744. decompressToBuffer(serialized.clear(), compressed);
  745. Owned<IStatisticCollection> collection = createStatisticCollection(serialized);
  746. curStat->timeStamp = collection->queryWhenCreated();
  747. return beginCollection(*collection);
  748. }
  749. bool beginCollection(IStatisticCollection & collection)
  750. {
  751. collections.append(OLINK(collection));
  752. numStats = collection.getNumStatistics();
  753. curStatIndex = 0;
  754. if (checkScope())
  755. {
  756. if (curStatIndex < numStats)
  757. {
  758. if (checkStatistic())
  759. return true;
  760. return nextStatistic();
  761. }
  762. }
  763. return nextChildScope();
  764. }
  765. bool nextStatistic()
  766. {
  767. //Finish iterating the statistics at this level.
  768. while (++curStatIndex < numStats)
  769. {
  770. if (checkStatistic())
  771. return true;
  772. }
  773. return nextChildScope();
  774. }
  775. bool nextChildScope()
  776. {
  777. loop
  778. {
  779. if (collections.ordinality() == 0)
  780. return false;
  781. IStatisticCollection * curCollection = &collections.tos();
  782. if (childIterators.ordinality() < collections.ordinality())
  783. {
  784. if (!filter || filter->recurseChildScopes(curStat->scopeType, curStat->scope))
  785. {
  786. //Start iterating the children for the current collection
  787. childIterators.append(curCollection->getScopes(NULL));
  788. if (!childIterators.tos().first())
  789. {
  790. finishCollection();
  791. continue;
  792. }
  793. }
  794. else
  795. {
  796. //Don't walk the child scopes
  797. collections.pop();
  798. continue;
  799. }
  800. }
  801. else if (!childIterators.tos().next())
  802. {
  803. finishCollection();
  804. continue;
  805. }
  806. if (beginCollection(childIterators.tos().query()))
  807. return true;
  808. }
  809. }
  810. void finishCollection()
  811. {
  812. collections.pop();
  813. childIterators.pop();
  814. }
  815. bool checkSubGraph()
  816. {
  817. if (!filter)
  818. return true;
  819. IPropertyTree & curSubGraph = subgraphIter->query();
  820. curStat->creatorType = queryCreatorType(curSubGraph.queryProp("@c"));
  821. curStat->creator.set(curSubGraph.queryProp("@creator"));
  822. return filter->matches(curStat->creatorType, curStat->creator, SSTall, NULL, SMeasureAll, StKindAll);
  823. }
  824. bool checkScope()
  825. {
  826. if (!filter)
  827. return true;
  828. IStatisticCollection * collection = &collections.tos();
  829. curStat->scopeType = collection->queryScopeType();
  830. collection->getFullScope(curStat->scope.clear());
  831. return filter->matches(SCTall, NULL, curStat->scopeType, curStat->scope, SMeasureAll, StKindAll);
  832. }
  833. bool checkStatistic()
  834. {
  835. IStatisticCollection & collection = collections.tos();
  836. collection.getStatistic(curStat->kind, curStat->value, curStatIndex);
  837. curStat->measure = queryMeasure(curStat->kind);
  838. if (!filter)
  839. return true;
  840. if (!filter->matches(SCTall, NULL, SSTall, NULL, curStat->measure, curStat->kind))
  841. return false;
  842. return true;
  843. }
  844. void ensureUniqueStatistic()
  845. {
  846. //If something else has linked this statistic, clone a unique one.
  847. if (curStat->IsShared())
  848. curStat.setown(new ExtractedStatistic(*curStat));
  849. }
  850. private:
  851. Owned<IRemoteConnection> conn;
  852. Owned<ExtractedStatistic> curStat;
  853. const IStatisticsFilter * filter;
  854. StringArray scopes;
  855. StringBuffer rootPath;
  856. Owned<IPropertyTreeIterator> graphIter;
  857. Owned<IPropertyTreeIterator> subgraphIter;
  858. IArrayOf<IStatisticCollection> collections;
  859. IArrayOf<IStatisticCollectionIterator> childIterators;
  860. MemoryBuffer compressed;
  861. MemoryBuffer serialized;
  862. unsigned numStats;
  863. unsigned curStatIndex;
  864. bool valid;
  865. };
  866. //--------------------------------------------------------------------------------------------------------------------
  867. struct mapEnums { int val; const char *str; };
  868. mapEnums states[] = {
  869. { WUStateUnknown, "unknown" },
  870. { WUStateCompiled, "compiled" },
  871. { WUStateRunning, "running" },
  872. { WUStateCompleted, "completed" },
  873. { WUStateFailed, "failed" },
  874. { WUStateArchived, "archived" },
  875. { WUStateAborting, "aborting" },
  876. { WUStateAborted, "aborted" },
  877. { WUStateBlocked, "blocked" },
  878. { WUStateSubmitted, "submitted" },
  879. { WUStateScheduled, "scheduled" },
  880. { WUStateCompiling, "compiling" },
  881. { WUStateWait, "wait" },
  882. { WUStateUploadingFiles, "uploading_files" },
  883. { WUStateDebugPaused, "debugging" },
  884. { WUStateDebugRunning, "debug_running" },
  885. { WUStatePaused, "paused" },
  886. { WUStateSize, NULL }
  887. };
  888. const char * getWorkunitStateStr(WUState state)
  889. {
  890. dbgassertex(state < WUStateSize);
  891. return states[state].str; // MORE - should be using getEnumText, or need to take steps to ensure values remain contiguous and in order.
  892. }
  893. const char *getEnumText(int value, const mapEnums *map)
  894. {
  895. const char *defval = map->str;
  896. while (map->str)
  897. {
  898. if (value==map->val)
  899. return map->str;
  900. map++;
  901. }
  902. assertex(!"Unexpected value in setEnum");
  903. return defval;
  904. }
  905. void setEnum(IPropertyTree *p, const char *propname, int value, const mapEnums *map)
  906. {
  907. const char *defval = map->str;
  908. while (map->str)
  909. {
  910. if (value==map->val)
  911. {
  912. p->setProp(propname, map->str);
  913. return;
  914. }
  915. map++;
  916. }
  917. assertex(!"Unexpected value in setEnum");
  918. p->setProp(propname, defval);
  919. }
  920. static int getEnum(const char *v, const mapEnums *map)
  921. {
  922. if (v)
  923. {
  924. while (map->str)
  925. {
  926. if (stricmp(v, map->str)==0)
  927. return map->val;
  928. map++;
  929. }
  930. assertex(!"Unexpected value in getEnum");
  931. }
  932. return 0;
  933. }
  934. static int getEnum(const IPropertyTree *p, const char *propname, const mapEnums *map)
  935. {
  936. return getEnum(p->queryProp(propname),map);
  937. }
  938. //==========================================================================================
  939. class CLightweightWorkunitInfo : public CInterfaceOf<IConstWorkUnitInfo>
  940. {
  941. public:
  942. CLightweightWorkunitInfo(IPropertyTree &p)
  943. {
  944. wuid.set(p.queryName());
  945. user.set(p.queryProp("@submitID"));
  946. jobName.set(p.queryProp("@jobName"));
  947. clusterName.set(p.queryProp("@clusterName"));
  948. timeScheduled.set(p.queryProp("@timeScheduled"));
  949. state = (WUState) getEnum(&p, "@state", states);
  950. _isProtected = p.getPropBool("@protected", false);
  951. _isAborting = false; // MORE - this one is tricky
  952. }
  953. virtual const char *queryWuid() const { return wuid.str(); }
  954. virtual const char *queryUser() const { return user.str(); }
  955. virtual const char *queryJobName() const { return jobName.str(); }
  956. virtual const char *queryClusterName() const { return clusterName.str(); }
  957. virtual WUState getState() const { return state; }
  958. virtual const char *queryStateDesc() const { return getEnumText(getState(), states); }
  959. virtual bool isProtected() const { return _isProtected; }
  960. // Not sure about these ones...
  961. virtual bool aborting() const { return _isAborting; }
  962. virtual IJlibDateTime & getTimeScheduled(IJlibDateTime & val) const
  963. {
  964. if (timeScheduled.length())
  965. val.setGmtString(timeScheduled.str());
  966. return val;
  967. }
  968. protected:
  969. StringAttr wuid, user, jobName, clusterName, timeScheduled;
  970. WUState state;
  971. bool _isProtected;
  972. bool _isAborting;
  973. };
  974. class CDaliWorkUnit : public CLocalWorkUnit
  975. {
  976. public:
  977. IMPLEMENT_IINTERFACE;
  978. CDaliWorkUnit(IRemoteConnection *_conn, ISecManager *secmgr, ISecUser *secuser)
  979. : connection(_conn), CLocalWorkUnit(secmgr, secuser)
  980. {
  981. loadPTree(connection->getRoot());
  982. abortDirty = true;
  983. abortState = false;
  984. }
  985. ~CDaliWorkUnit()
  986. {
  987. // NOTE - order is important - we need to construct connection before p and (especially) destroy after p
  988. // We use the beforeDIspose() in base class to help ensure this
  989. p.clear();
  990. }
  991. virtual void forceReload()
  992. {
  993. synchronized sync(locked); // protect locked workunits (uncommited writes) from reload
  994. StringBuffer wuRoot;
  995. getXPath(wuRoot, p->queryName());
  996. IRemoteConnection *newconn = querySDS().connect(wuRoot.str(), myProcessSession(), 0, SDS_LOCK_TIMEOUT);
  997. if (!newconn)
  998. throw MakeStringException(WUERR_ConnectFailed, "Could not connect to workunit %s (deleted?)",p->queryName());
  999. CriticalBlock block(crit);
  1000. clearCached(true);
  1001. connection.setown(newconn);
  1002. abortDirty = true;
  1003. p.setown(connection->getRoot());
  1004. }
  1005. virtual void cleanupAndDelete(bool deldll, bool deleteOwned, const StringArray *deleteExclusions)
  1006. {
  1007. CLocalWorkUnit::cleanupAndDelete(deldll, deleteOwned, deleteExclusions);
  1008. connection->close(true);
  1009. PROGLOG("WUID %s removed",p->queryName());
  1010. connection.clear();
  1011. }
  1012. virtual void commit()
  1013. {
  1014. CLocalWorkUnit::commit();
  1015. if (connection)
  1016. connection->commit();
  1017. }
  1018. virtual void _lockRemote()
  1019. {
  1020. StringBuffer wuRoot;
  1021. getXPath(wuRoot, p->queryName());
  1022. if (connection)
  1023. connection->changeMode(RTM_LOCK_WRITE,SDS_LOCK_TIMEOUT);
  1024. else
  1025. connection.setown(querySDS().connect(wuRoot.str(), myProcessSession(), RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT));
  1026. if (!connection)
  1027. throw MakeStringException(WUERR_LockFailed, "Failed to get connection for xpath %s", wuRoot.str());
  1028. clearCached(true);
  1029. abortDirty = true;
  1030. p.setown(connection->getRoot());
  1031. }
  1032. virtual void _unlockRemote()
  1033. {
  1034. try
  1035. {
  1036. //MORE: I'm not convinced this is useful...
  1037. setStatistic(queryStatisticsComponentType(), queryStatisticsComponentName(), SSTglobal, NULL, StWhenWorkunitModified, NULL, getTimeStampNowValue(), 1, 0, StatsMergeReplace);
  1038. try
  1039. {
  1040. connection->commit();
  1041. }
  1042. catch (IException *e)
  1043. {
  1044. EXCLOG(e, "Error during workunit commit");
  1045. connection->rollback();
  1046. connection->changeMode(0, SDS_LOCK_TIMEOUT);
  1047. throw;
  1048. }
  1049. connection->changeMode(0, SDS_LOCK_TIMEOUT);
  1050. }
  1051. catch (IException *E)
  1052. {
  1053. StringBuffer s;
  1054. PrintLog("Failed to release write lock on workunit: %s", E->errorMessage(s).str());
  1055. throw;
  1056. }
  1057. }
  1058. virtual void subscribe(WUSubscribeOptions options)
  1059. {
  1060. CriticalBlock block(crit);
  1061. assertex(options==SubscribeOptionAbort);
  1062. if (!abortWatcher)
  1063. {
  1064. abortWatcher.setown(new CWorkUnitAbortWatcher(this, p->queryName()));
  1065. abortDirty = true;
  1066. }
  1067. }
  1068. virtual void unsubscribe()
  1069. {
  1070. CriticalBlock block(crit);
  1071. if (abortWatcher)
  1072. {
  1073. abortWatcher->unsubscribe();
  1074. abortWatcher.clear();
  1075. }
  1076. }
  1077. virtual bool aborting() const
  1078. {
  1079. CriticalBlock block(crit);
  1080. if (abortDirty)
  1081. {
  1082. StringBuffer apath;
  1083. apath.append("/WorkUnitAborts/").append(p->queryName());
  1084. Owned<IRemoteConnection> acon = querySDS().connect(apath.str(), myProcessSession(), 0, SDS_LOCK_TIMEOUT);
  1085. if (acon)
  1086. abortState = acon->queryRoot()->getPropInt(NULL) != 0;
  1087. else
  1088. abortState = false;
  1089. abortDirty = false;
  1090. }
  1091. return abortState;
  1092. }
  1093. protected:
  1094. class CWorkUnitAbortWatcher : public CInterface, implements ISDSSubscription
  1095. {
  1096. CDaliWorkUnit *parent; // not linked - it links me
  1097. SubscriptionId abort;
  1098. public:
  1099. IMPLEMENT_IINTERFACE;
  1100. CWorkUnitAbortWatcher(CDaliWorkUnit *_parent, const char *wuid) : parent(_parent)
  1101. {
  1102. StringBuffer wuRoot;
  1103. wuRoot.append("/WorkUnitAborts/").append(wuid);
  1104. abort = querySDS().subscribe(wuRoot.str(), *this);
  1105. }
  1106. ~CWorkUnitAbortWatcher()
  1107. {
  1108. assertex(abort==0);
  1109. }
  1110. void unsubscribe()
  1111. {
  1112. querySDS().unsubscribe(abort);
  1113. abort = 0;
  1114. }
  1115. void notify(SubscriptionId id, const char *xpath, SDSNotifyFlags flags, unsigned valueLen, const void *valueData)
  1116. {
  1117. parent->abortDirty = true;
  1118. }
  1119. };
  1120. Owned<IRemoteConnection> connection;
  1121. Owned<CWorkUnitAbortWatcher> abortWatcher;
  1122. mutable bool abortDirty;
  1123. mutable bool abortState;
  1124. };
  1125. class CLockedWorkUnit : public CInterface, implements ILocalWorkUnit, implements IExtendedWUInterface
  1126. {
  1127. public:
  1128. Owned<CLocalWorkUnit> c;
  1129. IMPLEMENT_IINTERFACE;
  1130. CLockedWorkUnit(CLocalWorkUnit *_c) : c(_c) {}
  1131. ~CLockedWorkUnit()
  1132. {
  1133. if (workUnitTraceLevel > 1)
  1134. PrintLog("Releasing locked workunit %s", queryWuid());
  1135. if (c)
  1136. c->unlockRemote();
  1137. }
  1138. virtual IConstWorkUnit * unlock()
  1139. {
  1140. c->unlockRemote();
  1141. return c.getClear();
  1142. }
  1143. virtual bool aborting() const
  1144. { return c->aborting(); }
  1145. virtual void forceReload()
  1146. { UNIMPLEMENTED; }
  1147. virtual WUAction getAction() const
  1148. { return c->getAction(); }
  1149. virtual IStringVal& getActionEx(IStringVal & str) const
  1150. { return c->getActionEx(str); }
  1151. virtual IStringVal & getApplicationValue(const char * application, const char * propname, IStringVal & str) const
  1152. { return c->getApplicationValue(application, propname, str); }
  1153. virtual int getApplicationValueInt(const char * application, const char * propname, int defVal) const
  1154. { return c->getApplicationValueInt(application, propname, defVal); }
  1155. virtual IConstWUAppValueIterator & getApplicationValues() const
  1156. { return c->getApplicationValues(); }
  1157. virtual bool hasWorkflow() const
  1158. { return c->hasWorkflow(); }
  1159. virtual unsigned queryEventScheduledCount() const
  1160. { return c->queryEventScheduledCount(); }
  1161. virtual IPropertyTree * queryWorkflowTree() const
  1162. { return c->queryWorkflowTree(); }
  1163. virtual IConstWorkflowItemIterator * getWorkflowItems() const
  1164. { return c->getWorkflowItems(); }
  1165. virtual IWorkflowItemArray * getWorkflowClone() const
  1166. { return c->getWorkflowClone(); }
  1167. virtual bool requiresLocalFileUpload() const
  1168. { return c->requiresLocalFileUpload(); }
  1169. virtual IConstLocalFileUploadIterator * getLocalFileUploads() const
  1170. { return c->getLocalFileUploads(); }
  1171. virtual bool getIsQueryService() const
  1172. { return c->getIsQueryService(); }
  1173. virtual bool getCloneable() const
  1174. { return c->getCloneable(); }
  1175. virtual IUserDescriptor * queryUserDescriptor() const
  1176. { return c->queryUserDescriptor(); }
  1177. virtual const char *queryClusterName() const
  1178. { return c->queryClusterName(); }
  1179. virtual unsigned getCodeVersion() const
  1180. { return c->getCodeVersion(); }
  1181. virtual unsigned getWuidVersion() const
  1182. { return c->getWuidVersion(); }
  1183. virtual void getBuildVersion(IStringVal & buildVersion, IStringVal & eclVersion) const
  1184. { c->getBuildVersion(buildVersion, eclVersion); }
  1185. virtual bool hasDebugValue(const char * propname) const
  1186. { return c->hasDebugValue(propname); }
  1187. virtual IStringVal & getDebugValue(const char * propname, IStringVal & str) const
  1188. { return c->getDebugValue(propname, str); }
  1189. virtual int getDebugValueInt(const char * propname, int defVal) const
  1190. { return c->getDebugValueInt(propname, defVal); }
  1191. virtual __int64 getDebugValueInt64(const char * propname, __int64 defVal) const
  1192. { return c->getDebugValueInt64(propname, defVal); }
  1193. virtual bool getDebugValueBool(const char * propname, bool defVal) const
  1194. { return c->getDebugValueBool(propname, defVal); }
  1195. virtual IStringIterator & getDebugValues() const
  1196. { return c->getDebugValues(NULL); }
  1197. virtual IStringIterator & getDebugValues(const char *prop) const
  1198. { return c->getDebugValues(prop); }
  1199. virtual unsigned getExceptionCount() const
  1200. { return c->getExceptionCount(); }
  1201. virtual IConstWUExceptionIterator & getExceptions() const
  1202. { return c->getExceptions(); }
  1203. virtual unsigned getGraphCount() const
  1204. { return c->getGraphCount(); }
  1205. virtual unsigned getSourceFileCount() const
  1206. { return c->getSourceFileCount(); }
  1207. virtual unsigned getResultCount() const
  1208. { return c->getResultCount(); }
  1209. virtual unsigned getVariableCount() const
  1210. { return c->getVariableCount(); }
  1211. virtual unsigned getApplicationValueCount() const
  1212. { return c->getApplicationValueCount(); }
  1213. virtual IConstWUGraphIterator & getGraphs(WUGraphType type) const
  1214. { return c->getGraphs(type); }
  1215. virtual IConstWUGraphMetaIterator & getGraphsMeta(WUGraphType type) const
  1216. { return c->getGraphsMeta(type); }
  1217. virtual IConstWUGraph * getGraph(const char *name) const
  1218. { return c->getGraph(name); }
  1219. virtual IConstWUGraphProgress * getGraphProgress(const char * name) const
  1220. { return c->getGraphProgress(name); }
  1221. virtual const char *queryJobName() const
  1222. { return c->queryJobName(); }
  1223. virtual IConstWUPlugin * getPluginByName(const char * name) const
  1224. { return c->getPluginByName(name); }
  1225. virtual IConstWUPluginIterator & getPlugins() const
  1226. { return c->getPlugins(); }
  1227. virtual IConstWULibrary* getLibraryByName(const char *name) const
  1228. { return c->getLibraryByName(name); }
  1229. virtual IConstWULibraryIterator & getLibraries() const
  1230. { return c->getLibraries(); }
  1231. virtual WUPriorityClass getPriority() const
  1232. { return c->getPriority(); }
  1233. virtual int getPriorityLevel() const
  1234. { return c->getPriorityLevel(); }
  1235. virtual int getPriorityValue() const
  1236. { return c->getPriorityValue(); }
  1237. virtual IConstWUQuery * getQuery() const
  1238. { return c->getQuery(); }
  1239. virtual IConstWUWebServicesInfo * getWebServicesInfo() const
  1240. { return c->getWebServicesInfo(); }
  1241. virtual IConstWURoxieQueryInfo* getRoxieQueryInfo() const
  1242. { return c->getRoxieQueryInfo(); }
  1243. virtual bool getRescheduleFlag() const
  1244. { return c->getRescheduleFlag(); }
  1245. virtual IConstWUResult * getResultByName(const char * name) const
  1246. { return c->getResultByName(name); }
  1247. virtual IConstWUResult * getResultBySequence(unsigned seq) const
  1248. { return c->getResultBySequence(seq); }
  1249. virtual unsigned getResultLimit() const
  1250. { return c->getResultLimit(); }
  1251. virtual IConstWUResultIterator & getResults() const
  1252. { return c->getResults(); }
  1253. virtual IStringVal & getScope(IStringVal & str) const
  1254. { return c->getScope(str); }
  1255. virtual IStringVal & getSecurityToken(IStringVal & str) const
  1256. { return c->getSecurityToken(str); }
  1257. virtual WUState getState() const
  1258. { return c->getState(); }
  1259. virtual IStringVal & getStateEx(IStringVal & str) const
  1260. { return c->getStateEx(str); }
  1261. virtual __int64 getAgentSession() const
  1262. { return c->getAgentSession(); }
  1263. virtual unsigned getAgentPID() const
  1264. { return c->getAgentPID(); }
  1265. virtual const char *queryStateDesc() const
  1266. { return c->queryStateDesc(); }
  1267. virtual bool getRunningGraph(IStringVal & graphName, WUGraphIDType & subId) const
  1268. { return c->getRunningGraph(graphName, subId); }
  1269. virtual IConstWUStatisticIterator & getStatistics(const IStatisticsFilter * filter) const
  1270. { return c->getStatistics(filter); }
  1271. virtual IConstWUStatistic * getStatistic(const char * creator, const char * scope, StatisticKind kind) const
  1272. { return c->getStatistic(creator, scope, kind); }
  1273. virtual IStringVal & getSnapshot(IStringVal & str) const
  1274. { return c->getSnapshot(str); }
  1275. virtual const char *queryUser() const
  1276. { return c->queryUser(); }
  1277. virtual ErrorSeverity getWarningSeverity(unsigned code, ErrorSeverity defaultSeverity) const
  1278. { return c->getWarningSeverity(code, defaultSeverity); }
  1279. virtual IStringVal & getWuScope(IStringVal & str) const
  1280. { return c->getWuScope(str); }
  1281. virtual const char *queryWuid() const
  1282. { return c->queryWuid(); }
  1283. virtual IConstWUResult * getGlobalByName(const char * name) const
  1284. { return c->getGlobalByName(name); }
  1285. virtual IConstWUResult * getTemporaryByName(const char * name) const
  1286. { return c->getTemporaryByName(name); }
  1287. virtual IConstWUResultIterator & getTemporaries() const
  1288. { return c->getTemporaries(); }
  1289. virtual IConstWUResult * getVariableByName(const char * name) const
  1290. { return c->getVariableByName(name); }
  1291. virtual IConstWUResultIterator & getVariables() const
  1292. { return c->getVariables(); }
  1293. virtual bool isProtected() const
  1294. { return c->isProtected(); }
  1295. virtual bool isPausing() const
  1296. { return c->isPausing(); }
  1297. virtual IWorkUnit & lock()
  1298. { ((CInterface *)this)->Link(); return (IWorkUnit &) *this; }
  1299. virtual bool reload()
  1300. { UNIMPLEMENTED; }
  1301. virtual void subscribe(WUSubscribeOptions options)
  1302. { c->subscribe(options); }
  1303. virtual void requestAbort()
  1304. { c->requestAbort(); }
  1305. virtual unsigned calculateHash(unsigned prevHash)
  1306. { return queryExtendedWU(c)->calculateHash(prevHash); }
  1307. virtual void copyWorkUnit(IConstWorkUnit *cached, bool all)
  1308. { queryExtendedWU(c)->copyWorkUnit(cached, all); }
  1309. virtual IPropertyTree *queryPTree() const
  1310. { return queryExtendedWU(c)->queryPTree(); }
  1311. virtual IPropertyTree *getUnpackedTree(bool includeProgress) const
  1312. { return queryExtendedWU(c)->getUnpackedTree(includeProgress); }
  1313. virtual bool archiveWorkUnit(const char *base,bool del,bool deldll,bool deleteOwned)
  1314. { return queryExtendedWU(c)->archiveWorkUnit(base,del,deldll,deleteOwned); }
  1315. virtual void packWorkUnit(bool pack)
  1316. { queryExtendedWU(c)->packWorkUnit(pack); }
  1317. virtual unsigned queryFileUsage(const char *filename) const
  1318. { return c->queryFileUsage(filename); }
  1319. virtual IJlibDateTime & getTimeScheduled(IJlibDateTime &val) const
  1320. { return c->getTimeScheduled(val); }
  1321. virtual unsigned getDebugAgentListenerPort() const
  1322. { return c->getDebugAgentListenerPort(); }
  1323. virtual IStringVal & getDebugAgentListenerIP(IStringVal &ip) const
  1324. { return c->getDebugAgentListenerIP(ip); }
  1325. virtual IStringVal & getXmlParams(IStringVal & params, bool hidePasswords) const
  1326. { return c->getXmlParams(params, hidePasswords); }
  1327. virtual const IPropertyTree *getXmlParams() const
  1328. { return c->getXmlParams(); }
  1329. virtual unsigned __int64 getHash() const
  1330. { return c->getHash(); }
  1331. virtual IStringIterator *getLogs(const char *type, const char *instance) const
  1332. { return c->getLogs(type, instance); }
  1333. virtual IStringIterator *getProcesses(const char *type) const
  1334. { return c->getProcesses(type); }
  1335. virtual IPropertyTreeIterator* getProcesses(const char *type, const char *instance) const
  1336. { return c->getProcesses(type, instance); }
  1337. virtual void clearExceptions()
  1338. { c->clearExceptions(); }
  1339. virtual void commit()
  1340. { c->commit(); }
  1341. virtual IWUException * createException()
  1342. { return c->createException(); }
  1343. virtual void addProcess(const char *type, const char *instance, unsigned pid, const char *log)
  1344. { c->addProcess(type, instance, pid, log); }
  1345. virtual void protect(bool protectMode)
  1346. { c->protect(protectMode); }
  1347. virtual void setAction(WUAction action)
  1348. { c->setAction(action); }
  1349. virtual void setApplicationValue(const char * application, const char * propname, const char * value, bool overwrite)
  1350. { c->setApplicationValue(application, propname, value, overwrite); }
  1351. virtual void setApplicationValueInt(const char * application, const char * propname, int value, bool overwrite)
  1352. { c->setApplicationValueInt(application, propname, value, overwrite); }
  1353. virtual void incEventScheduledCount()
  1354. { c->incEventScheduledCount(); }
  1355. virtual void setIsQueryService(bool value)
  1356. { c->setIsQueryService(value); }
  1357. virtual void setCloneable(bool value)
  1358. { c->setCloneable(value); }
  1359. virtual void setIsClone(bool value)
  1360. { c->setIsClone(value); }
  1361. virtual void setClusterName(const char * value)
  1362. { c->setClusterName(value); }
  1363. virtual void setCodeVersion(unsigned version, const char * buildVersion, const char * eclVersion)
  1364. { c->setCodeVersion(version, buildVersion, eclVersion); }
  1365. virtual void setDebugValue(const char * propname, const char * value, bool overwrite)
  1366. { c->setDebugValue(propname, value, overwrite); }
  1367. virtual void setDebugValueInt(const char * propname, int value, bool overwrite)
  1368. { c->setDebugValueInt(propname, value, overwrite); }
  1369. virtual void setJobName(const char * value)
  1370. { c->setJobName(value); }
  1371. virtual void setPriority(WUPriorityClass cls)
  1372. { c->setPriority(cls); }
  1373. virtual void setPriorityLevel(int level)
  1374. { c->setPriorityLevel(level); }
  1375. virtual void setRescheduleFlag(bool value)
  1376. { c->setRescheduleFlag(value); }
  1377. virtual void setResultLimit(unsigned value)
  1378. { c->setResultLimit(value); }
  1379. virtual void setSecurityToken(const char *value)
  1380. { c->setSecurityToken(value); }
  1381. virtual void setState(WUState state)
  1382. { c->setState(state); }
  1383. virtual void setStateEx(const char * text)
  1384. { c->setStateEx(text); }
  1385. virtual void setAgentSession(__int64 sessionId)
  1386. { c->setAgentSession(sessionId); }
  1387. 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)
  1388. { c->setStatistic(creatorType, creator, scopeType, scope, kind, optDescription, value, count, maxValue, mergeAction); }
  1389. virtual void setTracingValue(const char * propname, const char * value)
  1390. { c->setTracingValue(propname, value); }
  1391. virtual void setTracingValueInt(const char * propname, int value)
  1392. { c->setTracingValueInt(propname, value); }
  1393. virtual void setUser(const char * value)
  1394. { c->setUser(value); }
  1395. virtual void setWuScope(const char * value)
  1396. { c->setWuScope(value); }
  1397. virtual IWorkflowItem* addWorkflowItem(unsigned wfid, WFType type, WFMode mode, unsigned success, unsigned failure, unsigned recovery, unsigned retriesAllowed, unsigned contingencyFor)
  1398. { return c->addWorkflowItem(wfid, type, mode, success, failure, recovery, retriesAllowed, contingencyFor); }
  1399. virtual void syncRuntimeWorkflow(IWorkflowItemArray * array)
  1400. { c->syncRuntimeWorkflow(array); }
  1401. virtual IWorkflowItemIterator * updateWorkflowItems()
  1402. { return c->updateWorkflowItems(); }
  1403. virtual void resetWorkflow()
  1404. { c->resetWorkflow(); }
  1405. virtual void schedule()
  1406. { c->schedule(); }
  1407. virtual void deschedule()
  1408. { c->deschedule(); }
  1409. virtual unsigned addLocalFileUpload(LocalFileUploadType type, char const * source, char const * destination, char const * eventTag)
  1410. { return c->addLocalFileUpload(type, source, destination, eventTag); }
  1411. virtual IWUResult * updateGlobalByName(const char * name)
  1412. { return c->updateGlobalByName(name); }
  1413. virtual IWUGraph * createGraph(const char * name, WUGraphType type, IPropertyTree *xgmml)
  1414. { return c->createGraph(name, type, xgmml); }
  1415. virtual IWUGraph * updateGraph(const char * name)
  1416. { return c->updateGraph(name); }
  1417. virtual IWUQuery * updateQuery()
  1418. { return c->updateQuery(); }
  1419. virtual IWUWebServicesInfo * updateWebServicesInfo(bool create)
  1420. { return c->updateWebServicesInfo(create); }
  1421. virtual IWURoxieQueryInfo * updateRoxieQueryInfo(const char *wuid, const char *roxieClusterName)
  1422. { return c->updateRoxieQueryInfo(wuid, roxieClusterName); }
  1423. virtual IWUPlugin * updatePluginByName(const char * name)
  1424. { return c->updatePluginByName(name); }
  1425. virtual IWULibrary * updateLibraryByName(const char * name)
  1426. { return c->updateLibraryByName(name); }
  1427. virtual IWUResult * updateResultByName(const char * name)
  1428. { return c->updateResultByName(name); }
  1429. virtual IWUResult * updateResultBySequence(unsigned seq)
  1430. { return c->updateResultBySequence(seq); }
  1431. virtual IWUResult * updateTemporaryByName(const char * name)
  1432. { return c->updateTemporaryByName(name); }
  1433. virtual IWUResult * updateVariableByName(const char * name)
  1434. { return c->updateVariableByName(name); }
  1435. virtual void addFile(const char *fileName, StringArray *clusters, unsigned usageCount, WUFileKind fileKind, const char *graphOwner)
  1436. { c->addFile(fileName, clusters, usageCount, fileKind, graphOwner); }
  1437. virtual void noteFileRead(IDistributedFile *file)
  1438. { c->noteFileRead(file); }
  1439. virtual void releaseFile(const char *fileName)
  1440. { c->releaseFile(fileName); }
  1441. virtual void clearGraphProgress()
  1442. { c->clearGraphProgress(); }
  1443. virtual void resetBeforeGeneration()
  1444. { c->resetBeforeGeneration(); }
  1445. virtual void deleteTempFiles(const char *graph, bool deleteOwned, bool deleteJobOwned)
  1446. { c->deleteTempFiles(graph, deleteOwned, deleteJobOwned); }
  1447. virtual void deleteTemporaries()
  1448. { c->deleteTemporaries(); }
  1449. virtual void addDiskUsageStats(__int64 avgNodeUsage, unsigned minNode, __int64 minNodeUsage, unsigned maxNode, __int64 maxNodeUsage, __int64 graphId)
  1450. { c->addDiskUsageStats(avgNodeUsage, minNode, minNodeUsage, maxNode, maxNodeUsage, graphId); }
  1451. virtual IPropertyTree * getDiskUsageStats()
  1452. { return c->getDiskUsageStats(); }
  1453. virtual IPropertyTreeIterator & getFileIterator() const
  1454. { return c->getFileIterator(); }
  1455. virtual IPropertyTreeIterator & getFilesReadIterator() const
  1456. { return c->getFilesReadIterator(); }
  1457. virtual void setSnapshot(const char * value)
  1458. { c->setSnapshot(value); }
  1459. virtual void setWarningSeverity(unsigned code, ErrorSeverity severity)
  1460. { c->setWarningSeverity(code, severity); }
  1461. virtual void setTimeScheduled(const IJlibDateTime &val)
  1462. { c->setTimeScheduled(val); }
  1463. virtual void setDebugAgentListenerPort(unsigned port)
  1464. { c->setDebugAgentListenerPort(port); }
  1465. virtual void setDebugAgentListenerIP(const char * ip)
  1466. { c->setDebugAgentListenerIP(ip); }
  1467. virtual void setXmlParams(const char *params)
  1468. { c->setXmlParams(params); }
  1469. virtual void setXmlParams(IPropertyTree *tree)
  1470. { c->setXmlParams(tree); }
  1471. virtual void setHash(unsigned __int64 hash)
  1472. { c->setHash(hash); }
  1473. // ILocalWorkUnit - used for debugging etc
  1474. virtual void serialize(MemoryBuffer &tgt)
  1475. { c->serialize(tgt); }
  1476. virtual void deserialize(MemoryBuffer &src)
  1477. { c->deserialize(src); }
  1478. virtual bool switchThorQueue(const char *cluster, IQueueSwitcher *qs)
  1479. { return c->switchThorQueue(cluster,qs); }
  1480. virtual void setAllowedClusters(const char *value)
  1481. { c->setAllowedClusters(value); }
  1482. virtual IStringVal& getAllowedClusters(IStringVal &str) const
  1483. { return c->getAllowedClusters(str); }
  1484. virtual void remoteCheckAccess(IUserDescriptor *user, bool writeaccess) const
  1485. { c->remoteCheckAccess(user,writeaccess); }
  1486. virtual void setAllowAutoQueueSwitch(bool val)
  1487. { c->setAllowAutoQueueSwitch(val); }
  1488. virtual bool getAllowAutoQueueSwitch() const
  1489. { return c->getAllowAutoQueueSwitch(); }
  1490. virtual void setLibraryInformation(const char * name, unsigned interfaceHash, unsigned definitionHash)
  1491. { c->setLibraryInformation(name, interfaceHash, definitionHash); }
  1492. virtual void setResultInt(const char * name, unsigned sequence, __int64 val)
  1493. { c->setResultInt(name, sequence, val); }
  1494. virtual void setResultUInt(const char * name, unsigned sequence, unsigned __int64 val)
  1495. { c->setResultUInt(name, sequence, val); }
  1496. virtual void setResultReal(const char *name, unsigned sequence, double val)
  1497. { c->setResultReal(name, sequence, val); }
  1498. virtual void setResultVarString(const char * stepname, unsigned sequence, const char *val)
  1499. { c->setResultVarString(stepname, sequence, val); }
  1500. virtual void setResultVarUnicode(const char * stepname, unsigned sequence, UChar const *val)
  1501. { c->setResultVarUnicode(stepname, sequence, val); }
  1502. virtual void setResultString(const char * stepname, unsigned sequence, int len, const char *val)
  1503. { c->setResultString(stepname, sequence, len, val); }
  1504. virtual void setResultData(const char * stepname, unsigned sequence, int len, const void *val)
  1505. { c->setResultData(stepname, sequence, len, val); }
  1506. virtual void setResultRaw(const char * name, unsigned sequence, int len, const void *val)
  1507. { c->setResultRaw(name, sequence, len, val); }
  1508. virtual void setResultSet(const char * name, unsigned sequence, bool isAll, size32_t len, const void *val, ISetToXmlTransformer *xform)
  1509. { c->setResultSet(name, sequence, isAll, len, val, xform); }
  1510. virtual void setResultUnicode(const char * name, unsigned sequence, int len, UChar const * val)
  1511. { c->setResultUnicode(name, sequence, len, val); }
  1512. virtual void setResultBool(const char *name, unsigned sequence, bool val)
  1513. { c->setResultBool(name, sequence, val); }
  1514. virtual void setResultDecimal(const char *name, unsigned sequence, int len, int precision, bool isSigned, const void *val)
  1515. { c->setResultDecimal(name, sequence, len, precision, isSigned, val); }
  1516. virtual void setResultDataset(const char * name, unsigned sequence, size32_t len, const void *val, unsigned numRows, bool extend)
  1517. { c->setResultDataset(name, sequence, len, val, numRows, extend); }
  1518. };
  1519. class CLocalWUAssociated : public CInterface, implements IConstWUAssociatedFile
  1520. {
  1521. Owned<IPropertyTree> p;
  1522. public:
  1523. IMPLEMENT_IINTERFACE;
  1524. CLocalWUAssociated(IPropertyTree *p);
  1525. virtual WUFileType getType() const;
  1526. virtual IStringVal & getDescription(IStringVal & ret) const;
  1527. virtual IStringVal & getIp(IStringVal & ret) const;
  1528. virtual IStringVal & getName(IStringVal & ret) const;
  1529. virtual IStringVal & getNameTail(IStringVal & ret) const;
  1530. virtual unsigned getCrc() const;
  1531. };
  1532. class CLocalWUQuery : public CInterface, implements IWUQuery
  1533. {
  1534. Owned<IPropertyTree> p;
  1535. mutable IArrayOf<IConstWUAssociatedFile> associated;
  1536. mutable CriticalSection crit;
  1537. mutable bool associatedCached;
  1538. private:
  1539. void addSpecialCaseAssociated(WUFileType type, const char * propname, unsigned crc) const;
  1540. void loadAssociated() const;
  1541. public:
  1542. IMPLEMENT_IINTERFACE;
  1543. CLocalWUQuery(IPropertyTree *p);
  1544. virtual WUQueryType getQueryType() const;
  1545. virtual IStringVal& getQueryText(IStringVal &str) const;
  1546. virtual IStringVal& getQueryShortText(IStringVal &str) const;
  1547. virtual IStringVal& getQueryName(IStringVal &str) const;
  1548. virtual IStringVal & getQueryMainDefinition(IStringVal & str) const;
  1549. virtual IStringVal& getQueryDllName(IStringVal &str) const;
  1550. virtual unsigned getQueryDllCrc() const;
  1551. virtual IStringVal& getQueryCppName(IStringVal &str) const;
  1552. virtual IStringVal& getQueryResTxtName(IStringVal &str) const;
  1553. virtual IConstWUAssociatedFile * getAssociatedFile(WUFileType type, unsigned index) const;
  1554. virtual IConstWUAssociatedFileIterator& getAssociatedFiles() const;
  1555. virtual void setQueryType(WUQueryType qt);
  1556. virtual void setQueryText(const char *pstr);
  1557. virtual void setQueryName(const char *);
  1558. virtual void setQueryMainDefinition(const char * str);
  1559. virtual void addAssociatedFile(WUFileType type, const char * name, const char * ip, const char * desc, unsigned crc);
  1560. virtual void removeAssociatedFiles();
  1561. virtual void removeAssociatedFile(WUFileType type, const char * name, const char * desc);
  1562. };
  1563. class CLocalWUWebServicesInfo : public CInterface, implements IWUWebServicesInfo
  1564. {
  1565. Owned<IPropertyTree> p;
  1566. mutable CriticalSection crit;
  1567. private:
  1568. public:
  1569. IMPLEMENT_IINTERFACE;
  1570. CLocalWUWebServicesInfo(IPropertyTree *p);
  1571. virtual IStringVal& getModuleName(IStringVal &str) const;
  1572. virtual IStringVal& getAttributeName(IStringVal &str) const;
  1573. virtual IStringVal& getDefaultName(IStringVal &str) const;
  1574. virtual IStringVal& getInfo(const char *name, IStringVal &str) const;
  1575. virtual IStringVal& getText(const char *name, IStringVal &str) const;
  1576. virtual unsigned getWebServicesCRC() const;
  1577. virtual void setModuleName(const char *);
  1578. virtual void setAttributeName(const char *);
  1579. virtual void setDefaultName(const char *);
  1580. virtual void setInfo(const char *name, const char *info);
  1581. virtual void setText(const char *name, const char *info);
  1582. virtual void setWebServicesCRC(unsigned);
  1583. };
  1584. class CLocalWURoxieQueryInfo : public CInterface, implements IWURoxieQueryInfo
  1585. {
  1586. Owned<IPropertyTree> p;
  1587. mutable CriticalSection crit;
  1588. private:
  1589. public:
  1590. IMPLEMENT_IINTERFACE;
  1591. CLocalWURoxieQueryInfo(IPropertyTree *p);
  1592. virtual IStringVal& getQueryInfo(IStringVal &str) const;
  1593. virtual IStringVal& getDefaultPackageInfo(IStringVal &str) const;
  1594. virtual IStringVal& getRoxieClusterName(IStringVal &str) const;
  1595. virtual IStringVal& getWuid(IStringVal &str) const;
  1596. virtual void setQueryInfo(const char *info);
  1597. virtual void setDefaultPackageInfo(const char *, int len);
  1598. virtual void setRoxieClusterName(const char *str);
  1599. virtual void setWuid(const char *str);
  1600. };
  1601. class CLocalWUResult : public CInterface, implements IWUResult
  1602. {
  1603. friend class CLocalWorkUnit;
  1604. mutable CriticalSection crit;
  1605. Owned<IPropertyTree> p;
  1606. Owned<IProperties> xmlns;
  1607. void getSchema(TypeInfoArray &types, StringAttrArray &names, IStringVal * ecl=NULL) const;
  1608. public:
  1609. IMPLEMENT_IINTERFACE;
  1610. CLocalWUResult(IPropertyTree *props);
  1611. ~CLocalWUResult() { try { p.clear(); } catch (IException *E) {E->Release();}}
  1612. virtual WUResultStatus getResultStatus() const;
  1613. virtual IStringVal& getResultName(IStringVal &str) const;
  1614. virtual int getResultSequence() const;
  1615. virtual bool isResultScalar() const;
  1616. virtual IStringVal& getResultXml(IStringVal &str, bool hidePasswords) const;
  1617. virtual unsigned getResultFetchSize() const;
  1618. virtual __int64 getResultTotalRowCount() const;
  1619. virtual __int64 getResultRowCount() const;
  1620. virtual void getResultDataset(IStringVal & ecl, IStringVal & defs) const;
  1621. virtual IStringVal& getResultLogicalName(IStringVal &ecl) const;
  1622. virtual IStringVal& getResultKeyField(IStringVal& ecl) const;
  1623. virtual unsigned getResultRequestedRows() const;
  1624. virtual __int64 getResultInt() const;
  1625. virtual bool getResultBool() const;
  1626. virtual double getResultReal() const;
  1627. virtual IStringVal& getResultString(IStringVal & str, bool hidePassword) const;
  1628. virtual IDataVal& getResultRaw(IDataVal & data, IXmlToRawTransformer * xmlTransformer, ICsvToRawTransformer * csvTransformer) const;
  1629. virtual IDataVal& getResultUnicode(IDataVal & data) const;
  1630. virtual void getResultDecimal(void * val, unsigned length, unsigned precision, bool isSigned) const;
  1631. virtual IStringVal& getResultEclSchema(IStringVal & str) const;
  1632. virtual __int64 getResultRawSize(IXmlToRawTransformer * xmlTransformer, ICsvToRawTransformer * csvTransformer) const;
  1633. virtual IDataVal& getResultRaw(IDataVal & data, __int64 from, __int64 length, IXmlToRawTransformer * xmlTransformer, ICsvToRawTransformer * csvTransformer) const;
  1634. virtual IStringVal& getResultRecordSizeEntry(IStringVal & str) const;
  1635. virtual IStringVal& getResultTransformerEntry(IStringVal & str) const;
  1636. virtual __int64 getResultRowLimit() const;
  1637. virtual IStringVal& getResultFilename(IStringVal & str) const;
  1638. virtual WUResultFormat getResultFormat() const;
  1639. virtual unsigned getResultHash() const;
  1640. virtual bool getResultIsAll() const;
  1641. virtual IProperties *queryResultXmlns();
  1642. virtual IStringVal& getResultFieldOpt(const char *name, IStringVal &str) const;
  1643. // interface IWUResult
  1644. virtual void setResultStatus(WUResultStatus status);
  1645. virtual void setResultName(const char *name);
  1646. virtual void setResultSequence(unsigned seq);
  1647. virtual void setResultSchemaRaw(unsigned len, const void *schema);
  1648. virtual void setResultScalar(bool isScalar);
  1649. virtual void setResultRaw(unsigned len, const void *xml, WUResultFormat format);
  1650. virtual void setResultFetchSize(unsigned rows); // 0 means file-loaded
  1651. virtual void setResultTotalRowCount(__int64 rows); // -1 means unknown
  1652. virtual void setResultRowCount(__int64 rows);
  1653. virtual void setResultDataset(const char *ecl, const char *defs);
  1654. virtual void setResultLogicalName(const char *logicalName);
  1655. virtual void setResultKeyField(const char * name);
  1656. virtual void setResultRequestedRows(unsigned req);
  1657. virtual void setResultRecordSizeEntry(const char * val);
  1658. virtual void setResultTransformerEntry(const char * val);
  1659. virtual void setResultInt(__int64 val);
  1660. virtual void setResultReal(double val);
  1661. virtual void setResultBool(bool val);
  1662. virtual void setResultString(const char * val, unsigned length);
  1663. virtual void setResultUnicode(const void * val, unsigned length);
  1664. virtual void setResultData(const void * val, unsigned length);
  1665. virtual void setResultDecimal(const void * val, unsigned length);
  1666. virtual void addResultRaw(unsigned len, const void * data, WUResultFormat format);
  1667. virtual void setResultRowLimit(__int64 value);
  1668. virtual void setResultFilename(const char * name);
  1669. virtual void setResultUInt(unsigned __int64 val);
  1670. virtual void setResultIsAll(bool value);
  1671. virtual void setResultFormat(WUResultFormat format);
  1672. virtual void setResultXML(const char *val);
  1673. virtual void setResultRow(unsigned len, const void * data);
  1674. virtual void setResultXmlns(const char *prefix, const char *uri);
  1675. virtual void setResultFieldOpt(const char *name, const char *value);
  1676. virtual IPropertyTree *queryPTree() { return p; }
  1677. };
  1678. class CLocalWUPlugin : public CInterface, implements IWUPlugin
  1679. {
  1680. Owned<IPropertyTree> p;
  1681. public:
  1682. IMPLEMENT_IINTERFACE;
  1683. CLocalWUPlugin(IPropertyTree *p);
  1684. virtual IStringVal& getPluginName(IStringVal &str) const;
  1685. virtual IStringVal& getPluginVersion(IStringVal &str) const;
  1686. virtual void setPluginName(const char *str);
  1687. virtual void setPluginVersion(const char *str);
  1688. };
  1689. class CLocalWULibrary : public CInterface, implements IWULibrary
  1690. {
  1691. Owned<IPropertyTree> p;
  1692. public:
  1693. IMPLEMENT_IINTERFACE;
  1694. CLocalWULibrary(IPropertyTree *p);
  1695. virtual IStringVal & getName(IStringVal & str) const;
  1696. virtual void setName(const char * str);
  1697. };
  1698. class CLocalWUGraph : public CInterface, implements IWUGraph
  1699. {
  1700. const CLocalWorkUnit &owner;
  1701. Owned<IPropertyTree> p;
  1702. mutable Owned<IPropertyTree> graph; // cached copy of graph xgmml
  1703. mutable Linked<IConstWUGraphProgress> progress;
  1704. unsigned wuidVersion;
  1705. void mergeProgress(IPropertyTree &tree, IPropertyTree &progressTree, const unsigned &progressV) const;
  1706. public:
  1707. IMPLEMENT_IINTERFACE;
  1708. CLocalWUGraph(const CLocalWorkUnit &owner, IPropertyTree *p);
  1709. virtual IStringVal & getXGMML(IStringVal & ret, bool mergeProgress) const;
  1710. virtual IStringVal & getName(IStringVal & ret) const;
  1711. virtual IStringVal & getLabel(IStringVal & ret) const;
  1712. virtual IStringVal & getTypeName(IStringVal & ret) const;
  1713. virtual WUGraphType getType() const;
  1714. virtual WUGraphState getState() const;
  1715. virtual IPropertyTree * getXGMMLTree(bool mergeProgress) const;
  1716. virtual IPropertyTree * getXGMMLTreeRaw() const;
  1717. virtual void setName(const char *str);
  1718. virtual void setLabel(const char *str);
  1719. virtual void setType(WUGraphType type);
  1720. virtual void setXGMML(const char *str);
  1721. virtual void setXGMMLTree(IPropertyTree * tree, bool compress=true);
  1722. };
  1723. class CLocalWUException : public CInterface, implements IWUException
  1724. {
  1725. Owned<IPropertyTree> p;
  1726. public:
  1727. IMPLEMENT_IINTERFACE;
  1728. CLocalWUException(IPropertyTree *p);
  1729. virtual IStringVal& getExceptionSource(IStringVal &str) const;
  1730. virtual IStringVal& getExceptionMessage(IStringVal &str) const;
  1731. virtual unsigned getExceptionCode() const;
  1732. virtual ErrorSeverity getSeverity() const;
  1733. virtual IStringVal & getTimeStamp(IStringVal & dt) const;
  1734. virtual IStringVal & getExceptionFileName(IStringVal & str) const;
  1735. virtual unsigned getExceptionLineNo() const;
  1736. virtual unsigned getExceptionColumn() const;
  1737. virtual void setExceptionSource(const char *str);
  1738. virtual void setExceptionMessage(const char *str);
  1739. virtual void setExceptionCode(unsigned code);
  1740. virtual void setSeverity(ErrorSeverity level);
  1741. virtual void setTimeStamp(const char * dt);
  1742. virtual void setExceptionFileName(const char *str);
  1743. virtual void setExceptionLineNo(unsigned r);
  1744. virtual void setExceptionColumn(unsigned c);
  1745. };
  1746. //==========================================================================================
  1747. extern WORKUNIT_API bool isSpecialResultSequence(unsigned sequence)
  1748. {
  1749. switch (sequence)
  1750. {
  1751. case ResultSequenceInternal:
  1752. case ResultSequenceOnce:
  1753. case ResultSequencePersist:
  1754. case ResultSequenceStored:
  1755. return true;
  1756. default:
  1757. assertex(sequence <= INT_MAX);
  1758. return false;
  1759. }
  1760. }
  1761. class CConstWUArrayIterator : public CInterface, implements IConstWorkUnitIterator
  1762. {
  1763. IArrayOf<IPropertyTree> trees;
  1764. Owned<IConstWorkUnitInfo> cur;
  1765. unsigned curTreeNum;
  1766. void setCurrent()
  1767. {
  1768. cur.setown(new CLightweightWorkunitInfo(trees.item(curTreeNum)));
  1769. }
  1770. public:
  1771. IMPLEMENT_IINTERFACE;
  1772. CConstWUArrayIterator(IArrayOf<IPropertyTree> &_trees)
  1773. {
  1774. ForEachItemIn(t, _trees)
  1775. trees.append(*LINK(&_trees.item(t)));
  1776. curTreeNum = 0;
  1777. }
  1778. bool first()
  1779. {
  1780. curTreeNum = 0;
  1781. return next();
  1782. }
  1783. bool isValid()
  1784. {
  1785. return (NULL != cur.get());
  1786. }
  1787. bool next()
  1788. {
  1789. if (curTreeNum >= trees.ordinality())
  1790. {
  1791. cur.clear();
  1792. return false;
  1793. }
  1794. setCurrent();
  1795. ++curTreeNum;
  1796. return true;
  1797. }
  1798. IConstWorkUnitInfo & query() { return *cur; }
  1799. };
  1800. //==========================================================================================
  1801. class CStringArrayIterator : public CInterface, implements IStringIterator
  1802. {
  1803. StringArray strings;
  1804. unsigned idx;
  1805. public:
  1806. IMPLEMENT_IINTERFACE;
  1807. CStringArrayIterator() { idx = 0; };
  1808. void append(const char *str) { strings.append(str); }
  1809. virtual bool first() { idx = 0; return strings.isItem(idx); }
  1810. virtual bool next() { idx ++; return strings.isItem(idx); }
  1811. virtual bool isValid() { return strings.isItem(idx); }
  1812. virtual IStringVal & str(IStringVal &s) { s.set(strings.item(idx)); return s; }
  1813. };
  1814. class CCachedJobNameIterator : public CInterface, implements IStringIterator
  1815. {
  1816. Owned<IPropertyTreeIterator> it;
  1817. public:
  1818. IMPLEMENT_IINTERFACE;
  1819. CCachedJobNameIterator(IPropertyTreeIterator *p) : it(p) {};
  1820. virtual bool first() { return it->first(); }
  1821. virtual bool next() { return it->next(); }
  1822. virtual bool isValid() { return it->isValid(); }
  1823. virtual IStringVal & str(IStringVal &s) { s.set(it->query().queryName()+1); return s; }
  1824. };
  1825. class CEmptyStringIterator : public CInterface, implements IStringIterator
  1826. {
  1827. public:
  1828. IMPLEMENT_IINTERFACE;
  1829. virtual bool first() { return false; }
  1830. virtual bool next() { return false; }
  1831. virtual bool isValid() { return false; }
  1832. virtual IStringVal & str(IStringVal &s) { s.clear(); return s; }
  1833. };
  1834. mapEnums workunitSortFields[] =
  1835. {
  1836. { WUSFuser, "@submitID" },
  1837. { WUSFcluster, "@clusterName" },
  1838. { WUSFjob, "@jobName" },
  1839. { WUSFstate, "@state" },
  1840. { WUSFpriority, "@priorityClass" },
  1841. { WUSFprotected, "@protected" },
  1842. { WUSFwuid, "@" },
  1843. { WUSFecl, "Query/Text" },
  1844. { WUSFfileread, "FilesRead/File/@name" },
  1845. { WUSFroxiecluster, "RoxieQueryInfo/@roxieClusterName" },
  1846. { WUSFtotalthortime, "Statistics/Statistic[@c='summary'][@creator='thor'][@kind='TimeElapsed']/@value|"
  1847. "Statistics/Statistic[@c='summary'][@creator='hthor'][@kind='TimeElapsed']/@value|"
  1848. "Statistics/Statistic[@c='summary'][@creator='roxie'][@kind='TimeElapsed']/@value|"
  1849. "Statistics/Statistic[@desc='Total thor time']/@value|"
  1850. "Timings/Timing[@name='Total thor time']/@duration" //Use Statistics first. If not found, use Timings
  1851. },
  1852. { WUSFterm, NULL }
  1853. };
  1854. mapEnums querySortFields[] =
  1855. {
  1856. { WUQSFId, "@id" },
  1857. { WUQSFwuid, "@wuid" },
  1858. { WUQSFname, "@name" },
  1859. { WUQSFdll, "@dll" },
  1860. { WUQSFmemoryLimit, "@memoryLimit" },
  1861. { WUQSFmemoryLimitHi, "@memoryLimit" },
  1862. { WUQSFtimeLimit, "@timeLimit" },
  1863. { WUQSFtimeLimitHi, "@timeLimit" },
  1864. { WUQSFwarnTimeLimit, "@warnTimeLimit" },
  1865. { WUQSFwarnTimeLimitHi, "@warnTimeLimit" },
  1866. { WUQSFpriority, "@priority" },
  1867. { WUQSFpriorityHi, "@priority" },
  1868. { WUQSFQuerySet, "@querySetId" },
  1869. { WUQSFActivited, "@activated" },
  1870. { WUQSFSuspendedByUser, "@suspended" },
  1871. { WUQSFLibrary, "Library"},
  1872. { WUQSFterm, NULL }
  1873. };
  1874. class asyncRemoveDllWorkItem: public CInterface, implements IWorkQueueItem // class only used in asyncRemoveDll
  1875. {
  1876. StringAttr name;
  1877. public:
  1878. IMPLEMENT_IINTERFACE;
  1879. asyncRemoveDllWorkItem(const char * _name) : name(_name)
  1880. {
  1881. }
  1882. void execute()
  1883. {
  1884. PROGLOG("WU removeDll %s", name.get());
  1885. queryDllServer().removeDll(name, true, true); // <name>, removeDlls=true, removeDirectory=true
  1886. }
  1887. };
  1888. class asyncRemoveRemoteFileWorkItem: public CInterface, implements IWorkQueueItem // class only used in asyncRemoveFile
  1889. {
  1890. RemoteFilename name;
  1891. public:
  1892. IMPLEMENT_IINTERFACE;
  1893. asyncRemoveRemoteFileWorkItem(const char * _ip, const char * _name)
  1894. {
  1895. SocketEndpoint ep(_ip);
  1896. name.setPath(ep, _name);
  1897. }
  1898. void execute()
  1899. {
  1900. Owned<IFile> file = createIFile(name);
  1901. PROGLOG("WU removeDll %s",file->queryFilename());
  1902. file->remove();
  1903. }
  1904. };
  1905. //==========================================================================================
  1906. class CConstQuerySetQueryIterator : public CInterface, implements IConstQuerySetQueryIterator
  1907. {
  1908. IArrayOf<IPropertyTree> trees;
  1909. unsigned index;
  1910. public:
  1911. IMPLEMENT_IINTERFACE;
  1912. CConstQuerySetQueryIterator(IArrayOf<IPropertyTree> &_trees)
  1913. {
  1914. ForEachItemIn(t, _trees)
  1915. trees.append(*LINK(&_trees.item(t)));
  1916. index = 0;
  1917. }
  1918. ~CConstQuerySetQueryIterator()
  1919. {
  1920. trees.kill();
  1921. }
  1922. bool first()
  1923. {
  1924. index = 0;
  1925. return (trees.ordinality()!=0);
  1926. }
  1927. bool next()
  1928. {
  1929. index++;
  1930. return (index<trees.ordinality());
  1931. }
  1932. bool isValid()
  1933. {
  1934. return (index<trees.ordinality());
  1935. }
  1936. IPropertyTree &query()
  1937. {
  1938. return trees.item(index);
  1939. }
  1940. };
  1941. class CConstWUIterator : public CInterface, implements IConstWorkUnitIterator
  1942. {
  1943. Owned<IConstWorkUnitInfo> cur;
  1944. Linked<IPropertyTreeIterator> ptreeIter;
  1945. Owned<ISecResourceList> scopes;
  1946. void setCurrent()
  1947. {
  1948. cur.setown(new CLightweightWorkunitInfo(ptreeIter->query()));
  1949. }
  1950. bool getNext() // scan for a workunit with permissions
  1951. {
  1952. if (!scopes)
  1953. {
  1954. setCurrent();
  1955. return true;
  1956. }
  1957. do
  1958. {
  1959. const char *scopeName = ptreeIter->query().queryProp("@scope");
  1960. if (!scopeName || !*scopeName || checkWuScopeListSecAccess(scopeName, scopes, SecAccess_Read, "iterating", false, false))
  1961. {
  1962. setCurrent();
  1963. return true;
  1964. }
  1965. } while (ptreeIter->next());
  1966. cur.clear();
  1967. return false;
  1968. }
  1969. public:
  1970. IMPLEMENT_IINTERFACE;
  1971. CConstWUIterator(IPropertyTreeIterator *_ptreeIter, ISecManager *secmgr=NULL, ISecUser *secuser=NULL)
  1972. : ptreeIter(_ptreeIter)
  1973. {
  1974. UniqueScopes us;
  1975. if (secmgr /* && secmgr->authTypeRequired(RT_WORKUNIT_SCOPE) tbd */)
  1976. {
  1977. // MORE - this will defeat any lazy-fetch mechanism in the incoming iterator
  1978. scopes.setown(secmgr->createResourceList("wuscopes"));
  1979. ForEach(*ptreeIter)
  1980. {
  1981. const char *scopeName = ptreeIter->query().queryProp("@scope");
  1982. if (scopeName && *scopeName && !us.getValue(scopeName))
  1983. {
  1984. scopes->addResource(scopeName);
  1985. us.setValue(scopeName, true);
  1986. }
  1987. }
  1988. if (scopes->count())
  1989. secmgr->authorizeEx(RT_WORKUNIT_SCOPE, *secuser, scopes);
  1990. else
  1991. scopes.clear();
  1992. }
  1993. }
  1994. bool first()
  1995. {
  1996. if (!ptreeIter->first())
  1997. {
  1998. cur.clear();
  1999. return false;
  2000. }
  2001. return getNext();
  2002. }
  2003. bool isValid()
  2004. {
  2005. return (NULL != cur.get());
  2006. }
  2007. bool next()
  2008. {
  2009. if (!ptreeIter->next())
  2010. {
  2011. cur.clear();
  2012. return false;
  2013. }
  2014. return getNext();
  2015. }
  2016. IConstWorkUnitInfo & query() { return *cur; }
  2017. };
  2018. #define WUID_VERSION 2 // recorded in each wuid created, useful for bkwd compat. checks
  2019. CWorkUnitFactory::CWorkUnitFactory()
  2020. {
  2021. }
  2022. CWorkUnitFactory::~CWorkUnitFactory()
  2023. {
  2024. }
  2025. IWorkUnit* CWorkUnitFactory::createNamedWorkUnit(const char *wuid, const char *app, const char *scope, ISecManager *secmgr, ISecUser *secuser)
  2026. {
  2027. checkWuScopeSecAccess(scope, secmgr, secuser, SecAccess_Write, "Create", true, true);
  2028. Owned<CLocalWorkUnit> cw = _createWorkUnit(wuid, secmgr, secuser);
  2029. if (scope)
  2030. 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...
  2031. IWorkUnit* ret = &cw->lockRemote(false); // Note - this may throw exception if user does not have rights.
  2032. ret->setDebugValue("CREATED_BY", app, true);
  2033. ret->setDebugValue("CREATED_FOR", scope, true);
  2034. return ret;
  2035. }
  2036. IWorkUnit* CWorkUnitFactory::createWorkUnit(const char *app, const char *scope, ISecManager *secmgr, ISecUser *secuser)
  2037. {
  2038. StringBuffer wuid("W");
  2039. char result[32];
  2040. time_t ltime;
  2041. time( &ltime );
  2042. tm *today = localtime( &ltime ); // MORE - this is not threadsafe. But I probably don't care that much!
  2043. strftime(result, sizeof(result), "%Y%m%d-%H%M%S", today);
  2044. wuid.append(result);
  2045. if (workUnitTraceLevel > 1)
  2046. PrintLog("createWorkUnit created %s", wuid.str());
  2047. IWorkUnit* ret = createNamedWorkUnit(wuid.str(), app, scope, secmgr, secuser);
  2048. if (workUnitTraceLevel > 1)
  2049. PrintLog("createWorkUnit created %s", ret->queryWuid());
  2050. addTimeStamp(ret, SSTglobal, NULL, StWhenCreated);
  2051. return ret;
  2052. }
  2053. bool CWorkUnitFactory::deleteWorkUnit(const char * wuid, ISecManager *secmgr, ISecUser *secuser)
  2054. {
  2055. if (workUnitTraceLevel > 1)
  2056. PrintLog("deleteWorkUnit %s", wuid);
  2057. StringBuffer wuRoot;
  2058. getXPath(wuRoot, wuid);
  2059. Owned<CLocalWorkUnit> cw = _updateWorkUnit(wuid, secmgr, secuser);
  2060. if (!checkWuSecAccess(*cw.get(), secmgr, secuser, SecAccess_Full, "delete", true, true))
  2061. return false;
  2062. try
  2063. {
  2064. cw->cleanupAndDelete(true, true);
  2065. }
  2066. catch (IException *E)
  2067. {
  2068. StringBuffer s;
  2069. LOG(MCexception(E, MSGCLS_warning), E, s.append("Exception during deleteWorkUnit: ").append(wuid).str());
  2070. E->Release();
  2071. return false;
  2072. }
  2073. removeWorkUnitFromAllQueues(wuid); //known active workunits wouldn't make it this far
  2074. return true;
  2075. }
  2076. IConstWorkUnit* CWorkUnitFactory::openWorkUnit(const char *wuid, bool lock, ISecManager *secmgr, ISecUser *secuser)
  2077. {
  2078. StringBuffer wuidStr(wuid);
  2079. wuidStr.trim();
  2080. if (wuidStr.length() && ('w' == wuidStr.charAt(0)))
  2081. wuidStr.setCharAt(0, 'W');
  2082. if (!wuidStr.length() || ('W' != wuidStr.charAt(0)))
  2083. {
  2084. if (workUnitTraceLevel > 1)
  2085. PrintLog("openWorkUnit %s invalid WUID", nullText(wuidStr.str()));
  2086. return NULL;
  2087. }
  2088. if (workUnitTraceLevel > 1)
  2089. PrintLog("openWorkUnit %s", wuidStr.str());
  2090. Owned<IConstWorkUnit> wu = _openWorkUnit(wuid, lock, secmgr, secuser);
  2091. if (wu)
  2092. {
  2093. if (!checkWuSecAccess(*wu, secmgr, secuser, SecAccess_Read, "opening", true, true))
  2094. return NULL; // Actually throws exception on failure, so won't reach here
  2095. return wu.getClear();
  2096. }
  2097. else
  2098. {
  2099. if (workUnitTraceLevel > 0)
  2100. PrintLog("openWorkUnit %s not found", wuidStr.str());
  2101. return NULL;
  2102. }
  2103. }
  2104. IWorkUnit* CWorkUnitFactory::updateWorkUnit(const char *wuid, ISecManager *secmgr, ISecUser *secuser)
  2105. {
  2106. if (workUnitTraceLevel > 1)
  2107. PrintLog("updateWorkUnit %s", wuid);
  2108. Owned<CLocalWorkUnit> wu = _updateWorkUnit(wuid, secmgr, secuser);
  2109. if (wu)
  2110. {
  2111. if (!checkWuSecAccess(*wu.get(), secmgr, secuser, SecAccess_Write, "updating", true, true))
  2112. return NULL;
  2113. return &wu->lockRemote(false);
  2114. }
  2115. else
  2116. {
  2117. if (workUnitTraceLevel > 0)
  2118. PrintLog("updateWorkUnit %s not found", wuid);
  2119. return NULL;
  2120. }
  2121. }
  2122. int CWorkUnitFactory::setTracingLevel(int newLevel)
  2123. {
  2124. if (newLevel)
  2125. PrintLog("Setting workunit trace level to %d", newLevel);
  2126. int level = workUnitTraceLevel;
  2127. workUnitTraceLevel = newLevel;
  2128. return level;
  2129. }
  2130. void CWorkUnitFactory::descheduleAllWorkUnits(ISecManager *secmgr, ISecUser *secuser)
  2131. {
  2132. Owned<IRemoteConnection> conn = querySDS().connect("/Schedule", myProcessSession(), RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT);
  2133. if(!conn) return;
  2134. Owned<IPropertyTree> root(conn->queryRoot()->getBranch("."));
  2135. KeptAtomTable entries;
  2136. Owned<IPropertyTreeIterator> iter(root->getElements("*/*/*/*"));
  2137. StringBuffer wuid;
  2138. for(iter->first(); iter->isValid(); iter->next())
  2139. {
  2140. char const * entry = iter->query().queryName();
  2141. if(!entries.find(entry))
  2142. {
  2143. entries.addAtom(entry);
  2144. ncnameUnescape(entry, wuid.clear());
  2145. Owned<IWorkUnit> wu = updateWorkUnit(wuid, secmgr, secuser);
  2146. if(wu && (wu->getState() == WUStateWait))
  2147. wu->setState(WUStateCompleted);
  2148. }
  2149. }
  2150. bool more;
  2151. do more = root->removeProp("*"); while(more);
  2152. }
  2153. IConstQuerySetQueryIterator* CWorkUnitFactory::getQuerySetQueriesSorted( WUQuerySortField *sortorder, // list of fields to sort by (terminated by WUSFterm)
  2154. WUQuerySortField *filters, // NULL or list of fields to filter on (terminated by WUSFterm)
  2155. const void *filterbuf, // (appended) string values for filters
  2156. unsigned startoffset,
  2157. unsigned maxnum,
  2158. __int64 *cachehint,
  2159. unsigned *total,
  2160. const MapStringTo<bool> *_subset)
  2161. {
  2162. struct PostFilters
  2163. {
  2164. WUQueryFilterBoolean activatedFilter;
  2165. WUQueryFilterBoolean suspendedByUserFilter;
  2166. PostFilters()
  2167. {
  2168. activatedFilter = WUQFSAll;
  2169. suspendedByUserFilter = WUQFSAll;
  2170. };
  2171. } postFilters;
  2172. class CQuerySetQueriesPager : public CSimpleInterface, implements IElementsPager
  2173. {
  2174. StringAttr querySet;
  2175. StringAttr xPath;
  2176. StringAttr sortOrder;
  2177. PostFilters postFilters;
  2178. StringArray unknownAttributes;
  2179. const MapStringTo<bool> *subset;
  2180. void populateQueryTree(const IPropertyTree* querySetTree, IPropertyTree* queryTree)
  2181. {
  2182. const char* querySetId = querySetTree->queryProp("@id");
  2183. VStringBuffer path("Query%s", xPath.get());
  2184. Owned<IPropertyTreeIterator> iter = querySetTree->getElements(path.str());
  2185. ForEach(*iter)
  2186. {
  2187. IPropertyTree &query = iter->query();
  2188. bool activated = false;
  2189. const char* queryId = query.queryProp("@id");
  2190. if (queryId && *queryId)
  2191. {
  2192. if (subset)
  2193. {
  2194. VStringBuffer match("%s/%s", querySetId, queryId);
  2195. if (!subset->getValue(match))
  2196. continue;
  2197. }
  2198. VStringBuffer aliasXPath("Alias[@id='%s']", queryId);
  2199. IPropertyTree *alias = querySetTree->queryPropTree(aliasXPath.str());
  2200. if (alias)
  2201. activated = true;
  2202. }
  2203. if (activated && (postFilters.activatedFilter == WUQFSNo))
  2204. continue;
  2205. if (!activated && (postFilters.activatedFilter == WUQFSYes))
  2206. continue;
  2207. if ((postFilters.suspendedByUserFilter == WUQFSNo) && query.hasProp(getEnumText(WUQSFSuspendedByUser,querySortFields)))
  2208. continue;
  2209. if ((postFilters.suspendedByUserFilter == WUQFSYes) && !query.hasProp(getEnumText(WUQSFSuspendedByUser,querySortFields)))
  2210. continue;
  2211. IPropertyTree *queryWithSetId = queryTree->addPropTree("Query", createPTreeFromIPT(&query));
  2212. queryWithSetId->setProp("@querySetId", querySetId);
  2213. queryWithSetId->setPropBool("@activated", activated);
  2214. }
  2215. }
  2216. IRemoteConnection* populateQueryTree(IPropertyTree* queryTree)
  2217. {
  2218. StringBuffer querySetXPath("QuerySets");
  2219. if (!querySet.isEmpty())
  2220. querySetXPath.appendf("/QuerySet[@id=\"%s\"]", querySet.get());
  2221. Owned<IRemoteConnection> conn = querySDS().connect(querySetXPath.str(), myProcessSession(), 0, SDS_LOCK_TIMEOUT);
  2222. if (!conn)
  2223. return NULL;
  2224. if (querySet.isEmpty())
  2225. {
  2226. Owned<IPropertyTreeIterator> querySetIter = conn->queryRoot()->getElements("*");
  2227. ForEach(*querySetIter)
  2228. populateQueryTree(&querySetIter->query(), queryTree);
  2229. }
  2230. else
  2231. populateQueryTree(conn->queryRoot(), queryTree);
  2232. return conn.getClear();
  2233. }
  2234. public:
  2235. IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
  2236. CQuerySetQueriesPager(const char* _querySet, const char* _xPath, const char *_sortOrder, PostFilters& _postFilters, StringArray& _unknownAttributes, const MapStringTo<bool> *_subset)
  2237. : querySet(_querySet), xPath(_xPath), sortOrder(_sortOrder), subset(_subset)
  2238. {
  2239. postFilters.activatedFilter = _postFilters.activatedFilter;
  2240. postFilters.suspendedByUserFilter = _postFilters.suspendedByUserFilter;
  2241. ForEachItemIn(x, _unknownAttributes)
  2242. unknownAttributes.append(_unknownAttributes.item(x));
  2243. }
  2244. virtual IRemoteConnection* getElements(IArrayOf<IPropertyTree> &elements)
  2245. {
  2246. Owned<IPropertyTree> elementTree = createPTree("Queries");
  2247. Owned<IRemoteConnection> conn = populateQueryTree(elementTree);
  2248. if (!conn)
  2249. return NULL;
  2250. Owned<IPropertyTreeIterator> iter = elementTree->getElements("*");
  2251. if (!iter)
  2252. return NULL;
  2253. sortElements(iter, sortOrder.get(), NULL, NULL, unknownAttributes, elements);
  2254. return conn.getClear();
  2255. }
  2256. };
  2257. StringAttr querySet;
  2258. StringBuffer xPath;
  2259. StringBuffer so;
  2260. StringArray unknownAttributes;
  2261. if (filters)
  2262. {
  2263. const char *fv = (const char *)filterbuf;
  2264. for (unsigned i=0;filters[i]!=WUQSFterm;i++) {
  2265. int fmt = filters[i];
  2266. int subfmt = (fmt&0xff);
  2267. if (subfmt==WUQSFQuerySet)
  2268. querySet.set(fv);
  2269. else if ((subfmt==WUQSFmemoryLimit) || (subfmt==WUQSFtimeLimit) || (subfmt==WUQSFwarnTimeLimit) || (subfmt==WUQSFpriority))
  2270. xPath.append('[').append(getEnumText(subfmt,querySortFields)).append(">=").append(fv).append("]");
  2271. else if ((subfmt==WUQSFmemoryLimitHi) || (subfmt==WUQSFtimeLimitHi) || (subfmt==WUQSFwarnTimeLimitHi) || (subfmt==WUQSFpriorityHi))
  2272. xPath.append('[').append(getEnumText(subfmt,querySortFields)).append("<=").append(fv).append("]");
  2273. else if (subfmt==WUQSFActivited)
  2274. postFilters.activatedFilter = (WUQueryFilterBoolean) atoi(fv);
  2275. else if (subfmt==WUQSFSuspendedByUser)
  2276. postFilters.suspendedByUserFilter = (WUQueryFilterBoolean) atoi(fv);
  2277. else if (!fv || !*fv)
  2278. unknownAttributes.append(getEnumText(subfmt,querySortFields));
  2279. else {
  2280. xPath.append('[').append(getEnumText(subfmt,querySortFields)).append('=');
  2281. if (fmt&WUQSFnocase)
  2282. xPath.append('?');
  2283. if (fmt&WUQSFnumeric)
  2284. xPath.append('#');
  2285. if (fmt&WUQSFwild)
  2286. xPath.append('~');
  2287. xPath.append('"').append(fv).append("\"]");
  2288. }
  2289. fv = fv + strlen(fv)+1;
  2290. }
  2291. }
  2292. if (sortorder) {
  2293. for (unsigned i=0;sortorder[i]!=WUQSFterm;i++) {
  2294. if (so.length())
  2295. so.append(',');
  2296. int fmt = sortorder[i];
  2297. if (fmt&WUQSFreverse)
  2298. so.append('-');
  2299. if (fmt&WUQSFnocase)
  2300. so.append('?');
  2301. if (fmt&WUQSFnumeric)
  2302. so.append('#');
  2303. so.append(getEnumText(fmt&0xff,querySortFields));
  2304. }
  2305. }
  2306. IArrayOf<IPropertyTree> results;
  2307. Owned<IElementsPager> elementsPager = new CQuerySetQueriesPager(querySet.get(), xPath.str(), so.length()?so.str():NULL, postFilters, unknownAttributes, _subset);
  2308. Owned<IRemoteConnection> conn=getElementsPaged(elementsPager,startoffset,maxnum,NULL,"",cachehint,results,total);
  2309. return new CConstQuerySetQueryIterator(results);
  2310. }
  2311. bool CWorkUnitFactory::isAborting(const char *wuid) const
  2312. {
  2313. VStringBuffer apath("/WorkUnitAborts/%s", wuid);
  2314. try
  2315. {
  2316. Owned<IRemoteConnection> acon = querySDS().connect(apath.str(), myProcessSession(), 0, SDS_LOCK_TIMEOUT);
  2317. if (acon)
  2318. return acon->queryRoot()->getPropInt(NULL) != 0;
  2319. }
  2320. catch (IException *E)
  2321. {
  2322. EXCLOG(E);
  2323. E->Release();
  2324. }
  2325. return false;
  2326. }
  2327. void CWorkUnitFactory::clearAborting(const char *wuid)
  2328. {
  2329. VStringBuffer apath("/WorkUnitAborts/%s", wuid);
  2330. try
  2331. {
  2332. Owned<IRemoteConnection> acon = querySDS().connect(apath.str(), myProcessSession(), RTM_LOCK_WRITE|RTM_LOCK_SUB, SDS_LOCK_TIMEOUT);
  2333. if (acon)
  2334. acon->close(true);
  2335. }
  2336. catch (IException *E)
  2337. {
  2338. EXCLOG(E);
  2339. E->Release();
  2340. }
  2341. }
  2342. static CriticalSection deleteDllLock;
  2343. static Owned<IWorkQueueThread> deleteDllWorkQ;
  2344. static void asyncRemoveDll(const char * name)
  2345. {
  2346. CriticalBlock b(deleteDllLock);
  2347. if (!deleteDllWorkQ)
  2348. deleteDllWorkQ.setown(createWorkQueueThread());
  2349. deleteDllWorkQ->post(new asyncRemoveDllWorkItem(name));
  2350. }
  2351. static void asyncRemoveFile(const char * ip, const char * name)
  2352. {
  2353. CriticalBlock b(deleteDllLock);
  2354. if (!deleteDllWorkQ)
  2355. deleteDllWorkQ.setown(createWorkQueueThread());
  2356. deleteDllWorkQ->post(new asyncRemoveRemoteFileWorkItem(ip, name));
  2357. }
  2358. class CDaliWorkUnitFactory : public CWorkUnitFactory, implements IDaliClientShutdown
  2359. {
  2360. public:
  2361. IMPLEMENT_IINTERFACE_USING(CWorkUnitFactory);
  2362. CDaliWorkUnitFactory()
  2363. {
  2364. // Assumes dali client configuration has already been done
  2365. sdsManager = &querySDS();
  2366. session = myProcessSession();
  2367. addShutdownHook(*this);
  2368. }
  2369. ~CDaliWorkUnitFactory()
  2370. {
  2371. removeShutdownHook(*this);
  2372. }
  2373. virtual unsigned validateRepository(bool fixErrors)
  2374. {
  2375. return 0;
  2376. }
  2377. virtual void deleteRepository(bool recreate)
  2378. {
  2379. UNIMPLEMENTED; // And will probably never be!
  2380. }
  2381. virtual void createRepository()
  2382. {
  2383. // Nothing to do
  2384. }
  2385. virtual CLocalWorkUnit *_createWorkUnit(const char *wuid, ISecManager *secmgr, ISecUser *secuser)
  2386. {
  2387. StringBuffer wuRoot;
  2388. getXPath(wuRoot, wuid);
  2389. IRemoteConnection *conn;
  2390. conn = sdsManager->connect(wuRoot.str(), session, RTM_LOCK_WRITE|RTM_CREATE_UNIQUE, SDS_LOCK_TIMEOUT);
  2391. conn->queryRoot()->setProp("@xmlns:xsi", "http://www.w3.org/1999/XMLSchema-instance");
  2392. conn->queryRoot()->setPropInt("@wuidVersion", WUID_VERSION);
  2393. return new CDaliWorkUnit(conn, secmgr, secuser);
  2394. }
  2395. virtual CLocalWorkUnit* _openWorkUnit(const char *wuid, bool lock, ISecManager *secmgr, ISecUser *secuser)
  2396. {
  2397. StringBuffer wuRoot;
  2398. getXPath(wuRoot, wuid);
  2399. IRemoteConnection* conn = sdsManager->connect(wuRoot.str(), session, lock ? RTM_LOCK_READ|RTM_LOCK_SUB : 0, SDS_LOCK_TIMEOUT);
  2400. if (conn)
  2401. return new CDaliWorkUnit(conn, secmgr, secuser);
  2402. else
  2403. return NULL;
  2404. }
  2405. virtual CLocalWorkUnit* _updateWorkUnit(const char *wuid, ISecManager *secmgr, ISecUser *secuser)
  2406. {
  2407. StringBuffer wuRoot;
  2408. getXPath(wuRoot, wuid);
  2409. IRemoteConnection* conn = sdsManager->connect(wuRoot.str(), session, RTM_LOCK_WRITE|RTM_LOCK_SUB, SDS_LOCK_TIMEOUT);
  2410. if (conn)
  2411. return new CDaliWorkUnit(conn, secmgr, secuser);
  2412. else
  2413. return NULL;
  2414. }
  2415. virtual IWorkUnit* getGlobalWorkUnit(ISecManager *secmgr, ISecUser *secuser)
  2416. {
  2417. // MORE - should it check security?
  2418. StringBuffer wuRoot;
  2419. getXPath(wuRoot, GLOBAL_WORKUNIT);
  2420. IRemoteConnection* conn = sdsManager->connect(wuRoot.str(), session, RTM_LOCK_WRITE|RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT);
  2421. conn->queryRoot()->setProp("@xmlns:xsi", "http://www.w3.org/1999/XMLSchema-instance");
  2422. Owned<CLocalWorkUnit> cw = new CDaliWorkUnit(conn, (ISecManager *) NULL, NULL);
  2423. return &cw->lockRemote(false);
  2424. }
  2425. virtual IConstWorkUnitIterator* getWorkUnitsByOwner(const char * owner, ISecManager *secmgr, ISecUser *secuser)
  2426. {
  2427. StringBuffer path("*");
  2428. if (owner && *owner)
  2429. path.append("[@submitID=\"").append(owner).append("\"]");
  2430. return _getWorkUnitsByXPath(path.str(), secmgr, secuser);
  2431. }
  2432. IConstWorkUnitIterator* getWorkUnitsByState(WUState state, ISecManager *secmgr, ISecUser *secuser)
  2433. {
  2434. StringBuffer path("*");
  2435. path.append("[@state=\"").append(getEnumText(state, states)).append("\"]");
  2436. return _getWorkUnitsByXPath(path.str(), secmgr, secuser);
  2437. }
  2438. IConstWorkUnitIterator* getWorkUnitsByECL(const char* ecl, ISecManager *secmgr, ISecUser *secuser)
  2439. {
  2440. StringBuffer path("*");
  2441. if (ecl && *ecl)
  2442. path.append("[Query/Text=~\"*").append(ecl).append("*\"]");
  2443. return _getWorkUnitsByXPath(path.str(), secmgr, secuser);
  2444. }
  2445. IConstWorkUnitIterator* getWorkUnitsByCluster(const char* cluster, ISecManager *secmgr, ISecUser *secuser)
  2446. {
  2447. StringBuffer path("*");
  2448. if (cluster && *cluster)
  2449. path.append("[@clusterName=\"").append(cluster).append("\"]");
  2450. return _getWorkUnitsByXPath(path.str(), secmgr, secuser);
  2451. }
  2452. IConstWorkUnitIterator* getWorkUnitsByXPath(const char *xpath, ISecManager *secmgr, ISecUser *secuser)
  2453. {
  2454. // NOTE - this is deprecated - we want to get rid of it (daliadmin MAY be allowed to use it, but nothing else should)
  2455. return _getWorkUnitsByXPath(xpath, secmgr, secuser);
  2456. }
  2457. virtual void clientShutdown();
  2458. virtual unsigned numWorkUnits()
  2459. {
  2460. Owned<IRemoteConnection> conn = sdsManager->connect("/WorkUnits", session, 0, SDS_LOCK_TIMEOUT);
  2461. if (!conn)
  2462. return 0;
  2463. IPropertyTree *root = conn->queryRoot();
  2464. return root->numChildren();
  2465. }
  2466. IConstWorkUnitIterator* getWorkUnitsSorted( WUSortField sortorder, // field to sort by (and flags for desc sort etc)
  2467. WUSortField *filters, // NULL or list of fields to filter on (terminated by WUSFterm)
  2468. const void *filterbuf, // (appended) string values for filters
  2469. unsigned startoffset,
  2470. unsigned maxnum,
  2471. const char *queryowner,
  2472. __int64 *cachehint,
  2473. unsigned *total,
  2474. ISecManager *secmgr,
  2475. ISecUser *secuser)
  2476. {
  2477. class CWorkUnitsPager : public CSimpleInterface, implements IElementsPager
  2478. {
  2479. StringAttr xPath;
  2480. StringAttr sortOrder;
  2481. StringAttr nameFilterLo;
  2482. StringAttr nameFilterHi;
  2483. StringArray unknownAttributes;
  2484. public:
  2485. IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
  2486. CWorkUnitsPager(const char* _xPath, const char *_sortOrder, const char* _nameFilterLo, const char* _nameFilterHi, StringArray& _unknownAttributes)
  2487. : xPath(_xPath), sortOrder(_sortOrder), nameFilterLo(_nameFilterLo), nameFilterHi(_nameFilterHi)
  2488. {
  2489. ForEachItemIn(x, _unknownAttributes)
  2490. unknownAttributes.append(_unknownAttributes.item(x));
  2491. }
  2492. virtual IRemoteConnection* getElements(IArrayOf<IPropertyTree> &elements)
  2493. {
  2494. Owned<IRemoteConnection> conn = querySDS().connect("WorkUnits", myProcessSession(), 0, SDS_LOCK_TIMEOUT);
  2495. if (!conn)
  2496. return NULL;
  2497. Owned<IPropertyTreeIterator> iter = conn->getElements(xPath);
  2498. if (!iter)
  2499. return NULL;
  2500. sortElements(iter, sortOrder.get(), nameFilterLo.get(), nameFilterHi.get(), unknownAttributes, elements);
  2501. return conn.getClear();
  2502. }
  2503. };
  2504. class CScopeChecker : public CSimpleInterface, implements ISortedElementsTreeFilter
  2505. {
  2506. UniqueScopes done;
  2507. ISecManager *secmgr;
  2508. ISecUser *secuser;
  2509. CriticalSection crit;
  2510. public:
  2511. IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
  2512. CScopeChecker(ISecManager *_secmgr,ISecUser *_secuser)
  2513. {
  2514. secmgr = _secmgr;
  2515. secuser = _secuser;
  2516. }
  2517. bool isOK(IPropertyTree &tree)
  2518. {
  2519. const char *scopename = tree.queryProp("@scope");
  2520. if (!scopename||!*scopename)
  2521. return true;
  2522. {
  2523. CriticalBlock block(crit);
  2524. const bool *b = done.getValue(scopename);
  2525. if (b)
  2526. return *b;
  2527. }
  2528. bool ret = checkWuScopeSecAccess(scopename,secmgr,secuser,SecAccess_Read,"iterating",false,false);
  2529. {
  2530. // conceivably could have already been checked and added, but ok.
  2531. CriticalBlock block(crit);
  2532. done.setValue(scopename,ret);
  2533. }
  2534. return ret;
  2535. }
  2536. };
  2537. Owned<ISortedElementsTreeFilter> sc = new CScopeChecker(secmgr,secuser);
  2538. StringBuffer query;
  2539. StringBuffer so;
  2540. StringAttr namefilter("*");
  2541. StringAttr namefilterlo;
  2542. StringAttr namefilterhi;
  2543. StringArray unknownAttributes;
  2544. if (filters) {
  2545. const char *fv = (const char *)filterbuf;
  2546. for (unsigned i=0;filters[i]!=WUSFterm;i++) {
  2547. int fmt = filters[i];
  2548. int subfmt = (fmt&0xff);
  2549. if (subfmt==WUSFwuid)
  2550. namefilterlo.set(fv);
  2551. else if (subfmt==WUSFwuidhigh)
  2552. namefilterhi.set(fv);
  2553. else if (subfmt==WUSFwildwuid)
  2554. namefilter.set(fv);
  2555. else if (subfmt==WUSFcustom)
  2556. query.append("[").append(fv).append("]");
  2557. else if (!fv || !*fv)
  2558. unknownAttributes.append(getEnumText(subfmt,workunitSortFields));
  2559. else {
  2560. query.append('[').append(getEnumText(subfmt,workunitSortFields)).append('=');
  2561. if (fmt&WUSFnocase)
  2562. query.append('?');
  2563. if (fmt&WUSFwild)
  2564. query.append('~');
  2565. query.append('"').append(fv).append("\"]");
  2566. }
  2567. fv = fv + strlen(fv)+1;
  2568. }
  2569. }
  2570. query.insert(0, namefilter.get());
  2571. if (sortorder)
  2572. {
  2573. if (so.length())
  2574. so.append(',');
  2575. if (sortorder & WUSFreverse)
  2576. so.append('-');
  2577. if (sortorder & WUSFnocase)
  2578. so.append('?');
  2579. if (sortorder & WUSFnumeric)
  2580. so.append('#');
  2581. so.append(getEnumText(sortorder&0xff,workunitSortFields));
  2582. }
  2583. IArrayOf<IPropertyTree> results;
  2584. Owned<IElementsPager> elementsPager = new CWorkUnitsPager(query.str(), so.length()?so.str():NULL, namefilterlo.get(), namefilterhi.get(), unknownAttributes);
  2585. Owned<IRemoteConnection> conn=getElementsPaged(elementsPager,startoffset,maxnum,secmgr?sc:NULL,queryowner,cachehint,results,total);
  2586. return new CConstWUArrayIterator(results);
  2587. }
  2588. virtual WUState waitForWorkUnit(const char * wuid, unsigned timeout, bool compiled, bool returnOnWaitState)
  2589. {
  2590. StringBuffer wuRoot;
  2591. getXPath(wuRoot, wuid);
  2592. Owned<WorkUnitWaiter> waiter = new WorkUnitWaiter(wuRoot.str());
  2593. LocalIAbortHandler abortHandler(*waiter);
  2594. WUState ret = WUStateUnknown;
  2595. Owned<IRemoteConnection> conn = sdsManager->connect(wuRoot.str(), session, 0, SDS_LOCK_TIMEOUT);
  2596. if (conn)
  2597. {
  2598. unsigned start = msTick();
  2599. loop
  2600. {
  2601. ret = (WUState) getEnum(conn->queryRoot(), "@state", states);
  2602. switch (ret)
  2603. {
  2604. case WUStateCompiled:
  2605. case WUStateUploadingFiles:
  2606. if (!compiled)
  2607. break;
  2608. // fall into
  2609. case WUStateCompleted:
  2610. case WUStateFailed:
  2611. case WUStateAborted:
  2612. waiter->unsubscribe();
  2613. return ret;
  2614. case WUStateWait:
  2615. if(returnOnWaitState)
  2616. {
  2617. waiter->unsubscribe();
  2618. return ret;
  2619. }
  2620. break;
  2621. case WUStateCompiling:
  2622. case WUStateRunning:
  2623. case WUStateDebugPaused:
  2624. case WUStateDebugRunning:
  2625. case WUStateBlocked:
  2626. case WUStateAborting:
  2627. if (queryDaliServerVersion().compare("2.1")>=0)
  2628. {
  2629. SessionId agent = conn->queryRoot()->getPropInt64("@agentSession", -1);
  2630. if((agent>0) && querySessionManager().sessionStopped(agent, 0))
  2631. {
  2632. waiter->unsubscribe();
  2633. conn->reload();
  2634. ret = (WUState) getEnum(conn->queryRoot(), "@state", states);
  2635. bool isEcl = false;
  2636. switch (ret)
  2637. {
  2638. case WUStateCompiling:
  2639. isEcl = true;
  2640. // drop into
  2641. case WUStateRunning:
  2642. case WUStateBlocked:
  2643. ret = WUStateFailed;
  2644. break;
  2645. case WUStateAborting:
  2646. ret = WUStateAborted;
  2647. break;
  2648. default:
  2649. return ret;
  2650. }
  2651. WARNLOG("_waitForWorkUnit terminated: %" I64F "d state = %d",(__int64)agent,(int)ret);
  2652. Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
  2653. Owned<IWorkUnit> wu = factory->updateWorkUnit(wuid);
  2654. wu->setState(ret);
  2655. Owned<IWUException> e = wu->createException();
  2656. e->setExceptionCode(isEcl ? 1001 : 1000);
  2657. e->setExceptionMessage(isEcl ? "EclServer terminated unexpectedly" : "Workunit terminated unexpectedly");
  2658. return ret;
  2659. }
  2660. }
  2661. break;
  2662. }
  2663. unsigned waited = msTick() - start;
  2664. if (timeout==-1)
  2665. {
  2666. waiter->wait(20000); // recheck state every 20 seconds even if no timeout, in case eclagent has crashed.
  2667. if (waiter->aborted)
  2668. {
  2669. ret = WUStateUnknown; // MORE - throw an exception?
  2670. break;
  2671. }
  2672. }
  2673. else if (waited > timeout || !waiter->wait(timeout-waited))
  2674. {
  2675. ret = WUStateUnknown; // MORE - throw an exception?
  2676. break;
  2677. }
  2678. conn->reload();
  2679. }
  2680. }
  2681. waiter->unsubscribe();
  2682. return ret;
  2683. }
  2684. protected:
  2685. class WorkUnitWaiter : public CInterface, implements ISDSSubscription, implements IAbortHandler
  2686. {
  2687. Semaphore changed;
  2688. SubscriptionId change;
  2689. public:
  2690. IMPLEMENT_IINTERFACE;
  2691. WorkUnitWaiter(const char *xpath)
  2692. {
  2693. change = querySDS().subscribe(xpath, *this, false);
  2694. aborted = false;
  2695. }
  2696. ~WorkUnitWaiter()
  2697. {
  2698. assertex(change==0);
  2699. }
  2700. void notify(SubscriptionId id, const char *xpath, SDSNotifyFlags flags, unsigned valueLen, const void *valueData)
  2701. {
  2702. changed.signal();
  2703. }
  2704. bool wait(unsigned timeout)
  2705. {
  2706. return changed.wait(timeout) && !aborted;
  2707. }
  2708. bool onAbort()
  2709. {
  2710. aborted = true;
  2711. changed.signal();
  2712. return false;
  2713. }
  2714. void unsubscribe()
  2715. {
  2716. querySDS().unsubscribe(change);
  2717. change = 0;
  2718. }
  2719. bool aborted;
  2720. };
  2721. IConstWorkUnitIterator * _getWorkUnitsByXPath(const char *xpath, ISecManager *secmgr, ISecUser *secuser)
  2722. {
  2723. Owned<IRemoteConnection> conn = sdsManager->connect("/WorkUnits", session, 0, SDS_LOCK_TIMEOUT);
  2724. if (conn)
  2725. {
  2726. CDaliVersion serverVersionNeeded("3.2");
  2727. Owned<IPropertyTreeIterator> iter(queryDaliServerVersion().compare(serverVersionNeeded) < 0 ?
  2728. conn->queryRoot()->getElements(xpath) :
  2729. conn->getElements(xpath));
  2730. return new CConstWUIterator(iter, secmgr, secuser);
  2731. }
  2732. else
  2733. return NULL;
  2734. }
  2735. ISDSManager *sdsManager;
  2736. SessionId session;
  2737. };
  2738. extern WORKUNIT_API IConstWorkUnitIterator *createConstWUIterator(IPropertyTreeIterator *iter, ISecManager *secmgr, ISecUser *secuser)
  2739. {
  2740. return new CConstWUIterator(iter, secmgr, secuser);
  2741. }
  2742. static CriticalSection factoryCrit;
  2743. static Owned<ILoadedDllEntry> workunitServerPlugin; // NOTE - unload AFTER the factory is released!
  2744. static Owned<IWorkUnitFactory> factory;
  2745. void CDaliWorkUnitFactory::clientShutdown()
  2746. {
  2747. CriticalBlock b(factoryCrit);
  2748. factory.clear();
  2749. }
  2750. void clientShutdownWorkUnit()
  2751. {
  2752. CriticalBlock b(factoryCrit);
  2753. factory.clear();
  2754. }
  2755. extern WORKUNIT_API void setWorkUnitFactory(IWorkUnitFactory * _factory)
  2756. {
  2757. CriticalBlock b(factoryCrit);
  2758. factory.setown(_factory);
  2759. }
  2760. extern WORKUNIT_API IWorkUnitFactory * getWorkUnitFactory()
  2761. {
  2762. if (!factory)
  2763. {
  2764. CriticalBlock b(factoryCrit);
  2765. 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.
  2766. {
  2767. const char *forceEnv = getenv("FORCE_DALI_WORKUNITS");
  2768. bool forceDali = forceEnv && !strieq(forceEnv, "off") && !strieq(forceEnv, "0");
  2769. Owned<IRemoteConnection> conn = querySDS().connect("/Environment/Software/WorkUnitsServer", myProcessSession(), 0, SDS_LOCK_TIMEOUT);
  2770. // MORE - arguably should be looking in the config section that corresponds to the dali we connected to. If you want to allow some dalis to be configured to use a WU server and others not.
  2771. if (conn && !forceDali)
  2772. {
  2773. const IPropertyTree *ptree = conn->queryRoot();
  2774. const char *pluginName = ptree->queryProp("@plugin");
  2775. if (!pluginName)
  2776. throw makeStringException(WUERR_WorkunitPluginError, "WorkUnitsServer information missing plugin name");
  2777. workunitServerPlugin.setown(createDllEntry(pluginName, false, NULL));
  2778. if (!workunitServerPlugin)
  2779. throw makeStringExceptionV(WUERR_WorkunitPluginError, "WorkUnitsServer: failed to load plugin %s", pluginName);
  2780. WorkUnitFactoryFactory pf = (WorkUnitFactoryFactory) workunitServerPlugin->getEntry("createWorkUnitFactory");
  2781. if (!pf)
  2782. throw makeStringExceptionV(WUERR_WorkunitPluginError, "WorkUnitsServer: function createWorkUnitFactory not found in plugin %s", pluginName);
  2783. factory.setown(pf(ptree));
  2784. if (!factory)
  2785. throw makeStringExceptionV(WUERR_WorkunitPluginError, "WorkUnitsServer: createWorkUnitFactory returned NULL in plugin %s", pluginName);
  2786. }
  2787. else
  2788. factory.setown(new CDaliWorkUnitFactory());
  2789. }
  2790. }
  2791. return factory.getLink();
  2792. }
  2793. // A SecureWorkUnitFactory allows the security params to be supplied once to the factory rather than being supplied to each call.
  2794. // They can still be supplied if you want...
  2795. class CSecureWorkUnitFactory : public CInterface, implements IWorkUnitFactory
  2796. {
  2797. public:
  2798. IMPLEMENT_IINTERFACE;
  2799. CSecureWorkUnitFactory(IWorkUnitFactory *_baseFactory, ISecManager *_secMgr, ISecUser *_secUser)
  2800. : baseFactory(_baseFactory), defaultSecMgr(_secMgr), defaultSecUser(_secUser)
  2801. {
  2802. }
  2803. virtual unsigned validateRepository(bool fix)
  2804. {
  2805. return baseFactory->validateRepository(fix);
  2806. }
  2807. virtual void deleteRepository(bool recreate)
  2808. {
  2809. return baseFactory->deleteRepository(recreate);
  2810. }
  2811. virtual void createRepository()
  2812. {
  2813. return baseFactory->createRepository();
  2814. }
  2815. virtual IWorkUnit* createNamedWorkUnit(const char *wuid, const char *app, const char *user, ISecManager *secMgr, ISecUser *secUser)
  2816. {
  2817. if (!secMgr) secMgr = defaultSecMgr.get();
  2818. if (!secUser) secUser = defaultSecUser.get();
  2819. return baseFactory->createNamedWorkUnit(wuid, app, user, secMgr, secUser);
  2820. }
  2821. virtual IWorkUnit* createWorkUnit(const char *app, const char *user, ISecManager *secMgr, ISecUser *secUser)
  2822. {
  2823. if (!secMgr) secMgr = defaultSecMgr.get();
  2824. if (!secUser) secUser = defaultSecUser.get();
  2825. return baseFactory->createWorkUnit(app, user, secMgr, secUser);
  2826. }
  2827. virtual bool deleteWorkUnit(const char * wuid, ISecManager *secMgr, ISecUser *secUser)
  2828. {
  2829. if (!secMgr) secMgr = defaultSecMgr.get();
  2830. if (!secUser) secUser = defaultSecUser.get();
  2831. return baseFactory->deleteWorkUnit(wuid, secMgr, secUser);
  2832. }
  2833. virtual IConstWorkUnit* openWorkUnit(const char *wuid, bool lock, ISecManager *secMgr, ISecUser *secUser)
  2834. {
  2835. if (!secMgr) secMgr = defaultSecMgr.get();
  2836. if (!secUser) secUser = defaultSecUser.get();
  2837. return baseFactory->openWorkUnit(wuid, lock, secMgr, secUser);
  2838. }
  2839. virtual IWorkUnit* updateWorkUnit(const char *wuid, ISecManager *secMgr, ISecUser *secUser)
  2840. {
  2841. if (!secMgr) secMgr = defaultSecMgr.get();
  2842. if (!secUser) secUser = defaultSecUser.get();
  2843. return baseFactory->updateWorkUnit(wuid, secMgr, secUser);
  2844. }
  2845. virtual IWorkUnit * getGlobalWorkUnit(ISecManager *secMgr, ISecUser *secUser)
  2846. {
  2847. if (!secMgr) secMgr = defaultSecMgr.get();
  2848. if (!secUser) secUser = defaultSecUser.get();
  2849. return baseFactory->getGlobalWorkUnit(secMgr, secUser);
  2850. }
  2851. virtual IConstWorkUnitIterator * getWorkUnitsByOwner(const char * owner, ISecManager *secMgr, ISecUser *secUser)
  2852. {
  2853. if (!secMgr) secMgr = defaultSecMgr.get();
  2854. if (!secUser) secUser = defaultSecUser.get();
  2855. return baseFactory->getWorkUnitsByOwner(owner, secMgr, secUser);
  2856. }
  2857. virtual IConstWorkUnitIterator * getWorkUnitsByState(WUState state, ISecManager *secMgr, ISecUser *secUser)
  2858. {
  2859. if (!secMgr) secMgr = defaultSecMgr.get();
  2860. if (!secUser) secUser = defaultSecUser.get();
  2861. return baseFactory->getWorkUnitsByState(state, secMgr, secUser);
  2862. }
  2863. virtual IConstWorkUnitIterator * getWorkUnitsByECL(const char* ecl, ISecManager *secMgr, ISecUser *secUser)
  2864. {
  2865. if (!secMgr) secMgr = defaultSecMgr.get();
  2866. if (!secUser) secUser = defaultSecUser.get();
  2867. return baseFactory->getWorkUnitsByECL(ecl, secMgr, secUser);
  2868. }
  2869. virtual IConstWorkUnitIterator * getWorkUnitsByCluster(const char* cluster, ISecManager *secMgr, ISecUser *secUser)
  2870. {
  2871. if (!secMgr) secMgr = defaultSecMgr.get();
  2872. if (!secUser) secUser = defaultSecUser.get();
  2873. return baseFactory->getWorkUnitsByCluster(cluster, secMgr, secUser);
  2874. }
  2875. virtual IConstWorkUnitIterator * getWorkUnitsByXPath(const char * xpath, ISecManager *secMgr, ISecUser *secUser)
  2876. {
  2877. if (!secMgr) secMgr = defaultSecMgr.get();
  2878. if (!secUser) secUser = defaultSecUser.get();
  2879. return baseFactory->getWorkUnitsByXPath(xpath, secMgr, secUser);
  2880. }
  2881. virtual void descheduleAllWorkUnits(ISecManager *secMgr, ISecUser *secUser)
  2882. {
  2883. if (!secMgr) secMgr = defaultSecMgr.get();
  2884. if (!secUser) secUser = defaultSecUser.get();
  2885. baseFactory->descheduleAllWorkUnits(secMgr, secUser);
  2886. }
  2887. virtual int setTracingLevel(int newLevel)
  2888. {
  2889. return baseFactory->setTracingLevel(newLevel);
  2890. }
  2891. virtual IConstWorkUnitIterator* getWorkUnitsSorted( WUSortField sortorder, // field to sort by
  2892. WUSortField *filters, // NULL or list of fields to filter on (terminated by WUSFterm)
  2893. const void *filterbuf, // (appended) string values for filters
  2894. unsigned startoffset,
  2895. unsigned maxnum,
  2896. const char *queryowner,
  2897. __int64 *cachehint,
  2898. unsigned *total,
  2899. ISecManager *secMgr, ISecUser *secUser)
  2900. {
  2901. if (!secMgr) secMgr = defaultSecMgr.get();
  2902. if (!secUser) secUser = defaultSecUser.get();
  2903. return baseFactory->getWorkUnitsSorted(sortorder,filters,filterbuf,startoffset,maxnum,queryowner,cachehint, total, secMgr, secUser);
  2904. }
  2905. virtual IConstQuerySetQueryIterator* getQuerySetQueriesSorted( WUQuerySortField *sortorder,
  2906. WUQuerySortField *filters,
  2907. const void *filterbuf,
  2908. unsigned startoffset,
  2909. unsigned maxnum,
  2910. __int64 *cachehint,
  2911. unsigned *total,
  2912. const MapStringTo<bool> *subset)
  2913. {
  2914. // MORE - why no security?
  2915. return baseFactory->getQuerySetQueriesSorted(sortorder,filters,filterbuf,startoffset,maxnum,cachehint,total,subset);
  2916. }
  2917. virtual unsigned numWorkUnits()
  2918. {
  2919. return baseFactory->numWorkUnits();
  2920. }
  2921. virtual bool isAborting(const char *wuid) const
  2922. {
  2923. return baseFactory->isAborting(wuid);
  2924. }
  2925. virtual void clearAborting(const char *wuid)
  2926. {
  2927. baseFactory->clearAborting(wuid);
  2928. }
  2929. virtual WUState waitForWorkUnit(const char * wuid, unsigned timeout, bool compiled, bool returnOnWaitState)
  2930. {
  2931. return baseFactory->waitForWorkUnit(wuid, timeout, compiled, returnOnWaitState);
  2932. }
  2933. private:
  2934. Owned<IWorkUnitFactory> baseFactory;
  2935. Linked<ISecManager> defaultSecMgr;
  2936. Linked<ISecUser> defaultSecUser;
  2937. };
  2938. extern WORKUNIT_API IWorkUnitFactory * getWorkUnitFactory(ISecManager *secmgr, ISecUser *secuser)
  2939. {
  2940. if (secmgr && secuser)
  2941. return new CSecureWorkUnitFactory(getWorkUnitFactory(), secmgr, secuser);
  2942. else
  2943. return getWorkUnitFactory();
  2944. }
  2945. //==========================================================================================
  2946. class CStringPTreeIterator : public CInterface, implements IStringIterator
  2947. {
  2948. Owned<IPropertyTreeIterator> it;
  2949. public:
  2950. IMPLEMENT_IINTERFACE;
  2951. CStringPTreeIterator(IPropertyTreeIterator *p) : it(p) {};
  2952. virtual bool first() { return it->first(); }
  2953. virtual bool next() { return it->next(); }
  2954. virtual bool isValid() { return it->isValid(); }
  2955. virtual IStringVal & str(IStringVal &s) { s.set(it->query().queryProp(NULL)); return s; }
  2956. };
  2957. class CStringPTreeTagIterator : public CInterface, implements IStringIterator
  2958. {
  2959. Owned<IPropertyTreeIterator> it;
  2960. public:
  2961. IMPLEMENT_IINTERFACE;
  2962. CStringPTreeTagIterator(IPropertyTreeIterator *p) : it(p) {};
  2963. virtual bool first() { return it->first(); }
  2964. virtual bool next() { return it->next(); }
  2965. virtual bool isValid() { return it->isValid(); }
  2966. virtual IStringVal & str(IStringVal &s) { s.set(it->query().queryName()); return s; }
  2967. };
  2968. class CStringPTreeAttrIterator : public CInterface, implements IStringIterator
  2969. {
  2970. Owned<IPropertyTreeIterator> it;
  2971. StringAttr name;
  2972. public:
  2973. IMPLEMENT_IINTERFACE;
  2974. CStringPTreeAttrIterator(IPropertyTreeIterator *p, const char *_name) : it(p), name(_name) {};
  2975. virtual bool first() { return it->first(); }
  2976. virtual bool next() { return it->next(); }
  2977. virtual bool isValid() { return it->isValid(); }
  2978. virtual IStringVal & str(IStringVal &s) { s.set(it->query().queryProp(name)); return s; }
  2979. };
  2980. //==========================================================================================
  2981. CLocalWorkUnit::CLocalWorkUnit(ISecManager *secmgr, ISecUser *secuser)
  2982. {
  2983. clearCached(false);
  2984. secMgr.set(secmgr);
  2985. secUser.set(secuser);
  2986. workflowIteratorCached = false;
  2987. resultsCached = false;
  2988. temporariesCached = false;
  2989. variablesCached = false;
  2990. exceptionsCached = false;
  2991. pluginsCached = false;
  2992. librariesCached = false;
  2993. activitiesCached = false;
  2994. webServicesInfoCached = false;
  2995. roxieQueryInfoCached = false;
  2996. }
  2997. void CLocalWorkUnit::clearCached(bool clearTree)
  2998. {
  2999. query.clear();
  3000. webServicesInfo.clear();
  3001. roxieQueryInfo.clear();
  3002. workflowIterator.clear();
  3003. cachedGraphs.clear();
  3004. graphs.kill();
  3005. results.kill();
  3006. variables.kill();
  3007. plugins.kill();
  3008. libraries.kill();
  3009. exceptions.kill();
  3010. temporaries.kill();
  3011. statistics.kill();
  3012. appvalues.kill();
  3013. if (clearTree)
  3014. p.clear();
  3015. workflowIteratorCached = false;
  3016. resultsCached = false;
  3017. temporariesCached = false;
  3018. variablesCached = false;
  3019. exceptionsCached = false;
  3020. pluginsCached = false;
  3021. librariesCached = false;
  3022. activitiesCached = false;
  3023. webServicesInfoCached = false;
  3024. roxieQueryInfoCached = false;
  3025. }
  3026. void CLocalWorkUnit::loadPTree(IPropertyTree *ptree)
  3027. {
  3028. clearCached(false);
  3029. p.setown(ptree);
  3030. }
  3031. void CLocalWorkUnit::beforeDispose()
  3032. {
  3033. try
  3034. {
  3035. unsubscribe();
  3036. clearCached(true);
  3037. userDesc.clear();
  3038. secMgr.clear();
  3039. secUser.clear();
  3040. }
  3041. catch (IException *E) { LOG(MCexception(E, MSGCLS_warning), E, "Exception during ~CLocalWorkUnit"); E->Release(); }
  3042. }
  3043. void CLocalWorkUnit::cleanupAndDelete(bool deldll, bool deleteOwned, const StringArray *deleteExclusions)
  3044. {
  3045. MTIME_SECTION(queryActiveTimer(), "WUDELETE cleanupAndDelete total");
  3046. // Delete any related things in SDS etc that might otherwise be forgotten
  3047. if (p->getPropBool("@protected", false))
  3048. throw MakeStringException(WUERR_WorkunitProtected, "%s: Workunit is protected",p->queryName());
  3049. switch (getState())
  3050. {
  3051. case WUStateAborted:
  3052. case WUStateCompleted:
  3053. case WUStateFailed:
  3054. case WUStateArchived:
  3055. break;
  3056. case WUStateCompiled:
  3057. if (getAction()==WUActionRun || getAction()==WUActionUnknown)
  3058. throw MakeStringException(WUERR_WorkunitActive, "%s: Workunit is active",p->queryName());
  3059. break;
  3060. case WUStateWait:
  3061. throw MakeStringException(WUERR_WorkunitScheduled, "%s: Workunit is scheduled",p->queryName());
  3062. default:
  3063. throw MakeStringException(WUERR_WorkunitActive, "%s: Workunit is active",p->queryName());
  3064. break;
  3065. }
  3066. if (getIsQueryService())
  3067. {
  3068. Owned<IPropertyTree> registry = getQueryRegistryRoot();
  3069. if (registry)
  3070. {
  3071. VStringBuffer xpath("QuerySet/Query[@wuid='%s']", p->queryName());
  3072. if (registry->hasProp(xpath.str()))
  3073. throw MakeStringException(WUERR_WorkunitPublished, "%s: Workunit is published",p->queryName());
  3074. }
  3075. }
  3076. try
  3077. {
  3078. if (deldll && !p->getPropBool("@isClone", false))
  3079. {
  3080. Owned<IConstWUQuery> q = getQuery();
  3081. if (q)
  3082. {
  3083. Owned<IConstWUAssociatedFileIterator> iter = &q->getAssociatedFiles();
  3084. SCMStringBuffer name;
  3085. ForEach(*iter)
  3086. {
  3087. IConstWUAssociatedFile & cur = iter->query();
  3088. cur.getNameTail(name);
  3089. if (!deleteExclusions || (NotFound == deleteExclusions->find(name.str())))
  3090. {
  3091. Owned<IDllEntry> entry = queryDllServer().getEntry(name.str());
  3092. if (entry.get())
  3093. asyncRemoveDll(name.str());
  3094. else
  3095. {
  3096. SCMStringBuffer ip, localPath;
  3097. cur.getName(localPath);
  3098. cur.getIp(ip);
  3099. asyncRemoveFile(ip.str(), localPath.str());
  3100. }
  3101. }
  3102. }
  3103. }
  3104. }
  3105. factory->clearAborting(queryWuid());
  3106. deleteTempFiles(NULL, deleteOwned, true); // all, any remaining.
  3107. }
  3108. catch(IException *E)
  3109. {
  3110. StringBuffer s;
  3111. LOG(MCexception(E, MSGCLS_warning), E, s.append("Exception during cleanupAndDelete: ").append(p->queryName()).str());
  3112. E->Release();
  3113. }
  3114. catch (...)
  3115. {
  3116. WARNLOG("Unknown exception during cleanupAndDelete: %s", p->queryName());
  3117. }
  3118. CConstGraphProgress::deleteWuidProgress(p->queryName());
  3119. }
  3120. void CLocalWorkUnit::setTimeScheduled(const IJlibDateTime &val)
  3121. {
  3122. SCMStringBuffer strval;
  3123. val.getGmtString(strval);
  3124. p->setProp("@timescheduled",strval.str());
  3125. }
  3126. IJlibDateTime & CLocalWorkUnit::getTimeScheduled(IJlibDateTime &val) const
  3127. {
  3128. StringBuffer str;
  3129. p->getProp("@timescheduled",str);
  3130. if(str.length())
  3131. val.setGmtString(str.str());
  3132. return val;
  3133. }
  3134. bool modifyAndWriteWorkUnitXML(char const * wuid, StringBuffer & buf, StringBuffer & extra, IFileIO * fileio)
  3135. {
  3136. // kludge in extra chunks of XML such as GraphProgress and GeneratedDlls
  3137. if(extra.length())
  3138. {
  3139. size32_t l = (size32_t)strlen(wuid);
  3140. size32_t p = buf.length()-l-4; // bit of a kludge
  3141. assertex(memcmp(buf.str()+p+2,wuid,l)==0);
  3142. StringAttr tail(buf.str()+p);
  3143. buf.setLength(p);
  3144. buf.append(extra);
  3145. buf.append(tail);
  3146. }
  3147. return (fileio->write(0,buf.length(),buf.str()) == buf.length());
  3148. }
  3149. bool CLocalWorkUnit::archiveWorkUnit(const char *base,bool del,bool ignoredllerrors,bool deleteOwned)
  3150. {
  3151. CriticalBlock block(crit);
  3152. StringBuffer path(base);
  3153. if (!p)
  3154. return false;
  3155. const char *wuid = p->queryName();
  3156. if (!wuid||!*wuid)
  3157. return false;
  3158. addPathSepChar(path).append(wuid).append(".xml");
  3159. Owned<IFile> file = createIFile(path.str());
  3160. if (!file)
  3161. return false;
  3162. Owned<IFileIO> fileio = file->open(IFOcreate);
  3163. if (!fileio)
  3164. return false;
  3165. StringBuffer buf;
  3166. exportWorkUnitToXML(this, buf, false, false, true);
  3167. StringBuffer extraWorkUnitXML;
  3168. StringBuffer xpath("/GraphProgress/");
  3169. xpath.append(wuid);
  3170. Owned<IRemoteConnection> conn = querySDS().connect(xpath.str(), myProcessSession(), RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT);
  3171. if (conn)
  3172. {
  3173. Owned<IPropertyTree> tmp = createPTree("GraphProgress");
  3174. mergePTree(tmp,conn->queryRoot());
  3175. toXML(tmp,extraWorkUnitXML,1,XML_Format);
  3176. conn->close();
  3177. }
  3178. Owned<IConstWUQuery> q = getQuery();
  3179. if (!q)
  3180. {
  3181. if (!modifyAndWriteWorkUnitXML(wuid, buf, extraWorkUnitXML, fileio))
  3182. return false;
  3183. if (del)
  3184. {
  3185. if (getState()==WUStateUnknown)
  3186. setState(WUStateArchived); // to allow delete
  3187. cleanupAndDelete(false,deleteOwned); // no query, may as well delete
  3188. }
  3189. return false;
  3190. }
  3191. StringArray deleteExclusions; // associated files not to delete, added if failure to copy
  3192. Owned<IConstWUAssociatedFileIterator> iter = &q->getAssociatedFiles();
  3193. Owned<IPropertyTree> generatedDlls = createPTree("GeneratedDlls");
  3194. ForEach(*iter)
  3195. {
  3196. IConstWUAssociatedFile & cur = iter->query();
  3197. SCMStringBuffer name;
  3198. cur.getNameTail(name);
  3199. if (name.length())
  3200. {
  3201. Owned<IDllEntry> entry = queryDllServer().getEntry(name.str());
  3202. SCMStringBuffer curPath, curIp;
  3203. cur.getName(curPath);
  3204. cur.getIp(curIp);
  3205. SocketEndpoint curEp(curIp.str());
  3206. RemoteFilename curRfn;
  3207. curRfn.setPath(curEp, curPath.str());
  3208. StringBuffer dst(base);
  3209. addPathSepChar(dst);
  3210. curRfn.getTail(dst);
  3211. Owned<IFile> dstFile = createIFile(dst.str());
  3212. if (entry.get())
  3213. {
  3214. Owned<IException> exception;
  3215. Owned<IDllLocation> loc;
  3216. Owned<IPropertyTree> generatedDllBranch = createPTree();
  3217. generatedDllBranch->setProp("@name", entry->queryName());
  3218. generatedDllBranch->setProp("@kind", entry->queryKind());
  3219. try
  3220. {
  3221. loc.setown(entry->getBestLocation()); //throws exception if no readable locations
  3222. }
  3223. catch(IException * e)
  3224. {
  3225. exception.setown(e);
  3226. loc.setown(entry->getBestLocationCandidate()); //this will be closest of the unreadable locations
  3227. }
  3228. RemoteFilename filename;
  3229. loc->getDllFilename(filename);
  3230. if (!exception)
  3231. {
  3232. Owned<IFile> srcfile = createIFile(filename);
  3233. try
  3234. {
  3235. if (dstFile->exists())
  3236. {
  3237. if (streq(srcfile->queryFilename(), dstFile->queryFilename()))
  3238. deleteExclusions.append(name.str()); // restored workunit, referencing archive location for query dll (no longer true post HPCC-11191 fix)
  3239. // still want to delete if already archived but there are source file copies
  3240. }
  3241. else
  3242. copyFile(dstFile, srcfile);
  3243. }
  3244. catch(IException * e)
  3245. {
  3246. exception.setown(e);
  3247. }
  3248. }
  3249. if (exception)
  3250. {
  3251. if (ignoredllerrors)
  3252. {
  3253. EXCLOG(exception.get(), "archiveWorkUnit (copying associated file)");
  3254. //copy failed, so don't delete the registred dll files
  3255. deleteExclusions.append(name.str());
  3256. }
  3257. else
  3258. throw exception.getClear();
  3259. }
  3260. // Record Associated path to restore back to
  3261. StringBuffer restorePath;
  3262. curRfn.getRemotePath(restorePath);
  3263. generatedDllBranch->setProp("@location", restorePath.str());
  3264. generatedDlls->addPropTree("GeneratedDll", generatedDllBranch.getClear());
  3265. }
  3266. else // no generated dll entry
  3267. {
  3268. Owned<IFile> srcFile = createIFile(curRfn);
  3269. try
  3270. {
  3271. copyFile(dstFile, srcFile);
  3272. }
  3273. catch (IException *e)
  3274. {
  3275. VStringBuffer msg("Failed to archive associated file '%s' to destination '%s'", srcFile->queryFilename(), dstFile->queryFilename());
  3276. EXCLOG(e, msg.str());
  3277. e->Release();
  3278. deleteExclusions.append(name.str());
  3279. }
  3280. }
  3281. }
  3282. }
  3283. iter.clear();
  3284. if (generatedDlls->numChildren())
  3285. toXML(generatedDlls, extraWorkUnitXML, 1, XML_Format);
  3286. if (!modifyAndWriteWorkUnitXML(wuid, buf, extraWorkUnitXML, fileio))
  3287. return false;
  3288. if (del)
  3289. {
  3290. //setState(WUStateArchived); // this isn't useful as about to delete it!
  3291. q.clear();
  3292. cleanupAndDelete(true, deleteOwned, &deleteExclusions);
  3293. }
  3294. return true;
  3295. }
  3296. void CLocalWorkUnit::packWorkUnit(bool pack)
  3297. {
  3298. // only packs Graph info currently
  3299. CriticalBlock block(crit);
  3300. if (!p)
  3301. return;
  3302. const char *wuid = p->queryName();
  3303. if (!wuid||!*wuid)
  3304. return;
  3305. if (pack) {
  3306. if (!p->hasProp("PackedGraphs")) {
  3307. cachedGraphs.clear();
  3308. IPropertyTree *t = p->queryPropTree("Graphs");
  3309. if (t) {
  3310. MemoryBuffer buf;
  3311. t->serialize(buf);
  3312. p->setPropBin("PackedGraphs",buf.length(),buf.bufferBase());
  3313. p->removeTree(t);
  3314. }
  3315. }
  3316. }
  3317. else {
  3318. ensureGraphsUnpacked();
  3319. }
  3320. CConstGraphProgress::packProgress(wuid,pack);
  3321. }
  3322. IPropertyTree * pruneBranch(IPropertyTree * from, char const * xpath)
  3323. {
  3324. Owned<IPropertyTree> ret;
  3325. IPropertyTree * branch = from->queryPropTree(xpath);
  3326. if(branch) {
  3327. ret.setown(createPTreeFromIPT(branch));
  3328. from->removeTree(branch);
  3329. }
  3330. return ret.getClear();
  3331. }
  3332. bool restoreWorkUnit(const char *base,const char *wuid)
  3333. {
  3334. StringBuffer path(base);
  3335. if (!wuid||!*wuid)
  3336. return false;
  3337. addPathSepChar(path).append(wuid).append(".xml");
  3338. Owned<IFile> file = createIFile(path.str());
  3339. if (!file)
  3340. return false;
  3341. Owned<IFileIO> fileio = file->open(IFOread);
  3342. if (!fileio)
  3343. return false;
  3344. Owned<IPropertyTree> pt = createPTree(*fileio);
  3345. if (!pt)
  3346. return false;
  3347. CDateTime dt;
  3348. dt.setNow();
  3349. StringBuffer dts;
  3350. dt.getString(dts);
  3351. pt->setProp("@restoredDate", dts.str());
  3352. VStringBuffer xpath("/WorkUnits/%s", wuid);
  3353. Owned<IRemoteConnection> conn = querySDS().connect(xpath.str(), myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT);
  3354. if (!conn)
  3355. {
  3356. ERRLOG("restoreWorkUnit could not create to %s", xpath.str());
  3357. return false;
  3358. }
  3359. IPropertyTree *root = conn->queryRoot();
  3360. if (root->hasChildren())
  3361. {
  3362. ERRLOG("restoreWorkUnit WUID %s already exists", wuid);
  3363. return false;
  3364. }
  3365. Owned<IPropertyTree> gprogress = pruneBranch(pt, "GraphProgress[1]");
  3366. Owned<IPropertyTree> generatedDlls = pruneBranch(pt, "GeneratedDlls[1]");
  3367. Owned<IPropertyTree> associatedFiles;
  3368. IPropertyTree *srcAssociated = pt->queryPropTree("Query/Associated");
  3369. if (srcAssociated)
  3370. associatedFiles.setown(createPTreeFromIPT(srcAssociated));
  3371. root->setPropTree(NULL, pt.getClear());
  3372. conn.clear();
  3373. // now kludge back GraphProgress and GeneratedDlls
  3374. if (gprogress)
  3375. {
  3376. VStringBuffer xpath("/GraphProgress/%s", wuid);
  3377. conn.setown(querySDS().connect(xpath, myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT));
  3378. if (conn)
  3379. {
  3380. IPropertyTree *groot = conn->queryRoot();
  3381. if (groot->hasChildren())
  3382. WARNLOG("restoreWorkUnit WUID %s graphprogress already exists, replacing",wuid);
  3383. groot->setPropTree(NULL, gprogress.getClear());
  3384. }
  3385. }
  3386. if (generatedDlls)
  3387. {
  3388. Owned<IPropertyTreeIterator> dlls = generatedDlls->getElements("GeneratedDll");
  3389. for(dlls->first(); dlls->isValid(); dlls->next())
  3390. {
  3391. IPropertyTree & dll = dlls->query();
  3392. char const * name = dll.queryProp("@name");
  3393. char const * kind = dll.queryProp("@kind");
  3394. char const * location = dll.queryProp("@location");
  3395. Owned<IDllEntry> got = queryDllServer().getEntry(name);
  3396. if (!got)
  3397. {
  3398. RemoteFilename dstRfn;
  3399. dstRfn.setRemotePath(location);
  3400. StringBuffer srcPath(base);
  3401. addPathSepChar(srcPath);
  3402. dstRfn.getTail(srcPath);
  3403. OwnedIFile srcFile = createIFile(srcPath);
  3404. OwnedIFile dstFile = createIFile(dstRfn);
  3405. copyFile(dstFile, srcFile);
  3406. queryDllServer().registerDll(name, kind, location);
  3407. }
  3408. }
  3409. }
  3410. if (associatedFiles)
  3411. {
  3412. Owned<IPropertyTreeIterator> associated = associatedFiles->getElements("*");
  3413. ForEach(*associated)
  3414. {
  3415. IPropertyTree &file = associated->query();
  3416. const char *filename = file.queryProp("@filename");
  3417. SocketEndpoint ep(file.queryProp("@ip"));
  3418. RemoteFilename rfn;
  3419. rfn.setPath(ep, filename);
  3420. OwnedIFile dstFile = createIFile(rfn);
  3421. StringBuffer srcPath(base), name;
  3422. addPathSepChar(srcPath);
  3423. rfn.getTail(name);
  3424. srcPath.append(name);
  3425. if (generatedDlls)
  3426. {
  3427. VStringBuffer gDllPath("GeneratedDll[@name=\"%s\"]", name.str());
  3428. if (generatedDlls->hasProp(gDllPath))
  3429. continue; // generated dlls handled separately - see above
  3430. }
  3431. OwnedIFile srcFile = createIFile(srcPath);
  3432. if (srcFile->exists())
  3433. {
  3434. try
  3435. {
  3436. copyFile(dstFile, srcFile);
  3437. }
  3438. catch (IException *e)
  3439. {
  3440. VStringBuffer msg("Failed to restore associated file '%s' to destination '%s'", srcFile->queryFilename(), dstFile->queryFilename());
  3441. EXCLOG(e, msg.str());
  3442. e->Release();
  3443. }
  3444. }
  3445. }
  3446. }
  3447. return true;
  3448. }
  3449. void CLocalWorkUnit::loadXML(const char *xml)
  3450. {
  3451. CriticalBlock block(crit);
  3452. clearCached(true);
  3453. assertex(xml);
  3454. p.setown(createPTreeFromXMLString(xml));
  3455. }
  3456. void CLocalWorkUnit::serialize(MemoryBuffer &tgt)
  3457. {
  3458. CriticalBlock block(crit);
  3459. StringBuffer x;
  3460. tgt.append(exportWorkUnitToXML(this, x, false, false, false).str());
  3461. }
  3462. void CLocalWorkUnit::deserialize(MemoryBuffer &src)
  3463. {
  3464. CriticalBlock block(crit);
  3465. StringAttr value;
  3466. src.read(value);
  3467. loadXML(value);
  3468. }
  3469. void CLocalWorkUnit::requestAbort()
  3470. {
  3471. CriticalBlock block(crit);
  3472. abortWorkUnit(p->queryName());
  3473. }
  3474. void CLocalWorkUnit::subscribe(WUSubscribeOptions options)
  3475. {
  3476. }
  3477. void CLocalWorkUnit::unlockRemote()
  3478. {
  3479. CriticalBlock block(crit);
  3480. locked.unlock();
  3481. if (IsShared()) // Is this right? Doesn't feel right! Commit on last unlock would seem smarter
  3482. {
  3483. _unlockRemote();
  3484. }
  3485. }
  3486. IWorkUnit &CLocalWorkUnit::lockRemote(bool commit)
  3487. {
  3488. if (secMgr)
  3489. checkWuSecAccess(*this, secMgr.get(), secUser.get(), SecAccess_Write, "write lock", true, true);
  3490. locked.lock();
  3491. CriticalBlock block(crit);
  3492. if (commit)
  3493. {
  3494. try
  3495. {
  3496. _lockRemote();
  3497. }
  3498. catch (IException *E)
  3499. {
  3500. StringBuffer s;
  3501. PrintLog("Failed to get write lock on workunit: %s", E->errorMessage(s).str());
  3502. locked.unlock();
  3503. throw;
  3504. }
  3505. }
  3506. return *new CLockedWorkUnit(LINK(this));
  3507. }
  3508. void CLocalWorkUnit::commit()
  3509. {
  3510. // Nothing to do if not backed by a persistent store
  3511. }
  3512. IWorkUnit& CLocalWorkUnit::lock()
  3513. {
  3514. return lockRemote(true);
  3515. }
  3516. const char *CLocalWorkUnit::queryWuid() const
  3517. {
  3518. CriticalBlock block(crit);
  3519. return p->queryName();
  3520. }
  3521. unsigned CLocalWorkUnit::getDebugAgentListenerPort() const
  3522. {
  3523. CriticalBlock block(crit);
  3524. return p->getPropInt("@DebugListenerPort", 0);
  3525. }
  3526. void CLocalWorkUnit::setDebugAgentListenerPort(unsigned port)
  3527. {
  3528. CriticalBlock block(crit);
  3529. p->setPropInt("@DebugListenerPort", port);
  3530. }
  3531. IStringVal& CLocalWorkUnit::getDebugAgentListenerIP(IStringVal &ip) const
  3532. {
  3533. CriticalBlock block(crit);
  3534. ip.set(p->queryProp("@DebugListenerIP"));
  3535. return ip;
  3536. }
  3537. void CLocalWorkUnit::setDebugAgentListenerIP(const char * ip)
  3538. {
  3539. CriticalBlock block(crit);
  3540. p->setProp("@DebugListenerIP", ip);
  3541. }
  3542. IStringVal& CLocalWorkUnit::getSecurityToken(IStringVal &str) const
  3543. {
  3544. CriticalBlock block(crit);
  3545. str.set(p->queryProp("@token"));
  3546. return str;
  3547. }
  3548. void CLocalWorkUnit::setSecurityToken(const char *value)
  3549. {
  3550. CriticalBlock block(crit);
  3551. p->setProp("@token", value);
  3552. }
  3553. bool CLocalWorkUnit::getRunningGraph(IStringVal &graphName, WUGraphIDType &subId) const
  3554. {
  3555. return CConstGraphProgress::getRunningGraph(p->queryName(), graphName, subId);
  3556. }
  3557. void CLocalWorkUnit::setJobName(const char *value)
  3558. {
  3559. CriticalBlock block(crit);
  3560. p->setProp("@jobName", value);
  3561. }
  3562. const char *CLocalWorkUnit::queryJobName() const
  3563. {
  3564. CriticalBlock block(crit);
  3565. const char *ret = p->queryProp("@jobName");
  3566. if (!ret)
  3567. ret = "";
  3568. return ret;
  3569. }
  3570. void CLocalWorkUnit::setClusterName(const char *value)
  3571. {
  3572. CriticalBlock block(crit);
  3573. p->setProp("@clusterName", value);
  3574. }
  3575. const char *CLocalWorkUnit::queryClusterName() const
  3576. {
  3577. CriticalBlock block(crit);
  3578. const char *ret = p->queryProp("@clusterName");
  3579. if (!ret)
  3580. ret = "";
  3581. return ret;
  3582. }
  3583. void CLocalWorkUnit::setAllowedClusters(const char *value)
  3584. {
  3585. setDebugValue("allowedclusters",value, true);
  3586. }
  3587. IStringVal& CLocalWorkUnit::getAllowedClusters(IStringVal &str) const
  3588. {
  3589. CriticalBlock block(crit);
  3590. getDebugValue("allowedclusters",str);
  3591. if (str.length()!=0)
  3592. return str;
  3593. str.set(p->queryProp("@clusterName"));
  3594. return str;
  3595. }
  3596. void CLocalWorkUnit::setAllowAutoQueueSwitch(bool val)
  3597. {
  3598. setDebugValueInt("allowautoqueueswitch",val?1:0,true);
  3599. }
  3600. bool CLocalWorkUnit::getAllowAutoQueueSwitch() const
  3601. {
  3602. CriticalBlock block(crit);
  3603. return getDebugValueBool("allowautoqueueswitch",false);
  3604. }
  3605. void CLocalWorkUnit::setLibraryInformation(const char * name, unsigned interfaceHash, unsigned definitionHash)
  3606. {
  3607. StringBuffer suffix;
  3608. if (name && *name)
  3609. setApplicationValue("LibraryModule", "name", name, true);
  3610. setApplicationValueInt("LibraryModule", "interfaceHash", interfaceHash, true);
  3611. setApplicationValueInt("LibraryModule", "definitionHash", definitionHash, true);
  3612. setApplicationValue("LibraryModule", "platform", appendLibrarySuffix(suffix).str(), true);
  3613. }
  3614. void CLocalWorkUnit::remoteCheckAccess(IUserDescriptor *user, bool writeaccess) const
  3615. {
  3616. unsigned auditflags = DALI_LDAP_AUDIT_REPORT|DALI_LDAP_READ_WANTED;
  3617. if (writeaccess)
  3618. auditflags |= DALI_LDAP_WRITE_WANTED;
  3619. int perm = 255;
  3620. const char *scopename = p->queryProp("@scope");
  3621. if (scopename&&*scopename) {
  3622. if (!user)
  3623. user = queryUserDescriptor();
  3624. perm = querySessionManager().getPermissionsLDAP("workunit",scopename,user,auditflags);
  3625. if (perm<0) {
  3626. if (perm==-1)
  3627. perm = 255;
  3628. else
  3629. perm = 0;
  3630. }
  3631. }
  3632. if (!HASREADPERMISSION(perm))
  3633. throw MakeStringException(WUERR_WorkunitAccessDenied, "Read access denied for workunit %s", queryWuid());
  3634. if (writeaccess && !HASWRITEPERMISSION(perm))
  3635. throw MakeStringException(WUERR_WorkunitAccessDenied, "Write access denied for workunit %s", queryWuid());
  3636. }
  3637. void CLocalWorkUnit::setUser(const char * value)
  3638. {
  3639. CriticalBlock block(crit);
  3640. p->setProp("@submitID", value);
  3641. }
  3642. const char *CLocalWorkUnit::queryUser() const
  3643. {
  3644. CriticalBlock block(crit);
  3645. const char *ret = p->queryProp("@submitID");
  3646. if (!ret)
  3647. ret = "";
  3648. return ret;
  3649. }
  3650. void CLocalWorkUnit::setWuScope(const char * value)
  3651. {
  3652. if (value && *value)
  3653. {
  3654. if (checkWuScopeSecAccess(value, secMgr.get(), secUser.get(), SecAccess_Write, "Change Scope", true, true))
  3655. {
  3656. CriticalBlock block(crit);
  3657. p->setProp("@scope", value);
  3658. }
  3659. }
  3660. }
  3661. IStringVal& CLocalWorkUnit::getWuScope(IStringVal &str) const
  3662. {
  3663. CriticalBlock block(crit);
  3664. str.set(p->queryProp("@scope"));
  3665. return str;
  3666. }
  3667. mapEnums priorityClasses[] = {
  3668. { PriorityClassUnknown, "unknown" },
  3669. { PriorityClassLow, "low" },
  3670. { PriorityClassNormal, "normal" },
  3671. { PriorityClassHigh, "high" },
  3672. { PriorityClassSize, NULL },
  3673. };
  3674. void CLocalWorkUnit::setPriority(WUPriorityClass cls)
  3675. {
  3676. CriticalBlock block(crit);
  3677. setEnum(p, "@priorityClass", cls, priorityClasses);
  3678. }
  3679. WUPriorityClass CLocalWorkUnit::getPriority() const
  3680. {
  3681. CriticalBlock block(crit);
  3682. return (WUPriorityClass) getEnum(p, "@priorityClass", priorityClasses);
  3683. }
  3684. void CLocalWorkUnit::setState(WUState value)
  3685. {
  3686. if (value==WUStateAborted || value==WUStatePaused || value==WUStateCompleted || value==WUStateFailed || value==WUStateSubmitted || value==WUStateWait)
  3687. {
  3688. if (factory)
  3689. factory->clearAborting(queryWuid());
  3690. }
  3691. CriticalBlock block(crit);
  3692. setEnum(p, "@state", value, states);
  3693. if (getDebugValueBool("monitorWorkunit", false))
  3694. {
  3695. switch(value)
  3696. {
  3697. case WUStateAborted:
  3698. FLLOG(MCoperatorWarning, "Workunit %s aborted", p->queryName());
  3699. break;
  3700. case WUStateCompleted:
  3701. FLLOG(MCoperatorProgress, "Workunit %s completed", p->queryName());
  3702. break;
  3703. case WUStateFailed:
  3704. FLLOG(MCoperatorProgress, "Workunit %s failed", p->queryName());
  3705. break;
  3706. }
  3707. }
  3708. p->removeProp("@stateEx");
  3709. }
  3710. void CLocalWorkUnit::setStateEx(const char * text)
  3711. {
  3712. CriticalBlock block(crit);
  3713. p->setProp("@stateEx", text);
  3714. }
  3715. void CLocalWorkUnit::setAgentSession(__int64 sessionId)
  3716. {
  3717. CriticalBlock block(crit);
  3718. p->setPropInt64("@agentSession", sessionId);
  3719. }
  3720. bool CLocalWorkUnit::aborting() const
  3721. {
  3722. return false;
  3723. }
  3724. bool CLocalWorkUnit::getIsQueryService() const
  3725. {
  3726. CriticalBlock block(crit);
  3727. return p->getPropBool("@isQueryService", false);
  3728. }
  3729. void CLocalWorkUnit::setIsQueryService(bool value)
  3730. {
  3731. CriticalBlock block(crit);
  3732. p->setPropBool("@isQueryService", value);
  3733. }
  3734. void CLocalWorkUnit::checkAgentRunning(WUState & state)
  3735. {
  3736. if (queryDaliServerVersion().compare("2.1")<0)
  3737. return;
  3738. switch(state)
  3739. {
  3740. case WUStateRunning:
  3741. case WUStateDebugPaused:
  3742. case WUStateDebugRunning:
  3743. case WUStateBlocked:
  3744. case WUStateAborting:
  3745. case WUStateCompiling:
  3746. case WUStatePaused:
  3747. {
  3748. SessionId agent = getAgentSession();
  3749. if((agent>0) && querySessionManager().sessionStopped(agent, 0))
  3750. {
  3751. forceReload();
  3752. state = (WUState) getEnum(p, "@state", states);
  3753. bool isecl=state==WUStateCompiling;
  3754. if (aborting())
  3755. state = WUStateAborted;
  3756. else if (state==WUStateRunning || state==WUStatePaused || state==WUStateDebugPaused || state==WUStateDebugRunning || state==WUStateBlocked || state==WUStateCompiling)
  3757. state = WUStateFailed;
  3758. else
  3759. return;
  3760. WARNLOG("checkAgentRunning terminated: %" I64F "d state = %d",(__int64)agent,(int)state);
  3761. Owned<IWorkUnit> w = &lock();
  3762. w->setState(state);
  3763. Owned<IWUException> e = w->createException();
  3764. WUAction action = w->getAction();
  3765. switch (action)
  3766. {
  3767. case WUActionPause:
  3768. case WUActionPauseNow:
  3769. case WUActionResume:
  3770. w->setAction(WUActionUnknown);
  3771. }
  3772. if(isecl)
  3773. {
  3774. e->setExceptionCode(1001);
  3775. e->setExceptionMessage("EclServer terminated unexpectedly");
  3776. }
  3777. else
  3778. {
  3779. e->setExceptionCode(1000);
  3780. e->setExceptionMessage("Workunit terminated unexpectedly");
  3781. }
  3782. }
  3783. }
  3784. }
  3785. }
  3786. WUState CLocalWorkUnit::getState() const
  3787. {
  3788. CriticalBlock block(crit);
  3789. WUState state = (WUState) getEnum(p, "@state", states);
  3790. switch (state)
  3791. {
  3792. case WUStateRunning:
  3793. case WUStateDebugPaused:
  3794. case WUStateDebugRunning:
  3795. case WUStateBlocked:
  3796. case WUStateCompiling:
  3797. if (aborting())
  3798. state = WUStateAborting;
  3799. break;
  3800. case WUStateSubmitted:
  3801. if (aborting())
  3802. state = WUStateAborted;
  3803. break;
  3804. }
  3805. const_cast<CLocalWorkUnit *>(this)->checkAgentRunning(state); //need const_cast as will change state if agent has died
  3806. return state;
  3807. }
  3808. IStringVal& CLocalWorkUnit::getStateEx(IStringVal & str) const
  3809. {
  3810. CriticalBlock block(crit);
  3811. str.set(p->queryProp("@stateEx"));
  3812. return str;
  3813. }
  3814. __int64 CLocalWorkUnit::getAgentSession() const
  3815. {
  3816. CriticalBlock block(crit);
  3817. return p->getPropInt64("@agentSession", -1);
  3818. }
  3819. unsigned CLocalWorkUnit::getAgentPID() const
  3820. {
  3821. CriticalBlock block(crit);
  3822. return p->getPropInt("@agentPID", -1);
  3823. }
  3824. const char * CLocalWorkUnit::queryStateDesc() const
  3825. {
  3826. // MORE - not sure about this - may prefer a separate interface
  3827. CriticalBlock block(crit);
  3828. try
  3829. {
  3830. return getEnumText(getState(), states);
  3831. }
  3832. catch (...)
  3833. {
  3834. return "???";
  3835. }
  3836. }
  3837. mapEnums actions[] = {
  3838. { WUActionUnknown, "unknown" },
  3839. { WUActionCompile, "compile" },
  3840. { WUActionCheck, "check" },
  3841. { WUActionRun, "run" },
  3842. { WUActionExecuteExisting, "execute" },
  3843. { WUActionPause, "pause" },
  3844. { WUActionPauseNow, "pausenow" },
  3845. { WUActionResume, "resume" },
  3846. { WUActionSize, NULL },
  3847. };
  3848. void CLocalWorkUnit::setAction(WUAction value)
  3849. {
  3850. CriticalBlock block(crit);
  3851. setEnum(p, "Action", value, actions);
  3852. }
  3853. WUAction CLocalWorkUnit::getAction() const
  3854. {
  3855. CriticalBlock block(crit);
  3856. return (WUAction) getEnum(p, "Action", actions);
  3857. }
  3858. IStringVal& CLocalWorkUnit::getActionEx(IStringVal & str) const
  3859. {
  3860. CriticalBlock block(crit);
  3861. str.set(p->queryProp("Action"));
  3862. return str;
  3863. }
  3864. IStringVal& CLocalWorkUnit::getApplicationValue(const char *app, const char *propname, IStringVal &str) const
  3865. {
  3866. CriticalBlock block(crit);
  3867. StringBuffer prop("Application/");
  3868. prop.append(app).append('/').append(propname);
  3869. str.set(p->queryProp(prop.str()));
  3870. return str;
  3871. }
  3872. int CLocalWorkUnit::getApplicationValueInt(const char *app, const char *propname, int defVal) const
  3873. {
  3874. CriticalBlock block(crit);
  3875. StringBuffer prop("Application/");
  3876. prop.append(app).append('/').append(propname);
  3877. return p->getPropInt(prop.str(), defVal);
  3878. }
  3879. IConstWUAppValueIterator& CLocalWorkUnit::getApplicationValues() const
  3880. {
  3881. CriticalBlock block(crit);
  3882. appvalues.load(p,"Application/*");
  3883. return *new CArrayIteratorOf<IConstWUAppValue,IConstWUAppValueIterator> (appvalues, 0, (IConstWorkUnit *) this);
  3884. }
  3885. void CLocalWorkUnit::setApplicationValue(const char *app, const char *propname, const char *value, bool overwrite)
  3886. {
  3887. CriticalBlock block(crit);
  3888. StringBuffer prop("Application/");
  3889. prop.append(app).append('/').append(propname);
  3890. if (overwrite || !p->hasProp(prop.str()))
  3891. {
  3892. // MORE - not sure these lines should be needed....
  3893. StringBuffer sp;
  3894. p->setProp(sp.append("Application").str(), "");
  3895. p->setProp(sp.append('/').append(app).str(), "");
  3896. p->setProp(prop.str(), value);
  3897. }
  3898. }
  3899. void CLocalWorkUnit::setApplicationValueInt(const char *app, const char *propname, int value, bool overwrite)
  3900. {
  3901. CriticalBlock block(crit);
  3902. StringBuffer prop("Application/");
  3903. prop.append(app).append('/').append(propname);
  3904. if (overwrite || !p->hasProp(prop.str()))
  3905. {
  3906. // MORE - not sure these lines should be needed....
  3907. StringBuffer sp;
  3908. p->setProp(sp.append("Application").str(), "");
  3909. p->setProp(sp.append('/').append(app).str(), "");
  3910. p->setPropInt(prop.str(), value);
  3911. }
  3912. }
  3913. void CLocalWorkUnit::setPriorityLevel(int level)
  3914. {
  3915. CriticalBlock block(crit);
  3916. p->setPropInt("PriorityFlag", level);
  3917. }
  3918. int CLocalWorkUnit::getPriorityLevel() const
  3919. {
  3920. CriticalBlock block(crit);
  3921. return p->getPropInt("PriorityFlag");
  3922. }
  3923. int calcPriorityValue(const IPropertyTree * p)
  3924. {
  3925. int priority = p->getPropInt("PriorityFlag");
  3926. switch((WUPriorityClass) getEnum(p, "@priorityClass", priorityClasses))
  3927. {
  3928. case PriorityClassLow:
  3929. priority -= 100;
  3930. break;
  3931. case PriorityClassHigh:
  3932. priority += 100;
  3933. break;
  3934. }
  3935. return priority;
  3936. }
  3937. int CLocalWorkUnit::getPriorityValue() const
  3938. {
  3939. CriticalBlock block(crit);
  3940. return calcPriorityValue(p);
  3941. }
  3942. void CLocalWorkUnit::setRescheduleFlag(bool value)
  3943. {
  3944. CriticalBlock block(crit);
  3945. p->setPropInt("RescheduleFlag", (int) value);
  3946. }
  3947. bool CLocalWorkUnit::getRescheduleFlag() const
  3948. {
  3949. CriticalBlock block(crit);
  3950. return p->getPropInt("RescheduleFlag") != 0;
  3951. }
  3952. class NullIStringIterator : public CInterface, extends IStringIterator
  3953. {
  3954. public:
  3955. IMPLEMENT_IINTERFACE;
  3956. bool first() { return false; }
  3957. bool next() { return false; }
  3958. bool isValid() { return false; }
  3959. IStringVal & str(IStringVal & str) { return str; }
  3960. };
  3961. ClusterType getClusterType(const char * platform, ClusterType dft)
  3962. {
  3963. if (stricmp(platform, "thor") == 0)
  3964. return ThorLCRCluster;
  3965. if (stricmp(platform, "thorlcr") == 0)
  3966. return ThorLCRCluster;
  3967. if (stricmp(platform, "hthor") == 0)
  3968. return HThorCluster;
  3969. if (stricmp(platform, "roxie") == 0)
  3970. return RoxieCluster;
  3971. return dft;
  3972. }
  3973. const char *clusterTypeString(ClusterType clusterType, bool lcrSensitive)
  3974. {
  3975. switch (clusterType)
  3976. {
  3977. case ThorLCRCluster:
  3978. if (lcrSensitive)
  3979. return "thorlcr";
  3980. return "thor";
  3981. case RoxieCluster:
  3982. return "roxie";
  3983. case HThorCluster:
  3984. return "hthor";
  3985. }
  3986. throwUnexpected();
  3987. }
  3988. IPropertyTree *queryRoxieProcessTree(IPropertyTree *environment, const char *process)
  3989. {
  3990. if (!process || !*process)
  3991. return NULL;
  3992. VStringBuffer xpath("Software/RoxieCluster[@name=\"%s\"]", process);
  3993. return environment->queryPropTree(xpath.str());
  3994. }
  3995. void getRoxieProcessServers(IPropertyTree *roxie, SocketEndpointArray &endpoints)
  3996. {
  3997. if (!roxie)
  3998. return;
  3999. Owned<IPropertyTreeIterator> servers = roxie->getElements("RoxieServerProcess");
  4000. ForEach(*servers)
  4001. {
  4002. IPropertyTree &server = servers->query();
  4003. const char *netAddress = server.queryProp("@netAddress");
  4004. if (netAddress && *netAddress)
  4005. {
  4006. SocketEndpoint ep(netAddress, server.getPropInt("@port", 9876));
  4007. endpoints.append(ep);
  4008. }
  4009. }
  4010. }
  4011. void getRoxieProcessServers(const char *process, SocketEndpointArray &servers)
  4012. {
  4013. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  4014. Owned<IConstEnvironment> env = factory->openEnvironment();
  4015. if (!env)
  4016. return;
  4017. Owned<IPropertyTree> root = &env->getPTree();
  4018. getRoxieProcessServers(queryRoxieProcessTree(root, process), servers);
  4019. }
  4020. class CEnvironmentClusterInfo: public CInterface, implements IConstWUClusterInfo
  4021. {
  4022. StringAttr name;
  4023. StringAttr serverQueue;
  4024. StringAttr agentQueue;
  4025. StringAttr roxieProcess;
  4026. SocketEndpointArray roxieServers;
  4027. StringAttr thorQueue;
  4028. StringArray thorProcesses;
  4029. StringArray primaryThorProcesses;
  4030. StringAttr prefix;
  4031. StringAttr ldapUser;
  4032. StringBuffer ldapPassword;
  4033. ClusterType platform;
  4034. unsigned clusterWidth;
  4035. unsigned roxieRedundancy;
  4036. unsigned channelsPerNode;
  4037. int roxieReplicateOffset;
  4038. public:
  4039. IMPLEMENT_IINTERFACE;
  4040. CEnvironmentClusterInfo(const char *_name, const char *_prefix, IPropertyTree *agent, IArrayOf<IPropertyTree> &thors, IPropertyTree *roxie)
  4041. : name(_name), prefix(_prefix), roxieRedundancy(0), channelsPerNode(0), roxieReplicateOffset(1)
  4042. {
  4043. StringBuffer queue;
  4044. if (thors.ordinality())
  4045. {
  4046. thorQueue.set(getClusterThorQueueName(queue.clear(), name));
  4047. clusterWidth = 0;
  4048. bool isMultiThor = (thors.length() > 1);
  4049. ForEachItemIn(i,thors)
  4050. {
  4051. IPropertyTree &thor = thors.item(i);
  4052. const char* thorName = thor.queryProp("@name");
  4053. thorProcesses.append(thorName);
  4054. if (!isMultiThor)
  4055. primaryThorProcesses.append(thorName);
  4056. else
  4057. {
  4058. const char *nodeGroup = thor.queryProp("@nodeGroup");
  4059. if (!nodeGroup || strieq(nodeGroup, thorName))
  4060. primaryThorProcesses.append(thorName);
  4061. }
  4062. unsigned nodes = thor.getCount("ThorSlaveProcess");
  4063. if (!nodes)
  4064. throw MakeStringException(WUERR_MismatchClusterSize,"CEnvironmentClusterInfo: Thor cluster can not have 0 slave processes");
  4065. unsigned ts = nodes * thor.getPropInt("@slavesPerNode", 1);
  4066. if (clusterWidth && (ts!=clusterWidth))
  4067. throw MakeStringException(WUERR_MismatchClusterSize,"CEnvironmentClusterInfo: mismatched thor sizes in cluster");
  4068. clusterWidth = ts;
  4069. bool islcr = !thor.getPropBool("@Legacy");
  4070. if (!islcr)
  4071. throw MakeStringException(WUERR_MismatchThorType,"CEnvironmentClusterInfo: Legacy Thor no longer supported");
  4072. }
  4073. platform = ThorLCRCluster;
  4074. }
  4075. else if (roxie)
  4076. {
  4077. roxieProcess.set(roxie->queryProp("@name"));
  4078. platform = RoxieCluster;
  4079. getRoxieProcessServers(roxie, roxieServers);
  4080. clusterWidth = roxieServers.length();
  4081. ldapUser.set(roxie->queryProp("@ldapUser"));
  4082. StringBuffer encPassword = roxie->queryProp("@ldapPassword");
  4083. if (encPassword.length())
  4084. decrypt(ldapPassword, encPassword);
  4085. const char *redundancyMode = roxie->queryProp("@slaveConfig");
  4086. if (redundancyMode && *redundancyMode)
  4087. {
  4088. unsigned dataCopies = roxie->getPropInt("@numDataCopies", 1);
  4089. if (strieq(redundancyMode, "overloaded"))
  4090. channelsPerNode = roxie->getPropInt("@channelsPernode", 1);
  4091. else if (strieq(redundancyMode, "full redundancy"))
  4092. {
  4093. roxieRedundancy = dataCopies-1;
  4094. roxieReplicateOffset = 0;
  4095. }
  4096. else if (strieq(redundancyMode, "cyclic redundancy"))
  4097. {
  4098. roxieRedundancy = dataCopies-1;
  4099. channelsPerNode = dataCopies;
  4100. roxieReplicateOffset = roxie->getPropInt("@cyclicOffset", 1);
  4101. }
  4102. }
  4103. }
  4104. else
  4105. {
  4106. clusterWidth = 1;
  4107. platform = HThorCluster;
  4108. }
  4109. if (agent)
  4110. {
  4111. assertex(!roxie);
  4112. agentQueue.set(getClusterEclAgentQueueName(queue.clear(), name));
  4113. }
  4114. else if (roxie)
  4115. agentQueue.set(getClusterRoxieQueueName(queue.clear(), name));
  4116. // MORE - does this need to be conditional?
  4117. serverQueue.set(getClusterEclCCServerQueueName(queue.clear(), name));
  4118. }
  4119. IStringVal & getName(IStringVal & str) const
  4120. {
  4121. str.set(name.get());
  4122. return str;
  4123. }
  4124. IStringVal & getScope(IStringVal & str) const
  4125. {
  4126. str.set(prefix.get());
  4127. return str;
  4128. }
  4129. IStringVal & getAgentQueue(IStringVal & str) const
  4130. {
  4131. str.set(agentQueue);
  4132. return str;
  4133. }
  4134. virtual IStringVal & getServerQueue(IStringVal & str) const
  4135. {
  4136. str.set(serverQueue);
  4137. return str;
  4138. }
  4139. IStringVal & getThorQueue(IStringVal & str) const
  4140. {
  4141. str.set(thorQueue);
  4142. return str;
  4143. }
  4144. unsigned getSize() const
  4145. {
  4146. return clusterWidth;
  4147. }
  4148. virtual ClusterType getPlatform() const
  4149. {
  4150. return platform;
  4151. }
  4152. IStringVal & getRoxieProcess(IStringVal & str) const
  4153. {
  4154. str.set(roxieProcess.get());
  4155. return str;
  4156. }
  4157. const StringArray & getThorProcesses() const
  4158. {
  4159. return thorProcesses;
  4160. }
  4161. const StringArray & getPrimaryThorProcesses() const
  4162. {
  4163. return primaryThorProcesses;
  4164. }
  4165. const SocketEndpointArray & getRoxieServers() const
  4166. {
  4167. return roxieServers;
  4168. }
  4169. unsigned getRoxieRedundancy() const
  4170. {
  4171. return roxieRedundancy;
  4172. }
  4173. unsigned getChannelsPerNode() const
  4174. {
  4175. return channelsPerNode;
  4176. }
  4177. int getRoxieReplicateOffset() const
  4178. {
  4179. return roxieReplicateOffset;
  4180. }
  4181. const char *getLdapUser() const
  4182. {
  4183. return ldapUser.get();
  4184. }
  4185. virtual const char *getLdapPassword() const
  4186. {
  4187. return ldapPassword.str();
  4188. }
  4189. };
  4190. IStringVal &getProcessQueueNames(IStringVal &ret, const char *process, const char *type, const char *suffix)
  4191. {
  4192. if (process)
  4193. {
  4194. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  4195. Owned<IConstEnvironment> env = factory->openEnvironment();
  4196. if (env)
  4197. {
  4198. Owned<IPropertyTree> root = &env->getPTree();
  4199. StringBuffer queueNames;
  4200. StringBuffer xpath;
  4201. xpath.appendf("%s[@process=\"%s\"]", type, process);
  4202. Owned<IPropertyTreeIterator> targets = root->getElements("Software/Topology/Cluster");
  4203. ForEach(*targets)
  4204. {
  4205. IPropertyTree &target = targets->query();
  4206. if (target.hasProp(xpath))
  4207. {
  4208. if (queueNames.length())
  4209. queueNames.append(',');
  4210. queueNames.append(target.queryProp("@name")).append(suffix);
  4211. }
  4212. }
  4213. ret.set(queueNames);
  4214. }
  4215. }
  4216. return ret;
  4217. }
  4218. #define ROXIE_QUEUE_EXT ".roxie"
  4219. #define THOR_QUEUE_EXT ".thor"
  4220. #define ECLCCSERVER_QUEUE_EXT ".eclserver"
  4221. #define ECLSERVER_QUEUE_EXT ECLCCSERVER_QUEUE_EXT
  4222. #define ECLSCHEDULER_QUEUE_EXT ".eclscheduler"
  4223. #define ECLAGENT_QUEUE_EXT ".agent"
  4224. extern WORKUNIT_API IStringVal &getEclCCServerQueueNames(IStringVal &ret, const char *process)
  4225. {
  4226. return getProcessQueueNames(ret, process, "EclCCServerProcess", ECLCCSERVER_QUEUE_EXT);
  4227. }
  4228. extern WORKUNIT_API IStringVal &getEclServerQueueNames(IStringVal &ret, const char *process)
  4229. {
  4230. return getProcessQueueNames(ret, process, "EclServerProcess", ECLSERVER_QUEUE_EXT); // shares queue name with EclCCServer
  4231. }
  4232. extern WORKUNIT_API IStringVal &getEclSchedulerQueueNames(IStringVal &ret, const char *process)
  4233. {
  4234. return getProcessQueueNames(ret, process, "EclSchedulerProcess", ECLSCHEDULER_QUEUE_EXT); // Shares deployment/config with EclCCServer
  4235. }
  4236. extern WORKUNIT_API IStringVal &getAgentQueueNames(IStringVal &ret, const char *process)
  4237. {
  4238. return getProcessQueueNames(ret, process, "EclAgentProcess", ECLAGENT_QUEUE_EXT);
  4239. }
  4240. extern WORKUNIT_API IStringVal &getRoxieQueueNames(IStringVal &ret, const char *process)
  4241. {
  4242. return getProcessQueueNames(ret, process, "RoxieCluster", ROXIE_QUEUE_EXT);
  4243. }
  4244. extern WORKUNIT_API IStringVal &getThorQueueNames(IStringVal &ret, const char *process)
  4245. {
  4246. return getProcessQueueNames(ret, process, "ThorCluster", THOR_QUEUE_EXT);
  4247. }
  4248. extern WORKUNIT_API StringBuffer &getClusterThorQueueName(StringBuffer &ret, const char *cluster)
  4249. {
  4250. return ret.append(cluster).append(THOR_QUEUE_EXT);
  4251. }
  4252. extern WORKUNIT_API StringBuffer &getClusterThorGroupName(StringBuffer &ret, const char *cluster)
  4253. {
  4254. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  4255. Owned<IConstEnvironment> env = factory->openEnvironment();
  4256. if (env)
  4257. {
  4258. Owned<IPropertyTree> root = &env->getPTree();
  4259. StringBuffer path;
  4260. path.append("Software/ThorCluster[@name=\"").append(cluster).append("\"]");
  4261. IPropertyTree * child = root->queryPropTree(path);
  4262. if (child)
  4263. getClusterGroupName(*child, ret);
  4264. }
  4265. return ret;
  4266. }
  4267. extern WORKUNIT_API StringBuffer &getClusterRoxieQueueName(StringBuffer &ret, const char *cluster)
  4268. {
  4269. return ret.append(cluster).append(ROXIE_QUEUE_EXT);
  4270. }
  4271. extern WORKUNIT_API StringBuffer &getClusterEclCCServerQueueName(StringBuffer &ret, const char *cluster)
  4272. {
  4273. return ret.append(cluster).append(ECLCCSERVER_QUEUE_EXT);
  4274. }
  4275. extern WORKUNIT_API StringBuffer &getClusterEclServerQueueName(StringBuffer &ret, const char *cluster)
  4276. {
  4277. return ret.append(cluster).append(ECLSERVER_QUEUE_EXT);
  4278. }
  4279. extern WORKUNIT_API StringBuffer &getClusterEclAgentQueueName(StringBuffer &ret, const char *cluster)
  4280. {
  4281. return ret.append(cluster).append(ECLAGENT_QUEUE_EXT);
  4282. }
  4283. extern WORKUNIT_API IStringIterator *getTargetClusters(const char *processType, const char *processName)
  4284. {
  4285. Owned<CStringArrayIterator> ret = new CStringArrayIterator;
  4286. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  4287. Owned<IConstEnvironment> env = factory->openEnvironment();
  4288. if (env)
  4289. {
  4290. Owned<IPropertyTree> root = &env->getPTree();
  4291. StringBuffer xpath;
  4292. xpath.appendf("%s", processType ? processType : "*");
  4293. if (processName && *processName)
  4294. xpath.appendf("[@process=\"%s\"]", processName);
  4295. Owned<IPropertyTreeIterator> targets = root->getElements("Software/Topology/Cluster");
  4296. ForEach(*targets)
  4297. {
  4298. IPropertyTree &target = targets->query();
  4299. if (target.hasProp(xpath))
  4300. {
  4301. ret->append(target.queryProp("@name"));
  4302. }
  4303. }
  4304. }
  4305. return ret.getClear();
  4306. }
  4307. extern WORKUNIT_API bool isProcessCluster(const char *process)
  4308. {
  4309. if (!process || !*process)
  4310. return false;
  4311. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  4312. Owned<IConstEnvironment> env = factory->openEnvironment();
  4313. if (!env)
  4314. return false;
  4315. Owned<IPropertyTree> root = &env->getPTree();
  4316. VStringBuffer xpath("Software/*Cluster[@name=\"%s\"]", process);
  4317. return root->hasProp(xpath.str());
  4318. }
  4319. extern WORKUNIT_API bool isProcessCluster(const char *remoteDali, const char *process)
  4320. {
  4321. if (!remoteDali || !*remoteDali)
  4322. return isProcessCluster(process);
  4323. if (!process || !*process)
  4324. return false;
  4325. Owned<INode> remote = createINode(remoteDali, 7070);
  4326. if (!remote)
  4327. return false;
  4328. //Cannot use getEnvironmentFactory() since it is using a remotedali
  4329. VStringBuffer xpath("Environment/Software/*Cluster[@name=\"%s\"]/@name", process);
  4330. try
  4331. {
  4332. Owned<IPropertyTreeIterator> clusters = querySDS().getElementsRaw(xpath, remote, 1000*60*1);
  4333. return clusters->first();
  4334. }
  4335. catch (IException *E)
  4336. {
  4337. StringBuffer msg;
  4338. E->errorMessage(msg);
  4339. DBGLOG("Exception validating cluster %s/%s: %s", remoteDali, xpath.str(), msg.str());
  4340. E->Release();
  4341. }
  4342. return true;
  4343. }
  4344. IConstWUClusterInfo* getTargetClusterInfo(IPropertyTree *environment, IPropertyTree *cluster)
  4345. {
  4346. const char *clustname = cluster->queryProp("@name");
  4347. // MORE - at the moment configenf specifies eclagent and thor queues by (in effect) placing an 'example' thor or eclagent in the topology
  4348. // that uses the queue that will be used.
  4349. // We should and I hope will change that, at which point the code below gets simpler
  4350. StringBuffer prefix(cluster->queryProp("@prefix"));
  4351. prefix.toLowerCase();
  4352. StringBuffer xpath;
  4353. StringBuffer querySetName;
  4354. IPropertyTree *agent = NULL;
  4355. const char *agentName = cluster->queryProp("EclAgentProcess/@process");
  4356. if (agentName)
  4357. {
  4358. xpath.clear().appendf("Software/EclAgentProcess[@name=\"%s\"]", agentName);
  4359. agent = environment->queryPropTree(xpath.str());
  4360. }
  4361. Owned<IPropertyTreeIterator> ti = cluster->getElements("ThorCluster");
  4362. IArrayOf<IPropertyTree> thors;
  4363. ForEach(*ti)
  4364. {
  4365. const char *thorName = ti->query().queryProp("@process");
  4366. if (thorName)
  4367. {
  4368. xpath.clear().appendf("Software/ThorCluster[@name=\"%s\"]", thorName);
  4369. thors.append(*environment->getPropTree(xpath.str()));
  4370. }
  4371. }
  4372. const char *roxieName = cluster->queryProp("RoxieCluster/@process");
  4373. return new CEnvironmentClusterInfo(clustname, prefix, agent, thors, queryRoxieProcessTree(environment, roxieName));
  4374. }
  4375. IPropertyTree* getTopologyCluster(Owned<IPropertyTree> &envRoot, const char *clustname)
  4376. {
  4377. if (!clustname || !*clustname)
  4378. return NULL;
  4379. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  4380. Owned<IConstEnvironment> env = factory->openEnvironment();
  4381. if (!env)
  4382. return NULL;
  4383. envRoot.setown(&env->getPTree());
  4384. StringBuffer xpath;
  4385. xpath.appendf("Software/Topology/Cluster[@name=\"%s\"]", clustname);
  4386. return envRoot->getPropTree(xpath.str());
  4387. }
  4388. bool validateTargetClusterName(const char *clustname)
  4389. {
  4390. Owned<IPropertyTree> envRoot;
  4391. Owned<IPropertyTree> cluster = getTopologyCluster(envRoot, clustname);
  4392. return (cluster.get()!=NULL);
  4393. }
  4394. IConstWUClusterInfo* getTargetClusterInfo(const char *clustname)
  4395. {
  4396. Owned<IPropertyTree> envRoot;
  4397. Owned<IPropertyTree> cluster = getTopologyCluster(envRoot, clustname);
  4398. if (!cluster)
  4399. return NULL;
  4400. return getTargetClusterInfo(envRoot, cluster);
  4401. }
  4402. unsigned getEnvironmentClusterInfo(CConstWUClusterInfoArray &clusters)
  4403. {
  4404. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  4405. Owned<IConstEnvironment> env = factory->openEnvironment();
  4406. if (!env)
  4407. return 0;
  4408. Owned<IPropertyTree> root = &env->getPTree();
  4409. return getEnvironmentClusterInfo(root, clusters);
  4410. }
  4411. unsigned getEnvironmentClusterInfo(IPropertyTree* environmentRoot, CConstWUClusterInfoArray &clusters)
  4412. {
  4413. if (!environmentRoot)
  4414. return 0;
  4415. Owned<IPropertyTreeIterator> clusterIter = environmentRoot->getElements("Software/Topology/Cluster");
  4416. ForEach(*clusterIter)
  4417. {
  4418. IPropertyTree &node = clusterIter->query();
  4419. Owned<IConstWUClusterInfo> cluster = getTargetClusterInfo(environmentRoot, &node);
  4420. clusters.append(*cluster.getClear());
  4421. }
  4422. return clusters.ordinality();
  4423. }
  4424. const char *getTargetClusterComponentName(const char *clustname, const char *processType, StringBuffer &name)
  4425. {
  4426. if (!clustname)
  4427. return NULL;
  4428. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  4429. Owned<IConstEnvironment> env = factory->openEnvironment();
  4430. if (!env)
  4431. return NULL;
  4432. Owned<IPropertyTree> root = &env->getPTree();
  4433. StringBuffer xpath;
  4434. xpath.appendf("Software/Topology/Cluster[@name=\"%s\"]", clustname);
  4435. Owned<IPropertyTree> cluster = root->getPropTree(xpath.str());
  4436. if (!cluster)
  4437. return NULL;
  4438. StringBuffer xpath1;
  4439. xpath1.appendf("%s/@process", processType);
  4440. name.append(cluster->queryProp(xpath1.str()));
  4441. return name.str();
  4442. }
  4443. unsigned getEnvironmentThorClusterNames(StringArray &thorNames, StringArray &groupNames, StringArray &targetNames, StringArray &queueNames)
  4444. {
  4445. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  4446. Owned<IConstEnvironment> env = factory->openEnvironment();
  4447. if (!env)
  4448. return 0;
  4449. Owned<IPropertyTree> root = &env->getPTree();
  4450. Owned<IPropertyTreeIterator> allTargets = root->getElements("Software/Topology/Cluster");
  4451. ForEach(*allTargets)
  4452. {
  4453. IPropertyTree &target = allTargets->query();
  4454. const char *targetName = target.queryProp("@name");
  4455. if (targetName && *targetName)
  4456. {
  4457. Owned<IPropertyTreeIterator> thorClusters = target.getElements("ThorCluster");
  4458. ForEach(*thorClusters)
  4459. {
  4460. const char *thorName = thorClusters->query().queryProp("@process");
  4461. VStringBuffer query("Software/ThorCluster[@name=\"%s\"]",thorName);
  4462. IPropertyTree *thorCluster = root->queryPropTree(query.str());
  4463. if (thorCluster)
  4464. {
  4465. const char *groupName = thorCluster->queryProp("@nodeGroup");
  4466. if (!groupName||!*groupName)
  4467. groupName = thorName;
  4468. thorNames.append(thorName);
  4469. groupNames.append(groupName);
  4470. targetNames.append(targetName);
  4471. StringBuffer queueName(targetName);
  4472. queueNames.append(queueName.append(THOR_QUEUE_EXT));
  4473. }
  4474. }
  4475. }
  4476. }
  4477. return thorNames.ordinality();
  4478. }
  4479. unsigned getEnvironmentHThorClusterNames(StringArray &eclAgentNames, StringArray &groupNames, StringArray &targetNames)
  4480. {
  4481. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  4482. Owned<IConstEnvironment> env = factory->openEnvironment();
  4483. if (!env)
  4484. return 0;
  4485. Owned<IPropertyTree> root = &env->getPTree();
  4486. Owned<IPropertyTreeIterator> allEclAgents = root->getElements("Software/EclAgentProcess");
  4487. ForEach(*allEclAgents)
  4488. {
  4489. IPropertyTree &eclAgent = allEclAgents->query();
  4490. const char *eclAgentName = eclAgent.queryProp("@name");
  4491. if (eclAgentName && *eclAgentName)
  4492. {
  4493. Owned<IPropertyTreeIterator> allTargets = root->getElements("Software/Topology/Cluster");
  4494. ForEach(*allTargets)
  4495. {
  4496. IPropertyTree &target = allTargets->query();
  4497. const char *targetName = target.queryProp("@name");
  4498. if (targetName && *targetName)
  4499. {
  4500. StringBuffer xpath;
  4501. xpath.appendf("EclAgentProcess[@process=\"%s\"]", eclAgentName);
  4502. if (target.hasProp(xpath) && !target.hasProp("ThorCluster"))
  4503. {
  4504. StringBuffer groupName("hthor__");
  4505. groupName.append(eclAgentName);
  4506. groupNames.append(groupName);
  4507. eclAgentNames.append(eclAgentName);
  4508. targetNames.append(targetName);
  4509. }
  4510. }
  4511. }
  4512. }
  4513. }
  4514. return eclAgentNames.ordinality();
  4515. }
  4516. IStringVal& CLocalWorkUnit::getScope(IStringVal &str) const
  4517. {
  4518. CriticalBlock block(crit);
  4519. if (p->hasProp("Debug/ForceScope"))
  4520. {
  4521. StringBuffer prefix(p->queryProp("Debug/ForceScope"));
  4522. str.set(prefix.toLowerCase().str());
  4523. }
  4524. else
  4525. {
  4526. Owned <IConstWUClusterInfo> ci = getTargetClusterInfo(p->queryProp("@clusterName"));
  4527. if (ci)
  4528. ci->getScope(str);
  4529. else
  4530. str.clear();
  4531. }
  4532. return str;
  4533. }
  4534. //Queries
  4535. void CLocalWorkUnit::setCodeVersion(unsigned codeVersion, const char * buildVersion, const char * eclVersion)
  4536. {
  4537. CriticalBlock block(crit);
  4538. p->setPropInt("@codeVersion", codeVersion);
  4539. p->setProp("@buildVersion", buildVersion);
  4540. p->setProp("@eclVersion", eclVersion);
  4541. }
  4542. unsigned CLocalWorkUnit::getCodeVersion() const
  4543. {
  4544. CriticalBlock block(crit);
  4545. return p->getPropInt("@codeVersion");
  4546. }
  4547. unsigned CLocalWorkUnit::getWuidVersion() const
  4548. {
  4549. CriticalBlock block(crit);
  4550. return p->getPropInt("@wuidVersion");
  4551. }
  4552. void CLocalWorkUnit::getBuildVersion(IStringVal & buildVersion, IStringVal & eclVersion) const
  4553. {
  4554. CriticalBlock block(crit);
  4555. buildVersion.set(p->queryProp("@buildVersion"));
  4556. eclVersion.set(p->queryProp("@eclVersion"));
  4557. }
  4558. void CLocalWorkUnit::setCloneable(bool value)
  4559. {
  4560. CriticalBlock block(crit);
  4561. p->setPropInt("@cloneable", value);
  4562. }
  4563. void CLocalWorkUnit::setIsClone(bool value)
  4564. {
  4565. CriticalBlock block(crit);
  4566. p->setPropInt("@isClone", value);
  4567. }
  4568. bool CLocalWorkUnit::getCloneable() const
  4569. {
  4570. CriticalBlock block(crit);
  4571. return p->getPropBool("@cloneable", false);
  4572. }
  4573. IUserDescriptor *CLocalWorkUnit::queryUserDescriptor() const
  4574. {
  4575. CriticalBlock block(crit);
  4576. if (!userDesc)
  4577. {
  4578. SCMStringBuffer token, user, password;
  4579. getSecurityToken(token);
  4580. extractToken(token.str(), queryWuid(), user, password);
  4581. userDesc.setown(createUserDescriptor());
  4582. userDesc->set(user.str(), password.str());
  4583. }
  4584. return userDesc;
  4585. }
  4586. bool CLocalWorkUnit::isProtected() const
  4587. {
  4588. CriticalBlock block(crit);
  4589. return p->getPropBool("@protected", false);
  4590. }
  4591. bool CLocalWorkUnit::isPausing() const
  4592. {
  4593. CriticalBlock block(crit);
  4594. if (WUActionPause == getAction())
  4595. {
  4596. switch (getState())
  4597. {
  4598. case WUStateRunning:
  4599. case WUStateAborting:
  4600. return true;
  4601. }
  4602. }
  4603. return false;
  4604. }
  4605. void CLocalWorkUnit::protect(bool protectMode)
  4606. {
  4607. CriticalBlock block(crit);
  4608. p->setPropBool("@protected", protectMode);
  4609. }
  4610. void CLocalWorkUnit::setResultLimit(unsigned value)
  4611. {
  4612. CriticalBlock block(crit);
  4613. p->setPropInt("resultLimit", value);
  4614. }
  4615. unsigned CLocalWorkUnit::getResultLimit() const
  4616. {
  4617. CriticalBlock block(crit);
  4618. return p->getPropInt("resultLimit");
  4619. }
  4620. IStringVal & CLocalWorkUnit::getSnapshot(IStringVal & str) const
  4621. {
  4622. CriticalBlock block(crit);
  4623. str.set(p->queryProp("SNAPSHOT"));
  4624. return str;
  4625. }
  4626. void CLocalWorkUnit::setSnapshot(const char * val)
  4627. {
  4628. CriticalBlock block(crit);
  4629. p->setProp("SNAPSHOT", val);
  4630. }
  4631. const static mapEnums warningSeverityMap[] =
  4632. {
  4633. { SeverityInformation, "info" },
  4634. { SeverityWarning, "warning" },
  4635. { SeverityError, "error" },
  4636. { SeverityAlert, "alert" },
  4637. { SeverityIgnore, "ignore" },
  4638. { SeverityFatal, "fatal" },
  4639. { SeverityUnknown, NULL }
  4640. };
  4641. ErrorSeverity CLocalWorkUnit::getWarningSeverity(unsigned code, ErrorSeverity defaultSeverity) const
  4642. {
  4643. StringBuffer xpath;
  4644. xpath.append("OnWarnings/OnWarning[@code='").append(code).append("']");
  4645. CriticalBlock block(crit);
  4646. IPropertyTree * mapping = p->queryPropTree(xpath);
  4647. if (mapping)
  4648. return (ErrorSeverity) getEnum(mapping, "@severity", warningSeverityMap);
  4649. return defaultSeverity;
  4650. }
  4651. void CLocalWorkUnit::setWarningSeverity(unsigned code, ErrorSeverity severity)
  4652. {
  4653. StringBuffer xpath;
  4654. xpath.append("OnWarnings/OnWarning[@code='").append(code).append("']");
  4655. CriticalBlock block(crit);
  4656. IPropertyTree * mapping = p->queryPropTree(xpath);
  4657. if (!mapping)
  4658. {
  4659. IPropertyTree * onWarnings = ensurePTree(p, "OnWarnings");
  4660. mapping = onWarnings->addPropTree("OnWarning", createPTree());
  4661. mapping->setPropInt("@code", code);
  4662. }
  4663. setEnum(mapping, "@severity", severity, warningSeverityMap);
  4664. }
  4665. static int comparePropTrees(IInterface * const *ll, IInterface * const *rr)
  4666. {
  4667. IPropertyTree *l = (IPropertyTree *) *ll;
  4668. IPropertyTree *r = (IPropertyTree *) *rr;
  4669. return stricmp(l->queryName(), r->queryName());
  4670. };
  4671. unsigned CLocalWorkUnit::calculateHash(unsigned crc)
  4672. {
  4673. // Any other values in the WU that could affect generated code should be crc'ed here
  4674. IPropertyTree *tree = p->queryBranch("Debug");
  4675. if (tree)
  4676. {
  4677. Owned<IPropertyTreeIterator> sub = tree->getElements("*");
  4678. ICopyArrayOf<IPropertyTree> subs;
  4679. for(sub->first(); sub->isValid(); sub->next())
  4680. subs.append(sub->query());
  4681. subs.sort(comparePropTrees);
  4682. ForEachItemIn(idx, subs)
  4683. {
  4684. const char *name = subs.item(idx).queryName();
  4685. const char *val = subs.item(idx).queryProp(NULL);
  4686. crc = crc32(name, (size32_t)strlen(name), crc);
  4687. if (val)
  4688. crc = crc32(val, (size32_t)strlen(val), crc);
  4689. }
  4690. }
  4691. Owned<IConstWUPluginIterator> plugins = &getPlugins();
  4692. for (plugins->first();plugins->isValid();plugins->next())
  4693. {
  4694. IConstWUPlugin &thisplugin = plugins->query();
  4695. SCMStringBuffer version;
  4696. thisplugin.getPluginVersion(version);
  4697. crc = crc32(version.str(), version.length(), crc);
  4698. }
  4699. return crc;
  4700. }
  4701. static void updateProp(IPropertyTree * to, const IPropertyTree * from, const char * xpath)
  4702. {
  4703. if (!to->hasProp(xpath) && from->hasProp(xpath))
  4704. to->setProp(xpath, from->queryProp(xpath));
  4705. }
  4706. static void setProp(IPropertyTree * to, const IPropertyTree * from, const char * xpath)
  4707. {
  4708. if (from->hasProp(xpath))
  4709. to->setProp(xpath, from->queryProp(xpath));
  4710. }
  4711. static void copyTree(IPropertyTree * to, const IPropertyTree * from, const char * xpath)
  4712. {
  4713. IPropertyTree * match = from->getBranch(xpath);
  4714. if (match)
  4715. to->setPropTree(xpath, match);
  4716. }
  4717. IPropertyTree *CLocalWorkUnit::queryPTree() const
  4718. {
  4719. return p;
  4720. }
  4721. void CLocalWorkUnit::copyWorkUnit(IConstWorkUnit *cached, bool all)
  4722. {
  4723. CLocalWorkUnit *from = QUERYINTERFACE(cached, CLocalWorkUnit);
  4724. if (!from)
  4725. {
  4726. CLockedWorkUnit *fl = QUERYINTERFACE(cached, CLockedWorkUnit);
  4727. if (!fl)
  4728. throw MakeStringException(WUERR_InternalUnknownImplementation, "Cached workunit not created using workunit dll");
  4729. from = fl->c;
  4730. }
  4731. // Need to copy the query, the results, and the graphs from the cached query.
  4732. // The cache is made before the query is executed so there is no need to clear them.
  4733. if (!cached->getCloneable())
  4734. throw MakeStringException(WUERR_CannotCloneWorkunit, "Source work unit not marked as clonable");
  4735. const IPropertyTree * fromP = from->p;
  4736. IPropertyTree *pt;
  4737. CriticalBlock block(crit);
  4738. clearCached(false);
  4739. query.clear();
  4740. updateProp(p, fromP, "@jobName");
  4741. copyTree(p, fromP, "Query");
  4742. pt = fromP->getBranch("Application/LibraryModule");
  4743. if (pt)
  4744. {
  4745. ensurePTree(p, "Application");
  4746. p->setPropTree("Application/LibraryModule", pt);
  4747. }
  4748. pt = fromP->queryBranch("Debug");
  4749. if (pt)
  4750. {
  4751. IPropertyTree *curDebug = p->queryPropTree("Debug");
  4752. if (curDebug)
  4753. {
  4754. Owned<IPropertyTreeIterator> elems = pt->getElements("*");
  4755. ForEach(*elems)
  4756. {
  4757. IPropertyTree *elem = &elems->query();
  4758. if (!curDebug->hasProp(elem->queryName()))
  4759. curDebug->setPropTree(elem->queryName(),LINK(elem));
  4760. }
  4761. }
  4762. else
  4763. p->setPropTree("Debug", LINK(pt));
  4764. }
  4765. copyTree(p, fromP, "OnWarnings");
  4766. copyTree(p, fromP, "Plugins");
  4767. copyTree(p, fromP, "Libraries");
  4768. copyTree(p, fromP, "Results");
  4769. copyTree(p, fromP, "Graphs");
  4770. copyTree(p, fromP, "Workflow");
  4771. copyTree(p, fromP, "WebServicesInfo");
  4772. if (all)
  4773. {
  4774. // 'all' mode is used when setting up a dali WU from the embedded wu in a workunit dll
  4775. // Merge timing info from both branches
  4776. pt = fromP->getBranch("Timings");
  4777. if (pt)
  4778. {
  4779. IPropertyTree *tgtTimings = ensurePTree(p, "Timings");
  4780. mergePTree(tgtTimings, pt);
  4781. pt->Release();
  4782. }
  4783. pt = fromP->getBranch("Statistics");
  4784. if (pt)
  4785. {
  4786. IPropertyTree *tgtStatistics = ensurePTree(p, "Statistics");
  4787. mergePTree(tgtStatistics, pt);
  4788. pt->Release();
  4789. }
  4790. }
  4791. updateProp(p, fromP, "@clusterName");
  4792. updateProp(p, fromP, "allowedclusters");
  4793. updateProp(p, fromP, "@submitID");
  4794. updateProp(p, fromP, "SNAPSHOT");
  4795. //MORE: This is very adhoc. All options that should be cloned should really be in a common branch
  4796. if (all)
  4797. {
  4798. setProp(p, fromP, "PriorityFlag");
  4799. setProp(p, fromP, "@priorityClass");
  4800. setProp(p, fromP, "@protected");
  4801. setProp(p, fromP, "@clusterName");
  4802. updateProp(p, fromP, "@scope");
  4803. }
  4804. //Variables may have been set up as parameters to the query - so need to preserve any values that were supplied.
  4805. pt = fromP->getBranch("Variables");
  4806. if (pt)
  4807. {
  4808. IPropertyTree *ptTgtVariables = ensurePTree(p, "Variables");
  4809. Owned<IPropertyTreeIterator> ptiVariable = pt->getElements("Variable");
  4810. for (ptiVariable->first(); ptiVariable->isValid(); ptiVariable->next())
  4811. {
  4812. IPropertyTree *ptSrcVariable = &ptiVariable->query();
  4813. const char *name = ptSrcVariable->queryProp("@name");
  4814. assertex(name);
  4815. StringBuffer xpath;
  4816. xpath.append("Variable[@name='").append(name).append("']");
  4817. IPropertyTree *ptTgtVariable = ptTgtVariables->queryPropTree(xpath.str());
  4818. IPropertyTree *merged = createPTreeFromIPT(ptSrcVariable); // clone entire source info...
  4819. merged->removeProp("Value"); // except value and status
  4820. merged->setProp("@status", "undefined");
  4821. if (!merged->getPropBool("@isScalar"))
  4822. merged->removeProp("totalRowCount");
  4823. merged->removeProp("rowCount");
  4824. // If there are any other fields that get set ONLY by eclagent, strip them out here...
  4825. if (ptTgtVariable)
  4826. {
  4827. // copy status and Value from what is already set in target
  4828. merged->setProp("@status", ptTgtVariable->queryProp("@status"));
  4829. MemoryBuffer value;
  4830. if (ptTgtVariable->getPropBin("Value", value))
  4831. merged->setPropBin("Value", value.length(), value.toByteArray());
  4832. ptTgtVariable->removeProp(xpath.str());
  4833. // If there are any other fields in a variable that get set by ws_ecl before submitting, copy them across here...
  4834. }
  4835. ptTgtVariables->addPropTree("Variable", merged);
  4836. }
  4837. pt->Release();
  4838. }
  4839. p->setProp("@codeVersion", fromP->queryProp("@codeVersion"));
  4840. p->setProp("@buildVersion", fromP->queryProp("@buildVersion"));
  4841. p->setProp("@eclVersion", fromP->queryProp("@eclVersion"));
  4842. p->setProp("@hash", fromP->queryProp("@hash"));
  4843. p->setPropBool("@cloneable", true);
  4844. p->setPropBool("@isClone", true);
  4845. resetWorkflow(); // the source Workflow section may have had some parts already executed...
  4846. // resetResults(); // probably should be resetting the results as well... rather than waiting for the rerun to overwrite them
  4847. }
  4848. bool CLocalWorkUnit::hasDebugValue(const char *propname) const
  4849. {
  4850. StringBuffer lower;
  4851. lower.append(propname).toLowerCase();
  4852. CriticalBlock block(crit);
  4853. StringBuffer prop("Debug/");
  4854. return p->hasProp(prop.append(lower));
  4855. }
  4856. IStringVal& CLocalWorkUnit::getDebugValue(const char *propname, IStringVal &str) const
  4857. {
  4858. StringBuffer lower;
  4859. lower.append(propname).toLowerCase();
  4860. CriticalBlock block(crit);
  4861. StringBuffer prop("Debug/");
  4862. str.set(p->queryProp(prop.append(lower).str()));
  4863. return str;
  4864. }
  4865. IStringIterator& CLocalWorkUnit::getDebugValues() const
  4866. {
  4867. return getDebugValues(NULL);
  4868. }
  4869. IStringIterator& CLocalWorkUnit::getDebugValues(const char *prop) const
  4870. {
  4871. CriticalBlock block(crit);
  4872. StringBuffer path("Debug/");
  4873. if (prop)
  4874. {
  4875. StringBuffer lower;
  4876. lower.append(prop).toLowerCase();
  4877. path.append(lower);
  4878. }
  4879. else
  4880. path.append("*");
  4881. return *new CStringPTreeTagIterator(p->getElements(path.str()));
  4882. }
  4883. int CLocalWorkUnit::getDebugValueInt(const char *propname, int defVal) const
  4884. {
  4885. StringBuffer lower;
  4886. lower.append(propname).toLowerCase();
  4887. CriticalBlock block(crit);
  4888. StringBuffer prop("Debug/");
  4889. prop.append(lower);
  4890. return p->getPropInt(prop.str(), defVal);
  4891. }
  4892. __int64 CLocalWorkUnit::getDebugValueInt64(const char *propname, __int64 defVal) const
  4893. {
  4894. StringBuffer lower;
  4895. lower.append(propname).toLowerCase();
  4896. CriticalBlock block(crit);
  4897. StringBuffer prop("Debug/");
  4898. prop.append(lower);
  4899. return p->getPropInt64(prop.str(), defVal);
  4900. }
  4901. bool CLocalWorkUnit::getDebugValueBool(const char * propname, bool defVal) const
  4902. {
  4903. StringBuffer lower;
  4904. lower.append(propname).toLowerCase();
  4905. CriticalBlock block(crit);
  4906. StringBuffer prop("Debug/");
  4907. prop.append(lower);
  4908. return p->getPropBool(prop.str(), defVal);
  4909. }
  4910. IStringIterator *CLocalWorkUnit::getLogs(const char *type, const char *instance) const
  4911. {
  4912. VStringBuffer xpath("Process/%s/", type);
  4913. if (instance)
  4914. xpath.append(instance);
  4915. else
  4916. xpath.append("*");
  4917. CriticalBlock block(crit);
  4918. if (p->getPropInt("@wuidVersion") < 1) // legacy wuid
  4919. {
  4920. // NB: instance unused
  4921. if (streq("EclAgent", type))
  4922. return new CStringPTreeIterator(p->getElements("Debug/eclagentlog"));
  4923. else if (streq("Thor", type))
  4924. return new CStringPTreeIterator(p->getElements("Debug/thorlog*"));
  4925. VStringBuffer xpath("Debug/%s", type);
  4926. return new CStringPTreeIterator(p->getElements(xpath.str()));
  4927. }
  4928. else
  4929. return new CStringPTreeAttrIterator(p->getElements(xpath.str()), "@log");
  4930. }
  4931. IPropertyTreeIterator* CLocalWorkUnit::getProcesses(const char *type, const char *instance) const
  4932. {
  4933. VStringBuffer xpath("Process/%s/", type);
  4934. if (instance)
  4935. xpath.append(instance);
  4936. else
  4937. xpath.append("*");
  4938. CriticalBlock block(crit);
  4939. return p->getElements(xpath.str());
  4940. }
  4941. IStringIterator *CLocalWorkUnit::getProcesses(const char *type) const
  4942. {
  4943. VStringBuffer xpath("Process/%s/*", type);
  4944. CriticalBlock block(crit);
  4945. return new CStringPTreeTagIterator(p->getElements(xpath.str()));
  4946. }
  4947. void CLocalWorkUnit::addProcess(const char *type, const char *instance, unsigned pid, const char *log)
  4948. {
  4949. VStringBuffer processType("Process/%s", type);
  4950. VStringBuffer xpath("%s/%s", processType.str(), instance);
  4951. if (log)
  4952. xpath.appendf("[@log=\"%s\"]", log);
  4953. CriticalBlock block(crit);
  4954. if (!p->hasProp(xpath))
  4955. {
  4956. IPropertyTree *node = ensurePTree(p, processType.str());
  4957. node = node->addPropTree(instance, createPTree());
  4958. node->setProp("@log", log);
  4959. node->setPropInt("@pid", pid);
  4960. }
  4961. }
  4962. void CLocalWorkUnit::setDebugValue(const char *propname, const char *value, bool overwrite)
  4963. {
  4964. StringBuffer lower;
  4965. lower.append(propname).toLowerCase();
  4966. CriticalBlock block(crit);
  4967. StringBuffer prop("Debug/");
  4968. prop.append(lower);
  4969. if (overwrite || !p->hasProp(prop.str()))
  4970. {
  4971. // MORE - not sure this line should be needed....
  4972. p->setProp("Debug", "");
  4973. p->setProp(prop.str(), value);
  4974. }
  4975. }
  4976. void CLocalWorkUnit::setDebugValueInt(const char *propname, int value, bool overwrite)
  4977. {
  4978. StringBuffer lower;
  4979. lower.append(propname).toLowerCase();
  4980. CriticalBlock block(crit);
  4981. StringBuffer prop("Debug/");
  4982. prop.append(lower);
  4983. if (overwrite || !p->hasProp(prop.str()))
  4984. {
  4985. // MORE - not sure this line should be needed....
  4986. p->setProp("Debug", "");
  4987. p->setPropInt(prop.str(), value);
  4988. }
  4989. }
  4990. void CLocalWorkUnit::setTracingValue(const char *propname, const char *value)
  4991. {
  4992. CriticalBlock block(crit);
  4993. // MORE - not sure this line should be needed....
  4994. p->setProp("Tracing", "");
  4995. StringBuffer prop("Tracing/");
  4996. p->setProp(prop.append(propname).str(), value);
  4997. }
  4998. void CLocalWorkUnit::setTracingValueInt(const char *propname, int value)
  4999. {
  5000. CriticalBlock block(crit);
  5001. StringBuffer prop("Tracing/");
  5002. p->setPropInt(prop.append(propname).str(), value);
  5003. }
  5004. IConstWUQuery* CLocalWorkUnit::getQuery() const
  5005. {
  5006. // For this to be legally called, we must have the read-able interface. So we are already locked for (at least) read.
  5007. CriticalBlock block(crit);
  5008. if (!query)
  5009. {
  5010. IPropertyTree *s = p->getPropTree("Query");
  5011. if (s)
  5012. query.setown(new CLocalWUQuery(s)); // NB takes ownership of 's'
  5013. }
  5014. return query.getLink();
  5015. }
  5016. IWUQuery* CLocalWorkUnit::updateQuery()
  5017. {
  5018. // For this to be legally called, we must have the write-able interface. So we are already locked for write.
  5019. CriticalBlock block(crit);
  5020. if (!query)
  5021. {
  5022. IPropertyTree *s = p->queryPropTree("Query");
  5023. if (!s)
  5024. s = p->addPropTree("Query", createPTreeFromXMLString("<Query fetchEntire='1'/>"));
  5025. s->Link();
  5026. query.setown(new CLocalWUQuery(s));
  5027. }
  5028. return query.getLink();
  5029. }
  5030. void CLocalWorkUnit::loadPlugins() const
  5031. {
  5032. CriticalBlock block(crit);
  5033. if (!pluginsCached)
  5034. {
  5035. assertex(plugins.length() == 0);
  5036. Owned<IPropertyTreeIterator> r = p->getElements("Plugins/Plugin");
  5037. for (r->first(); r->isValid(); r->next())
  5038. {
  5039. IPropertyTree *rp = &r->query();
  5040. rp->Link();
  5041. plugins.append(*new CLocalWUPlugin(rp));
  5042. }
  5043. pluginsCached = true;
  5044. }
  5045. }
  5046. IConstWUPluginIterator& CLocalWorkUnit::getPlugins() const
  5047. {
  5048. CriticalBlock block(crit);
  5049. loadPlugins();
  5050. return *new CArrayIteratorOf<IConstWUPlugin,IConstWUPluginIterator> (plugins, 0, (IConstWorkUnit *) this);
  5051. }
  5052. void CLocalWorkUnit::loadLibraries() const
  5053. {
  5054. CriticalBlock block(crit);
  5055. if (!librariesCached)
  5056. {
  5057. assertex(libraries.length() == 0);
  5058. Owned<IPropertyTreeIterator> r = p->getElements("Libraries/Library");
  5059. ForEach(*r)
  5060. {
  5061. IPropertyTree *rp = &r->query();
  5062. rp->Link();
  5063. libraries.append(*new CLocalWULibrary(rp));
  5064. }
  5065. librariesCached = true;
  5066. }
  5067. }
  5068. IConstWULibraryIterator& CLocalWorkUnit::getLibraries() const
  5069. {
  5070. CriticalBlock block(crit);
  5071. loadLibraries();
  5072. return *new CArrayIteratorOf<IConstWULibrary,IConstWULibraryIterator> (libraries, 0, (IConstWorkUnit *) this);
  5073. }
  5074. IConstWULibrary * CLocalWorkUnit::getLibraryByName(const char * search) const
  5075. {
  5076. CriticalBlock block(crit);
  5077. loadLibraries();
  5078. ForEachItemIn(idx, libraries)
  5079. {
  5080. SCMStringBuffer name;
  5081. IConstWULibrary &cur = libraries.item(idx);
  5082. cur.getName(name);
  5083. if (stricmp(name.str(), search)==0)
  5084. return &OLINK(cur);
  5085. }
  5086. return NULL;
  5087. }
  5088. StringBuffer &formatGraphTimerLabel(StringBuffer &str, const char *graphName, unsigned subGraphNum, unsigned __int64 subId)
  5089. {
  5090. str.append("Graph ").append(graphName);
  5091. if (subGraphNum) str.append(" - ").append(subGraphNum).append(" (").append(subId).append(")");
  5092. else if (subId) str.append(" - id(").append(subId).append(")");
  5093. return str;
  5094. }
  5095. StringBuffer &formatGraphTimerScope(StringBuffer &str, const char *graphName, unsigned subGraphNum, unsigned __int64 subId)
  5096. {
  5097. str.append(graphName);
  5098. if (subId) str.append(":sg").append(subId);
  5099. return str;
  5100. }
  5101. bool parseGraphTimerLabel(const char *label, StringAttr &graphName, unsigned & graphNum, unsigned &subGraphNum, unsigned &subId)
  5102. {
  5103. // expects format: "Graph <graphname>[ - <subgraphnum> (<subgraphid>)]"
  5104. unsigned len = (size32_t)strlen(label);
  5105. if (len < 6 || (0 != memcmp(label, "Graph ", 6)))
  5106. return false;
  5107. graphNum = 0;
  5108. subGraphNum = 0;
  5109. subId = 0;
  5110. const char *finger = label+6;
  5111. const char *finger2 = strchr(finger, '-');
  5112. if (NULL == finger2) // just graphName
  5113. graphName.set(finger);
  5114. else
  5115. {
  5116. graphName.set(finger, (size32_t)((finger2-1)-finger));
  5117. finger = finger2+2; // skip '-' and space
  5118. finger2 = strchr(finger, ' ');
  5119. if (finger2)
  5120. {
  5121. subGraphNum = atoi_l(finger, (size32_t)(finger2-finger));
  5122. finger = finger2+2; // skip space and '('
  5123. finger2 = strchr(finger, ')');
  5124. if (finger2)
  5125. subId = atoi_l(finger, (size32_t)(finger2-finger));
  5126. }
  5127. else if (((len-(finger-label))>3) && 0 == memcmp(finger, "id(", 3)) // subgraph id only, new format.
  5128. {
  5129. finger += 3;
  5130. finger2 = strchr(finger, ')');
  5131. if (finger2)
  5132. subId = atoi_l(finger, (size32_t)(finger2-finger));
  5133. }
  5134. }
  5135. if (graphName && !memicmp(graphName, "graph", 5))
  5136. graphNum = atoi(graphName + 5);
  5137. return true;
  5138. }
  5139. bool parseGraphScope(const char *scope, StringAttr &graphName, unsigned & graphNum, unsigned &subGraphId)
  5140. {
  5141. if (!MATCHES_CONST_PREFIX(scope, GraphScopePrefix))
  5142. return false;
  5143. graphNum = atoi(scope + CONST_STRLEN(GraphScopePrefix));
  5144. const char * colon = strchr(scope, ':');
  5145. if (!colon)
  5146. {
  5147. graphName.set(scope);
  5148. subGraphId = 0;
  5149. return true;
  5150. }
  5151. const char * subgraph = colon+1;
  5152. graphName.set(scope, (size32_t)(colon - scope));
  5153. if (MATCHES_CONST_PREFIX(subgraph, SubGraphScopePrefix))
  5154. subGraphId = atoi(subgraph+CONST_STRLEN(SubGraphScopePrefix));
  5155. return true;
  5156. }
  5157. class WorkUnitStatisticsIterator : public CArrayIteratorOf<IConstWUStatistic,IConstWUStatisticIterator>
  5158. {
  5159. typedef CArrayIteratorOf<IConstWUStatistic,IConstWUStatisticIterator> PARENT;
  5160. public:
  5161. WorkUnitStatisticsIterator(const IArray &a, aindex_t start, IInterface *owner, const IStatisticsFilter * _filter)
  5162. : PARENT(a,start, owner), filter(_filter)
  5163. {
  5164. }
  5165. virtual bool first()
  5166. {
  5167. if (!PARENT::first())
  5168. return false;
  5169. if (matchesFilter())
  5170. return true;
  5171. return next();
  5172. }
  5173. virtual bool next()
  5174. {
  5175. loop
  5176. {
  5177. if (!PARENT::next())
  5178. return false;
  5179. if (matchesFilter())
  5180. return true;
  5181. }
  5182. }
  5183. protected:
  5184. bool matchesFilter()
  5185. {
  5186. if (!filter)
  5187. return true;
  5188. return query().matches(filter);
  5189. }
  5190. protected:
  5191. Linked<const IStatisticsFilter> filter;
  5192. };
  5193. 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)
  5194. {
  5195. if (!scope || !*scope) scope = GLOBAL_SCOPE;
  5196. const char * kindName = queryStatisticName(kind);
  5197. StatisticMeasure measure = queryMeasure(kind);
  5198. //creator. scope and name must all be present, and must not contain semi colons.
  5199. assertex(creator && scope);
  5200. CriticalBlock block(crit);
  5201. IPropertyTree * stats = p->queryPropTree("Statistics");
  5202. if (!stats)
  5203. stats = p->addPropTree("Statistics", createPTree("Statistics"));
  5204. IPropertyTree * statTree = NULL;
  5205. if (mergeAction != StatsMergeAppend)
  5206. {
  5207. StringBuffer xpath;
  5208. xpath.append("Statistic[@creator='").append(creator).append("'][@scope='").append(scope).append("'][@kind='").append(kindName).append("']");
  5209. statTree = stats->queryPropTree(xpath.str());
  5210. }
  5211. if (!statTree)
  5212. {
  5213. statTree = stats->addPropTree("Statistic", createPTree("Statistic"));
  5214. statTree->setProp("@creator", creator);
  5215. statTree->setProp("@scope", scope);
  5216. statTree->setProp("@kind", kindName);
  5217. //These items are primarily here to facilitate filtering.
  5218. statTree->setProp("@unit", queryMeasureName(measure));
  5219. statTree->setProp("@c", queryCreatorTypeName(creatorType));
  5220. statTree->setProp("@s", queryScopeTypeName(scopeType));
  5221. statTree->setPropInt64("@ts", getTimeStampNowValue());
  5222. if (optDescription)
  5223. statTree->setProp("@desc", optDescription);
  5224. if (statistics.cached)
  5225. statistics.append(LINK(statTree));
  5226. mergeAction = StatsMergeAppend;
  5227. }
  5228. if (mergeAction != StatsMergeAppend)
  5229. {
  5230. unsigned __int64 oldValue = statTree->getPropInt64("@value", 0);
  5231. unsigned __int64 oldCount = statTree->getPropInt64("@count", 0);
  5232. unsigned __int64 oldMax = statTree->getPropInt64("@max", 0);
  5233. if (oldMax < oldValue)
  5234. oldMax = oldValue;
  5235. statTree->setPropInt64("@value", mergeStatisticValue(oldValue, value, mergeAction));
  5236. statTree->setPropInt64("@count", count + oldCount);
  5237. if (maxValue > oldMax)
  5238. statTree->setPropInt64("@max", maxValue);
  5239. }
  5240. else
  5241. {
  5242. statTree->setPropInt64("@value", value);
  5243. statTree->setPropInt64("@count", count);
  5244. if (maxValue)
  5245. statTree->setPropInt64("@max", maxValue);
  5246. else
  5247. statTree->removeProp("@max");
  5248. }
  5249. }
  5250. void CLocalWorkUnit::_loadStatistics() const
  5251. {
  5252. statistics.load(p,"Statistics/*");
  5253. }
  5254. IConstWUStatisticIterator& CLocalWorkUnit::getStatistics(const IStatisticsFilter * filter) const
  5255. {
  5256. CriticalBlock block(crit);
  5257. //This should be deleted in version 6.0 when support for 4.x is no longer required
  5258. legacyTimings.load(p,"Timings/*");
  5259. if (legacyTimings.ordinality())
  5260. return *new WorkUnitStatisticsIterator(legacyTimings, 0, (IConstWorkUnit *) this, filter);
  5261. statistics.load(p,"Statistics/*");
  5262. Owned<IConstWUStatisticIterator> localStats = new WorkUnitStatisticsIterator(statistics, 0, (IConstWorkUnit *) this, filter);
  5263. const char * wuid = p->queryName();
  5264. Owned<IConstWUStatisticIterator> graphStats = new CConstGraphProgressStatisticsIterator(wuid, filter);
  5265. return * new CCompoundIteratorOf<IConstWUStatisticIterator, IConstWUStatistic>(localStats, graphStats);
  5266. }
  5267. IConstWUStatistic * CLocalWorkUnit::getStatistic(const char * creator, const char * scope, StatisticKind kind) const
  5268. {
  5269. //MORE: Optimize this....
  5270. StatisticsFilter filter;
  5271. filter.setCreator(creator);
  5272. filter.setScope(scope);
  5273. filter.setKind(kind);
  5274. Owned<IConstWUStatisticIterator> stats = &getStatistics(&filter);
  5275. if (stats->first())
  5276. return LINK(&stats->query());
  5277. return NULL;
  5278. }
  5279. IWUPlugin* CLocalWorkUnit::updatePluginByName(const char *qname)
  5280. {
  5281. CriticalBlock block(crit);
  5282. IConstWUPlugin *existing = getPluginByName(qname);
  5283. if (existing)
  5284. return (IWUPlugin *) existing;
  5285. if (!plugins.length())
  5286. p->addPropTree("Plugins", createPTree("Plugins"));
  5287. IPropertyTree *pl = p->queryPropTree("Plugins");
  5288. IPropertyTree *s = pl->addPropTree("Plugin", createPTree("Plugin"));
  5289. s->Link();
  5290. IWUPlugin* q = new CLocalWUPlugin(s);
  5291. q->Link();
  5292. plugins.append(*q);
  5293. q->setPluginName(qname);
  5294. return q;
  5295. }
  5296. IConstWUPlugin* CLocalWorkUnit::getPluginByName(const char *qname) const
  5297. {
  5298. CriticalBlock block(crit);
  5299. loadPlugins();
  5300. ForEachItemIn(idx, plugins)
  5301. {
  5302. SCMStringBuffer name;
  5303. IConstWUPlugin &cur = plugins.item(idx);
  5304. cur.getPluginName(name);
  5305. if (stricmp(name.str(), qname)==0)
  5306. {
  5307. cur.Link();
  5308. return &cur;
  5309. }
  5310. }
  5311. return NULL;
  5312. }
  5313. IWULibrary* CLocalWorkUnit::updateLibraryByName(const char *qname)
  5314. {
  5315. CriticalBlock block(crit);
  5316. IConstWULibrary *existing = getLibraryByName(qname);
  5317. if (existing)
  5318. return (IWULibrary *) existing;
  5319. if (!libraries.length())
  5320. p->addPropTree("Libraries", createPTree("Libraries"));
  5321. IPropertyTree *pl = p->queryPropTree("Libraries");
  5322. IPropertyTree *s = pl->addPropTree("Library", createPTree("Library"));
  5323. s->Link();
  5324. IWULibrary* q = new CLocalWULibrary(s);
  5325. q->Link();
  5326. libraries.append(*q);
  5327. q->setName(qname);
  5328. return q;
  5329. }
  5330. void CLocalWorkUnit::unsubscribe()
  5331. {
  5332. // Only overriding versions need to do anything
  5333. }
  5334. void CLocalWorkUnit::loadExceptions() const
  5335. {
  5336. CriticalBlock block(crit);
  5337. if (!exceptionsCached)
  5338. {
  5339. assertex(exceptions.length() == 0);
  5340. Owned<IPropertyTreeIterator> r = p->getElements("Exceptions/Exception");
  5341. for (r->first(); r->isValid(); r->next())
  5342. {
  5343. IPropertyTree *rp = &r->query();
  5344. rp->Link();
  5345. exceptions.append(*new CLocalWUException(rp));
  5346. }
  5347. exceptionsCached = true;
  5348. }
  5349. }
  5350. IConstWUExceptionIterator& CLocalWorkUnit::getExceptions() const
  5351. {
  5352. CriticalBlock block(crit);
  5353. loadExceptions();
  5354. return *new CArrayIteratorOf<IConstWUException,IConstWUExceptionIterator> (exceptions, 0, (IConstWorkUnit *) this);
  5355. }
  5356. unsigned CLocalWorkUnit::getExceptionCount() const
  5357. {
  5358. CriticalBlock block(crit);
  5359. loadExceptions();
  5360. return exceptions.length();
  5361. }
  5362. void CLocalWorkUnit::clearExceptions()
  5363. {
  5364. CriticalBlock block(crit);
  5365. // For this to be legally called, we must have the write-able interface. So we are already locked for write.
  5366. exceptions.kill();
  5367. exceptionsCached = true;
  5368. p->removeProp("Exceptions");
  5369. }
  5370. IWUException* CLocalWorkUnit::createException()
  5371. {
  5372. CriticalBlock block(crit);
  5373. // For this to be legally called, we must have the write-able interface. So we are already locked for write.
  5374. loadExceptions();
  5375. if (!exceptions.length())
  5376. p->addPropTree("Exceptions", createPTree("Exceptions"));
  5377. IPropertyTree *r = p->queryPropTree("Exceptions");
  5378. IPropertyTree *s = r->addPropTree("Exception", createPTree("Exception"));
  5379. IWUException* q = new CLocalWUException(LINK(s));
  5380. exceptions.append(*LINK(q));
  5381. Owned<IJlibDateTime> now = createDateTimeNow();
  5382. SCMStringBuffer temp;
  5383. now->getString(temp);
  5384. q->setTimeStamp(temp.str());
  5385. return q;
  5386. }
  5387. IConstWUWebServicesInfo* CLocalWorkUnit::getWebServicesInfo() const
  5388. {
  5389. // For this to be legally called, we must have the read-able interface. So we are already locked for (at least) read.
  5390. CriticalBlock block(crit);
  5391. if (!webServicesInfoCached)
  5392. {
  5393. assertex(!webServicesInfo);
  5394. IPropertyTree *s = p->getPropTree("WebServicesInfo");
  5395. if (s)
  5396. webServicesInfo.setown(new CLocalWUWebServicesInfo(s)); // NB takes ownership of 's'
  5397. webServicesInfoCached = true;
  5398. }
  5399. return webServicesInfo.getLink();
  5400. }
  5401. IWUWebServicesInfo* CLocalWorkUnit::updateWebServicesInfo(bool create)
  5402. {
  5403. // For this to be legally called, we must have the write-able interface. So we are already locked for write.
  5404. CriticalBlock block(crit);
  5405. if (!webServicesInfoCached)
  5406. {
  5407. IPropertyTree *s = p->queryPropTree("WebServicesInfo");
  5408. if (!s)
  5409. {
  5410. if (create)
  5411. s = p->addPropTree("WebServicesInfo", createPTreeFromXMLString("<WebServicesInfo />"));
  5412. else
  5413. return NULL;
  5414. }
  5415. s->Link();
  5416. webServicesInfo.setown(new CLocalWUWebServicesInfo(s));
  5417. webServicesInfoCached = true;
  5418. }
  5419. return webServicesInfo.getLink();
  5420. }
  5421. IConstWURoxieQueryInfo* CLocalWorkUnit::getRoxieQueryInfo() const
  5422. {
  5423. // For this to be legally called, we must have the read-able interface. So we are already locked for (at least) read.
  5424. CriticalBlock block(crit);
  5425. if (!roxieQueryInfoCached)
  5426. {
  5427. assertex(!roxieQueryInfo);
  5428. IPropertyTree *s = p->getPropTree("RoxieQueryInfo");
  5429. if (s)
  5430. roxieQueryInfo.setown(new CLocalWURoxieQueryInfo(s)); // NB takes ownership of 's'
  5431. roxieQueryInfoCached = true;
  5432. }
  5433. return roxieQueryInfo.getLink();
  5434. }
  5435. IWURoxieQueryInfo* CLocalWorkUnit::updateRoxieQueryInfo(const char *wuid, const char *roxieClusterName)
  5436. {
  5437. // For this to be legally called, we must have the write-able interface. So we are already locked for write.
  5438. CriticalBlock block(crit);
  5439. if (!roxieQueryInfoCached)
  5440. {
  5441. IPropertyTree *s = p->queryPropTree("RoxieQueryInfo");
  5442. if (!s)
  5443. s = p->addPropTree("RoxieQueryInfo", createPTreeFromXMLString("<RoxieQueryInfo />"));
  5444. if (wuid && *wuid)
  5445. s->addProp("@wuid", wuid);
  5446. if (roxieClusterName && *roxieClusterName)
  5447. s->addProp("@roxieClusterName", roxieClusterName);
  5448. s->Link();
  5449. roxieQueryInfo.setown(new CLocalWURoxieQueryInfo(s));
  5450. roxieQueryInfoCached = true;
  5451. }
  5452. return roxieQueryInfo.getLink();
  5453. }
  5454. static int compareResults(IInterface * const *ll, IInterface * const *rr)
  5455. {
  5456. CLocalWUResult *l = (CLocalWUResult *) *ll;
  5457. CLocalWUResult *r = (CLocalWUResult *) *rr;
  5458. return l->getResultSequence() - r->getResultSequence();
  5459. }
  5460. void CLocalWorkUnit::_loadResults() const
  5461. {
  5462. Owned<IPropertyTreeIterator> r = p->getElements("Results/Result");
  5463. for (r->first(); r->isValid(); r->next())
  5464. {
  5465. IPropertyTree *rp = &r->query();
  5466. rp->Link();
  5467. results.append(*new CLocalWUResult(rp));
  5468. }
  5469. }
  5470. void CLocalWorkUnit::loadResults() const
  5471. {
  5472. CriticalBlock block(crit);
  5473. if (!resultsCached)
  5474. {
  5475. assertex(results.length() == 0);
  5476. _loadResults();
  5477. results.sort(compareResults);
  5478. resultsCached = true;
  5479. }
  5480. }
  5481. void CLocalWorkUnit::loadVariables() const
  5482. {
  5483. CriticalBlock block(crit);
  5484. if (!variablesCached)
  5485. {
  5486. assertex(variables.length() == 0);
  5487. Owned<IPropertyTreeIterator> r = p->getElements("Variables/Variable");
  5488. for (r->first(); r->isValid(); r->next())
  5489. {
  5490. IPropertyTree *rp = &r->query();
  5491. rp->Link();
  5492. variables.append(*new CLocalWUResult(rp));
  5493. }
  5494. variablesCached = true;
  5495. }
  5496. }
  5497. void CLocalWorkUnit::loadTemporaries() const
  5498. {
  5499. CriticalBlock block(crit);
  5500. if (!temporariesCached)
  5501. {
  5502. assertex(temporaries.length() == 0);
  5503. Owned<IPropertyTreeIterator> r = p->getElements("Temporaries/Variable");
  5504. for (r->first(); r->isValid(); r->next())
  5505. {
  5506. IPropertyTree *rp = &r->query();
  5507. rp->Link();
  5508. temporaries.append(*new CLocalWUResult(rp));
  5509. }
  5510. temporariesCached = true;
  5511. }
  5512. }
  5513. void CLocalWorkUnit::deleteTemporaries()
  5514. {
  5515. CriticalBlock block(crit);
  5516. if (temporariesCached)
  5517. {
  5518. temporaries.kill();
  5519. temporariesCached = false;
  5520. }
  5521. p->removeProp("Temporaries");
  5522. }
  5523. IWUResult* CLocalWorkUnit::createResult()
  5524. {
  5525. CriticalBlock block(crit);
  5526. // For this to be legally called, we must have the write-able interface. So we are already locked for write.
  5527. loadResults();
  5528. if (!results.length())
  5529. p->addPropTree("Results", createPTree("Results"));
  5530. IPropertyTree *r = p->queryPropTree("Results");
  5531. IPropertyTree *s = r->addPropTree("Result", createPTree());
  5532. s->Link();
  5533. IWUResult* q = new CLocalWUResult(s);
  5534. q->Link();
  5535. results.append(*q);
  5536. return q;
  5537. }
  5538. IWUResult* CLocalWorkUnit::updateResultByName(const char *qname)
  5539. {
  5540. CriticalBlock block(crit);
  5541. IConstWUResult *existing = getResultByName(qname);
  5542. if (existing)
  5543. return (IWUResult *) existing;
  5544. IWUResult* q = createResult();
  5545. q->setResultName(qname);
  5546. return q;
  5547. }
  5548. IWUResult* CLocalWorkUnit::updateResultBySequence(unsigned seq)
  5549. {
  5550. CriticalBlock block(crit);
  5551. IConstWUResult *existing = getResultBySequence(seq);
  5552. if (existing)
  5553. return (IWUResult *) existing;
  5554. IWUResult* q = createResult();
  5555. q->setResultSequence(seq);
  5556. return q;
  5557. }
  5558. IConstWUResultIterator& CLocalWorkUnit::getResults() const
  5559. {
  5560. CriticalBlock block(crit);
  5561. loadResults();
  5562. return *new CArrayIteratorOf<IConstWUResult,IConstWUResultIterator> (results, 0, (IConstWorkUnit *) this);
  5563. }
  5564. IConstWUResult* CLocalWorkUnit::getResultByName(const char *qname) const
  5565. {
  5566. CriticalBlock block(crit);
  5567. loadResults();
  5568. ForEachItemIn(idx, results)
  5569. {
  5570. SCMStringBuffer name;
  5571. IConstWUResult &cur = results.item(idx);
  5572. cur.getResultName(name);
  5573. if (stricmp(name.str(), qname)==0)
  5574. {
  5575. cur.Link();
  5576. return &cur;
  5577. }
  5578. }
  5579. return NULL;
  5580. }
  5581. IConstWUResult* CLocalWorkUnit::getResultBySequence(unsigned seq) const
  5582. {
  5583. CriticalBlock block(crit);
  5584. loadResults();
  5585. ForEachItemIn(idx, results)
  5586. {
  5587. IConstWUResult &cur = results.item(idx);
  5588. if (cur.getResultSequence() == seq)
  5589. {
  5590. cur.Link();
  5591. return &cur;
  5592. }
  5593. }
  5594. return NULL;
  5595. }
  5596. IConstWUResultIterator& CLocalWorkUnit::getVariables() const
  5597. {
  5598. CriticalBlock block(crit);
  5599. loadVariables();
  5600. return *new CArrayIteratorOf<IConstWUResult,IConstWUResultIterator> (variables, 0, (IConstWorkUnit *) this);
  5601. }
  5602. IConstWUResult* CLocalWorkUnit::getGlobalByName(const char *qname) const
  5603. {
  5604. CriticalBlock block(crit);
  5605. if (strcmp(p->queryName(), GLOBAL_WORKUNIT)==0)
  5606. return getVariableByName(qname);
  5607. Owned <IWorkUnit> global = factory->getGlobalWorkUnit(secMgr, secUser);
  5608. return global->getVariableByName(qname);
  5609. }
  5610. IWUResult* CLocalWorkUnit::updateGlobalByName(const char *qname)
  5611. {
  5612. CriticalBlock block(crit);
  5613. if (strcmp(p->queryName(), GLOBAL_WORKUNIT)==0)
  5614. return updateVariableByName(qname);
  5615. Owned <IWorkUnit> global = factory->getGlobalWorkUnit(secMgr, secUser);
  5616. return global->updateVariableByName(qname);
  5617. }
  5618. IConstWUResult* CLocalWorkUnit::getVariableByName(const char *qname) const
  5619. {
  5620. CriticalBlock block(crit);
  5621. loadVariables();
  5622. ForEachItemIn(idx, variables)
  5623. {
  5624. SCMStringBuffer name;
  5625. IConstWUResult &cur = variables.item(idx);
  5626. cur.getResultName(name);
  5627. if (stricmp(name.str(), qname)==0)
  5628. {
  5629. cur.Link();
  5630. return &cur;
  5631. }
  5632. }
  5633. return NULL;
  5634. }
  5635. IConstWUResult* CLocalWorkUnit::getTemporaryByName(const char *qname) const
  5636. {
  5637. CriticalBlock block(crit);
  5638. loadTemporaries();
  5639. ForEachItemIn(idx, temporaries)
  5640. {
  5641. SCMStringBuffer name;
  5642. IConstWUResult &cur = temporaries.item(idx);
  5643. cur.getResultName(name);
  5644. if (stricmp(name.str(), qname)==0)
  5645. {
  5646. cur.Link();
  5647. return &cur;
  5648. }
  5649. }
  5650. return NULL;
  5651. }
  5652. IConstWUResultIterator& CLocalWorkUnit::getTemporaries() const
  5653. {
  5654. CriticalBlock block(crit);
  5655. loadTemporaries();
  5656. return *new CArrayIteratorOf<IConstWUResult,IConstWUResultIterator> (temporaries, 0, (IConstWorkUnit *) this);
  5657. }
  5658. IWUResult* CLocalWorkUnit::updateTemporaryByName(const char *qname)
  5659. {
  5660. CriticalBlock block(crit);
  5661. IConstWUResult *existing = getTemporaryByName(qname);
  5662. if (existing)
  5663. return (IWUResult *) existing;
  5664. if (!temporaries.length())
  5665. p->addPropTree("Temporaries", createPTree("Temporaries"));
  5666. IPropertyTree *vars = p->queryPropTree("Temporaries");
  5667. IPropertyTree *s = vars->addPropTree("Variable", createPTree("Variable"));
  5668. s->Link();
  5669. IWUResult* q = new CLocalWUResult(s);
  5670. q->Link();
  5671. temporaries.append(*q);
  5672. q->setResultName(qname);
  5673. return q;
  5674. }
  5675. IWUResult* CLocalWorkUnit::updateVariableByName(const char *qname)
  5676. {
  5677. CriticalBlock block(crit);
  5678. IConstWUResult *existing = getVariableByName(qname);
  5679. if (existing)
  5680. return (IWUResult *) existing;
  5681. if (!variables.length())
  5682. p->addPropTree("Variables", createPTree("Variables"));
  5683. IPropertyTree *vars = p->queryPropTree("Variables");
  5684. IPropertyTree *s = vars->addPropTree("Variable", createPTree("Variable"));
  5685. s->Link();
  5686. IWUResult* q = new CLocalWUResult(s);
  5687. q->Link();
  5688. variables.append(*q);
  5689. q->setResultName(qname);
  5690. return q;
  5691. }
  5692. void CLocalWorkUnit::deleteTempFiles(const char *graph, bool deleteOwned, bool deleteJobOwned)
  5693. {
  5694. CriticalBlock block(crit);
  5695. IPropertyTree *files = p->queryPropTree("Files");
  5696. if (!files) return;
  5697. Owned<IPropertyTreeIterator> iter = files->getElements("File");
  5698. ICopyArrayOf<IPropertyTree> toRemove;
  5699. ForEach (*iter)
  5700. {
  5701. IPropertyTree &file = iter->query();
  5702. WUFileKind fileKind = (WUFileKind) file.getPropInt("@kind", WUFileStandard);
  5703. if(file.getPropBool("@temporary")) fileKind = WUFileTemporary; // @temporary, legacy check
  5704. bool needDelete;
  5705. switch(fileKind)
  5706. {
  5707. case WUFileTemporary:
  5708. if(graph==NULL)
  5709. needDelete = true;
  5710. else
  5711. {
  5712. const char *graphOwner = file.queryProp("@graph");
  5713. needDelete = ((graphOwner==NULL) || (strcmp(graph, graphOwner)==0));
  5714. }
  5715. break;
  5716. case WUFileJobOwned:
  5717. needDelete = ((graph==NULL) && deleteJobOwned);
  5718. break;
  5719. case WUFileOwned:
  5720. needDelete = ((graph==NULL) && deleteOwned);
  5721. break;
  5722. default:
  5723. needDelete = false;
  5724. }
  5725. if(needDelete)
  5726. {
  5727. const char *name = file.queryProp("@name");
  5728. LOG(MCdebugProgress, unknownJob, "Removing workunit file %s from DFS", name);
  5729. queryDistributedFileDirectory().removeEntry(name, queryUserDescriptor());
  5730. toRemove.append(file);
  5731. }
  5732. }
  5733. ForEachItemIn(r, toRemove) files->removeTree(&toRemove.item(r));
  5734. }
  5735. static void _noteFileRead(IDistributedFile *file, IPropertyTree *filesRead)
  5736. {
  5737. IDistributedSuperFile *super = file->querySuperFile();
  5738. StringBuffer fname;
  5739. file->getLogicalName(fname);
  5740. StringBuffer path("File[@name=\"");
  5741. path.append(fname).append("\"]");
  5742. IPropertyTree *fileTree = filesRead->queryPropTree(path.str());
  5743. if (fileTree)
  5744. fileTree->setPropInt("@useCount", fileTree->getPropInt("@useCount")+1);
  5745. else
  5746. {
  5747. StringBuffer cluster;
  5748. file->getClusterName(0,cluster);
  5749. fileTree = createPTree();
  5750. fileTree->setProp("@name", fname.str());
  5751. fileTree->setProp("@cluster", cluster.str());
  5752. fileTree->setPropInt("@useCount", 1);
  5753. fileTree = filesRead->addPropTree("File", fileTree);
  5754. }
  5755. if (super)
  5756. {
  5757. Owned<IDistributedFileIterator> iter = super->getSubFileIterator(false);
  5758. ForEach (*iter)
  5759. {
  5760. IDistributedFile &file = iter->query();
  5761. StringBuffer fname;
  5762. file.getLogicalName(fname);
  5763. Owned<IPropertyTree> subfile = createPTree();
  5764. subfile->setProp("@name", fname.str());
  5765. fileTree->addPropTree("Subfile", subfile.getClear());
  5766. _noteFileRead(&file, filesRead);
  5767. }
  5768. }
  5769. }
  5770. void CLocalWorkUnit::noteFileRead(IDistributedFile *file)
  5771. {
  5772. CriticalBlock block(crit);
  5773. IPropertyTree *files = p->queryPropTree("FilesRead");
  5774. if (!files)
  5775. files = p->addPropTree("FilesRead", createPTree());
  5776. _noteFileRead(file, files);
  5777. }
  5778. static void addFile(IPropertyTree *files, const char *fileName, const char *cluster, unsigned usageCount, WUFileKind fileKind, const char *graphOwner)
  5779. {
  5780. StringBuffer path("File[@name=\"");
  5781. path.append(fileName).append("\"]");
  5782. if (cluster)
  5783. path.append("[@cluster=\"").append(cluster).append("\"]");
  5784. IPropertyTree *file = files->queryPropTree(path.str());
  5785. if (file) files->removeTree(file);
  5786. file = createPTree();
  5787. file->setProp("@name", fileName);
  5788. if (cluster)
  5789. file->setProp("@cluster", cluster);
  5790. if (graphOwner)
  5791. file->setProp("@graph", graphOwner);
  5792. file->setPropInt("@kind", (unsigned)fileKind);
  5793. if (WUFileTemporary == fileKind)
  5794. file->setPropInt("@usageCount", usageCount);
  5795. files->addPropTree("File", file);
  5796. }
  5797. void CLocalWorkUnit::addFile(const char *fileName, StringArray *clusters, unsigned usageCount, WUFileKind fileKind, const char *graphOwner)
  5798. {
  5799. CriticalBlock block(crit);
  5800. IPropertyTree *files = p->queryPropTree("Files");
  5801. if (!files)
  5802. files = p->addPropTree("Files", createPTree());
  5803. if (!clusters)
  5804. addFile(fileName, NULL, usageCount, fileKind, graphOwner);
  5805. else
  5806. {
  5807. ForEachItemIn(c, *clusters)
  5808. ::addFile(files, fileName, clusters->item(c), usageCount, fileKind, graphOwner);
  5809. }
  5810. }
  5811. void CLocalWorkUnit::releaseFile(const char *fileName)
  5812. {
  5813. StringBuffer path("File[@name=\"");
  5814. path.append(fileName).append("\"]");
  5815. CriticalBlock block(crit);
  5816. IPropertyTree *files = p->queryPropTree("Files");
  5817. if (!files) return;
  5818. Owned<IPropertyTreeIterator> fiter = files->getElements(path.str());
  5819. ForEach (*fiter)
  5820. {
  5821. IPropertyTree *file = &fiter->query();
  5822. unsigned usageCount = file->getPropInt("@usageCount");
  5823. if (usageCount > 1)
  5824. file->setPropInt("@usageCount", usageCount-1);
  5825. else
  5826. {
  5827. StringAttr name(file->queryProp("@name"));
  5828. files->removeTree(file);
  5829. if (!name.isEmpty()&&(1 == usageCount))
  5830. {
  5831. if (queryDistributedFileDirectory().removeEntry(fileName, queryUserDescriptor()))
  5832. LOG(MCdebugProgress, unknownJob, "Removed (released) file %s from DFS", name.get());
  5833. }
  5834. }
  5835. }
  5836. }
  5837. void CLocalWorkUnit::clearGraphProgress()
  5838. {
  5839. CConstGraphProgress::deleteWuidProgress(p->queryName());
  5840. }
  5841. void CLocalWorkUnit::resetBeforeGeneration()
  5842. {
  5843. CriticalBlock block(crit);
  5844. //Remove all associated files
  5845. Owned<IWUQuery> q = updateQuery();
  5846. q->removeAssociatedFiles();
  5847. //Remove any pre-existing workflow information
  5848. workflowIterator.clear();
  5849. p->removeProp("Workflow");
  5850. }
  5851. unsigned CLocalWorkUnit::queryFileUsage(const char *fileName) const
  5852. {
  5853. StringBuffer path("Files/File[@name=\"");
  5854. path.append(fileName).append("\"]/@usageCount");
  5855. CriticalBlock block(crit);
  5856. return p->getPropInt(path.str());
  5857. }
  5858. IPropertyTree *CLocalWorkUnit::getDiskUsageStats()
  5859. {
  5860. return p->getPropTree("DiskUsageStats");
  5861. }
  5862. void CLocalWorkUnit::addDiskUsageStats(__int64 _avgNodeUsage, unsigned _minNode, __int64 _minNodeUsage, unsigned _maxNode, __int64 _maxNodeUsage, __int64 _graphId)
  5863. {
  5864. IPropertyTree *stats = p->queryPropTree("DiskUsageStats");
  5865. offset_t maxNodeUsage;
  5866. if (stats)
  5867. maxNodeUsage = stats->getPropInt64("@maxNodeUsage");
  5868. else
  5869. {
  5870. stats = p->addPropTree("DiskUsageStats", createPTree());
  5871. maxNodeUsage = 0;
  5872. }
  5873. if ((offset_t)_maxNodeUsage > maxNodeUsage)
  5874. {
  5875. // record all details at time of max node usage.
  5876. stats->setPropInt("@minNode", _minNode);
  5877. stats->setPropInt("@maxNode", _maxNode);
  5878. stats->setPropInt64("@minNodeUsage", _minNodeUsage);
  5879. stats->setPropInt64("@maxNodeUsage", _maxNodeUsage);
  5880. stats->setPropInt64("@graphId", _graphId);
  5881. if (_avgNodeUsage)
  5882. {
  5883. unsigned _skewHi = (unsigned)((100 * (_maxNodeUsage-_avgNodeUsage))/_avgNodeUsage);
  5884. unsigned _skewLo = (unsigned)((100 * (_avgNodeUsage-_minNodeUsage))/_avgNodeUsage);
  5885. stats->setPropInt("@skewHi", _skewHi);
  5886. stats->setPropInt("@skewLo", _skewLo);
  5887. }
  5888. }
  5889. }
  5890. IPropertyTreeIterator & CLocalWorkUnit::getFileIterator() const
  5891. {
  5892. CriticalBlock block(crit);
  5893. return * p->getElements("Files/File");
  5894. }
  5895. IPropertyTreeIterator & CLocalWorkUnit::getFilesReadIterator() const
  5896. {
  5897. CriticalBlock block(crit);
  5898. return * p->getElements("FilesRead/File");
  5899. }
  5900. //=================================================================================================
  5901. bool CLocalWorkUnit::switchThorQueue(const char *cluster, IQueueSwitcher *qs)
  5902. {
  5903. CriticalBlock block(crit);
  5904. if (qs->isAuto()&&!getAllowAutoQueueSwitch())
  5905. return false;
  5906. Owned<IConstWUClusterInfo> newci = getTargetClusterInfo(cluster);
  5907. if (!newci)
  5908. return false;
  5909. StringBuffer currentcluster;
  5910. if (!p->getProp("@clusterName",currentcluster))
  5911. return false;
  5912. Owned<IConstWUClusterInfo> curci = getTargetClusterInfo(currentcluster.str());
  5913. if (!curci)
  5914. return false;
  5915. SCMStringBuffer curqname;
  5916. curci->getThorQueue(curqname);
  5917. const char *wuid = p->queryName();
  5918. void *qi = qs->getQ(curqname.str(),wuid);
  5919. if (!qi)
  5920. return false;
  5921. setClusterName(cluster);
  5922. SCMStringBuffer newqname;
  5923. newci->getThorQueue(newqname);
  5924. qs->putQ(newqname.str(),wuid,qi);
  5925. return true;
  5926. }
  5927. //=================================================================================================
  5928. IPropertyTree *CLocalWorkUnit::getUnpackedTree(bool includeProgress) const
  5929. {
  5930. Owned<IPropertyTree> ret = createPTreeFromIPT(p);
  5931. Owned<IConstWUGraphIterator> graphIter = &getGraphs(GraphTypeAny);
  5932. ForEach(*graphIter)
  5933. {
  5934. IConstWUGraph &graph = graphIter->query();
  5935. Owned<IPropertyTree> graphTree = graph.getXGMMLTree(includeProgress);
  5936. SCMStringBuffer gName;
  5937. graph.getName(gName);
  5938. StringBuffer xpath("Graphs/Graph[@name=\"");
  5939. xpath.append(gName.s).append("\"]/xgmml");
  5940. IPropertyTree *xgmml = ret->queryPropTree(xpath.str());
  5941. if (xgmml) // don't know of any reason it shouldn't exist
  5942. {
  5943. xgmml->removeProp("graphBin");
  5944. xgmml->setPropTree("graph", graphTree.getClear());
  5945. }
  5946. }
  5947. return ret.getClear();
  5948. }
  5949. void CLocalWorkUnit::loadGraphs() const
  5950. {
  5951. CriticalBlock block(crit);
  5952. if (!cachedGraphs.get())
  5953. {
  5954. MemoryBuffer buf;
  5955. IPropertyTree *t = p->queryPropTree("PackedGraphs");
  5956. if (t&&t->getPropBin(NULL,buf)) {
  5957. cachedGraphs.setown(createPTree(buf));
  5958. }
  5959. else
  5960. cachedGraphs.set(p->queryPropTree("Graphs"));
  5961. if (cachedGraphs.get())
  5962. {
  5963. Owned<IPropertyTreeIterator> iter = cachedGraphs->getElements("Graph");
  5964. ForEach(*iter)
  5965. {
  5966. IPropertyTree &graph = iter->query();
  5967. graphs.append(*new CLocalWUGraph(*this, LINK(&graph)));
  5968. }
  5969. }
  5970. }
  5971. }
  5972. mapEnums graphTypes[] = {
  5973. { GraphTypeAny, "unknown" },
  5974. { GraphTypeProgress, "progress" },
  5975. { GraphTypeEcl, "ECL" },
  5976. { GraphTypeActivities, "activities" },
  5977. { GraphTypeSubProgress, "subgraph" },
  5978. { GraphTypeSize, NULL },
  5979. };
  5980. CLocalWUGraph::CLocalWUGraph(const CLocalWorkUnit &_owner, IPropertyTree *props) : p(props), owner(_owner)
  5981. {
  5982. wuidVersion = owner.getWuidVersion();
  5983. }
  5984. IStringVal& CLocalWUGraph::getName(IStringVal &str) const
  5985. {
  5986. str.set(p->queryProp("@name"));
  5987. return str;
  5988. }
  5989. IStringVal& CLocalWUGraph::getLabel(IStringVal &str) const
  5990. {
  5991. if (wuidVersion >= 2)
  5992. {
  5993. str.set(p->queryProp("@label"));
  5994. return str;
  5995. }
  5996. else
  5997. {
  5998. Owned<IPropertyTree> xgmml = getXGMMLTree(false);
  5999. str.set(xgmml->queryProp("@label"));
  6000. return str;
  6001. }
  6002. }
  6003. WUGraphState CLocalWUGraph::getState() const
  6004. {
  6005. Owned<IConstWUGraphProgress> graphProgress = owner.getGraphProgress(p->queryProp("@name"));
  6006. if (!graphProgress)
  6007. return WUGraphUnknown;
  6008. return graphProgress->queryGraphState();
  6009. }
  6010. IStringVal& CLocalWUGraph::getXGMML(IStringVal &str, bool mergeProgress) const
  6011. {
  6012. Owned<IPropertyTree> xgmml = getXGMMLTree(mergeProgress);
  6013. if (xgmml)
  6014. {
  6015. StringBuffer x;
  6016. toXML(xgmml, x);
  6017. str.set(x.str());
  6018. }
  6019. return str;
  6020. }
  6021. unsigned CLocalWorkUnit::getGraphCount() const
  6022. {
  6023. CriticalBlock block(crit);
  6024. if (p->hasProp("Graphs"))
  6025. {
  6026. return p->queryPropTree("Graphs")->numChildren();
  6027. }
  6028. return 0;
  6029. }
  6030. unsigned CLocalWorkUnit::getSourceFileCount() const
  6031. {
  6032. CriticalBlock block(crit);
  6033. if (p->hasProp("FilesRead"))
  6034. {
  6035. return p->queryPropTree("FilesRead")->numChildren();
  6036. }
  6037. return 0;
  6038. }
  6039. unsigned CLocalWorkUnit::getResultCount() const
  6040. {
  6041. CriticalBlock block(crit);
  6042. if (p->hasProp("Results"))
  6043. {
  6044. return p->queryPropTree("Results")->numChildren();
  6045. }
  6046. return 0;
  6047. }
  6048. unsigned CLocalWorkUnit::getVariableCount() const
  6049. {
  6050. CriticalBlock block(crit);
  6051. if (p->hasProp("Variables"))
  6052. {
  6053. return p->queryPropTree("Variables")->numChildren();
  6054. }
  6055. return 0;
  6056. }
  6057. unsigned CLocalWorkUnit::getApplicationValueCount() const
  6058. {
  6059. CriticalBlock block(crit);
  6060. if (p->hasProp("Application"))
  6061. {
  6062. return p->queryPropTree("Application")->numChildren();
  6063. }
  6064. return 0;
  6065. }
  6066. StringBuffer &appendPTreeOpenTag(StringBuffer &s, IPropertyTree *tree, const char *name, unsigned indent)
  6067. {
  6068. appendXMLOpenTag(s, name, NULL, false);
  6069. Owned<IAttributeIterator> attrs = tree->getAttributes(true);
  6070. if (attrs->first())
  6071. {
  6072. unsigned attributeindent = indent + (size32_t) strlen(name);
  6073. unsigned count = attrs->count();
  6074. bool doindent = false;
  6075. ForEach(*attrs)
  6076. {
  6077. if (doindent)
  6078. s.append('\n').appendN(attributeindent, ' ');
  6079. else if (count > 3)
  6080. doindent = true;
  6081. appendXMLAttr(s, attrs->queryName()+1, attrs->queryValue());
  6082. }
  6083. }
  6084. s.append('>');
  6085. return s;
  6086. }
  6087. IStringVal &CLocalWorkUnit::getXmlParams(IStringVal &str, bool hidePasswords) const
  6088. {
  6089. CriticalBlock block(crit);
  6090. IPropertyTree *paramTree = p->queryPropTree("Parameters");
  6091. if (!paramTree)
  6092. return str;
  6093. StringBuffer xml;
  6094. if (!hidePasswords)
  6095. toXML(paramTree, xml);
  6096. else
  6097. {
  6098. appendPTreeOpenTag(xml.append(' '), paramTree, "Parameters", 0).append('\n');
  6099. Owned<IPropertyTreeIterator> elems = paramTree->getElements("*");
  6100. ForEach(*elems)
  6101. {
  6102. const char *paramname = elems->query().queryName();
  6103. VStringBuffer xpath("Variables/Variable[@name='%s']/Format/@password", paramname);
  6104. if (p->getPropBool(xpath))
  6105. appendXMLTag(xml.append(" "), paramname, "***").append('\n');
  6106. else
  6107. toXML(&elems->query(), xml, 2);
  6108. }
  6109. appendXMLCloseTag(xml.append(' '), "Parameters").append('\n');
  6110. }
  6111. str.set(xml);
  6112. return str;
  6113. }
  6114. const IPropertyTree *CLocalWorkUnit::getXmlParams() const
  6115. {
  6116. CriticalBlock block(crit);
  6117. return p->getPropTree("Parameters");
  6118. }
  6119. void CLocalWorkUnit::setXmlParams(const char *params)
  6120. {
  6121. CriticalBlock block(crit);
  6122. p->setPropTree("Parameters", createPTreeFromXMLString(params));
  6123. }
  6124. void CLocalWorkUnit::setXmlParams(IPropertyTree *tree)
  6125. {
  6126. CriticalBlock block(crit);
  6127. p->setPropTree("Parameters", tree);
  6128. }
  6129. unsigned __int64 CLocalWorkUnit::getHash() const
  6130. {
  6131. CriticalBlock block(crit);
  6132. return p->getPropInt64("@hash");
  6133. }
  6134. void CLocalWorkUnit::setHash(unsigned __int64 hash)
  6135. {
  6136. CriticalBlock block(crit);
  6137. p->setPropInt64("@hash", hash);
  6138. }
  6139. IConstWUGraphMetaIterator& CLocalWorkUnit::getGraphsMeta(WUGraphType type) const
  6140. {
  6141. /* NB: this method should be 'cheap', loadGraphs() creates IConstWUGraph interfaces to the graphs
  6142. * it does not actually pull the graph data. We only use IConstWUGraphMeta here, which never probes the xgmml
  6143. * This method also connects to the graph progress (/GraphProgress/<wuid>) using a single connection, in order
  6144. * to get state information, it does not pull all the progress data.
  6145. */
  6146. CriticalBlock block(crit);
  6147. loadGraphs();
  6148. class CConstWUGraphMetaIterator: public CInterface, implements IConstWUGraphMetaIterator, implements IConstWUGraphMeta
  6149. {
  6150. StringAttr wuid;
  6151. WUGraphType type;
  6152. Owned<IConstWUGraphIterator> graphIter;
  6153. IConstWUGraph *curGraph;
  6154. Owned<IConstWUGraphProgress> curGraphProgress;
  6155. Owned<IRemoteConnection> progressConn;
  6156. bool match()
  6157. {
  6158. return (GraphTypeAny == type) || (type == graphIter->query().getType());
  6159. }
  6160. void setCurrent(IConstWUGraph &graph)
  6161. {
  6162. curGraph = &graph;
  6163. SCMStringBuffer graphName;
  6164. curGraph->getName(graphName);
  6165. if (progressConn)
  6166. {
  6167. IPropertyTree *progress = progressConn->queryRoot()->queryPropTree(graphName.str());
  6168. if (progress)
  6169. {
  6170. curGraphProgress.setown(new CConstGraphProgress(wuid, graphName.str(), progress));
  6171. return;
  6172. }
  6173. }
  6174. curGraphProgress.clear();
  6175. }
  6176. public:
  6177. IMPLEMENT_IINTERFACE;
  6178. CConstWUGraphMetaIterator(const char *_wuid, IConstWUGraphIterator *_graphIter, WUGraphType _type)
  6179. : wuid(_wuid), graphIter(_graphIter), type(_type)
  6180. {
  6181. curGraph = NULL;
  6182. StringBuffer progressPath;
  6183. progressPath.append("/GraphProgress/").append(wuid);
  6184. progressConn.setown(querySDS().connect(progressPath.str(), myProcessSession(), RTM_NONE, SDS_LOCK_TIMEOUT));
  6185. }
  6186. virtual bool first()
  6187. {
  6188. curGraph = NULL;
  6189. curGraphProgress.clear();
  6190. if (!graphIter->first())
  6191. return false;
  6192. if (match())
  6193. {
  6194. setCurrent(graphIter->query());
  6195. return true;
  6196. }
  6197. return next();
  6198. }
  6199. virtual bool next()
  6200. {
  6201. while (graphIter->next())
  6202. {
  6203. if (match())
  6204. {
  6205. setCurrent(graphIter->query());
  6206. return true;
  6207. }
  6208. }
  6209. curGraph = NULL;
  6210. curGraphProgress.clear();
  6211. return false;
  6212. }
  6213. virtual bool isValid()
  6214. {
  6215. return NULL != curGraph;
  6216. }
  6217. virtual IConstWUGraphMeta & query()
  6218. {
  6219. return *this;
  6220. }
  6221. // IConstWUGraphMeta
  6222. virtual IStringVal & getName(IStringVal & ret) const
  6223. {
  6224. return curGraph->getName(ret);
  6225. }
  6226. virtual IStringVal & getLabel(IStringVal & ret) const
  6227. {
  6228. return curGraph->getLabel(ret);
  6229. }
  6230. virtual IStringVal & getTypeName(IStringVal & ret) const
  6231. {
  6232. return curGraph->getTypeName(ret);
  6233. }
  6234. virtual WUGraphType getType() const
  6235. {
  6236. return curGraph->getType();
  6237. }
  6238. virtual WUGraphState getState() const
  6239. {
  6240. if (!curGraphProgress)
  6241. return WUGraphUnknown;
  6242. return curGraphProgress->queryGraphState();
  6243. }
  6244. };
  6245. IConstWUGraphIterator *graphIter = new CArrayIteratorOf<IConstWUGraph,IConstWUGraphIterator> (graphs, 0, (IConstWorkUnit *) this);
  6246. return * new CConstWUGraphMetaIterator(p->queryName(), graphIter, type);
  6247. }
  6248. IConstWUGraphIterator& CLocalWorkUnit::getGraphs(WUGraphType type) const
  6249. {
  6250. CriticalBlock block(crit);
  6251. loadGraphs();
  6252. IConstWUGraphIterator *giter = new CArrayIteratorOf<IConstWUGraph,IConstWUGraphIterator> (graphs, 0, (IConstWorkUnit *) this);
  6253. if (type!=GraphTypeAny) {
  6254. class CConstWUGraphIterator: public CInterface, implements IConstWUGraphIterator
  6255. {
  6256. WUGraphType type;
  6257. Owned<IConstWUGraphIterator> base;
  6258. bool match()
  6259. {
  6260. return base->query().getType()==type;
  6261. }
  6262. public:
  6263. IMPLEMENT_IINTERFACE;
  6264. CConstWUGraphIterator(IConstWUGraphIterator *_base,WUGraphType _type)
  6265. : base(_base)
  6266. {
  6267. type = _type;
  6268. }
  6269. bool first()
  6270. {
  6271. if (!base->first())
  6272. return false;
  6273. if (match())
  6274. return true;
  6275. return next();
  6276. }
  6277. bool next()
  6278. {
  6279. while (base->next())
  6280. if (match())
  6281. return true;
  6282. return false;
  6283. }
  6284. virtual bool isValid()
  6285. {
  6286. return base->isValid();
  6287. }
  6288. IConstWUGraph & query()
  6289. {
  6290. return base->query();
  6291. }
  6292. };
  6293. giter = new CConstWUGraphIterator(giter,type);
  6294. }
  6295. return *giter;
  6296. }
  6297. IConstWUGraph* CLocalWorkUnit::getGraph(const char *qname) const
  6298. {
  6299. CriticalBlock block(crit);
  6300. loadGraphs();
  6301. ForEachItemIn(idx, graphs)
  6302. {
  6303. SCMStringBuffer name;
  6304. IConstWUGraph &cur = graphs.item(idx);
  6305. cur.getName(name);
  6306. if (stricmp(name.str(), qname)==0)
  6307. {
  6308. cur.Link();
  6309. return &cur;
  6310. }
  6311. }
  6312. return NULL;
  6313. }
  6314. IWUGraph* CLocalWorkUnit::createGraph()
  6315. {
  6316. // For this to be legally called, we must have the write-able interface. So we are already locked for write.
  6317. CriticalBlock block(crit);
  6318. ensureGraphsUnpacked();
  6319. loadGraphs();
  6320. if (!graphs.ordinality())
  6321. p->addPropTree("Graphs", createPTree("Graphs"));
  6322. IPropertyTree *r = p->queryPropTree("Graphs");
  6323. IPropertyTree *s = r->addPropTree("Graph", createPTree());
  6324. s->Link();
  6325. IWUGraph* q = new CLocalWUGraph(*this, s);
  6326. q->Link();
  6327. graphs.append(*q);
  6328. return q;
  6329. }
  6330. IWUGraph * CLocalWorkUnit::createGraph(const char * name, WUGraphType type, IPropertyTree *xgmml)
  6331. {
  6332. CriticalBlock block(crit);
  6333. ensureGraphsUnpacked();
  6334. Linked<IConstWUGraph> existing = getGraph(name);
  6335. if (existing)
  6336. throwUnexpected();
  6337. if (!graphs.length())
  6338. p->addPropTree("Graphs", createPTree("Graphs"));
  6339. IPropertyTree *r = p->queryPropTree("Graphs");
  6340. IPropertyTree *s = r->addPropTree("Graph", createPTree());
  6341. IWUGraph* q = new CLocalWUGraph(*this, LINK(s));
  6342. graphs.append(*LINK(q));
  6343. q->setName(name);
  6344. q->setXGMMLTree(xgmml);
  6345. q->setType(type);
  6346. return q;
  6347. }
  6348. IWUGraph * CLocalWorkUnit::updateGraph(const char * name)
  6349. {
  6350. CriticalBlock block(crit);
  6351. ensureGraphsUnpacked();
  6352. return (IWUGraph *)getGraph(name);
  6353. }
  6354. IConstWUGraphProgress *CLocalWorkUnit::getGraphProgress(const char *name) const
  6355. {
  6356. CriticalBlock block(crit);
  6357. return new CConstGraphProgress(p->queryName(), name);
  6358. }
  6359. void CLocalWUGraph::setName(const char *str)
  6360. {
  6361. p->setProp("@name", str);
  6362. progress.clear();
  6363. progress.setown(new CConstGraphProgress(owner.queryWuid(), str));
  6364. }
  6365. void CLocalWUGraph::setLabel(const char *str)
  6366. {
  6367. p->setProp("@label", str);
  6368. }
  6369. void CLocalWUGraph::setXGMML(const char *str)
  6370. {
  6371. setXGMMLTree(createPTreeFromXMLString(str));
  6372. }
  6373. void CLocalWUGraph::setXGMMLTree(IPropertyTree *_graph, bool compress)
  6374. {
  6375. assertex(strcmp(_graph->queryName(), "graph")==0);
  6376. IPropertyTree *xgmml = p->setPropTree("xgmml", createPTree());
  6377. if (compress)
  6378. {
  6379. MemoryBuffer mb;
  6380. _graph->serialize(mb);
  6381. xgmml->setPropBin("graphBin", mb.length(), mb.toByteArray());
  6382. graph.setown(_graph);
  6383. }
  6384. else
  6385. xgmml->setPropTree("graph", _graph);
  6386. }
  6387. static void expandAttributes(IPropertyTree & targetNode, IPropertyTree & progressNode)
  6388. {
  6389. Owned<IAttributeIterator> aIter = progressNode.getAttributes();
  6390. ForEach (*aIter)
  6391. {
  6392. const char *aName = aIter->queryName()+1;
  6393. if (0 != stricmp("id", aName)) // "id" reserved.
  6394. {
  6395. IPropertyTree *att = targetNode.addPropTree("att", createPTree());
  6396. att->setProp("@name", aName);
  6397. att->setProp("@value", aIter->queryValue());
  6398. }
  6399. }
  6400. }
  6401. void CLocalWUGraph::mergeProgress(IPropertyTree &rootNode, IPropertyTree &progressTree, const unsigned &progressV) const
  6402. {
  6403. IPropertyTree *graphNode = rootNode.queryPropTree("att/graph");
  6404. if (!graphNode) return;
  6405. unsigned nodeId = rootNode.getPropInt("@id");
  6406. StringBuffer progressNodePath("node[@id=\"");
  6407. progressNodePath.append(nodeId).append("\"]");
  6408. IPropertyTree *progressNode = progressTree.queryPropTree(progressNodePath.str());
  6409. if (progressNode)
  6410. {
  6411. expandAttributes(*graphNode, *progressNode);
  6412. Owned<IPropertyTreeIterator> edges = progressNode->getElements("edge");
  6413. ForEach (*edges)
  6414. {
  6415. IPropertyTree &edge = edges->query();
  6416. StringBuffer edgePath("edge[@id=\"");
  6417. edgePath.append(edge.queryProp("@id")).append("\"]");
  6418. IPropertyTree *graphEdge = graphNode->queryPropTree(edgePath.str());
  6419. if (graphEdge)
  6420. {
  6421. if (progressV < 1)
  6422. mergePTree(graphEdge, &edge);
  6423. else
  6424. { // must translate to XGMML format
  6425. expandAttributes(*graphEdge, edge);
  6426. // 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)
  6427. Owned<IPropertyTreeIterator> iter = edge.getElements("*");
  6428. ForEach (*iter)
  6429. {
  6430. IPropertyTree &t = iter->query();
  6431. IPropertyTree *att = graphEdge->addPropTree("att", createPTree());
  6432. att->setProp("@name", t.queryName());
  6433. att->setProp("@value", t.queryProp(NULL));
  6434. }
  6435. }
  6436. }
  6437. }
  6438. Owned<IPropertyTreeIterator> nodes = progressNode->getElements("node");
  6439. ForEach (*nodes)
  6440. {
  6441. IPropertyTree &node = nodes->query();
  6442. StringBuffer nodePath("node[@id=\"");
  6443. nodePath.append(node.queryProp("@id")).append("\"]");
  6444. IPropertyTree *_node = graphNode->queryPropTree(nodePath.str());
  6445. if (_node)
  6446. {
  6447. if (progressV < 1)
  6448. mergePTree(_node, &node);
  6449. else
  6450. { // must translate to XGMML format
  6451. expandAttributes(*_node, node);
  6452. }
  6453. }
  6454. }
  6455. }
  6456. Owned<IPropertyTreeIterator> iter = graphNode->getElements("node");
  6457. ForEach (*iter)
  6458. mergeProgress(iter->query(), progressTree, progressV);
  6459. }
  6460. IPropertyTree * CLocalWUGraph::getXGMMLTreeRaw() const
  6461. {
  6462. return p->getPropTree("xgmml");
  6463. }
  6464. IPropertyTree * CLocalWUGraph::getXGMMLTree(bool doMergeProgress) const
  6465. {
  6466. if (!graph)
  6467. {
  6468. // NB: although graphBin introduced in wuidVersion==2,
  6469. // daliadmin can retrospectively compress existing graphs, so need to check for all versions
  6470. MemoryBuffer mb;
  6471. if (p->getPropBin("xgmml/graphBin", mb))
  6472. graph.setown(createPTree(mb));
  6473. else
  6474. graph.setown(p->getBranch("xgmml/graph"));
  6475. if (!graph)
  6476. return NULL;
  6477. }
  6478. if (!doMergeProgress)
  6479. return graph.getLink();
  6480. else
  6481. {
  6482. Owned<IPropertyTree> copy = createPTreeFromIPT(graph);
  6483. Owned<IConstWUGraphProgress> _progress;
  6484. if (progress) _progress.set(progress);
  6485. else
  6486. _progress.setown(new CConstGraphProgress(owner.queryWuid(), p->queryProp("@name")));
  6487. //MORE: Eventually this should directly access the new stats structure
  6488. unsigned progressV = _progress->queryFormatVersion();
  6489. Owned<IPropertyTree> progressTree = _progress->getProgressTree();
  6490. Owned<IPropertyTreeIterator> nodeIterator = copy->getElements("node");
  6491. ForEach (*nodeIterator)
  6492. mergeProgress(nodeIterator->query(), *progressTree, progressV);
  6493. return copy.getClear();
  6494. }
  6495. }
  6496. WUGraphType CLocalWUGraph::getType() const
  6497. {
  6498. return (WUGraphType) getEnum(p, "@type", graphTypes);
  6499. }
  6500. IStringVal & CLocalWUGraph::getTypeName(IStringVal &str) const
  6501. {
  6502. str.set(p->queryProp("@type"));
  6503. if (!str.length())
  6504. str.set("unknown");
  6505. return str;
  6506. }
  6507. void CLocalWUGraph::setType(WUGraphType _type)
  6508. {
  6509. setEnum(p, "@type", _type, graphTypes);
  6510. }
  6511. //=================================================================================================
  6512. mapEnums queryFileTypes[] = {
  6513. { FileTypeCpp, "cpp" },
  6514. { FileTypeDll, "dll" },
  6515. { FileTypeResText, "res" },
  6516. { FileTypeHintXml, "hint" },
  6517. { FileTypeXml, "xml" },
  6518. { FileTypeSize, NULL },
  6519. };
  6520. CLocalWUAssociated::CLocalWUAssociated(IPropertyTree *props) : p(props)
  6521. {
  6522. }
  6523. WUFileType CLocalWUAssociated::getType() const
  6524. {
  6525. return (WUFileType)getEnum(p, "@type", queryFileTypes);
  6526. }
  6527. IStringVal & CLocalWUAssociated::getDescription(IStringVal & str) const
  6528. {
  6529. str.set(p->queryProp("@desc"));
  6530. return str;
  6531. }
  6532. IStringVal & CLocalWUAssociated::getIp(IStringVal & str) const
  6533. {
  6534. str.set(p->queryProp("@ip"));
  6535. return str;
  6536. }
  6537. IStringVal & CLocalWUAssociated::getName(IStringVal & str) const
  6538. {
  6539. str.set(p->queryProp("@filename"));
  6540. return str;
  6541. }
  6542. IStringVal & CLocalWUAssociated::getNameTail(IStringVal & str) const
  6543. {
  6544. str.set(pathTail(p->queryProp("@filename")));
  6545. return str;
  6546. }
  6547. unsigned CLocalWUAssociated::getCrc() const
  6548. {
  6549. return p->getPropInt("@crc", 0);
  6550. }
  6551. //=================================================================================================
  6552. CLocalWUQuery::CLocalWUQuery(IPropertyTree *props) : p(props)
  6553. {
  6554. associatedCached = false;
  6555. }
  6556. mapEnums queryTypes[] = {
  6557. { QueryTypeUnknown, "unknown" },
  6558. { QueryTypeEcl, "ECL" },
  6559. { QueryTypeSql, "SQL" },
  6560. { QueryTypeXml, "XML" },
  6561. { QueryTypeAttribute, "Attribute" },
  6562. { QueryTypeSize, NULL },
  6563. };
  6564. WUQueryType CLocalWUQuery::getQueryType() const
  6565. {
  6566. return (WUQueryType) getEnum(p, "@type", queryTypes);
  6567. }
  6568. void CLocalWUQuery::setQueryType(WUQueryType qt)
  6569. {
  6570. setEnum(p, "@type", qt, queryTypes);
  6571. }
  6572. IStringVal& CLocalWUQuery::getQueryText(IStringVal &str) const
  6573. {
  6574. str.set(p->queryProp("Text"));
  6575. return str;
  6576. }
  6577. IStringVal& CLocalWUQuery::getQueryShortText(IStringVal &str) const
  6578. {
  6579. const char * text = p->queryProp("Text");
  6580. if (isArchiveQuery(text))
  6581. {
  6582. Owned<IPropertyTree> xml = createPTreeFromXMLString(text, ipt_caseInsensitive);
  6583. const char * path = xml->queryProp("Query/@attributePath");
  6584. if (path)
  6585. {
  6586. IPropertyTree * resolved = resolveDefinitionInArchive(xml, path);
  6587. if (resolved)
  6588. str.set(resolved->queryProp(NULL));
  6589. }
  6590. else
  6591. str.set(xml->queryProp("Query"));
  6592. }
  6593. else
  6594. str.set(text);
  6595. return str;
  6596. }
  6597. IStringVal& CLocalWUQuery::getQueryName(IStringVal &str) const
  6598. {
  6599. str.set(p->queryProp("@name"));
  6600. return str;
  6601. }
  6602. IStringVal & CLocalWUQuery::getQueryMainDefinition(IStringVal & str) const
  6603. {
  6604. str.set(p->queryProp("@main"));
  6605. return str;
  6606. }
  6607. IStringVal& CLocalWUQuery::getQueryDllName(IStringVal &str) const
  6608. {
  6609. Owned<IConstWUAssociatedFile> entry = getAssociatedFile(FileTypeDll, 0);
  6610. if (entry)
  6611. entry->getNameTail(str);
  6612. return str;
  6613. }
  6614. IStringVal& CLocalWUQuery::getQueryCppName(IStringVal &str) const
  6615. {
  6616. Owned<IConstWUAssociatedFile> entry = getAssociatedFile(FileTypeCpp, 0);
  6617. if (entry)
  6618. entry->getName(str);
  6619. return str;
  6620. }
  6621. IStringVal& CLocalWUQuery::getQueryResTxtName(IStringVal &str) const
  6622. {
  6623. Owned<IConstWUAssociatedFile> entry = getAssociatedFile(FileTypeResText, 0);
  6624. if (entry)
  6625. entry->getName(str);
  6626. return str;
  6627. }
  6628. unsigned CLocalWUQuery::getQueryDllCrc() const
  6629. {
  6630. Owned<IConstWUAssociatedFile> entry = getAssociatedFile(FileTypeDll, 0);
  6631. if (entry)
  6632. return entry->getCrc();
  6633. return 0;
  6634. }
  6635. void CLocalWUQuery::setQueryText(const char *text)
  6636. {
  6637. p->setProp("Text", text);
  6638. }
  6639. void CLocalWUQuery::setQueryName(const char *qname)
  6640. {
  6641. p->setProp("@name", qname);
  6642. }
  6643. void CLocalWUQuery::setQueryMainDefinition(const char * str)
  6644. {
  6645. p->setProp("@main", str);
  6646. }
  6647. void CLocalWUQuery::addAssociatedFile(WUFileType type, const char * name, const char * ip, const char * desc, unsigned crc)
  6648. {
  6649. CriticalBlock block(crit);
  6650. loadAssociated();
  6651. if (!associated.length())
  6652. p->addPropTree("Associated", createPTree("Associated"));
  6653. IPropertyTree *pl = p->queryPropTree("Associated");
  6654. IPropertyTree *s = pl->addPropTree("File", createPTree("File"));
  6655. setEnum(s, "@type", type, queryFileTypes);
  6656. s->setProp("@filename", name);
  6657. s->setProp("@ip", ip);
  6658. s->setProp("@desc", desc);
  6659. if (crc)
  6660. s->setPropInt("@crc", crc);
  6661. IConstWUAssociatedFile * q = new CLocalWUAssociated(LINK(s));
  6662. associated.append(*q);
  6663. }
  6664. void CLocalWUQuery::removeAssociatedFile(WUFileType type, const char * name, const char * desc)
  6665. {
  6666. CriticalBlock block(crit);
  6667. associatedCached = false;
  6668. associated.kill();
  6669. StringBuffer xpath;
  6670. xpath.append("Associated/File");
  6671. if (type)
  6672. xpath.append("[@type=\"").append(getEnumText(type, queryFileTypes)).append("\"]");
  6673. if (name)
  6674. xpath.append("[@filename=\"").append(name).append("\"]");
  6675. if (desc)
  6676. xpath.append("[@desc=\"").append(desc).append("\"]");
  6677. p->removeProp(xpath.str());
  6678. }
  6679. void CLocalWUQuery::removeAssociatedFiles()
  6680. {
  6681. associatedCached = false;
  6682. associated.kill();
  6683. p->removeProp("Associated");
  6684. }
  6685. IConstWUAssociatedFile * CLocalWUQuery::getAssociatedFile(WUFileType type, unsigned index) const
  6686. {
  6687. CriticalBlock block(crit);
  6688. loadAssociated();
  6689. ForEachItemIn(idx, associated)
  6690. {
  6691. CLocalWUAssociated &cur = static_cast<CLocalWUAssociated &>(associated.item(idx));
  6692. if (cur.getType() == type)
  6693. {
  6694. if (index-- == 0)
  6695. return &OLINK(cur);
  6696. }
  6697. }
  6698. return NULL;
  6699. }
  6700. void CLocalWUQuery::addSpecialCaseAssociated(WUFileType type, const char * propname, unsigned crc) const
  6701. {
  6702. const char * name = p->queryProp(propname);
  6703. if (name)
  6704. {
  6705. IPropertyTree *s = createPTree("File");
  6706. setEnum(s, "@type", type, queryFileTypes);
  6707. s->setProp("@filename", name);
  6708. if (crc)
  6709. s->setPropInt("@crc", crc);
  6710. associated.append(*new CLocalWUAssociated(s));
  6711. }
  6712. }
  6713. void CLocalWUQuery::loadAssociated() const
  6714. {
  6715. CriticalBlock block(crit);
  6716. if (!associatedCached)
  6717. {
  6718. assertex(associated.length() == 0);
  6719. addSpecialCaseAssociated(FileTypeDll, "DllName", p->getPropInt("DllCrc", 0));
  6720. addSpecialCaseAssociated(FileTypeCpp, "CppName", 0);
  6721. addSpecialCaseAssociated(FileTypeResText, "ResTxtName", 0);
  6722. Owned<IPropertyTreeIterator> r = p->getElements("Associated/File");
  6723. for (r->first(); r->isValid(); r->next())
  6724. {
  6725. IPropertyTree *rp = &r->query();
  6726. rp->Link();
  6727. associated.append(*new CLocalWUAssociated(rp));
  6728. }
  6729. associatedCached = true;
  6730. }
  6731. }
  6732. IConstWUAssociatedFileIterator& CLocalWUQuery::getAssociatedFiles() const
  6733. {
  6734. CriticalBlock block(crit);
  6735. loadAssociated();
  6736. return *new CArrayIteratorOf<IConstWUAssociatedFile,IConstWUAssociatedFileIterator> (associated, 0, (IConstWUQuery *) this);
  6737. }
  6738. //========================================================================================
  6739. CLocalWUWebServicesInfo::CLocalWUWebServicesInfo(IPropertyTree *props) : p(props)
  6740. {
  6741. }
  6742. IStringVal& CLocalWUWebServicesInfo::getModuleName(IStringVal &str) const
  6743. {
  6744. str.set(p->queryProp("@module"));
  6745. return str;
  6746. }
  6747. IStringVal& CLocalWUWebServicesInfo::getAttributeName(IStringVal &str) const
  6748. {
  6749. str.set(p->queryProp("@attribute"));
  6750. return str;
  6751. }
  6752. IStringVal& CLocalWUWebServicesInfo::getDefaultName(IStringVal &str) const
  6753. {
  6754. str.set(p->queryProp("@defaultName"));
  6755. return str;
  6756. }
  6757. unsigned CLocalWUWebServicesInfo::getWebServicesCRC() const
  6758. {
  6759. return (unsigned) p->getPropInt("@crc");
  6760. }
  6761. IStringVal& CLocalWUWebServicesInfo::getInfo(const char *name, IStringVal &str) const
  6762. {
  6763. if (!name)
  6764. {
  6765. StringBuffer ws_info;
  6766. ws_info.appendf("<%s ", p->queryName());
  6767. Owned<IAttributeIterator> attrs = p->getAttributes();
  6768. for(attrs->first(); attrs->isValid(); attrs->next())
  6769. {
  6770. const char *name = attrs->queryName()+1;
  6771. const char *value = attrs->queryValue();
  6772. ws_info.appendf("%s='%s' ", name, value);
  6773. }
  6774. ws_info.append("> \n");
  6775. Owned<IPropertyTreeIterator> info = p->getElements("*");
  6776. ForEach(*info)
  6777. {
  6778. IPropertyTree &item = info->query();
  6779. const char *name = item.queryName();
  6780. if (name)
  6781. {
  6782. MemoryBuffer mb;
  6783. bool isbin = p->isBinary(name);
  6784. if (isbin)
  6785. {
  6786. p->getPropBin(name,mb);
  6787. if (mb.length())
  6788. {
  6789. unsigned len = 0;
  6790. mb.read(len);
  6791. StringBuffer encodedString;
  6792. StringBuffer val(len, (const char *) mb.readDirect(len));
  6793. encodeXML(val, encodedString);
  6794. ws_info.appendf("<%s>%s</%s>", name, encodedString.str(), name);
  6795. }
  6796. }
  6797. else
  6798. {
  6799. StringBuffer tmp;
  6800. toXML(&item, tmp);
  6801. ws_info.append(tmp.str());
  6802. }
  6803. }
  6804. }
  6805. ws_info.appendf("</%s>", p->queryName());
  6806. str.setLen(ws_info.str(), ws_info.length());
  6807. }
  6808. else
  6809. {
  6810. MemoryBuffer mb;
  6811. p->getPropBin(name,mb);
  6812. if (mb.length())
  6813. {
  6814. unsigned len;
  6815. mb.read(len);
  6816. str.setLen((const char *) mb.readDirect(len), len);
  6817. }
  6818. }
  6819. return str;
  6820. }
  6821. IStringVal& CLocalWUWebServicesInfo::getText(const char *name, IStringVal &str) const
  6822. {
  6823. str.set(p->queryProp(name));
  6824. return str;
  6825. }
  6826. void CLocalWUWebServicesInfo::setModuleName(const char *mname)
  6827. {
  6828. p->setProp("@module", mname);
  6829. }
  6830. void CLocalWUWebServicesInfo::setAttributeName(const char *aname)
  6831. {
  6832. p->setProp("@attribute", aname);
  6833. }
  6834. void CLocalWUWebServicesInfo::setDefaultName(const char *dname)
  6835. {
  6836. p->setProp("@defaultName", dname);
  6837. }
  6838. void CLocalWUWebServicesInfo::setWebServicesCRC(unsigned crc)
  6839. {
  6840. p->setPropInt("@crc", crc);
  6841. }
  6842. void CLocalWUWebServicesInfo::setInfo(const char *name, const char *info)
  6843. {
  6844. MemoryBuffer m;
  6845. unsigned len = (size32_t)strlen(info);
  6846. serializeLPString(len, info, m);
  6847. p->setPropBin(name, m.length(), m.toByteArray());
  6848. }
  6849. void CLocalWUWebServicesInfo::setText(const char *name, const char *info)
  6850. {
  6851. p->setProp(name, info);
  6852. }
  6853. //========================================================================================
  6854. CLocalWURoxieQueryInfo::CLocalWURoxieQueryInfo(IPropertyTree *props) : p(props)
  6855. {
  6856. }
  6857. IStringVal& CLocalWURoxieQueryInfo::getQueryInfo(IStringVal &str) const
  6858. {
  6859. IPropertyTree *queryTree = p->queryPropTree("query");
  6860. if (queryTree)
  6861. {
  6862. StringBuffer temp;
  6863. toXML(queryTree, temp);
  6864. str.set(temp.str());
  6865. }
  6866. return str;
  6867. }
  6868. IStringVal& CLocalWURoxieQueryInfo::getDefaultPackageInfo(IStringVal &str) const
  6869. {
  6870. MemoryBuffer mb;
  6871. p->getPropBin("RoxiePackages",mb);
  6872. if (mb.length())
  6873. {
  6874. unsigned len;
  6875. mb.read(len);
  6876. str.setLen((const char *) mb.readDirect(len), len);
  6877. }
  6878. return str;
  6879. }
  6880. IStringVal& CLocalWURoxieQueryInfo::getRoxieClusterName(IStringVal &str) const
  6881. {
  6882. const char *val = p->queryProp("@roxieClusterName");
  6883. if (val)
  6884. str.set(val);
  6885. return str;
  6886. }
  6887. IStringVal& CLocalWURoxieQueryInfo::getWuid(IStringVal &str) const
  6888. {
  6889. const char *val = p->queryProp("@wuid");
  6890. if (val)
  6891. str.set(val);
  6892. return str;
  6893. }
  6894. void CLocalWURoxieQueryInfo::setQueryInfo(const char *info)
  6895. {
  6896. IPropertyTree *queryTree = p->queryPropTree("query");
  6897. if (queryTree)
  6898. p->removeTree(queryTree);
  6899. IPropertyTree * tempTree = p->addPropTree("query", createPTreeFromXMLString(info));
  6900. if (!p->hasProp("@roxieClusterName"))
  6901. {
  6902. const char *roxieClusterName = tempTree->queryProp("@roxieName");
  6903. if (roxieClusterName && *roxieClusterName)
  6904. p->addProp("@roxieClusterName", roxieClusterName);
  6905. }
  6906. if (!p->hasProp("@wuid"))
  6907. {
  6908. const char *wuid = tempTree->queryProp("Query/@wuid");
  6909. if (wuid && *wuid)
  6910. p->addProp("@wuid", wuid);
  6911. }
  6912. }
  6913. void CLocalWURoxieQueryInfo::setDefaultPackageInfo(const char *info, int len)
  6914. {
  6915. MemoryBuffer m;
  6916. serializeLPString(len, info, m);
  6917. p->setPropBin("RoxiePackages", m.length(), m.toByteArray());
  6918. }
  6919. void CLocalWURoxieQueryInfo::setRoxieClusterName(const char *info)
  6920. {
  6921. p->setProp("@roxieClusterName", info);
  6922. }
  6923. void CLocalWURoxieQueryInfo::setWuid(const char *info)
  6924. {
  6925. p->setProp("@wuid", info);
  6926. }
  6927. //========================================================================================
  6928. CLocalWUResult::CLocalWUResult(IPropertyTree *props) : p(props)
  6929. {
  6930. }
  6931. mapEnums resultStatuses[] = {
  6932. { ResultStatusUndefined, "undefined" },
  6933. { ResultStatusCalculated, "calculated" },
  6934. { ResultStatusSupplied, "supplied" },
  6935. { ResultStatusFailed, "failed" },
  6936. { ResultStatusPartial, "partial" },
  6937. { ResultStatusSize, NULL }
  6938. };
  6939. WUResultStatus CLocalWUResult::getResultStatus() const
  6940. {
  6941. return (WUResultStatus ) getEnum(p, "@status", resultStatuses);
  6942. }
  6943. IStringVal& CLocalWUResult::getResultName(IStringVal &str) const
  6944. {
  6945. str.set(p->queryProp("@name"));
  6946. return str;
  6947. }
  6948. int CLocalWUResult::getResultSequence() const
  6949. {
  6950. return p->getPropInt("@sequence", -1);
  6951. }
  6952. bool CLocalWUResult::isResultScalar() const
  6953. {
  6954. return p->getPropInt("@isScalar", 1) != 0;
  6955. }
  6956. bool findSize(int size, IntArray &sizes)
  6957. {
  6958. ForEachItemIn(idx, sizes)
  6959. {
  6960. if (sizes.item(idx)==size)
  6961. return true;
  6962. }
  6963. return false;
  6964. }
  6965. void CLocalWUResult::getSchema(TypeInfoArray &types, StringAttrArray &names, IStringVal * eclText) const
  6966. {
  6967. MemoryBuffer schema;
  6968. p->getPropBin("SchemaRaw", schema);
  6969. if (schema.length())
  6970. {
  6971. for (;;)
  6972. {
  6973. StringAttr name;
  6974. schema.read(name);
  6975. if (*schema.readDirect(0)==type_void)
  6976. break;
  6977. names.append(*new StringAttrItem(name));
  6978. types.append(*deserializeType(schema)); // MORE - nested records!
  6979. }
  6980. schema.skip(1);
  6981. if (schema.length() != schema.getPos())
  6982. {
  6983. unsigned eclLen;
  6984. schema.read(eclLen);
  6985. const char * schemaData = (const char *)schema.readDirect(eclLen);
  6986. if (eclText)
  6987. {
  6988. eclText->setLen(schemaData, eclLen);
  6989. if ((eclLen == 0) && names.ordinality())
  6990. {
  6991. const char * firstName = names.item(0).text;
  6992. StringBuffer temp;
  6993. temp.append("RECORD ");
  6994. types.item(0).getECLType(temp);
  6995. temp.append(" value{NAMED('").append(firstName).append("')}").append("; END;");
  6996. eclText->set(temp.str());
  6997. }
  6998. }
  6999. }
  7000. }
  7001. }
  7002. void readRow(StringBuffer &out, MemoryBuffer &in, TypeInfoArray &types, StringAttrArray &names)
  7003. {
  7004. ForEachItemIn(idx, types)
  7005. {
  7006. StringAttrItem &name = names.item(idx);
  7007. ITypeInfo &type = types.item(idx);
  7008. unsigned size = type.getSize();
  7009. switch(type.getTypeCode())
  7010. {
  7011. case type_data:
  7012. if (size==UNKNOWN_LENGTH)
  7013. {
  7014. if (in.remaining() < sizeof(int))
  7015. throw MakeStringException(WUERR_CorruptResult, "corrupt workunit information");
  7016. in.read(size);
  7017. }
  7018. outputXmlData(size, in.readDirect(size), name.text, out);
  7019. break;
  7020. case type_string:
  7021. if (size==UNKNOWN_LENGTH)
  7022. {
  7023. if (in.remaining() < sizeof(int))
  7024. throw MakeStringException(WUERR_CorruptResult, "corrupt workunit information");
  7025. in.read(size);
  7026. }
  7027. outputXmlString(size, (const char *) in.readDirect(size), name.text, out);
  7028. break;
  7029. case type_varstring:
  7030. {
  7031. if (size == UNKNOWN_LENGTH)
  7032. size = (size32_t)strlen((const char *) in.readDirect(0))+1;
  7033. const char * text = (const char *) in.readDirect(size);
  7034. outputXmlString((size32_t)strlen(text), text, name.text, out);
  7035. break;
  7036. }
  7037. case type_unicode:
  7038. {
  7039. unsigned len = type.getStringLen();
  7040. if (size==UNKNOWN_LENGTH)
  7041. in.read(len);
  7042. outputXmlUnicode(len, (UChar const *) in.readDirect(len*2), name.text, out);
  7043. }
  7044. break;
  7045. case type_utf8:
  7046. {
  7047. unsigned len = type.getStringLen();
  7048. if (size==UNKNOWN_LENGTH)
  7049. {
  7050. in.read(len);
  7051. size = rtlUtf8Size(len, in.readDirect(0));
  7052. }
  7053. outputXmlUtf8(len, (const char *) in.readDirect(size), name.text, out);
  7054. }
  7055. break;
  7056. case type_qstring:
  7057. {
  7058. unsigned len = type.getStringLen();
  7059. if (size==UNKNOWN_LENGTH)
  7060. in.read(len);
  7061. unsigned outlen;
  7062. char *outstr;
  7063. rtlQStrToStrX(outlen, outstr, len, (const char *) in.readDirect(rtlQStrSize(len)));
  7064. outputXmlString(outlen, outstr, name.text, out);
  7065. free(outstr);
  7066. break;
  7067. }
  7068. case type_int:
  7069. case type_swapint:
  7070. if (type.isSigned())
  7071. {
  7072. const unsigned char *raw = (const unsigned char *) in.readDirect(size);
  7073. unsigned __int64 cval8 = 0;
  7074. //MORE: I think this is wrong - swapped doesn't mean little/big/
  7075. if (type.isSwappedEndian())
  7076. {
  7077. unsigned idx = 0;
  7078. if (raw[idx] & 0x80)
  7079. cval8 = (__int64)-1;
  7080. while (size--)
  7081. cval8 = (cval8 << 8) | raw[idx++];
  7082. }
  7083. else
  7084. {
  7085. if (raw[size-1] & 0x80)
  7086. cval8 = (__int64)-1;
  7087. while (size--)
  7088. cval8 = (cval8 << 8) | raw[size];
  7089. }
  7090. outputXmlInt((__int64) cval8, name.text, out);
  7091. }
  7092. else
  7093. {
  7094. const unsigned char *raw = (const unsigned char *) in.readDirect(size);
  7095. unsigned __int64 cval8 = 0;
  7096. if (type.isSwappedEndian())
  7097. {
  7098. unsigned idx = 0;
  7099. while (size--)
  7100. cval8 = (cval8 << 8) | raw[idx++];
  7101. }
  7102. else
  7103. {
  7104. while (size--)
  7105. cval8 = (cval8 << 8) | raw[size];
  7106. }
  7107. outputXmlUInt(cval8, name.text, out);
  7108. }
  7109. break;
  7110. case type_boolean:
  7111. bool cvalb;
  7112. in.read(cvalb);
  7113. outputXmlBool(cvalb, name.text, out);
  7114. break;
  7115. case type_decimal:
  7116. if (type.isSigned())
  7117. outputXmlDecimal(in.readDirect(size), size, type.getPrecision(), name.text, out);
  7118. else
  7119. outputXmlUDecimal(in.readDirect(size), size, type.getPrecision(), name.text, out);
  7120. break;
  7121. case type_real:
  7122. double cvald;
  7123. switch(size)
  7124. {
  7125. case 4:
  7126. float cvalf;
  7127. in.read(cvalf);
  7128. cvald = cvalf;
  7129. break;
  7130. case 8:
  7131. in.read(cvald);
  7132. break;
  7133. }
  7134. outputXmlReal(cvald, name.text, out);
  7135. break;
  7136. default:
  7137. assertex(!"unexpected type in raw record");
  7138. break;
  7139. }
  7140. }
  7141. }
  7142. IStringVal& CLocalWUResult::getResultXml(IStringVal &str, bool hidePassword) const
  7143. {
  7144. TypeInfoArray types;
  7145. StringAttrArray names;
  7146. getSchema(types, names);
  7147. StringBuffer xml;
  7148. const char * name = p->queryProp("@name");
  7149. if (name)
  7150. xml.appendf("<Dataset name=\'%s\'>\n", name);
  7151. else
  7152. xml.append("<Dataset>\n");
  7153. if (hidePassword && p->getPropBool("Format/@password"))
  7154. {
  7155. xml.append(" <Row>");
  7156. appendXMLTag(xml, name, "****");
  7157. xml.append("</Row>\n");
  7158. }
  7159. else if (p->hasProp("Value"))
  7160. {
  7161. MemoryBuffer raw;
  7162. p->getPropBin("Value", raw);
  7163. unsigned __int64 numrows = getResultRowCount();
  7164. while (numrows--)
  7165. {
  7166. xml.append(" <Row>");
  7167. readRow(xml, raw, types, names);
  7168. xml.append("</Row>\n");
  7169. }
  7170. }
  7171. else if (p->hasProp("xmlValue"))
  7172. {
  7173. xml.append(" <Row>");
  7174. appendXMLTag(xml, name, p->queryProp("xmlValue"));
  7175. xml.append("</Row>\n");
  7176. }
  7177. xml.append("</Dataset>\n");
  7178. str.set(xml.str());
  7179. return str;
  7180. }
  7181. IProperties *CLocalWUResult::queryResultXmlns()
  7182. {
  7183. CriticalBlock block(crit);
  7184. if (xmlns)
  7185. return xmlns;
  7186. xmlns.setown(createProperties());
  7187. Owned<IAttributeIterator> it = p->getAttributes();
  7188. unsigned prefixLen = strlen("@xmlns");
  7189. ForEach(*it)
  7190. {
  7191. const char *name = it->queryName();
  7192. if (!strncmp("@xmlns", name, prefixLen))
  7193. {
  7194. if (name[prefixLen]==':') //normal case
  7195. xmlns->setProp(name+prefixLen+1, it->queryValue());
  7196. else if (!name[prefixLen]) //special case, unprefixed namespace
  7197. xmlns->setProp("xmlns", it->queryValue());
  7198. }
  7199. }
  7200. return xmlns;
  7201. }
  7202. unsigned CLocalWUResult::getResultFetchSize() const
  7203. {
  7204. return p->getPropInt("fetchSize", 100);
  7205. }
  7206. __int64 CLocalWUResult::getResultTotalRowCount() const
  7207. {
  7208. return p->getPropInt64("totalRowCount", -1);
  7209. }
  7210. __int64 CLocalWUResult::getResultRowCount() const
  7211. {
  7212. return p->getPropInt64("rowCount", 0);
  7213. }
  7214. void CLocalWUResult::getResultDataset(IStringVal & ecl, IStringVal & defs) const
  7215. {
  7216. ecl.set(p->queryProp("datasetEcl"));
  7217. defs.set(p->queryProp("datasetEclDefs"));
  7218. }
  7219. IStringVal& CLocalWUResult::getResultLogicalName(IStringVal & val) const
  7220. {
  7221. val.set(p->queryProp("logicalName"));
  7222. return val;
  7223. }
  7224. IStringVal& CLocalWUResult::getResultKeyField(IStringVal & ecl) const
  7225. {
  7226. ecl.set(p->queryProp("keyField"));
  7227. return ecl;
  7228. }
  7229. unsigned CLocalWUResult::getResultRequestedRows() const
  7230. {
  7231. return p->getPropInt("requestedRows", 1);
  7232. }
  7233. IStringVal& CLocalWUResult::getResultEclSchema(IStringVal & str) const
  7234. {
  7235. TypeInfoArray types;
  7236. StringAttrArray names;
  7237. getSchema(types, names, &str);
  7238. return str;
  7239. }
  7240. IStringVal& CLocalWUResult::getResultRecordSizeEntry(IStringVal & str) const
  7241. {
  7242. str.set(p->queryProp("@recordSizeEntry"));
  7243. return str;
  7244. }
  7245. IStringVal& CLocalWUResult::getResultTransformerEntry(IStringVal & str) const
  7246. {
  7247. str.set(p->queryProp("@transformerEntry"));
  7248. return str;
  7249. }
  7250. __int64 CLocalWUResult::getResultRowLimit() const
  7251. {
  7252. return p->getPropInt64("@rowLimit");
  7253. }
  7254. IStringVal& CLocalWUResult::getResultFilename(IStringVal & str) const
  7255. {
  7256. str.set(p->queryProp("@tempFilename"));
  7257. return str;
  7258. }
  7259. IStringVal& CLocalWUResult::getResultFieldOpt(const char *name, IStringVal &str) const
  7260. {
  7261. str.clear();
  7262. if (!name || !*name)
  7263. return str;
  7264. IPropertyTree *format = p->queryPropTree("Format");
  7265. if (!format)
  7266. return str;
  7267. VStringBuffer xpath("@%s", name);
  7268. str.set(format->queryProp(xpath));
  7269. return str;
  7270. }
  7271. void CLocalWUResult::setResultStatus(WUResultStatus status)
  7272. {
  7273. setEnum(p, "@status", status, resultStatuses);
  7274. if (status==ResultStatusUndefined)
  7275. p->removeProp("Value");
  7276. }
  7277. void CLocalWUResult::setResultName(const char *s)
  7278. {
  7279. p->setProp("@name", s);
  7280. }
  7281. void CLocalWUResult::setResultSequence(unsigned seq)
  7282. {
  7283. p->setPropInt("@sequence", seq);
  7284. }
  7285. void CLocalWUResult::setResultSchemaRaw(unsigned size, const void *schema)
  7286. {
  7287. p->setPropBin("SchemaRaw", size, schema);
  7288. }
  7289. void CLocalWUResult::setResultXmlns(const char *prefix, const char *uri)
  7290. {
  7291. StringBuffer xpath("@xmlns");
  7292. if (prefix && *prefix)
  7293. xpath.append(':').append(prefix);
  7294. p->setProp(xpath, uri);
  7295. }
  7296. void CLocalWUResult::setResultFieldOpt(const char *name, const char *value)
  7297. {
  7298. if (!name || !*name)
  7299. return;
  7300. IPropertyTree *format = ensurePTree(p, "Format");
  7301. VStringBuffer xpath("@%s", name);
  7302. format->setProp(xpath, value);
  7303. }
  7304. void CLocalWUResult::setResultScalar(bool isScalar)
  7305. {
  7306. p->setPropInt("@isScalar", (int) isScalar);
  7307. if (isScalar)
  7308. setResultTotalRowCount(1);
  7309. }
  7310. void CLocalWUResult::setResultRaw(unsigned len, const void *data, WUResultFormat format)
  7311. {
  7312. p->setPropBin("Value", len, data);
  7313. setResultStatus(ResultStatusSupplied);
  7314. setResultFormat(format);
  7315. }
  7316. void CLocalWUResult::setResultFormat(WUResultFormat format)
  7317. {
  7318. switch (format)
  7319. {
  7320. case ResultFormatXml:
  7321. p->setProp("@format","xml");
  7322. break;
  7323. case ResultFormatXmlSet:
  7324. p->setProp("@format","xmlSet");
  7325. break;
  7326. case ResultFormatCsv:
  7327. p->setProp("@format","csv");
  7328. break;
  7329. default:
  7330. p->removeProp("@format");
  7331. break;
  7332. }
  7333. }
  7334. void CLocalWUResult::setResultXML(const char *val)
  7335. {
  7336. p->setProp("xmlValue", val);
  7337. }
  7338. void CLocalWUResult::addResultRaw(unsigned len, const void *data, WUResultFormat format)
  7339. {
  7340. p->appendPropBin("Value", len, data);
  7341. setResultStatus(ResultStatusPartial);
  7342. const char *existingFormat = p->queryProp("@format");
  7343. const char *formatStr = NULL;
  7344. switch (format)
  7345. {
  7346. case ResultFormatXml:
  7347. formatStr = "xml";
  7348. break;
  7349. case ResultFormatXmlSet:
  7350. formatStr = "xmlSet";
  7351. break;
  7352. case ResultFormatCsv:
  7353. formatStr = "csv";
  7354. break;
  7355. default:
  7356. p->removeProp("@format");
  7357. break;
  7358. }
  7359. if (format)
  7360. {
  7361. if (existingFormat)
  7362. {
  7363. if (0 != stricmp(formatStr, existingFormat))
  7364. throw MakeStringException(WUERR_ResultFormatMismatch, "addResult format %s, does not match existing format %s", formatStr, existingFormat);
  7365. }
  7366. else
  7367. p->setProp("@format", formatStr);
  7368. }
  7369. }
  7370. void CLocalWUResult::setResultFetchSize(unsigned rows)
  7371. {
  7372. p->setPropInt("fetchSize", rows);
  7373. }
  7374. void CLocalWUResult::setResultTotalRowCount(__int64 rows)
  7375. {
  7376. p->setPropInt64("totalRowCount", rows);
  7377. }
  7378. void CLocalWUResult::setResultRowCount(__int64 rows)
  7379. {
  7380. p->setPropInt64("rowCount", rows);
  7381. }
  7382. void CLocalWUResult::setResultDataset(const char *ecl, const char *defs)
  7383. {
  7384. p->setProp("datasetEcl", ecl);
  7385. p->setProp("datasetEclDefs", defs);
  7386. }
  7387. void CLocalWUResult::setResultLogicalName(const char *logicalName)
  7388. {
  7389. p->setProp("logicalName", logicalName);
  7390. }
  7391. void CLocalWUResult::setResultKeyField(const char *ecl)
  7392. {
  7393. p->setProp("keyField", ecl);
  7394. }
  7395. void CLocalWUResult::setResultRequestedRows(unsigned rows)
  7396. {
  7397. p->setPropInt("requestedRows", rows);
  7398. }
  7399. void CLocalWUResult::setResultRecordSizeEntry(const char * entry)
  7400. {
  7401. p->setProp("@recordSizeEntry", entry);
  7402. }
  7403. void CLocalWUResult::setResultTransformerEntry(const char * entry)
  7404. {
  7405. p->setProp("@transformerEntry", entry);
  7406. }
  7407. void CLocalWUResult::setResultRowLimit(__int64 value)
  7408. {
  7409. p->setPropInt64("@rowLimit", value);
  7410. }
  7411. void CLocalWUResult::setResultFilename(const char * name)
  7412. {
  7413. p->setProp("@tempFilename", name);
  7414. }
  7415. // MORE - it's an undetected error if we call getResult... of a type that does not match schema
  7416. __int64 CLocalWUResult::getResultInt() const
  7417. {
  7418. __int64 result = 0;
  7419. MemoryBuffer s;
  7420. p->getPropBin("Value", s);
  7421. if (s.length())
  7422. s.read(result);
  7423. else
  7424. result = p->getPropInt64("xmlValue");
  7425. return result;
  7426. }
  7427. bool CLocalWUResult::getResultBool() const
  7428. {
  7429. bool result = false;
  7430. MemoryBuffer s;
  7431. p->getPropBin("Value", s);
  7432. if (s.length())
  7433. s.read(result);
  7434. else
  7435. result = p->getPropBool("xmlValue");
  7436. return result;
  7437. }
  7438. double CLocalWUResult::getResultReal() const
  7439. {
  7440. double result = 0;
  7441. MemoryBuffer s;
  7442. p->getPropBin("Value", s);
  7443. if (s.length())
  7444. s.read(result);
  7445. else
  7446. {
  7447. const char *xmlVal = p->queryProp("xmlValue");
  7448. if (xmlVal)
  7449. result = atof(xmlVal);
  7450. }
  7451. return result;
  7452. }
  7453. void CLocalWUResult::getResultDecimal(void * val, unsigned len, unsigned precision, bool isSigned) const
  7454. {
  7455. MemoryBuffer s;
  7456. p->getPropBin("Value", s);
  7457. if (s.length())
  7458. {
  7459. assertex(s.length() == len);
  7460. s.read(len, val);
  7461. }
  7462. else
  7463. {
  7464. const char *xmlVal = p->queryProp("xmlValue");
  7465. if (xmlVal)
  7466. {
  7467. Decimal d;
  7468. d.setString(strlen(xmlVal), xmlVal);
  7469. if (isSigned)
  7470. d.getDecimal(len, precision, val);
  7471. else
  7472. d.getUDecimal(len, precision, val);
  7473. }
  7474. else
  7475. memset(val, 0, len);
  7476. }
  7477. }
  7478. IStringVal& CLocalWUResult::getResultString(IStringVal & str, bool hidePassword) const
  7479. {
  7480. if (hidePassword && p->getPropBool("@password"))
  7481. {
  7482. str.set("****");
  7483. return str;
  7484. }
  7485. MemoryBuffer s;
  7486. p->getPropBin("Value", s);
  7487. if (s.length())
  7488. {
  7489. unsigned len;
  7490. s.read(len);
  7491. str.setLen((const char *) s.readDirect(len), len);
  7492. }
  7493. else
  7494. {
  7495. p->getPropBin("xmlValue", s);
  7496. if (p->isBinary("xmlValue"))
  7497. str.setLen(s.toByteArray(), s.length());
  7498. else
  7499. {
  7500. char *ascii = rtlUtf8ToVStr(rtlUtf8Length(s.length(), s.toByteArray()), s.toByteArray());
  7501. str.set(ascii);
  7502. rtlFree(ascii);
  7503. }
  7504. }
  7505. return str;
  7506. }
  7507. WUResultFormat CLocalWUResult::getResultFormat() const
  7508. {
  7509. const char * format = p->queryProp("@format");
  7510. if (!format)
  7511. return ResultFormatRaw;
  7512. else if (strcmp(format, "xml") == 0)
  7513. return ResultFormatXml;
  7514. else if (strcmp(format, "xmlSet") == 0)
  7515. return ResultFormatXmlSet;
  7516. else if (strcmp(format, "csv") == 0)
  7517. return ResultFormatCsv;
  7518. else
  7519. throw MakeStringException(WUERR_InvalidResultFormat, "Unrecognised result format %s", format);
  7520. }
  7521. IDataVal& CLocalWUResult::getResultRaw(IDataVal & data, IXmlToRawTransformer * xmlTransformer, ICsvToRawTransformer * csvTransformer) const
  7522. {
  7523. MemoryBuffer s;
  7524. p->getPropBin("Value", s);
  7525. unsigned len = s.length();
  7526. if (len)
  7527. {
  7528. WUResultFormat format = getResultFormat();
  7529. if (format == ResultFormatXml || format == ResultFormatXmlSet)
  7530. {
  7531. if (!xmlTransformer)
  7532. throw MakeStringException(WUERR_MissingFormatTranslator, "No transformer supplied to translate XML format result");
  7533. xmlTransformer->transform(data, len, s.readDirect(len), format == ResultFormatXml);
  7534. }
  7535. else if (format == ResultFormatCsv)
  7536. {
  7537. if (!csvTransformer)
  7538. throw MakeStringException(WUERR_MissingFormatTranslator, "No transformer supplied to translate Csv format result");
  7539. csvTransformer->transform(data, len, s.readDirect(len), true);
  7540. }
  7541. else
  7542. data.setLen(s.readDirect(len), len);
  7543. }
  7544. else
  7545. data.clear();
  7546. return data;
  7547. }
  7548. unsigned CLocalWUResult::getResultHash() const
  7549. {
  7550. MemoryBuffer s;
  7551. p->getPropBin("Value", s);
  7552. unsigned len = s.length();
  7553. const byte * data = (const byte *)s.toByteArray();
  7554. return ~hashc(data, len, ~0);
  7555. }
  7556. IDataVal& CLocalWUResult::getResultUnicode(IDataVal & data) const
  7557. {
  7558. MemoryBuffer s;
  7559. p->getPropBin("Value", s);
  7560. if (s.length())
  7561. {
  7562. unsigned len;
  7563. s.read(len);
  7564. data.setLen(s.readDirect(len*2), len*2);
  7565. }
  7566. else
  7567. {
  7568. StringBuffer utf8;
  7569. if (p->getProp("xmlValue", utf8))
  7570. {
  7571. unsigned outlen;
  7572. UChar *out;
  7573. rtlUtf8ToUnicodeX(outlen, out, utf8.length(), utf8.str());
  7574. data.setLen(out, outlen*2);
  7575. rtlFree(out);
  7576. }
  7577. else
  7578. data.clear();
  7579. }
  7580. return data;
  7581. }
  7582. __int64 CLocalWUResult::getResultRawSize(IXmlToRawTransformer * xmlTransformer, ICsvToRawTransformer * csvTransformer) const
  7583. {
  7584. WUResultFormat format = getResultFormat();
  7585. if (format == ResultFormatRaw)
  7586. {
  7587. //MORE: This should not load the whole property...
  7588. MemoryBuffer s;
  7589. p->getPropBin("Value", s);
  7590. return s.length();
  7591. }
  7592. else
  7593. {
  7594. MemoryBuffer temp;
  7595. MemoryBuffer2IDataVal adaptor(temp);
  7596. getResultRaw(adaptor, xmlTransformer, csvTransformer);
  7597. return temp.length();
  7598. }
  7599. }
  7600. IDataVal& CLocalWUResult::getResultRaw(IDataVal & data, __int64 from, __int64 length, IXmlToRawTransformer * xmlTransformer, ICsvToRawTransformer * csvTransformer) const
  7601. {
  7602. WUResultFormat format = getResultFormat();
  7603. if (format != ResultFormatRaw)
  7604. {
  7605. MemoryBuffer temp;
  7606. MemoryBuffer2IDataVal adaptor(temp);
  7607. getResultRaw(adaptor, xmlTransformer, csvTransformer);
  7608. unsigned len = temp.length();
  7609. if (from > len) from = len;
  7610. if (from + length > len) length = len - from;
  7611. data.setLen(temp.readDirect(len) + from, (size32_t)length);
  7612. return data;
  7613. }
  7614. else
  7615. {
  7616. //MORE: This should not load the whole property, and should be different from the code above...
  7617. MemoryBuffer s;
  7618. p->getPropBin("Value", s);
  7619. unsigned len = s.length();
  7620. if (from > len) from = len;
  7621. if (from + length > len) length = len - from;
  7622. data.setLen(s.readDirect(len) + from, (size32_t)length);
  7623. return data;
  7624. }
  7625. }
  7626. bool CLocalWUResult::getResultIsAll() const
  7627. {
  7628. return p->getPropBool("@isAll", false);
  7629. }
  7630. // MORE - it's an undetected error if we call setResult... of a type that does not match schema
  7631. void CLocalWUResult::setResultInt(__int64 val)
  7632. {
  7633. // Note: we always serialize scalar integer results as int8, and schema must reflect this
  7634. MemoryBuffer m;
  7635. serializeInt8(val, m);
  7636. p->setPropBin("Value", m.length(), m.toByteArray());
  7637. setResultRowCount(1);
  7638. setResultTotalRowCount(1);
  7639. }
  7640. void CLocalWUResult::setResultUInt(unsigned __int64 val)
  7641. {
  7642. setResultInt((__int64) val);
  7643. }
  7644. void CLocalWUResult::setResultReal(double val)
  7645. {
  7646. // Note: we always serialize scalar real results as real8, and schema must reflect this
  7647. MemoryBuffer m;
  7648. serializeReal8(val, m);
  7649. p->setPropBin("Value", m.length(), m.toByteArray());
  7650. setResultRowCount(1);
  7651. setResultTotalRowCount(1);
  7652. }
  7653. void CLocalWUResult::setResultBool(bool val)
  7654. {
  7655. MemoryBuffer m;
  7656. serializeBool(val, m);
  7657. p->setPropBin("Value", m.length(), m.toByteArray());
  7658. setResultRowCount(1);
  7659. setResultTotalRowCount(1);
  7660. }
  7661. void CLocalWUResult::setResultString(const char *val, unsigned len)
  7662. {
  7663. // Note: we always serialize scalar strings with length prefix, and schema must reflect this
  7664. MemoryBuffer m;
  7665. serializeLPString(len, val, m);
  7666. p->setPropBin("Value", m.length(), m.toByteArray());
  7667. setResultRowCount(1);
  7668. setResultTotalRowCount(1);
  7669. }
  7670. void CLocalWUResult::setResultUnicode(const void *val, unsigned len)
  7671. {
  7672. // Note: we always serialize scalar strings with length prefix, and schema must reflect this
  7673. MemoryBuffer m;
  7674. m.append(len).append(len*2, val);
  7675. p->setPropBin("Value", m.length(), m.toByteArray());
  7676. setResultRowCount(1);
  7677. setResultTotalRowCount(1);
  7678. }
  7679. void CLocalWUResult::setResultData(const void *val, unsigned len)
  7680. {
  7681. // Note: we always serialize scalar data with length prefix, and schema must reflect this
  7682. MemoryBuffer m;
  7683. serializeLPString(len, (const char *)val, m);
  7684. p->setPropBin("Value", m.length(), m.toByteArray());
  7685. setResultRowCount(1);
  7686. setResultTotalRowCount(1);
  7687. }
  7688. void CLocalWUResult::setResultDecimal(const void *val, unsigned len)
  7689. {
  7690. // Note: serialized as data but with length known from schema
  7691. MemoryBuffer m;
  7692. serializeFixedData(len, val, m);
  7693. p->setPropBin("Value", m.length(), m.toByteArray());
  7694. setResultRowCount(1);
  7695. setResultTotalRowCount(1);
  7696. }
  7697. void CLocalWUResult::setResultRow(unsigned len, const void * data)
  7698. {
  7699. p->setPropBin("Value", len, data);
  7700. setResultRowCount(1);
  7701. setResultTotalRowCount(1);
  7702. setResultFormat(ResultFormatRaw);
  7703. }
  7704. void CLocalWUResult::setResultIsAll(bool value)
  7705. {
  7706. p->setPropBool("@isAll", value);
  7707. }
  7708. //==========================================================================================
  7709. CLocalWUPlugin::CLocalWUPlugin(IPropertyTree *props) : p(props)
  7710. {
  7711. }
  7712. IStringVal& CLocalWUPlugin::getPluginName(IStringVal &str) const
  7713. {
  7714. str.set(p->queryProp("@dllname"));
  7715. return str;
  7716. }
  7717. IStringVal& CLocalWUPlugin::getPluginVersion(IStringVal &str) const
  7718. {
  7719. str.set(p->queryProp("@version"));
  7720. return str;
  7721. }
  7722. void CLocalWUPlugin::setPluginName(const char *str)
  7723. {
  7724. p->setProp("@dllname", str);
  7725. }
  7726. void CLocalWUPlugin::setPluginVersion(const char *str)
  7727. {
  7728. p->setProp("@version", str);
  7729. }
  7730. //==========================================================================================
  7731. CLocalWULibrary::CLocalWULibrary(IPropertyTree *props) : p(props)
  7732. {
  7733. }
  7734. IStringVal& CLocalWULibrary::getName(IStringVal &str) const
  7735. {
  7736. str.set(p->queryProp("@name"));
  7737. return str;
  7738. }
  7739. void CLocalWULibrary::setName(const char *str)
  7740. {
  7741. p->setProp("@name", str);
  7742. }
  7743. //==========================================================================================
  7744. CLocalWUException::CLocalWUException(IPropertyTree *props) : p(props)
  7745. {
  7746. }
  7747. IStringVal& CLocalWUException::getExceptionSource(IStringVal &str) const
  7748. {
  7749. str.set(p->queryProp("@source"));
  7750. return str;
  7751. }
  7752. IStringVal& CLocalWUException::getExceptionMessage(IStringVal &str) const
  7753. {
  7754. str.set(p->queryProp(NULL));
  7755. return str;
  7756. }
  7757. unsigned CLocalWUException::getExceptionCode() const
  7758. {
  7759. return p->getPropInt("@code", 0);
  7760. }
  7761. ErrorSeverity CLocalWUException::getSeverity() const
  7762. {
  7763. return (ErrorSeverity)p->getPropInt("@severity", SeverityError);
  7764. }
  7765. IStringVal & CLocalWUException::getTimeStamp(IStringVal & dt) const
  7766. {
  7767. dt.set(p->queryProp("@time"));
  7768. return dt;
  7769. }
  7770. IStringVal & CLocalWUException::getExceptionFileName(IStringVal & str) const
  7771. {
  7772. str.set(p->queryProp("@filename"));
  7773. return str;
  7774. }
  7775. unsigned CLocalWUException::getExceptionLineNo() const
  7776. {
  7777. return p->getPropInt("@row", 0);
  7778. }
  7779. unsigned CLocalWUException::getExceptionColumn() const
  7780. {
  7781. return p->getPropInt("@col", 0);
  7782. }
  7783. void CLocalWUException::setExceptionSource(const char *str)
  7784. {
  7785. p->setProp("@source", str);
  7786. }
  7787. void CLocalWUException::setExceptionMessage(const char *str)
  7788. {
  7789. p->setProp(NULL, str);
  7790. }
  7791. void CLocalWUException::setExceptionCode(unsigned code)
  7792. {
  7793. p->setPropInt("@code", code);
  7794. }
  7795. void CLocalWUException::setSeverity(ErrorSeverity level)
  7796. {
  7797. p->setPropInt("@severity", level);
  7798. }
  7799. void CLocalWUException::setTimeStamp(const char *str)
  7800. {
  7801. p->setProp("@time", str);
  7802. }
  7803. void CLocalWUException::setExceptionFileName(const char *str)
  7804. {
  7805. p->setProp("@filename", str);
  7806. }
  7807. void CLocalWUException::setExceptionLineNo(unsigned r)
  7808. {
  7809. p->setPropInt("@row", r);
  7810. }
  7811. void CLocalWUException::setExceptionColumn(unsigned c)
  7812. {
  7813. p->setPropInt("@col", c);
  7814. }
  7815. //==========================================================================================
  7816. CLocalWUAppValue::CLocalWUAppValue(IPropertyTree *props,unsigned child): p(props)
  7817. {
  7818. StringAttrBuilder propPath(prop);
  7819. propPath.append("*[").append(child).append("]");
  7820. }
  7821. IStringVal & CLocalWUAppValue::getApplication(IStringVal & str) const
  7822. {
  7823. str.set(p->queryName());
  7824. return str;
  7825. }
  7826. IStringVal & CLocalWUAppValue::getName(IStringVal & str) const
  7827. {
  7828. IPropertyTree* val=p->queryPropTree(prop.str());
  7829. if(val)
  7830. str.set(val->queryName());
  7831. return str;
  7832. }
  7833. IStringVal & CLocalWUAppValue::getValue(IStringVal & str) const
  7834. {
  7835. str.set(p->queryProp(prop.str()));
  7836. return str;
  7837. }
  7838. //==========================================================================================
  7839. CLocalWUStatistic::CLocalWUStatistic(IPropertyTree *props) : p(props)
  7840. {
  7841. }
  7842. IStringVal & CLocalWUStatistic::getCreator(IStringVal & str) const
  7843. {
  7844. const char * creator = p->queryProp("@creator");
  7845. str.set(creator);
  7846. return str;
  7847. }
  7848. IStringVal & CLocalWUStatistic::getDescription(IStringVal & str, bool createDefault) const
  7849. {
  7850. const char * desc = p->queryProp("@desc");
  7851. if (desc)
  7852. {
  7853. str.set(desc); // legacy and in case it is overridden
  7854. }
  7855. else if (createDefault)
  7856. {
  7857. StatisticKind kind = getKind();
  7858. assertex(kind != StKindNone);
  7859. const char * scope = p->queryProp("@scope");
  7860. assertex(scope);
  7861. //Clean up the format of the scope when converting it to a description
  7862. StringBuffer descriptionText;
  7863. if (streq(scope, GLOBAL_SCOPE))
  7864. {
  7865. const char * creator = p->queryProp("@creator");
  7866. descriptionText.append(creator).append(":");
  7867. queryLongStatisticName(descriptionText, kind);
  7868. }
  7869. else
  7870. {
  7871. loop
  7872. {
  7873. char c = *scope++;
  7874. if (!c)
  7875. break;
  7876. if (c == ':')
  7877. descriptionText.append(": ");
  7878. else
  7879. descriptionText.append(c);
  7880. }
  7881. if (kind != StTimeElapsed)
  7882. queryLongStatisticName(descriptionText.append(": "), kind);
  7883. }
  7884. str.set(descriptionText);
  7885. }
  7886. else
  7887. str.clear();
  7888. return str;
  7889. }
  7890. IStringVal & CLocalWUStatistic::getType(IStringVal & str) const
  7891. {
  7892. StatisticKind kind = getKind();
  7893. if (kind != StKindNone)
  7894. str.set(queryStatisticName(kind));
  7895. return str;
  7896. }
  7897. IStringVal & CLocalWUStatistic::getFormattedValue(IStringVal & str) const
  7898. {
  7899. StringBuffer formatted;
  7900. formatStatistic(formatted, getValue(), getMeasure());
  7901. str.set(formatted);
  7902. return str;
  7903. }
  7904. StatisticCreatorType CLocalWUStatistic::getCreatorType() const
  7905. {
  7906. return queryCreatorType(p->queryProp("@c"));
  7907. }
  7908. StatisticScopeType CLocalWUStatistic::getScopeType() const
  7909. {
  7910. return queryScopeType(p->queryProp("@s"));
  7911. }
  7912. StatisticKind CLocalWUStatistic::getKind() const
  7913. {
  7914. return queryStatisticKind(p->queryProp("@kind"));
  7915. }
  7916. IStringVal & CLocalWUStatistic::getScope(IStringVal & str) const
  7917. {
  7918. const char * scope = p->queryProp("@scope");
  7919. str.set(scope);
  7920. return str;
  7921. }
  7922. StatisticMeasure CLocalWUStatistic::getMeasure() const
  7923. {
  7924. return queryMeasure(p->queryProp("@unit"));
  7925. }
  7926. unsigned __int64 CLocalWUStatistic::getValue() const
  7927. {
  7928. return p->getPropInt64("@value", 0);
  7929. }
  7930. unsigned __int64 CLocalWUStatistic::getCount() const
  7931. {
  7932. return p->getPropInt64("@count", 0);
  7933. }
  7934. unsigned __int64 CLocalWUStatistic::getMax() const
  7935. {
  7936. return p->getPropInt64("@max", 0);
  7937. }
  7938. unsigned __int64 CLocalWUStatistic::getTimestamp() const
  7939. {
  7940. return p->getPropInt64("@ts", 0);
  7941. }
  7942. bool CLocalWUStatistic::matches(const IStatisticsFilter * filter) const
  7943. {
  7944. if (!filter)
  7945. return true;
  7946. const char * creator = p->queryProp("@creator");
  7947. const char * scope = p->queryProp("@scope");
  7948. return filter->matches(getCreatorType(), creator, getScopeType(), scope, getMeasure(), getKind());
  7949. }
  7950. //==========================================================================================
  7951. CLocalWULegacyTiming::CLocalWULegacyTiming(IPropertyTree *props) : p(props)
  7952. {
  7953. }
  7954. IStringVal & CLocalWULegacyTiming::getCreator(IStringVal & str) const
  7955. {
  7956. str.clear();
  7957. return str;
  7958. }
  7959. IStringVal & CLocalWULegacyTiming::getDescription(IStringVal & str, bool createDefault) const
  7960. {
  7961. str.set(p->queryProp("@name"));
  7962. return str;
  7963. }
  7964. IStringVal & CLocalWULegacyTiming::getType(IStringVal & str) const
  7965. {
  7966. str.set(queryStatisticName(StTimeElapsed));
  7967. return str;
  7968. }
  7969. IStringVal & CLocalWULegacyTiming::getFormattedValue(IStringVal & str) const
  7970. {
  7971. StringBuffer formatted;
  7972. formatStatistic(formatted, getValue(), getMeasure());
  7973. str.set(formatted);
  7974. return str;
  7975. }
  7976. StatisticCreatorType CLocalWULegacyTiming::getCreatorType() const
  7977. {
  7978. return SCTunknown;
  7979. }
  7980. StatisticScopeType CLocalWULegacyTiming::getScopeType() const
  7981. {
  7982. return SSTnone;
  7983. }
  7984. StatisticKind CLocalWULegacyTiming::getKind() const
  7985. {
  7986. return StTimeElapsed;
  7987. }
  7988. IStringVal & CLocalWULegacyTiming::getScope(IStringVal & str) const
  7989. {
  7990. str.clear();
  7991. return str;
  7992. }
  7993. StatisticMeasure CLocalWULegacyTiming::getMeasure() const
  7994. {
  7995. return SMeasureTimeNs;
  7996. }
  7997. unsigned __int64 CLocalWULegacyTiming::getValue() const
  7998. {
  7999. return p->getPropInt64("@duration", 0) * 1000000;
  8000. }
  8001. unsigned __int64 CLocalWULegacyTiming::getCount() const
  8002. {
  8003. return p->getPropInt64("@count", 0);
  8004. }
  8005. unsigned __int64 CLocalWULegacyTiming::getMax() const
  8006. {
  8007. return p->getPropInt64("@max", 0);
  8008. }
  8009. unsigned __int64 CLocalWULegacyTiming::getTimestamp() const
  8010. {
  8011. return 0;
  8012. }
  8013. bool CLocalWULegacyTiming::matches(const IStatisticsFilter * filter) const
  8014. {
  8015. if (!filter)
  8016. return true;
  8017. const char * creator = p->queryProp("@creator");
  8018. const char * scope = p->queryProp("@scope");
  8019. return filter->matches(SCTall, NULL, SSTall, NULL, getMeasure(), getKind());
  8020. }
  8021. //==========================================================================================
  8022. extern WORKUNIT_API ILocalWorkUnit * createLocalWorkUnit(const char *xml)
  8023. {
  8024. Owned<CLocalWorkUnit> cw = new CLocalWorkUnit((ISecManager *) NULL, NULL);
  8025. if (xml)
  8026. cw->loadPTree(createPTreeFromXMLString(xml));
  8027. else
  8028. {
  8029. Owned<IPropertyTree> p = createPTree("W_LOCAL");
  8030. p->setProp("@xmlns:xsi", "http://www.w3.org/1999/XMLSchema-instance");
  8031. cw->loadPTree(p.getClear());
  8032. }
  8033. ILocalWorkUnit* ret = QUERYINTERFACE(&cw->lockRemote(false), ILocalWorkUnit);
  8034. return ret;
  8035. }
  8036. void exportWorkUnitToXMLWithHiddenPasswords(IPropertyTree *p, IIOStream &out, unsigned extraXmlFlags)
  8037. {
  8038. const char *name = p->queryName();
  8039. if (!name)
  8040. name = "__unnamed__";
  8041. StringBuffer temp;
  8042. writeStringToStream(out, appendPTreeOpenTag(temp, p, name, 1));
  8043. Owned<IPropertyTreeIterator> elems = p->getElements("*", iptiter_sort);
  8044. ForEach(*elems)
  8045. {
  8046. IPropertyTree &elem = elems->query();
  8047. if (streq(elem.queryName(), "Parameters"))
  8048. {
  8049. writeStringToStream(out, appendPTreeOpenTag(temp.clear().append(' '), &elem, "Parameters", 2).append('\n'));
  8050. Owned<IPropertyTreeIterator> params = elem.getElements("*", iptiter_sort);
  8051. ForEach(*params)
  8052. {
  8053. IPropertyTree &param = params->query();
  8054. const char *paramname = param.queryName();
  8055. VStringBuffer xpath("Variables/Variable[@name='%s']/Format/@password", paramname);
  8056. if (p->getPropBool(xpath))
  8057. writeStringToStream(out, appendXMLTag(temp.clear().append(" "), paramname, "****").append('\n'));
  8058. else
  8059. {
  8060. toXML(&param, out, 2, XML_Format|XML_SortTags|extraXmlFlags);
  8061. }
  8062. }
  8063. writeStringToStream(out, appendXMLCloseTag(temp.clear().append(' '), "Parameters").append('\n'));
  8064. }
  8065. else if (streq(elem.queryName(), "Variables"))
  8066. {
  8067. writeStringToStream(out, appendPTreeOpenTag(temp.clear().append(' '), &elem, "Variables", 2).append('\n'));
  8068. Owned<IPropertyTreeIterator> vars = elem.getElements("*", iptiter_sort);
  8069. ForEach(*vars)
  8070. {
  8071. Owned<IPropertyTree> var = LINK(&vars->query());
  8072. if (var->getPropBool("Format/@password"))
  8073. {
  8074. var.setown(createPTreeFromIPT(var)); //copy and remove password values
  8075. var->removeProp("Value");
  8076. var->removeProp("xmlValue");
  8077. }
  8078. toXML(var, out, 2, XML_Format|XML_SortTags|extraXmlFlags);
  8079. }
  8080. writeStringToStream(out, appendXMLCloseTag(temp.clear().append(' '), "Variables").append('\n'));
  8081. }
  8082. else
  8083. toXML(&elem, out, 1, XML_Format|XML_SortTags|extraXmlFlags);
  8084. }
  8085. writeStringToStream(out, appendXMLCloseTag(temp.clear(), name));
  8086. }
  8087. StringBuffer &exportWorkUnitToXMLWithHiddenPasswords(IPropertyTree *p, StringBuffer &str)
  8088. {
  8089. class CAdapter : public CInterface, implements IIOStream
  8090. {
  8091. StringBuffer &out;
  8092. public:
  8093. IMPLEMENT_IINTERFACE;
  8094. CAdapter(StringBuffer &_out) : out(_out) { }
  8095. virtual void flush() { }
  8096. virtual size32_t read(size32_t len, void * data) { UNIMPLEMENTED; return 0; }
  8097. virtual size32_t write(size32_t len, const void * data) { out.append(len, (const char *)data); return len; }
  8098. } adapter(str);
  8099. exportWorkUnitToXMLWithHiddenPasswords(p->queryBranch(NULL), adapter, 0);
  8100. return str;
  8101. }
  8102. void exportWorkUnitToXMLFileWithHiddenPasswords(IPropertyTree *p, const char *filename, unsigned extraXmlFlags)
  8103. {
  8104. OwnedIFile ifile = createIFile(filename);
  8105. OwnedIFileIO ifileio = ifile->open(IFOcreate);
  8106. Owned<IIOStream> stream = createIOStream(ifileio);
  8107. exportWorkUnitToXMLWithHiddenPasswords(p->queryBranch(NULL), *stream, extraXmlFlags);
  8108. }
  8109. extern WORKUNIT_API StringBuffer &exportWorkUnitToXML(const IConstWorkUnit *wu, StringBuffer &str, bool unpack, bool includeProgress, bool hidePasswords)
  8110. {
  8111. // MORE - queryPTree isn't really safe without holding CLocalWorkUnit::crit - really need to move these functions into CLocalWorkunit
  8112. const IExtendedWUInterface *ewu = queryExtendedWU(wu);
  8113. if (ewu)
  8114. {
  8115. Linked<IPropertyTree> p;
  8116. if (unpack||includeProgress)
  8117. p.setown(ewu->getUnpackedTree(includeProgress));
  8118. else
  8119. p.set(ewu->queryPTree());
  8120. if (hidePasswords && p->hasProp("Variables/Variable[Format/@password]"))
  8121. return exportWorkUnitToXMLWithHiddenPasswords(p, str);
  8122. toXML(p, str, 0, XML_Format|XML_SortTags);
  8123. }
  8124. else
  8125. str.append("Unrecognized workunit format");
  8126. return str;
  8127. }
  8128. extern WORKUNIT_API void exportWorkUnitToXMLFile(const IConstWorkUnit *wu, const char * filename, unsigned extraXmlFlags, bool unpack, bool includeProgress, bool hidePasswords)
  8129. {
  8130. const IExtendedWUInterface *ewu = queryExtendedWU(wu);
  8131. if (ewu)
  8132. {
  8133. Linked<IPropertyTree> p;
  8134. if (unpack||includeProgress)
  8135. p.setown(ewu->getUnpackedTree(includeProgress));
  8136. else
  8137. p.set(ewu->queryPTree());
  8138. if (hidePasswords && p->hasProp("Variables/Variable[Format/@password]"))
  8139. return exportWorkUnitToXMLFileWithHiddenPasswords(p, filename, extraXmlFlags);
  8140. saveXML(filename, p, 0, XML_Format|XML_SortTags|extraXmlFlags);
  8141. }
  8142. else
  8143. throw makeStringException(0, "Unrecognized workunit format");
  8144. }
  8145. extern WORKUNIT_API void submitWorkUnit(const char *wuid, const char *username, const char *password)
  8146. {
  8147. MemoryBuffer buffer;
  8148. Owned<INamedQueueConnection> conn = createNamedQueueConnection(0); // MORE - security token?
  8149. Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
  8150. Owned<IWorkUnit> workunit = factory->updateWorkUnit(wuid);
  8151. assertex(workunit);
  8152. SCMStringBuffer token;
  8153. createToken(wuid, username, password, token);
  8154. workunit->setSecurityToken(token.str());
  8155. StringAttr clusterName(workunit->queryClusterName());
  8156. if (!clusterName.length())
  8157. throw MakeStringException(WUERR_InvalidCluster, "No target cluster specified");
  8158. workunit->commit();
  8159. workunit.clear();
  8160. Owned<IConstWUClusterInfo> clusterInfo = getTargetClusterInfo(clusterName.str());
  8161. if (!clusterInfo)
  8162. throw MakeStringException(WUERR_InvalidCluster, "Unknown cluster %s", clusterName.str());
  8163. SCMStringBuffer serverQueue;
  8164. clusterInfo->getServerQueue(serverQueue);
  8165. assertex(serverQueue.length());
  8166. Owned<IJobQueue> queue = createJobQueue(serverQueue.str());
  8167. if (!queue.get())
  8168. throw MakeStringException(WUERR_InvalidQueue, "Could not create workunit queue");
  8169. IJobQueueItem *item = createJobQueueItem(wuid);
  8170. queue->enqueue(item);
  8171. }
  8172. extern WORKUNIT_API void abortWorkUnit(const char *wuid)
  8173. {
  8174. StringBuffer xpath("/WorkUnitAborts/");
  8175. xpath.append(wuid);
  8176. Owned<IRemoteConnection> acon = querySDS().connect(xpath.str(), myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE, SDS_LOCK_TIMEOUT);
  8177. acon->queryRoot()->setPropInt(NULL, 1);
  8178. }
  8179. extern WORKUNIT_API void secSubmitWorkUnit(const char *wuid, ISecManager &secmgr, ISecUser &secuser)
  8180. {
  8181. if (checkWuSecAccess(wuid, &secmgr, &secuser, SecAccess_Write, "Submit", true, true))
  8182. submitWorkUnit(wuid, secuser.getName(), secuser.credentials().getPassword());
  8183. }
  8184. extern WORKUNIT_API void secAbortWorkUnit(const char *wuid, ISecManager &secmgr, ISecUser &secuser)
  8185. {
  8186. if (checkWuSecAccess(wuid, &secmgr, &secuser, SecAccess_Write, "Submit", true, true))
  8187. abortWorkUnit(wuid);
  8188. }
  8189. extern WORKUNIT_API void submitWorkUnit(const char *wuid, ISecManager *secmgr, ISecUser *secuser)
  8190. {
  8191. if (secmgr && secuser)
  8192. return secSubmitWorkUnit(wuid, *secmgr, *secuser);
  8193. if (secuser)
  8194. return submitWorkUnit(wuid, secuser->getName(), secuser->credentials().getPassword());
  8195. submitWorkUnit(wuid, "", "");
  8196. }
  8197. extern WORKUNIT_API void abortWorkUnit(const char *wuid, ISecManager *secmgr, ISecUser *secuser)
  8198. {
  8199. if (secmgr && secuser)
  8200. return secAbortWorkUnit(wuid, *secmgr, *secuser);
  8201. abortWorkUnit(wuid);
  8202. }
  8203. bool CLocalWorkUnit::hasWorkflow() const
  8204. {
  8205. return p->hasProp("Workflow");
  8206. }
  8207. unsigned CLocalWorkUnit::queryEventScheduledCount() const
  8208. {
  8209. CriticalBlock block(crit);
  8210. return p->getPropInt("Workflow/@eventScheduledCount", 0);
  8211. }
  8212. void CLocalWorkUnit::incEventScheduledCount()
  8213. {
  8214. CriticalBlock block(crit);
  8215. p->setPropInt("Workflow/@eventScheduledCount", p->getPropInt("Workflow/@eventScheduledCount", 0)+1);
  8216. }
  8217. IPropertyTree * CLocalWorkUnit::queryWorkflowTree() const
  8218. {
  8219. CriticalBlock block(crit);
  8220. return p->queryPropTree("Workflow");
  8221. }
  8222. IConstWorkflowItemIterator* CLocalWorkUnit::getWorkflowItems() const
  8223. {
  8224. // For this to be legally called, we must have the read-able interface. So we are already locked for (at least) read.
  8225. CriticalBlock block(crit);
  8226. if(!workflowIteratorCached)
  8227. {
  8228. assertex(!workflowIterator);
  8229. Owned<IPropertyTree> s = p->getPropTree("Workflow");
  8230. if(s)
  8231. workflowIterator.setown(createWorkflowItemIterator(s));
  8232. workflowIteratorCached = true;
  8233. }
  8234. return workflowIterator.getLink();
  8235. }
  8236. IWorkflowItemArray * CLocalWorkUnit::getWorkflowClone() const
  8237. {
  8238. unsigned count = 0;
  8239. Owned<IConstWorkflowItemIterator> iter = getWorkflowItems();
  8240. for(iter->first(); iter->isValid(); iter->next())
  8241. count++;
  8242. Owned<IWorkflowItemArray> array = createWorkflowItemArray(count);
  8243. for(iter->first(); iter->isValid(); iter->next())
  8244. array->addClone(iter->query());
  8245. return array.getLink();
  8246. }
  8247. IWorkflowItem * CLocalWorkUnit::addWorkflowItem(unsigned wfid, WFType type, WFMode mode, unsigned success, unsigned failure, unsigned recovery, unsigned retriesAllowed, unsigned contingencyFor)
  8248. {
  8249. // For this to be legally called, we must have the write-able interface. So we are already locked for write.
  8250. CriticalBlock block(crit);
  8251. workflowIterator.clear();
  8252. workflowIteratorCached = false;
  8253. IPropertyTree * s = p->queryPropTree("Workflow");
  8254. if(!s)
  8255. s = p->addPropTree("Workflow", createPTree("Workflow"));
  8256. return createWorkflowItem(s, wfid, type, mode, success, failure, recovery, retriesAllowed, contingencyFor);
  8257. }
  8258. IWorkflowItemIterator * CLocalWorkUnit::updateWorkflowItems()
  8259. {
  8260. // For this to be legally called, we must have the write-able interface. So we are already locked for write.
  8261. CriticalBlock block(crit);
  8262. if(!workflowIterator)
  8263. {
  8264. IPropertyTree * s = p->queryPropTree("Workflow");
  8265. if(!s)
  8266. s = p->addPropTree("Workflow", createPTree("Workflow"));
  8267. workflowIterator.setown(createWorkflowItemIterator(s));
  8268. workflowIteratorCached = true;
  8269. }
  8270. return workflowIterator.getLink();
  8271. }
  8272. void CLocalWorkUnit::syncRuntimeWorkflow(IWorkflowItemArray * array)
  8273. {
  8274. Owned<IWorkflowItemIterator> iter = updateWorkflowItems();
  8275. Owned<IWorkflowItem> item;
  8276. for(iter->first(); iter->isValid(); iter->next())
  8277. {
  8278. item.setown(iter->get());
  8279. item->syncRuntimeData(array->queryWfid(item->queryWfid()));
  8280. }
  8281. workflowIterator.clear();
  8282. workflowIteratorCached = false;
  8283. }
  8284. void CLocalWorkUnit::resetWorkflow()
  8285. {
  8286. if (hasWorkflow())
  8287. {
  8288. Owned<IWorkflowItemIterator> iter = updateWorkflowItems();
  8289. Owned<IWorkflowItem> wf;
  8290. for(iter->first(); iter->isValid(); iter->next())
  8291. {
  8292. wf.setown(iter->get());
  8293. wf->reset();
  8294. }
  8295. workflowIterator.clear();
  8296. workflowIteratorCached = false;
  8297. }
  8298. }
  8299. void CLocalWorkUnit::schedule()
  8300. {
  8301. CriticalBlock block(crit);
  8302. if(queryEventScheduledCount() == 0) return;
  8303. switch(getState())
  8304. {
  8305. case WUStateCompleted:
  8306. setState(WUStateWait);
  8307. break;
  8308. case WUStateFailed:
  8309. case WUStateArchived:
  8310. case WUStateAborting:
  8311. case WUStateAborted:
  8312. case WUStateScheduled:
  8313. throw MakeStringException(WUERR_CannotSchedule, "Cannot schedule workunit in this state");
  8314. }
  8315. StringBuffer rootPath;
  8316. rootPath.append("/Schedule/").append(queryClusterName());
  8317. Owned<IRemoteConnection> conn = querySDS().connect(rootPath.str(), myProcessSession(), RTM_LOCK_WRITE | RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT);
  8318. Owned<IPropertyTree> root = conn->getRoot();
  8319. if(!root->hasChildren())
  8320. {
  8321. StringBuffer addPath;
  8322. addPath.append("/Schedulers/").append(queryClusterName());
  8323. Owned<IRemoteConnection> addConn = querySDS().connect(addPath.str(), myProcessSession(), RTM_LOCK_WRITE | RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT);
  8324. }
  8325. char const * wuid = p->queryName();
  8326. StringBuffer xpath("*/*/");
  8327. ncnameEscape(wuid, xpath);
  8328. bool more;
  8329. do more = root->removeProp(xpath.str()); while(more);
  8330. Owned<IConstWorkflowItemIterator> iter = getWorkflowItems();
  8331. Owned<IWorkflowEvent> event;
  8332. Owned<IPropertyTree> branch1, branch2;
  8333. for(iter->first(); iter->isValid(); iter->next())
  8334. {
  8335. event.setown(iter->query()->getScheduleEvent());
  8336. if(!event) continue;
  8337. ncnameEscape(event->queryName(), xpath.clear());
  8338. ensurePTree(root, xpath.str());
  8339. branch1.setown(root->getPropTree(xpath.str()));
  8340. ncnameEscape(event->queryText(), xpath.clear());
  8341. ensurePTree(branch1, xpath.str());
  8342. branch2.setown(branch1->getPropTree(xpath.str()));
  8343. ncnameEscape(wuid, xpath.clear());
  8344. ensurePTree(branch2, xpath.str());
  8345. }
  8346. }
  8347. void CLocalWorkUnit::deschedule()
  8348. {
  8349. if(queryEventScheduledCount() == 0) return;
  8350. if(getState() == WUStateWait)
  8351. setState(WUStateCompleted);
  8352. doDescheduleWorkkunit(p->queryName());
  8353. }
  8354. mapEnums localFileUploadTypes[] = {
  8355. { UploadTypeFileSpray, "FileSpray" },
  8356. { UploadTypeWUResult, "WUResult" },
  8357. { UploadTypeWUResultCsv, "WUResultCsv" },
  8358. { UploadTypeWUResultXml, "WUResultXml" },
  8359. { UploadTypeSize, NULL }
  8360. };
  8361. class CLocalFileUpload : public CInterface, implements IConstLocalFileUpload
  8362. {
  8363. public:
  8364. CLocalFileUpload(IPropertyTree * _tree) : tree(_tree) {}
  8365. CLocalFileUpload(unsigned id, LocalFileUploadType type, char const * source, char const * destination, char const * eventTag)
  8366. {
  8367. tree.setown(createPTree());
  8368. tree->setPropInt("@id", id);
  8369. setEnum(tree, "@type", type, localFileUploadTypes);
  8370. tree->setProp("@source", source);
  8371. tree->setProp("@destination", destination);
  8372. if (eventTag)
  8373. tree->setProp("@eventTag", eventTag);
  8374. }
  8375. IMPLEMENT_IINTERFACE;
  8376. IPropertyTree * getTree() { return tree.getLink(); }
  8377. virtual unsigned queryID() const { return tree->getPropInt("@id"); }
  8378. virtual LocalFileUploadType queryType() const { return (LocalFileUploadType)getEnum(tree, "@type", localFileUploadTypes); }
  8379. virtual IStringVal & getSource(IStringVal & ret) const { ret.set(tree->queryProp("@source")); return ret; }
  8380. virtual IStringVal & getDestination(IStringVal & ret) const { ret.set(tree->queryProp("@destination")); return ret; }
  8381. virtual IStringVal & getEventTag(IStringVal & ret) const { if(tree->hasProp("@eventTag")) ret.set(tree->queryProp("@eventTag")); else ret.clear(); return ret; }
  8382. private:
  8383. Owned<IPropertyTree> tree;
  8384. };
  8385. class CLocalFileUploadIterator : public CInterface, implements IConstLocalFileUploadIterator
  8386. {
  8387. public:
  8388. CLocalFileUploadIterator(IPropertyTree * _tree) : tree(_tree), iter(tree->getElements("LocalFileUpload")) {}
  8389. IMPLEMENT_IINTERFACE;
  8390. bool first() { return iter->first(); }
  8391. bool isValid() { return iter->isValid(); }
  8392. bool next() { return iter->next(); }
  8393. IConstLocalFileUpload * get() { return new CLocalFileUpload(&iter->get()); }
  8394. private:
  8395. Owned<IPropertyTree> tree;
  8396. Owned<IPropertyTreeIterator> iter;
  8397. };
  8398. IConstLocalFileUploadIterator * CLocalWorkUnit::getLocalFileUploads() const
  8399. {
  8400. // For this to be legally called, we must have the read-able interface. So we are already locked for (at least) read.
  8401. CriticalBlock block(crit);
  8402. Owned<IPropertyTree> s = p->getPropTree("LocalFileUploads");
  8403. if(s)
  8404. return new CLocalFileUploadIterator(s.getClear());
  8405. else
  8406. return NULL;
  8407. }
  8408. bool CLocalWorkUnit::requiresLocalFileUpload() const
  8409. {
  8410. SCMStringBuffer dest;
  8411. Owned<IConstWUResult> result;
  8412. Owned<IConstLocalFileUploadIterator> iter(getLocalFileUploads());
  8413. if(!iter)
  8414. return false;
  8415. for(iter->first(); iter->isValid(); iter->next())
  8416. {
  8417. Owned<IConstLocalFileUpload> upload(iter->get());
  8418. switch(upload->queryType())
  8419. {
  8420. case UploadTypeWUResult:
  8421. case UploadTypeWUResultCsv:
  8422. case UploadTypeWUResultXml:
  8423. upload->getDestination(dest);
  8424. result.setown(getResultByName(dest.str()));
  8425. if(!result)
  8426. return true;
  8427. break;
  8428. default:
  8429. throw MakeStringException(WUERR_InvalidUploadFormat, "Unsupported local file upload type %s", getEnumText(upload->queryType(), localFileUploadTypes));
  8430. }
  8431. }
  8432. return false;
  8433. }
  8434. unsigned CLocalWorkUnit::addLocalFileUpload(LocalFileUploadType type, char const * source, char const * destination, char const * eventTag)
  8435. {
  8436. // For this to be legally called, we must have the write-able interface. So we are already locked for write.
  8437. CriticalBlock block(crit);
  8438. IPropertyTree * s = p->queryPropTree("LocalFileUploads");
  8439. if(!s)
  8440. s = p->addPropTree("LocalFileUploads", createPTree());
  8441. unsigned id = s->numChildren();
  8442. Owned<CLocalFileUpload> upload = new CLocalFileUpload(id, type, source, destination, eventTag);
  8443. s->addPropTree("LocalFileUpload", upload->getTree());
  8444. return id;
  8445. }
  8446. #if 0
  8447. void testConstWorkflow(IConstWorkflowItem * cwf, bool * okay, bool * dep)
  8448. {
  8449. DBGLOG("Test workflow const iface %u", cwf->queryWfid());
  8450. unsigned deps = 0;
  8451. Owned<IWorkflowDependencyIterator> diter;
  8452. switch(cwf->queryWfid())
  8453. {
  8454. case 1:
  8455. assertex(!cwf->isScheduled());
  8456. assertex(cwf->queryType() == WFTypeNormal);
  8457. assertex(cwf->queryState() == WFStateNull);
  8458. diter.setown(cwf->getDependencies());
  8459. for(diter->first(); diter->isValid(); diter->next())
  8460. deps++;
  8461. assertex(deps==0);
  8462. okay[0] = true;
  8463. break;
  8464. case 2:
  8465. assertex(!cwf->isScheduled());
  8466. assertex(cwf->queryType() == WFTypeRecovery);
  8467. assertex(cwf->queryState() == WFStateSkip);
  8468. okay[1] = true;
  8469. break;
  8470. case 3:
  8471. assertex(cwf->queryContingencyFor() == 4);
  8472. okay[2] = true;
  8473. break;
  8474. case 4:
  8475. assertex(cwf->isScheduled());
  8476. assertex(cwf->queryType() == WFTypeNormal);
  8477. assertex(cwf->queryState() == WFStateReqd);
  8478. assertex(cwf->querySuccess() == 0);
  8479. assertex(cwf->queryFailure() == 3);
  8480. assertex(cwf->queryRecovery() == 2);
  8481. assertex(cwf->queryRetriesAllowed() == 10);
  8482. assertex(cwf->queryRetriesRemaining() == 10);
  8483. diter.setown(cwf->getDependencies());
  8484. for(diter->first(); diter->isValid(); diter->next())
  8485. {
  8486. dep[diter->query()-1] = true;
  8487. deps++;
  8488. }
  8489. assertex(deps==2);
  8490. assertex(dep[0]);
  8491. assertex(dep[1]);
  8492. okay[3] = true;
  8493. break;
  8494. case 5:
  8495. assertex(cwf->isScheduled());
  8496. assertex(!cwf->isScheduledNow());
  8497. assertex(cwf->querySchedulePriority() == 75);
  8498. assertex(cwf->queryScheduleCount() == 5);
  8499. assertex(cwf->queryScheduleCountRemaining() == 5);
  8500. okay[4] = true;
  8501. break;
  8502. case 6:
  8503. assertex(cwf->isScheduled());
  8504. assertex(!cwf->isScheduledNow());
  8505. assertex(cwf->querySchedulePriority() == 25);
  8506. assertex(!cwf->hasScheduleCount());
  8507. okay[5] = true;
  8508. break;
  8509. default:
  8510. assertex(!"unknown wfid in test");
  8511. }
  8512. }
  8513. void testRuntimeWorkflow(IRuntimeWorkflowItem * rwf, bool * okay)
  8514. {
  8515. DBGLOG("Test workflow runtime iface %u", rwf->queryWfid());
  8516. switch(rwf->queryWfid())
  8517. {
  8518. case 1:
  8519. case 2:
  8520. case 3:
  8521. okay[rwf->queryWfid()-1] = true;
  8522. break;
  8523. case 4:
  8524. {
  8525. unsigned tries = 0;
  8526. while(rwf->testAndDecRetries())
  8527. tries++;
  8528. assertex(tries == 10);
  8529. assertex(rwf->queryRetriesRemaining() == 0);
  8530. rwf->setState(WFStateFail);
  8531. assertex(rwf->queryState() == WFStateFail);
  8532. rwf->reset();
  8533. assertex(rwf->queryRetriesRemaining() == 10);
  8534. assertex(rwf->queryState() == WFStateReqd);
  8535. }
  8536. okay[3] = true;
  8537. break;
  8538. case 5:
  8539. {
  8540. assertex(rwf->queryScheduleCountRemaining() == 5);
  8541. unsigned count = 0;
  8542. do count++; while(rwf->decAndTestScheduleCountRemaining());
  8543. assertex(count == 5);
  8544. assertex(rwf->queryScheduleCountRemaining() == 0);
  8545. rwf->reset();
  8546. assertex(rwf->queryScheduleCountRemaining() == 5);
  8547. }
  8548. okay[4] = true;
  8549. break;
  8550. case 6:
  8551. {
  8552. assertex(!rwf->hasScheduleCount());
  8553. unsigned count;
  8554. for(count=0; count<20; count++)
  8555. assertex(rwf->decAndTestScheduleCountRemaining());
  8556. }
  8557. okay[5] = true;
  8558. break;
  8559. default:
  8560. assertex(!"unknown wfid in test");
  8561. }
  8562. }
  8563. void testWorkflow()
  8564. {
  8565. DBGLOG("workunit.cpp : testWorkflow");
  8566. CLocalWorkUnit wu("W-WF-TEST", 0, 0, 0);
  8567. Owned<IWorkflowItem> wf;
  8568. wf.setown(wu.addWorkflowItem(1, WFTypeNormal, 0, 0, 0, 0, 0));
  8569. wf.setown(wu.addWorkflowItem(2, WFTypeRecovery, 0, 0, 0, 0, 0));
  8570. wf.setown(wu.addWorkflowItem(3, WFTypeFailure, 0, 0, 0, 0, 4));
  8571. wf.setown(wu.addWorkflowItem(4, WFTypeNormal, 0, 3, 2, 10, 0));
  8572. wf->setScheduledNow();
  8573. wf->addDependency(1);
  8574. wf.setown(wu.addWorkflowItem(5, WFTypeNormal, 0, 0, 0, 0, 0));
  8575. wf->setScheduledOn("test", "foo*");
  8576. wf->setSchedulePriority(75);
  8577. wf->setScheduleCount(5);
  8578. wf.setown(wu.addWorkflowItem(6, WFTypeNormal, 0, 0, 0, 0, 0));
  8579. wf->setScheduledOn("test", "bar*");
  8580. wf->setSchedulePriority(25);
  8581. unsigned const n = 6;
  8582. bool okay[n];
  8583. bool dep[n];
  8584. unsigned i;
  8585. for(i=0; i<n; i++)
  8586. okay[i] = dep[i] = 0;
  8587. Owned<IConstWorkflowItemIterator> citer(wu.getWorkflowItems());
  8588. for(citer->first(); citer->isValid(); citer->next())
  8589. testConstWorkflow(citer->query(), okay, dep);
  8590. for(i=0; i<n; i++)
  8591. {
  8592. assertex(okay[i]);
  8593. okay[i] = false;
  8594. }
  8595. Owned<IWorkflowItemIterator> miter(wu.updateWorkflowItems());
  8596. for(miter->first(); miter->isValid(); miter->next())
  8597. {
  8598. Owned<IRuntimeWorkflowItem> rwf(miter->get());
  8599. testRuntimeWorkflow(rwf, okay);
  8600. }
  8601. for(i=0; i<n; i++)
  8602. {
  8603. assertex(okay[i]);
  8604. okay[i] = dep[i] = false;
  8605. }
  8606. Owned<IWorkflowItemArray> array(wu.getWorkflowClone());
  8607. unsigned wfid;
  8608. for(wfid = 1; array->isValid(wfid); wfid++)
  8609. testConstWorkflow(&array->queryWfid(wfid), okay, dep);
  8610. for(i=0; i<n; i++)
  8611. {
  8612. assertex(okay[i]);
  8613. okay[i] = false;
  8614. }
  8615. for(wfid = 1; array->isValid(wfid); wfid++)
  8616. testRuntimeWorkflow(&array->queryWfid(wfid), okay);
  8617. for(i=0; i<n; i++)
  8618. {
  8619. assertex(okay[i]);
  8620. okay[i] = false;
  8621. }
  8622. }
  8623. #endif
  8624. //------------------------------------------------------------------------------------------
  8625. extern WUState waitForWorkUnitToComplete(const char * wuid, int timeout, bool returnOnWaitState)
  8626. {
  8627. return factory->waitForWorkUnit(wuid, (unsigned) timeout, false, returnOnWaitState);
  8628. }
  8629. extern WORKUNIT_API WUState secWaitForWorkUnitToComplete(const char * wuid, ISecManager &secmgr, ISecUser &secuser, int timeout, bool returnOnWaitState)
  8630. {
  8631. if (checkWuSecAccess(wuid, &secmgr, &secuser, SecAccess_Read, "Wait for Complete", false, true))
  8632. return waitForWorkUnitToComplete(wuid, timeout, returnOnWaitState);
  8633. return WUStateUnknown;
  8634. }
  8635. extern bool waitForWorkUnitToCompile(const char * wuid, int timeout)
  8636. {
  8637. switch(factory->waitForWorkUnit(wuid, (unsigned) timeout, true, true))
  8638. {
  8639. case WUStateCompiled:
  8640. case WUStateCompleted:
  8641. case WUStateWait:
  8642. case WUStateUploadingFiles:
  8643. return true;
  8644. default:
  8645. return false;
  8646. }
  8647. }
  8648. extern WORKUNIT_API bool secWaitForWorkUnitToCompile(const char * wuid, ISecManager &secmgr, ISecUser &secuser, int timeout)
  8649. {
  8650. if (checkWuSecAccess(wuid, &secmgr, &secuser, SecAccess_Read, "Wait for Compile", false, true))
  8651. return waitForWorkUnitToCompile(wuid, timeout);
  8652. return false;
  8653. }
  8654. extern WORKUNIT_API bool secDebugWorkunit(const char * wuid, ISecManager &secmgr, ISecUser &secuser, const char *command, StringBuffer &response)
  8655. {
  8656. if (strnicmp(command, "<debug:", 7) == 0 && checkWuSecAccess(wuid, &secmgr, &secuser, SecAccess_Read, "Debug", false, true))
  8657. {
  8658. Owned<IConstWorkUnit> wu = factory->openWorkUnit(wuid, false, &secmgr, &secuser);
  8659. SCMStringBuffer ip;
  8660. unsigned port;
  8661. port = wu->getDebugAgentListenerPort();
  8662. wu->getDebugAgentListenerIP(ip);
  8663. SocketEndpoint debugEP(ip.str(), port);
  8664. Owned<ISocket> socket = ISocket::connect_timeout(debugEP, 1000);
  8665. unsigned len = (size32_t)strlen(command);
  8666. unsigned revlen = len;
  8667. _WINREV(revlen);
  8668. socket->write(&revlen, sizeof(revlen));
  8669. socket->write(command, len);
  8670. for (;;)
  8671. {
  8672. socket->read(&len, sizeof(len));
  8673. _WINREV(len);
  8674. if (len == 0)
  8675. break;
  8676. if (len & 0x80000000)
  8677. {
  8678. throwUnexpected();
  8679. }
  8680. char * mem = (char*) response.reserve(len);
  8681. socket->read(mem, len);
  8682. }
  8683. return true;
  8684. }
  8685. return false;
  8686. }
  8687. void updateSuppliedXmlParams(IWorkUnit * w)
  8688. {
  8689. Owned<const IPropertyTree> params = w->getXmlParams();
  8690. if (!params)
  8691. return;
  8692. Owned<IPropertyTreeIterator> elems = params->getElements("*");
  8693. ForEach(*elems)
  8694. {
  8695. IPropertyTree & curVal = elems->query();
  8696. const char *name = curVal.queryName();
  8697. Owned<IWUResult> r = updateWorkUnitResult(w, name, -1);
  8698. if (r)
  8699. {
  8700. StringBuffer s;
  8701. if (r->isResultScalar() && !curVal.hasChildren())
  8702. {
  8703. curVal.getProp(".", s);
  8704. r->setResultXML(s);
  8705. r->setResultStatus(ResultStatusSupplied);
  8706. }
  8707. else
  8708. {
  8709. toXML(&curVal, s);
  8710. bool isSet = (curVal.hasProp("Item") || curVal.hasProp("string"));
  8711. r->setResultRaw(s.length(), s.str(), isSet ? ResultFormatXmlSet : ResultFormatXml);
  8712. }
  8713. }
  8714. else
  8715. DBGLOG("WARNING: no matching variable in workunit for input parameter %s", name);
  8716. }
  8717. }
  8718. IWUResult * updateWorkUnitResult(IWorkUnit * w, const char *name, unsigned sequence)
  8719. {
  8720. switch ((int)sequence)
  8721. {
  8722. case ResultSequenceStored:
  8723. return w->updateVariableByName(name);
  8724. case ResultSequencePersist:
  8725. return w->updateGlobalByName(name);
  8726. case ResultSequenceInternal:
  8727. case ResultSequenceOnce:
  8728. return w->updateTemporaryByName(name);
  8729. default:
  8730. return w->updateResultBySequence(sequence);
  8731. }
  8732. }
  8733. IConstWUResult * getWorkUnitResult(IConstWorkUnit * w, const char *name, unsigned sequence)
  8734. {
  8735. switch ((int)sequence)
  8736. {
  8737. case ResultSequenceStored:
  8738. return w->getVariableByName(name);
  8739. case ResultSequencePersist:
  8740. return w->getGlobalByName(name);
  8741. case ResultSequenceInternal:
  8742. case ResultSequenceOnce:
  8743. return w->getTemporaryByName(name);
  8744. default:
  8745. if (name && name[0])
  8746. return w->getResultByName(name);//name takes precedence over sequence
  8747. else
  8748. return w->getResultBySequence(sequence);
  8749. }
  8750. }
  8751. extern WORKUNIT_API bool getWorkUnitCreateTime(const char *wuid,CDateTime &time)
  8752. {
  8753. if (wuid) {
  8754. char prefchar;
  8755. unsigned year,month,day,hour,min,sec;
  8756. if (sscanf(wuid, "%c%4u%2u%2u-%2u%2u%2u", &prefchar, &year, &month, &day, &hour, &min, &sec)==7) {
  8757. time.set(year, month, day, hour, min, sec, 0, true);
  8758. // time.setDate(year, month, day);
  8759. // time.setTime(hour, min, sec, 0, true); // for some reason time is local
  8760. return true;
  8761. }
  8762. }
  8763. return false;
  8764. }
  8765. extern WORKUNIT_API IStringVal& createToken(const char *wuid, const char *user, const char *password, IStringVal &str)
  8766. {
  8767. StringBuffer wu, token("X");
  8768. wu.append(wuid).append(';').append(user).append(';').append(password);
  8769. encrypt(token,wu.str());
  8770. str.set(token.str());
  8771. return str;
  8772. }
  8773. // This will be replaced by something more secure!
  8774. extern WORKUNIT_API void extractToken(const char *token, const char *wuid, IStringVal &user, IStringVal &password)
  8775. {
  8776. if (token && *token)
  8777. {
  8778. StringBuffer wu;
  8779. decrypt(wu, token+1);
  8780. const char *finger = strchr(wu.str(),';');
  8781. if (finger && strnicmp(wuid, wu.str(), finger-wu.str())==0)
  8782. {
  8783. const char *finger1 = strchr(++finger,';');
  8784. if(finger1)
  8785. {
  8786. user.setLen(finger, (size32_t)(finger1-finger));
  8787. finger1++;
  8788. password.setLen(finger1, (size32_t)(wu.str() + wu.length() - finger1));
  8789. return;
  8790. }
  8791. }
  8792. throw MakeStringException(WUERR_InvalidSecurityToken, "Invalid call to extractToken");
  8793. }
  8794. }
  8795. extern WORKUNIT_API WUState getWorkUnitState(const char* state)
  8796. {
  8797. return (WUState) getEnum(state, states);
  8798. }
  8799. const LogMsgCategory MCschedconn = MCprogress(1000); // Category used to inform about schedule synchronization
  8800. class CWorkflowScheduleConnection : public CInterface, implements IWorkflowScheduleConnection
  8801. {
  8802. public:
  8803. CWorkflowScheduleConnection(char const * wuid)
  8804. {
  8805. basexpath.append("/WorkflowSchedule/").append(wuid);
  8806. flagxpath.append(basexpath.str()).append("/Active");
  8807. }
  8808. IMPLEMENT_IINTERFACE;
  8809. virtual void lock()
  8810. {
  8811. LOG(MCschedconn, "Locking base schedule connection");
  8812. baseconn.setown(querySDS().connect(basexpath.str(), myProcessSession(), RTM_CREATE_QUERY | RTM_LOCK_WRITE, INFINITE));
  8813. if(!baseconn)
  8814. throw MakeStringException(WUERR_ScheduleLockFailed, "Could not get base workflow schedule lock");
  8815. }
  8816. virtual void unlock()
  8817. {
  8818. LOG(MCschedconn, "Unlocking base schedule connection");
  8819. baseconn.clear();
  8820. }
  8821. virtual void setActive()
  8822. {
  8823. LOG(MCschedconn, "Setting active flag in schedule connection");
  8824. flagconn.setown(querySDS().connect(flagxpath.str(), myProcessSession(), RTM_CREATE | RTM_LOCK_WRITE | RTM_DELETE_ON_DISCONNECT, INFINITE));
  8825. if(!flagconn)
  8826. throw MakeStringException(WUERR_ScheduleLockFailed, "Could not get active workflow schedule lock");
  8827. }
  8828. virtual void resetActive()
  8829. {
  8830. LOG(MCschedconn, "Resetting active flag in schedule connection");
  8831. flagconn.clear();
  8832. }
  8833. virtual bool queryActive()
  8834. {
  8835. return baseconn->queryRoot()->hasProp("Active");
  8836. }
  8837. virtual bool pull(IWorkflowItemArray * workflow)
  8838. {
  8839. assertex(baseconn);
  8840. Owned<IPropertyTree> root = baseconn->getRoot();
  8841. Owned<IPropertyTree> eventQueue = root->getPropTree("EventQueue");
  8842. if(!eventQueue) return false;
  8843. if(!eventQueue->hasProp("Item")) return false;
  8844. {
  8845. Owned<IPropertyTreeIterator> eventItems = eventQueue->getElements("Item");
  8846. Owned<IPropertyTree> eventItem;
  8847. Owned<IRuntimeWorkflowItemIterator> wfItems = workflow->getSequenceIterator();
  8848. Owned<IRuntimeWorkflowItem> wfItem;
  8849. for(eventItems->first(); eventItems->isValid(); eventItems->next())
  8850. {
  8851. eventItem.setown(&eventItems->get());
  8852. const char * eventName = eventItem->queryProp("@name");
  8853. const char * eventText = eventItem->queryProp("@text");
  8854. for(wfItems->first(); wfItems->isValid(); wfItems->next())
  8855. {
  8856. wfItem.setown(wfItems->get());
  8857. if(wfItem->queryState() != WFStateWait)
  8858. continue;
  8859. Owned<IWorkflowEvent> targetEvent = wfItem->getScheduleEvent();
  8860. if(!targetEvent || !targetEvent->matches(eventName, eventText))
  8861. continue;
  8862. wfItem->setEvent(eventName, eventText);
  8863. wfItem->setState(WFStateReqd);
  8864. resetDependentsState(workflow, *wfItem);
  8865. }
  8866. }
  8867. }
  8868. bool more;
  8869. do
  8870. more = eventQueue->removeProp("Item");
  8871. while(more);
  8872. return true;
  8873. }
  8874. virtual void push(char const * name, char const * text)
  8875. {
  8876. assertex(baseconn);
  8877. Owned<IPropertyTree> root = baseconn->getRoot();
  8878. ensurePTree(root, "EventQueue");
  8879. Owned<IPropertyTree> eventQueue = root->getPropTree("EventQueue");
  8880. Owned<IPropertyTree> eventItem = createPTree();
  8881. eventItem->setProp("@name", name);
  8882. eventItem->setProp("@text", text);
  8883. eventQueue->addPropTree("Item", eventItem.getLink());
  8884. }
  8885. virtual void remove()
  8886. {
  8887. if (baseconn)
  8888. {
  8889. baseconn->close(true);
  8890. baseconn.clear();
  8891. }
  8892. }
  8893. private:
  8894. void resetItemStateAndDependents(IWorkflowItemArray * workflow, unsigned wfid) const
  8895. {
  8896. if (wfid)
  8897. resetItemStateAndDependents(workflow, workflow->queryWfid(wfid));
  8898. }
  8899. void resetItemStateAndDependents(IWorkflowItemArray * workflow, IRuntimeWorkflowItem & item) const
  8900. {
  8901. switch(item.queryState())
  8902. {
  8903. case WFStateDone:
  8904. case WFStateFail:
  8905. {
  8906. item.setState(WFStateNull);
  8907. resetItemStateAndDependents(workflow, item.queryPersistWfid());
  8908. resetDependentsState(workflow, item);
  8909. break;
  8910. }
  8911. }
  8912. }
  8913. void resetDependentsState(IWorkflowItemArray * workflow, IRuntimeWorkflowItem & item) const
  8914. {
  8915. Owned<IWorkflowDependencyIterator> iter(item.getDependencies());
  8916. for(iter->first(); iter->isValid(); iter->next())
  8917. {
  8918. IRuntimeWorkflowItem & dep = workflow->queryWfid(iter->query());
  8919. resetItemStateAndDependents(workflow, dep);
  8920. }
  8921. }
  8922. private:
  8923. StringBuffer basexpath;
  8924. StringBuffer flagxpath;
  8925. Owned<IRemoteConnection> baseconn;
  8926. Owned<IRemoteConnection> flagconn;
  8927. };
  8928. extern WORKUNIT_API IWorkflowScheduleConnection * getWorkflowScheduleConnection(char const * wuid)
  8929. {
  8930. return new CWorkflowScheduleConnection(wuid);
  8931. }
  8932. extern WORKUNIT_API IExtendedWUInterface * queryExtendedWU(IConstWorkUnit * wu)
  8933. {
  8934. return QUERYINTERFACE(wu, IExtendedWUInterface);
  8935. }
  8936. extern WORKUNIT_API const IExtendedWUInterface * queryExtendedWU(const IConstWorkUnit * wu)
  8937. {
  8938. return QUERYINTERFACE(wu, const IExtendedWUInterface);
  8939. }
  8940. extern WORKUNIT_API void addExceptionToWorkunit(IWorkUnit * wu, ErrorSeverity severity, const char * source, unsigned code, const char * text, const char * filename, unsigned lineno, unsigned column)
  8941. {
  8942. Owned<IWUException> we = wu->createException();
  8943. we->setSeverity(severity);
  8944. we->setExceptionMessage(text);
  8945. if (source)
  8946. we->setExceptionSource(source);
  8947. if (code)
  8948. we->setExceptionCode(code);
  8949. if (filename)
  8950. we->setExceptionFileName(filename);
  8951. if (lineno)
  8952. {
  8953. we->setExceptionLineNo(lineno);
  8954. if (column)
  8955. we->setExceptionColumn(lineno);
  8956. }
  8957. }
  8958. const char * skipLeadingXml(const char * text)
  8959. {
  8960. if (!text)
  8961. return NULL;
  8962. //skip utf8 BOM, probably excessive
  8963. if (memcmp(text, UTF8_BOM, 3) == 0)
  8964. text += 3;
  8965. loop
  8966. {
  8967. if (isspace(*text))
  8968. text++;
  8969. else if (text[0] == '<' && text[1] == '?')
  8970. {
  8971. text += 2;
  8972. loop
  8973. {
  8974. if (!*text) break;
  8975. if (text[0] == '?' && text[1] == '>')
  8976. {
  8977. text += 2;
  8978. break;
  8979. }
  8980. text++;
  8981. }
  8982. }
  8983. else if (text[0] == '<' && text[1] == '!' && text[2] == '-' && text[3] == '-')
  8984. {
  8985. text += 4;
  8986. loop
  8987. {
  8988. if (!*text) break;
  8989. if (text[0] == '-' && text[1] == '-' && text[2] == '>')
  8990. {
  8991. text += 3;
  8992. break;
  8993. }
  8994. text++;
  8995. }
  8996. }
  8997. else
  8998. break;
  8999. }
  9000. return text;
  9001. }
  9002. extern WORKUNIT_API bool isArchiveQuery(const char * text)
  9003. {
  9004. text = skipLeadingXml(text);
  9005. if (!text)
  9006. return false;
  9007. const char * archivePrefix = "<Archive";
  9008. return memicmp(text, archivePrefix, strlen(archivePrefix)) == 0;
  9009. }
  9010. extern WORKUNIT_API bool isQueryManifest(const char * text)
  9011. {
  9012. text = skipLeadingXml(text);
  9013. if (!text)
  9014. return false;
  9015. const char * manifestPrefix = "<Manifest";
  9016. return memicmp(text, manifestPrefix, strlen(manifestPrefix)) == 0;
  9017. }
  9018. //------------------------------------------------------------------------------
  9019. // Named Alias helper function
  9020. static IPropertyTree * resolveQueryByDll(IPropertyTree * queryRegistry, const char * dll)
  9021. {
  9022. StringBuffer xpath;
  9023. xpath.append("Query[@dll=\"").append(dll).append("\"]");
  9024. return queryRegistry->getPropTree(xpath);
  9025. }
  9026. static IPropertyTree * resolveQueryByWuid(IPropertyTree * queryRegistry, const char * wuid)
  9027. {
  9028. StringBuffer xpath;
  9029. xpath.append("Query[@wuid=\"").append(wuid).append("\"]");
  9030. return queryRegistry->getPropTree(xpath);
  9031. }
  9032. static void clearAliases(IPropertyTree * queryRegistry, const char * id)
  9033. {
  9034. StringBuffer lcId(id);
  9035. lcId.toLowerCase();
  9036. StringBuffer xpath;
  9037. xpath.append("Alias[@id=\"").append(lcId).append("\"]");
  9038. Owned<IPropertyTreeIterator> iter = queryRegistry->getElements(xpath);
  9039. ForEach(*iter)
  9040. {
  9041. queryRegistry->removeProp(xpath.str());
  9042. }
  9043. }
  9044. IPropertyTree * addNamedQuery(IPropertyTree * queryRegistry, const char * name, const char * wuid, const char * dll, bool library, const char *userid, const char *snapshot)
  9045. {
  9046. StringBuffer lcName(name);
  9047. lcName.toLowerCase();
  9048. StringBuffer xpath;
  9049. xpath.append("Query[@name=\"").append(lcName.str()).append("\"]");
  9050. Owned<IPropertyTreeIterator> iter = queryRegistry->getElements(xpath);
  9051. unsigned seq = 1;
  9052. ForEach(*iter)
  9053. {
  9054. IPropertyTree &item = iter->query();
  9055. const char *thisWuid = item.queryProp("@wuid");
  9056. if (strieq(wuid, thisWuid))
  9057. return &item;
  9058. unsigned thisSeq = item.getPropInt("@seq");
  9059. if (thisSeq >= seq)
  9060. seq = thisSeq + 1;
  9061. }
  9062. StringBuffer id;
  9063. id.append(lcName).append(".").append(seq);
  9064. IPropertyTree * newEntry = createPTree("Query", ipt_caseInsensitive);
  9065. newEntry->setProp("@name", lcName);
  9066. newEntry->setProp("@wuid", wuid);
  9067. newEntry->setProp("@dll", dll);
  9068. newEntry->setProp("@id", id);
  9069. newEntry->setPropInt("@seq", seq);
  9070. if (library)
  9071. newEntry->setPropBool("@isLibrary", true);
  9072. if (userid && *userid)
  9073. newEntry->setProp("@publishedBy", userid);
  9074. if (snapshot && *snapshot)
  9075. newEntry->setProp("@snapshot", snapshot);
  9076. return queryRegistry->addPropTree("Query", newEntry);
  9077. }
  9078. void removeNamedQuery(IPropertyTree * queryRegistry, const char * id)
  9079. {
  9080. StringBuffer lcId(id);
  9081. lcId.toLowerCase();
  9082. clearAliases(queryRegistry, lcId);
  9083. StringBuffer xpath;
  9084. xpath.append("Query[@id=\"").append(lcId).append("\"]");
  9085. queryRegistry->removeProp(xpath);
  9086. }
  9087. void removeDllFromNamedQueries(IPropertyTree * queryRegistry, const char * dll)
  9088. {
  9089. Owned<IPropertyTree> match = resolveQueryByDll(queryRegistry, dll);
  9090. if (!match)
  9091. return;
  9092. clearAliases(queryRegistry, match->queryProp("@id"));
  9093. queryRegistry->removeTree(match);
  9094. }
  9095. void removeWuidFromNamedQueries(IPropertyTree * queryRegistry, const char * wuid)
  9096. {
  9097. Owned<IPropertyTree> match = resolveQueryByWuid(queryRegistry, wuid);
  9098. if (!match)
  9099. return;
  9100. clearAliases(queryRegistry, match->queryProp("@id"));
  9101. queryRegistry->removeTree(match);
  9102. }
  9103. void removeAliasesFromNamedQuery(IPropertyTree * queryRegistry, const char * id)
  9104. {
  9105. clearAliases(queryRegistry, id);
  9106. }
  9107. void setQueryAlias(IPropertyTree * queryRegistry, const char * name, const char * value)
  9108. {
  9109. StringBuffer lcName(name);
  9110. lcName.toLowerCase();
  9111. StringBuffer xpath;
  9112. xpath.append("Alias[@name=\"").append(lcName).append("\"]");
  9113. IPropertyTree * match = queryRegistry->queryPropTree(xpath);
  9114. if (!match)
  9115. {
  9116. IPropertyTree * newEntry = createPTree("Alias");
  9117. newEntry->setProp("@name", lcName);
  9118. match = queryRegistry->addPropTree("Alias", newEntry);
  9119. }
  9120. match->setProp("@id", value);
  9121. }
  9122. extern WORKUNIT_API IPropertyTree * getQueryById(IPropertyTree * queryRegistry, const char *queryid)
  9123. {
  9124. if (!queryRegistry || !queryid)
  9125. return NULL;
  9126. StringBuffer xpath;
  9127. xpath.append("Query[@id=\"").append(queryid).append("\"]");
  9128. return queryRegistry->getPropTree(xpath);
  9129. }
  9130. extern WORKUNIT_API IPropertyTree * getQueryById(const char *queryset, const char *queryid, bool readonly)
  9131. {
  9132. Owned<IPropertyTree> queryRegistry = getQueryRegistry(queryset, readonly);
  9133. return getQueryById(queryRegistry, queryid);
  9134. }
  9135. extern WORKUNIT_API IPropertyTree * resolveQueryAlias(IPropertyTree * queryRegistry, const char * alias)
  9136. {
  9137. if (!queryRegistry || !alias)
  9138. return NULL;
  9139. StringBuffer xpath;
  9140. unsigned cnt = 0;
  9141. StringBuffer lc(alias);
  9142. const char * search = lc.toLowerCase().str();
  9143. loop
  9144. {
  9145. xpath.set("Alias[@name='").append(search).append("']/@id");
  9146. const char * queryId = queryRegistry->queryProp(xpath);
  9147. if (!queryId)
  9148. break;
  9149. //Check for too many alias indirections.
  9150. if (cnt++ > 10)
  9151. return NULL;
  9152. search = lc.set(queryId).toLowerCase().str();
  9153. }
  9154. return getQueryById(queryRegistry, search);
  9155. }
  9156. extern WORKUNIT_API IPropertyTree * resolveQueryAlias(const char *queryset, const char *alias, bool readonly)
  9157. {
  9158. Owned<IPropertyTree> queryRegistry = getQueryRegistry(queryset, readonly);
  9159. return resolveQueryAlias(queryRegistry, alias);
  9160. }
  9161. void setQuerySuspendedState(IPropertyTree * queryRegistry, const char *id, bool suspend, const char *userid)
  9162. {
  9163. StringBuffer lcId(id);
  9164. lcId.toLowerCase();
  9165. StringBuffer xpath;
  9166. xpath.append("Query[@id=\"").append(lcId).append("\"]");
  9167. IPropertyTree *tree = queryRegistry->queryPropTree(xpath);
  9168. if (tree)
  9169. {
  9170. if (tree->getPropBool("@suspended", false) == suspend)
  9171. return;
  9172. if (suspend)
  9173. {
  9174. tree->addPropBool("@suspended", true);
  9175. if (userid && *userid)
  9176. tree->addProp("@suspendedBy", userid);
  9177. }
  9178. else
  9179. {
  9180. tree->removeProp("@suspended");
  9181. tree->removeProp("@suspendedBy");
  9182. }
  9183. }
  9184. else
  9185. throw MakeStringException((suspend)? QUERRREG_SUSPEND : QUERRREG_UNSUSPEND, "Modifying query suspended state failed. Could not find query %s", id);
  9186. }
  9187. void setQueryCommentForNamedQuery(IPropertyTree * queryRegistry, const char *id, const char *queryComment)
  9188. {
  9189. if (queryComment)
  9190. {
  9191. StringBuffer lcId(id);
  9192. lcId.toLowerCase();
  9193. StringBuffer xpath;
  9194. xpath.append("Query[@id=\"").append(lcId).append("\"]");
  9195. IPropertyTree *tree = queryRegistry->queryPropTree(xpath);
  9196. if (tree)
  9197. tree->setProp("@queryComment", queryComment);
  9198. else
  9199. throw MakeStringException(QUERRREG_COMMENT, "Could not find query %s", id);
  9200. }
  9201. }
  9202. extern WORKUNIT_API IPropertyTree * getQueryRegistryRoot()
  9203. {
  9204. Owned<IRemoteConnection> conn = querySDS().connect("/QuerySets", myProcessSession(), RTM_LOCK_READ, SDS_LOCK_TIMEOUT);
  9205. if (conn)
  9206. return conn->getRoot();
  9207. else
  9208. return NULL;
  9209. }
  9210. extern WORKUNIT_API void checkAddLibrariesToQueryEntry(IPropertyTree *queryTree, IConstWULibraryIterator *libraries)
  9211. {
  9212. if (!queryTree || !libraries)
  9213. return;
  9214. if (queryTree->hasProp("@libCount")) //already added
  9215. return;
  9216. unsigned libCount=0;
  9217. ForEach(*libraries)
  9218. {
  9219. IConstWULibrary &library = libraries->query();
  9220. SCMStringBuffer libname;
  9221. if (!library.getName(libname).length())
  9222. continue;
  9223. queryTree->addProp("Library", libname.str());
  9224. libCount++;
  9225. }
  9226. queryTree->setPropInt("@libCount", libCount);
  9227. }
  9228. extern WORKUNIT_API void checkAddLibrariesToQueryEntry(IPropertyTree *queryTree, IConstWorkUnit *cw)
  9229. {
  9230. Owned<IConstWULibraryIterator> libraries = &cw->getLibraries();
  9231. checkAddLibrariesToQueryEntry(queryTree, libraries);
  9232. }
  9233. extern WORKUNIT_API IPropertyTree * getQueryRegistry(const char * wsEclId, bool readonly)
  9234. {
  9235. //Only lock the branch for the target we're interested in.
  9236. StringBuffer xpath;
  9237. xpath.append("/QuerySets/QuerySet[@id=\"").append(wsEclId).append("\"]");
  9238. Owned<IRemoteConnection> conn = querySDS().connect(xpath.str(), myProcessSession(), readonly ? RTM_LOCK_READ : RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT);
  9239. if (conn)
  9240. return conn->getRoot();
  9241. if (readonly)
  9242. return NULL;
  9243. //Lock the QuerySets in case another thread/client wants to check/add the same QuerySet.
  9244. Owned<IRemoteConnection> globalLock = querySDS().connect("/QuerySets/", myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT);
  9245. //Re-check if the QuerySet has been added between checking the 1st time and gaining the globalLock.
  9246. conn.setown(querySDS().connect(xpath.str(), myProcessSession(), RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT));
  9247. if (conn)
  9248. return conn->getRoot();
  9249. conn.setown(querySDS().connect("/QuerySets/QuerySet", myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_ADD, SDS_LOCK_TIMEOUT));
  9250. if (!conn)
  9251. throwUnexpected();
  9252. IPropertyTree * root = conn->queryRoot();
  9253. root->setProp("@id",wsEclId);
  9254. conn->commit();
  9255. return LINK(root);
  9256. }
  9257. IPropertyTree * addNamedPackageSet(IPropertyTree * packageRegistry, const char * name, IPropertyTree *packageInfo, bool overWrite)
  9258. {
  9259. StringBuffer xpath;
  9260. StringBuffer lcName(name);
  9261. lcName.toLowerCase();
  9262. // see if "name" already exists
  9263. xpath.append("Package[@id='").append(name).append("']");
  9264. IPropertyTree *pkgTree = packageRegistry->queryPropTree(xpath.str());
  9265. if (pkgTree)
  9266. {
  9267. if (overWrite)
  9268. packageRegistry->removeTree(pkgTree);
  9269. else
  9270. throw MakeStringException(WUERR_PackageAlreadyExists, "Package name %s already exists, either delete it or specify overwrite",name);
  9271. }
  9272. IPropertyTree *tree = packageRegistry->addPropTree("Package", packageInfo);
  9273. tree->setProp("@id", lcName);
  9274. return tree;
  9275. }
  9276. void removeNamedPackage(IPropertyTree * packageRegistry, const char * id)
  9277. {
  9278. StringBuffer lcId(id);
  9279. lcId.toLowerCase();
  9280. StringBuffer xpath;
  9281. xpath.append("Package[@id=\"").append(lcId).append("\"]");
  9282. packageRegistry->removeProp(xpath);
  9283. }
  9284. extern WORKUNIT_API IPropertyTree * getPackageSetRegistry(const char * wsEclId, bool readonly)
  9285. {
  9286. //Only lock the branch for the target we're interested in.
  9287. StringBuffer xpath;
  9288. xpath.append("/PackageSets/PackageSet[@id=\"").append(wsEclId).append("\"]");
  9289. Owned<IRemoteConnection> conn = querySDS().connect(xpath.str(), myProcessSession(), readonly ? RTM_LOCK_READ : RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT);
  9290. if (conn)
  9291. return conn->getRoot();
  9292. if (readonly)
  9293. return NULL;
  9294. //Lock the PackageSets in case another thread/client wants to check/add the same PackageSet.
  9295. Owned<IRemoteConnection> globalLock = querySDS().connect("/PackageSets/", myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT);
  9296. //Re-check if the PackageSet has been added between checking the 1st time and gaining the globalLock.
  9297. conn.setown(querySDS().connect(xpath.str(), myProcessSession(), RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT));
  9298. if (conn)
  9299. return conn->getRoot();
  9300. conn.setown(querySDS().connect("/PackageSets/PackageSet", myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_ADD, SDS_LOCK_TIMEOUT));
  9301. if (!conn)
  9302. throwUnexpected();
  9303. IPropertyTree* root = conn->queryRoot();
  9304. root->setProp("@id",wsEclId);
  9305. conn->commit();
  9306. return LINK(root);
  9307. }
  9308. void addQueryToQuerySet(IWorkUnit *workunit, IPropertyTree *queryRegistry, const char *queryName, WUQueryActivationOptions activateOption, StringBuffer &newQueryId, const char *userid)
  9309. {
  9310. StringBuffer cleanQueryName;
  9311. appendUtf8XmlName(cleanQueryName, strlen(queryName), queryName);
  9312. SCMStringBuffer dllName;
  9313. Owned<IConstWUQuery> q = workunit->getQuery();
  9314. q->getQueryDllName(dllName);
  9315. if (!dllName.length())
  9316. throw MakeStringException(WUERR_InvalidDll, "Cannot deploy query - no associated dll.");
  9317. StringBuffer currentTargetClusterType;
  9318. queryRegistry->getProp("@targetclustertype", currentTargetClusterType);
  9319. SCMStringBuffer targetClusterType;
  9320. workunit->getDebugValue("targetclustertype", targetClusterType);
  9321. SCMStringBuffer snapshot;
  9322. workunit->getSnapshot(snapshot);
  9323. if (currentTargetClusterType.length() < 1)
  9324. {
  9325. queryRegistry->setProp("@targetclustertype", targetClusterType.str());
  9326. }
  9327. else
  9328. {
  9329. if (strcmp(currentTargetClusterType.str(), "roxie") == 0 && strcmp(currentTargetClusterType.str(), targetClusterType.str())!=0)
  9330. {
  9331. throw MakeStringException(WUERR_MismatchClusterType, "TargetClusterTypes of workunit and queryset do not match.");
  9332. }
  9333. }
  9334. IPropertyTree *newEntry = addNamedQuery(queryRegistry, cleanQueryName, workunit->queryWuid(), dllName.str(), isLibrary(workunit), userid, snapshot.str());
  9335. Owned<IConstWULibraryIterator> libraries = &workunit->getLibraries();
  9336. checkAddLibrariesToQueryEntry(newEntry, libraries);
  9337. newQueryId.append(newEntry->queryProp("@id"));
  9338. workunit->setIsQueryService(true); //will check querysets before delete
  9339. workunit->commit();
  9340. activateQuery(queryRegistry, activateOption, queryName, newQueryId, userid);
  9341. }
  9342. void activateQuery(IPropertyTree *queryRegistry, WUQueryActivationOptions activateOption, const char *queryName, const char *queryId, const char *userid)
  9343. {
  9344. StringBuffer cleanQueryName;
  9345. appendUtf8XmlName(cleanQueryName, strlen(queryName), queryName);
  9346. if (activateOption == ACTIVATE_SUSPEND_PREVIOUS|| activateOption == ACTIVATE_DELETE_PREVIOUS)
  9347. {
  9348. Owned<IPropertyTree> prevQuery = resolveQueryAlias(queryRegistry, cleanQueryName);
  9349. setQueryAlias(queryRegistry, cleanQueryName, queryId);
  9350. if (prevQuery && !streq(queryId, prevQuery->queryProp("@id")))
  9351. {
  9352. if (activateOption == ACTIVATE_SUSPEND_PREVIOUS)
  9353. setQuerySuspendedState(queryRegistry, prevQuery->queryProp("@id"), true, userid);
  9354. else
  9355. removeNamedQuery(queryRegistry, prevQuery->queryProp("@id"));
  9356. }
  9357. }
  9358. else if (activateOption == MAKE_ACTIVATE || activateOption == MAKE_ACTIVATE_LOAD_DATA_ONLY)
  9359. setQueryAlias(queryRegistry, cleanQueryName, queryId);
  9360. }
  9361. void addQueryToQuerySet(IWorkUnit *workunit, const char *querySetName, const char *queryName, WUQueryActivationOptions activateOption, StringBuffer &newQueryId, const char *userid)
  9362. {
  9363. Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySetName, false);
  9364. addQueryToQuerySet(workunit, queryRegistry, queryName, activateOption, newQueryId, userid);
  9365. }
  9366. bool removeQuerySetAlias(const char *querySetName, const char *alias)
  9367. {
  9368. Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySetName, true);
  9369. StringBuffer xpath;
  9370. xpath.appendf("Alias[@name='%s']", alias);
  9371. IPropertyTree *t = queryRegistry->queryPropTree(xpath);
  9372. return queryRegistry->removeTree(t);
  9373. }
  9374. void addQuerySetAlias(const char *querySetName, const char *alias, const char *id)
  9375. {
  9376. Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySetName, false);
  9377. setQueryAlias(queryRegistry, alias, id);
  9378. }
  9379. void setSuspendQuerySetQuery(const char *querySetName, const char *id, bool suspend, const char *userid)
  9380. {
  9381. Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySetName, true);
  9382. setQuerySuspendedState(queryRegistry, id, suspend, userid);
  9383. }
  9384. void deleteQuerySetQuery(const char *querySetName, const char *id)
  9385. {
  9386. Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySetName, true);
  9387. removeNamedQuery(queryRegistry, id);
  9388. }
  9389. void removeQuerySetAliasesFromNamedQuery(const char *querySetName, const char * id)
  9390. {
  9391. Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySetName, true);
  9392. clearAliases(queryRegistry, id);
  9393. }
  9394. void setQueryCommentForNamedQuery(const char *querySetName, const char *id, const char *queryComment)
  9395. {
  9396. Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySetName, true);
  9397. setQueryCommentForNamedQuery(queryRegistry, id, queryComment);
  9398. }
  9399. const char *queryIdFromQuerySetWuid(IPropertyTree *queryRegistry, const char *wuid, const char *queryName, IStringVal &id)
  9400. {
  9401. if (!queryRegistry)
  9402. return NULL;
  9403. StringBuffer xpath;
  9404. xpath.appendf("Query[@wuid='%s']", wuid);
  9405. if (queryName && *queryName)
  9406. xpath.appendf("[@name='%s']", queryName);
  9407. IPropertyTree *q = queryRegistry->queryPropTree(xpath.str());
  9408. if (q)
  9409. {
  9410. id.set(q->queryProp("@id"));
  9411. }
  9412. return id.str();
  9413. }
  9414. const char *queryIdFromQuerySetWuid(const char *querySetName, const char *wuid, const char *queryName, IStringVal &id)
  9415. {
  9416. Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySetName, true);
  9417. return queryIdFromQuerySetWuid(queryRegistry, wuid, queryName, id);
  9418. }
  9419. extern WORKUNIT_API void gatherLibraryNames(StringArray &names, StringArray &unresolved, IWorkUnitFactory &workunitFactory, IConstWorkUnit &cw, IPropertyTree *queryset)
  9420. {
  9421. Owned<IConstWULibraryIterator> wulibraries = &cw.getLibraries();
  9422. ForEach(*wulibraries)
  9423. {
  9424. SCMStringBuffer libname;
  9425. IConstWULibrary &wulibrary = wulibraries->query();
  9426. wulibrary.getName(libname);
  9427. if (names.contains(libname.str()) || unresolved.contains(libname.str()))
  9428. continue;
  9429. Owned<IPropertyTree> query = resolveQueryAlias(queryset, libname.str());
  9430. if (query && query->getPropBool("@isLibrary"))
  9431. {
  9432. const char *wuid = query->queryProp("@wuid");
  9433. Owned<IConstWorkUnit> libcw = workunitFactory.openWorkUnit(wuid, false);
  9434. if (libcw)
  9435. {
  9436. names.appendUniq(libname.str());
  9437. gatherLibraryNames(names, unresolved, workunitFactory, *libcw, queryset);
  9438. continue;
  9439. }
  9440. }
  9441. unresolved.appendUniq(libname.str());
  9442. }
  9443. }
  9444. bool looksLikeAWuid(const char * wuid, const char firstChar)
  9445. {
  9446. if (!wuid)
  9447. return false;
  9448. if (wuid[0] != firstChar)
  9449. return false;
  9450. if (!isdigit(wuid[1]) || !isdigit(wuid[2]) || !isdigit(wuid[3]) || !isdigit(wuid[4]))
  9451. return false;
  9452. if (!isdigit(wuid[5]) || !isdigit(wuid[6]) || !isdigit(wuid[7]) || !isdigit(wuid[8]))
  9453. return false;
  9454. return (wuid[9]=='-');
  9455. }
  9456. IPropertyTree * resolveDefinitionInArchive(IPropertyTree * archive, const char * path)
  9457. {
  9458. IPropertyTree * module = archive;
  9459. const char * dot = strrchr(path, '.');
  9460. StringBuffer xpath;
  9461. if (dot)
  9462. {
  9463. xpath.clear().append("Module[@key='").appendLower(dot-path, path).append("']");
  9464. module = archive->queryPropTree(xpath);
  9465. path = dot+1;
  9466. }
  9467. else
  9468. module = archive->queryPropTree("Module[@key='']");
  9469. if (!module)
  9470. return NULL;
  9471. xpath.clear().append("Attribute[@key='").appendLower(strlen(path), path).append("']");
  9472. return module->queryPropTree(xpath);
  9473. }
  9474. extern WORKUNIT_API void associateLocalFile(IWUQuery * query, WUFileType type, const char * name, const char * description, unsigned crc)
  9475. {
  9476. StringBuffer hostname;
  9477. queryHostIP().getIpText(hostname);
  9478. StringBuffer fullPathname;
  9479. makeAbsolutePath(name, fullPathname);
  9480. query->addAssociatedFile(type, fullPathname, hostname, description, crc);
  9481. }
  9482. extern WORKUNIT_API void descheduleWorkunit(char const * wuid)
  9483. {
  9484. Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
  9485. Owned<IWorkUnit> workunit = factory->updateWorkUnit(wuid);
  9486. if(workunit)
  9487. workunit->deschedule();
  9488. else
  9489. doDescheduleWorkkunit(wuid);
  9490. }
  9491. extern WORKUNIT_API void updateWorkunitTimeStat(IWorkUnit * wu, StatisticScopeType scopeType, const char * scope, StatisticKind kind, const char * description, unsigned __int64 value)
  9492. {
  9493. wu->setStatistic(queryStatisticsComponentType(), queryStatisticsComponentName(), scopeType, scope, kind, description, value, 1, 0, StatsMergeReplace);
  9494. }
  9495. extern WORKUNIT_API void updateWorkunitTimings(IWorkUnit * wu, ITimeReporter *timer)
  9496. {
  9497. StringBuffer scope;
  9498. for (unsigned i = 0; i < timer->numSections(); i++)
  9499. {
  9500. StatisticScopeType scopeType= timer->getScopeType(i);
  9501. timer->getScope(i, scope.clear());
  9502. StatisticKind kind = timer->getTimerType(i);
  9503. wu->setStatistic(queryStatisticsComponentType(), queryStatisticsComponentName(), scopeType, scope, kind, NULL, timer->getTime(i), timer->getCount(i), timer->getMaxTime(i), StatsMergeReplace);
  9504. }
  9505. }
  9506. extern WORKUNIT_API void getWorkunitTotalTime(IConstWorkUnit* workunit, const char* creator, unsigned __int64 & totalTimeNs, unsigned __int64 & totalThisTimeNs)
  9507. {
  9508. StatisticsFilter summaryTimeFilter(SCTsummary, creator, SSTglobal, GLOBAL_SCOPE, SMeasureTimeNs, StTimeElapsed);
  9509. Owned<IConstWUStatistic> totalThorTime = getStatistic(workunit, summaryTimeFilter);
  9510. Owned<IConstWUStatistic> totalThisThorTime = workunit->getStatistic(queryStatisticsComponentName(), GLOBAL_SCOPE, StTimeElapsed);
  9511. if (totalThorTime)
  9512. totalTimeNs = totalThorTime->getValue();
  9513. else
  9514. totalTimeNs = 0;
  9515. if (totalThisThorTime)
  9516. totalThisTimeNs = totalThisThorTime->getValue();
  9517. else
  9518. totalThisTimeNs = 0;
  9519. }
  9520. extern WORKUNIT_API void addTimeStamp(IWorkUnit * wu, StatisticScopeType scopeType, const char * scope, StatisticKind kind)
  9521. {
  9522. wu->setStatistic(queryStatisticsComponentType(), queryStatisticsComponentName(), scopeType, scope, kind, NULL, getTimeStampNowValue(), 1, 0, StatsMergeAppend);
  9523. }
  9524. IConstWUStatistic * getStatistic(IConstWorkUnit * wu, const IStatisticsFilter & filter)
  9525. {
  9526. Owned<IConstWUStatisticIterator> iter = &wu->getStatistics(&filter);
  9527. if (iter->first())
  9528. return &OLINK(iter->query());
  9529. return NULL;
  9530. }
  9531. class GlobalStatisticGatherer : public CInterfaceOf<IStatisticGatherer>
  9532. {
  9533. public:
  9534. GlobalStatisticGatherer(IWorkUnit * _wu) : wu(_wu) {}
  9535. virtual void beginScope(const StatsScopeId & id)
  9536. {
  9537. prevLenStack.append(scope.length());
  9538. if (scope.length())
  9539. scope.append(":");
  9540. id.getScopeText(scope);
  9541. scopeTypeStack.append(id.queryScopeType());
  9542. }
  9543. virtual void beginSubGraphScope(unsigned id)
  9544. {
  9545. StatsScopeId scopeId(SSTsubgraph, id);
  9546. beginScope(scopeId);
  9547. }
  9548. virtual void beginActivityScope(unsigned id)
  9549. {
  9550. StatsScopeId scopeId(SSTactivity, id);
  9551. beginScope(scopeId);
  9552. }
  9553. virtual void beginEdgeScope(unsigned id, unsigned oid)
  9554. {
  9555. StatsScopeId scopeId(SSTedge, id, oid);
  9556. beginScope(scopeId);
  9557. }
  9558. virtual void endScope()
  9559. {
  9560. scope.setLength(prevLenStack.popGet());
  9561. scopeTypeStack.pop();
  9562. }
  9563. virtual void addStatistic(StatisticKind kind, unsigned __int64 value)
  9564. {
  9565. StatisticScopeType scopeType = scopeTypeStack.ordinality() ? (StatisticScopeType)scopeTypeStack.tos() : SSTglobal;
  9566. wu->setStatistic(queryStatisticsComponentType(), queryStatisticsComponentName(), scopeType, scope, kind, NULL, value, 1, 0, StatsMergeAppend);
  9567. }
  9568. virtual void updateStatistic(StatisticKind kind, unsigned __int64 value, StatsMergeAction mergeAction)
  9569. {
  9570. StatisticScopeType scopeType = scopeTypeStack.ordinality() ? (StatisticScopeType)scopeTypeStack.tos() : SSTglobal;
  9571. wu->setStatistic(queryStatisticsComponentType(), queryStatisticsComponentName(), scopeType, scope, kind, NULL, value, 1, 0, mergeAction);
  9572. }
  9573. virtual IStatisticCollection * getResult()
  9574. {
  9575. return NULL;
  9576. }
  9577. protected:
  9578. Linked<IWorkUnit> wu;
  9579. StringBuffer scope;
  9580. UnsignedArray prevLenStack;
  9581. UnsignedArray scopeTypeStack;
  9582. };
  9583. IStatisticGatherer * createGlobalStatisticGatherer(IWorkUnit * wu)
  9584. {
  9585. return new GlobalStatisticGatherer(wu);
  9586. }