12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636 |
- /*##############################################################################
- HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- ############################################################################## */
- #include "jlib.hpp"
- #include "workunit.hpp"
- #include "jprop.hpp"
- #include "jmisc.hpp"
- #include "jexcept.hpp"
- #include "jiter.ipp"
- #include "jptree.hpp"
- #include "jtime.ipp"
- #include "jencrypt.hpp"
- #include "junicode.hpp"
- #include "jlzw.hpp"
- #include "jregexp.hpp"
- #include "eclrtl.hpp"
- #include "deftype.hpp"
- #include <time.h>
- #include "mpbase.hpp"
- #include "daclient.hpp"
- #include "dadfs.hpp"
- #include "dafdesc.hpp"
- #include "dasds.hpp"
- #include "danqs.hpp"
- #include "dautils.hpp"
- #include "dllserver.hpp"
- #include "thorplugin.hpp"
- #include "thorhelper.hpp"
- #include "workflow.hpp"
- #include "nbcd.hpp"
- #include "seclib.hpp"
- #include "wuerror.hpp"
- #include "wujobq.hpp"
- #include "environment.hpp"
- #include "workunit.ipp"
- static int workUnitTraceLevel = 1;
- static StringBuffer &getXPath(StringBuffer &wuRoot, const char *wuid)
- {
- // MORE - can fold in the date
- return wuRoot.append("/WorkUnits/").append(wuid);
- }
- //To be called by eclserver, but esp etc. won't know, so we need to store it.
- static StringBuffer & appendLibrarySuffix(StringBuffer & suffix)
- {
- #ifdef _WIN32
- suffix.append("W");
- #else
- suffix.append("L");
- #endif
- #ifdef __64BIT__
- suffix.append("64");
- #else
- suffix.append("32");
- #endif
- return suffix;
- }
- typedef MapStringTo<bool> UniqueScopes;
- static void wuAccessError(const char *username, const char *action, const char *wuscope, const char *wuid, bool excpt, bool log)
- {
- StringBuffer err;
- err.append("Workunit Access Denied - action: ").append(action).append(" user:").append(username ? username : "<Unknown>");
- if (wuid)
- err.append(" workunit:").append(wuid);
- if (wuscope)
- err.append(" scope:").append(wuscope);
- //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
- SYSLOG(AUDIT_TYPE_ACCESS_FAILURE, err.str());
- if (log)
- LOG(MCuserError, "%s", err.str());
- if (excpt)
- throw MakeStringException(WUERR_AccessError, "%s", err.str());
- }
- static bool checkWuScopeSecAccess(const char *wuscope, ISecManager *secmgr, ISecUser *secuser, int required, const char *action, bool excpt, bool log)
- {
- if (!secmgr || !secuser)
- return true;
- bool ret = secmgr->authorizeEx(RT_WORKUNIT_SCOPE, *secuser, wuscope)>=required;
- if (!ret && (log || excpt))
- wuAccessError(secuser->getName(), action, wuscope, NULL, excpt, log);
- return ret;
- }
- static bool checkWuScopeListSecAccess(const char *wuscope, ISecResourceList *scopes, int required, const char *action, bool excpt, bool log)
- {
- if (!scopes)
- return true;
- bool ret=true;
- if (wuscope)
- {
- Owned<ISecResource> res=scopes->getResource(wuscope);
- if (!res || res->getAccessFlags()<required)
- ret=false;
- }
- else
- {
- for (int seq=0; ret && seq<scopes->count(); seq++)
- {
- ISecResource *res=scopes->queryResource(seq);
- if (res && res->getAccessFlags()<required)
- return false;
- }
- }
- if (!ret && (log || excpt))
- wuAccessError(NULL, action, wuscope, NULL, excpt, log);
- return ret;
- }
- static bool checkWuSecAccess(IConstWorkUnit &cw, ISecManager *secmgr, ISecUser *secuser, int required, const char *action, bool excpt, bool log)
- {
- if (!secmgr || !secuser)
- return true;
- bool ret=secmgr->authorizeEx(RT_WORKUNIT_SCOPE, *secuser, cw.queryWuScope())>=required;
- if (!ret && (log || excpt))
- {
- wuAccessError(secuser->getName(), action, cw.queryWuScope(), cw.queryWuid(), excpt, log);
- }
- return ret;
- }
- static bool checkWuSecAccess(const char *wuid, ISecManager *secmgr, ISecUser *secuser, int required, const char *action, bool excpt, bool log)
- {
- if (!secmgr || !secuser)
- return true;
- Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
- Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid);
- bool ret=secmgr->authorizeEx(RT_WORKUNIT_SCOPE, *secuser, cw->queryWuScope())>=required;
- if (!ret && (log || excpt))
- {
- wuAccessError(secuser->getName(), action, cw->queryWuScope(), cw->queryWuid(), excpt, log);
- }
- return ret;
- }
- void doDescheduleWorkkunit(char const * wuid)
- {
- StringBuffer xpath;
- xpath.append("*/*/*/");
- ncnameEscape(wuid, xpath);
- Owned<IRemoteConnection> conn = querySDS().connect("/Schedule", myProcessSession(), RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT);
- if(!conn) return;
- Owned<IPropertyTree> root = conn->getRoot();
- bool more;
- do more = root->removeProp(xpath.str()); while(more);
- }
- //======================================================
- /*
- * Graph progress support
- */
- CWuGraphStats::CWuGraphStats(IPropertyTree *_progress, StatisticCreatorType _creatorType, const char * _creator, const char * _rootScope, unsigned _id)
- : progress(_progress), creatorType(_creatorType), creator(_creator), id(_id)
- {
- StatisticScopeType scopeType = SSTgraph;
- StatsScopeId rootScopeId;
- verifyex(rootScopeId.setScopeText(_rootScope));
- collector.setown(createStatisticsGatherer(_creatorType, _creator, rootScopeId));
- }
- void CWuGraphStats::beforeDispose()
- {
- Owned<IStatisticCollection> stats = collector->getResult();
- MemoryBuffer compressed;
- {
- MemoryBuffer serialized;
- serializeStatisticCollection(serialized, stats);
- compressToBuffer(compressed, serialized.length(), serialized.toByteArray());
- }
- unsigned minActivity = 0;
- unsigned maxActivity = 0;
- stats->getMinMaxActivity(minActivity, maxActivity);
- StringBuffer tag;
- tag.append("sg").append(id);
- IPropertyTree * subgraph = createPTree(tag);
- subgraph->setProp("@c", queryCreatorTypeName(creatorType));
- subgraph->setProp("@creator", creator);
- subgraph->setPropInt("@minActivity", minActivity);
- subgraph->setPropInt("@maxActivity", maxActivity);
- //Replace the particular subgraph statistics added by this creator
- StringBuffer qualified(tag);
- qualified.append("[@creator='").append(creator).append("']");
- progress->removeProp(qualified);
- subgraph = progress->addPropTree(tag, subgraph);
- subgraph->setPropBin("Stats", compressed.length(), compressed.toByteArray());
- if (!progress->getPropBool("@stats", false))
- progress->setPropBool("@stats", true);
- }
- IStatisticGatherer & CWuGraphStats::queryStatsBuilder()
- {
- return *collector;
- }
- class CConstGraphProgress : public CInterface, implements IConstWUGraphProgress
- {
- public:
- IMPLEMENT_IINTERFACE;
- CConstGraphProgress(const char *_wuid, const char *_graphName, IPropertyTree *_progress) : wuid(_wuid), graphName(_graphName), progress(_progress)
- {
- if (!progress)
- progress.setown(createPTree());
- formatVersion = progress->getPropInt("@format", PROGRESS_FORMAT_V);
- }
- virtual IPropertyTree * getProgressTree()
- {
- if (progress->getPropBool("@stats"))
- return createProcessTreeFromStats(); // Should we cache that?
- return LINK(progress);
- }
- virtual unsigned queryFormatVersion()
- {
- return formatVersion;
- }
- protected:
- CConstGraphProgress(const char *_wuid, const char *_graphName) : wuid(_wuid), graphName(_graphName)
- {
- formatVersion = PROGRESS_FORMAT_V;
- }
- static void expandStats(IPropertyTree * target, IStatisticCollection & collection)
- {
- StringBuffer formattedValue;
- unsigned numStats = collection.getNumStatistics();
- for (unsigned i=0; i < numStats; i++)
- {
- StatisticKind kind;
- unsigned __int64 value;
- collection.getStatistic(kind, value, i);
- formatStatistic(formattedValue.clear(), value, kind);
- target->setProp(queryTreeTag(kind), formattedValue);
- }
- }
- void expandProcessTreeFromStats(IPropertyTree * rootTarget, IPropertyTree * target, IStatisticCollection * collection)
- {
- expandStats(target, *collection);
- StringBuffer scopeName;
- Owned<IStatisticCollectionIterator> activityIter = &collection->getScopes(NULL);
- ForEach(*activityIter)
- {
- IStatisticCollection & cur = activityIter->query();
- cur.getScope(scopeName.clear());
- const char * id = scopeName.str();
- const char * tag;
- IPropertyTree * curTarget = target;
- switch (cur.queryScopeType())
- {
- case SSTedge:
- tag = "edge";
- id += strlen(EdgeScopePrefix);
- break;
- case SSTactivity:
- tag = "node";
- id += strlen(ActivityScopePrefix);
- break;
- case SSTsubgraph:
- //All subgraphs are added a root elements in the progress tree
- curTarget = rootTarget;
- tag = "node";
- id += strlen(SubGraphScopePrefix);
- break;
- case SSTfunction:
- //MORE:Should function scopes be included in the graph scope somehow, and if so how?
- continue;
- default:
- throwUnexpected();
- }
- IPropertyTree * next = curTarget->addPropTree(tag, createPTree());
- next->setProp("@id", id);
- expandProcessTreeFromStats(rootTarget, next, &cur);
- }
- }
- IPropertyTree * createProcessTreeFromStats()
- {
- MemoryBuffer compressed;
- MemoryBuffer serialized;
- Owned<IPropertyTree> progressTree = createPTree();
- Owned<IPropertyTreeIterator> iter = progress->getElements("sg*");
- ForEach(*iter)
- {
- IPropertyTree & curSubGraph = iter->query();
- curSubGraph.getPropBin("Stats", compressed.clear());
- //Protect against updates that delete the stats while we are iterating
- if (compressed.length())
- {
- decompressToBuffer(serialized.clear(), compressed);
- Owned<IStatisticCollection> collection = createStatisticCollection(serialized);
- expandProcessTreeFromStats(progressTree, progressTree, collection);
- }
- }
- return progressTree.getClear();
- }
- protected:
- Linked<IPropertyTree> progress;
- StringAttr wuid, graphName;
- unsigned formatVersion;
- };
- extern WORKUNIT_API IConstWUGraphProgress *createConstGraphProgress(const char *_wuid, const char *_graphName, IPropertyTree *_progress)
- {
- return new CConstGraphProgress(_wuid, _graphName, _progress);
- }
- //--------------------------------------------------------------------------------------------------------------------
- class ExtractedStatistic : public CInterfaceOf<IConstWUStatistic>
- {
- public:
- virtual IStringVal & getDescription(IStringVal & str, bool createDefault) const
- {
- if (!description && createDefault)
- {
- switch (kind)
- {
- case StTimeElapsed:
- {
- if (scopeType != SSTsubgraph)
- break;
- //Create a default description for a root subgraph
- const char * colon = strchr(scope, ':');
- if (!colon)
- break;
- const char * subgraph = colon+1;
- //Check for nested subgraph
- if (strchr(subgraph, ':'))
- break;
- assertex(strncmp(subgraph, SubGraphScopePrefix, strlen(SubGraphScopePrefix)) == 0);
- StringAttr graphname;
- graphname.set(scope, colon - scope);
- unsigned subId = atoi(subgraph + strlen(SubGraphScopePrefix));
- StringBuffer desc;
- formatGraphTimerLabel(desc, graphname, 0, subId);
- str.set(desc);
- return str;
- }
- }
- }
- str.set(description);
- return str;
- }
- virtual IStringVal & getCreator(IStringVal & str) const
- {
- str.set(creator);
- return str;
- }
- virtual IStringVal & getScope(IStringVal & str) const
- {
- str.set(scope);
- return str;
- }
- virtual IStringVal & getFormattedValue(IStringVal & str) const
- {
- StringBuffer formatted;
- formatStatistic(formatted, value, measure);
- str.set(formatted);
- return str;
- }
- virtual StatisticMeasure getMeasure() const
- {
- return measure;
- }
- virtual StatisticKind getKind() const
- {
- return kind;
- }
- virtual StatisticCreatorType getCreatorType() const
- {
- return creatorType;
- }
- virtual StatisticScopeType getScopeType() const
- {
- return scopeType;
- }
- virtual unsigned __int64 getValue() const
- {
- return value;
- }
- virtual unsigned __int64 getCount() const
- {
- return count;
- }
- virtual unsigned __int64 getMax() const
- {
- return max;
- }
- virtual unsigned __int64 getTimestamp() const
- {
- return timeStamp;
- }
- virtual bool matches(const IStatisticsFilter * filter) const
- {
- return filter->matches(creatorType, creator, scopeType, scope, measure, kind);
- }
- public:
- StringAttr creator;
- StringAttr description;
- StringBuffer scope;
- StatisticMeasure measure;
- StatisticKind kind;
- StatisticCreatorType creatorType;
- StatisticScopeType scopeType;
- unsigned __int64 value;
- unsigned __int64 count;
- unsigned __int64 max;
- unsigned __int64 timeStamp;
- };
- class CConstGraphProgressStatisticsIterator : public CInterfaceOf<IConstWUStatisticIterator>
- {
- public:
- CConstGraphProgressStatisticsIterator(const char * wuid, const IStatisticsFilter * _filter) : filter(_filter)
- {
- if (filter)
- scopes.appendList(filter->queryScope(), ":");
- const char * searchGraph = "*";
- if (scopes.ordinality())
- searchGraph = scopes.item(0);
- rootPath.append("/GraphProgress/").append(wuid).append('/');
- bool singleGraph = false;
- if (!containsWildcard(searchGraph))
- {
- rootPath.append(searchGraph).append("/");
- singleGraph = true;
- }
- //Don't lock the statistics while we iterate - any partial updates must not cause problems
- if (daliClientActive())
- conn.setown(querySDS().connect(rootPath.str(), myProcessSession(), RTM_NONE, SDS_LOCK_TIMEOUT));
- if (conn && !singleGraph)
- graphIter.setown(conn->queryRoot()->getElements("*"));
- curStat.setown(new ExtractedStatistic);
- //These are currently constant for all graph statistics instances
- curStat->count = 1;
- curStat->max = 0;
- valid = false;
- }
- virtual IConstWUStatistic & query()
- {
- return *curStat;
- }
- virtual bool first()
- {
- valid = false;
- if (!conn)
- return false;
- if (graphIter && !graphIter->first())
- return false;
- ensureUniqueStatistic();
- if (!firstSubGraph())
- {
- if (!nextGraph())
- return false;
- }
- valid = true;
- return true;
- }
- virtual bool next()
- {
- ensureUniqueStatistic();
- if (!nextStatistic())
- {
- if (!nextSubGraph())
- {
- if (!nextGraph())
- {
- valid = false;
- return false;
- }
- }
- }
- return true;
- }
- virtual bool isValid()
- {
- return valid;
- }
- protected:
- bool firstSubGraph()
- {
- IPropertyTree & graphNode = graphIter ? graphIter->query() : *conn->queryRoot();
- const char * xpath = "sg*";
- StringBuffer childXpath;
- if (scopes.isItem(1))
- {
- const char * scope1 = scopes.item(1);
- if (strnicmp(scope1, "sg", 2) == 0)
- {
- childXpath.append(scope1);
- xpath = childXpath.str();
- }
- }
- subgraphIter.setown(graphNode.getElements(xpath));
- if (!subgraphIter)
- subgraphIter.setown(graphNode.getElements("sg0"));
- if (!subgraphIter->first())
- return false;
- if (firstStat())
- return true;
- return nextSubGraph();
- }
- bool nextSubGraph()
- {
- loop
- {
- if (!subgraphIter->next())
- return false;
- if (firstStat())
- return true;
- }
- }
- bool nextGraph()
- {
- if (!graphIter)
- return false;
- loop
- {
- if (!graphIter->next())
- return false;
- if (firstSubGraph())
- return true;
- }
- }
- bool firstStat()
- {
- IPropertyTree & curSubGraph = subgraphIter->query();
- if (!checkSubGraph())
- return false;
- curSubGraph.getPropBin("Stats", compressed.clear());
- //Don't crash on old format progress...
- if (compressed.length() == 0)
- return false;
- decompressToBuffer(serialized.clear(), compressed);
- Owned<IStatisticCollection> collection = createStatisticCollection(serialized);
- curStat->timeStamp = collection->queryWhenCreated();
- return beginCollection(*collection);
- }
- bool beginCollection(IStatisticCollection & collection)
- {
- collections.append(OLINK(collection));
- numStats = collection.getNumStatistics();
- curStatIndex = 0;
- if (checkScope())
- {
- if (curStatIndex < numStats)
- {
- if (checkStatistic())
- return true;
- return nextStatistic();
- }
- }
- return nextChildScope();
- }
- bool nextStatistic()
- {
- //Finish iterating the statistics at this level.
- while (++curStatIndex < numStats)
- {
- if (checkStatistic())
- return true;
- }
- return nextChildScope();
- }
- bool nextChildScope()
- {
- loop
- {
- if (collections.ordinality() == 0)
- return false;
- IStatisticCollection * curCollection = &collections.tos();
- if (childIterators.ordinality() < collections.ordinality())
- {
- if (!filter || filter->recurseChildScopes(curStat->scopeType, curStat->scope))
- {
- //Start iterating the children for the current collection
- childIterators.append(curCollection->getScopes(NULL));
- if (!childIterators.tos().first())
- {
- finishCollection();
- continue;
- }
- }
- else
- {
- //Don't walk the child scopes
- collections.pop();
- continue;
- }
- }
- else if (!childIterators.tos().next())
- {
- finishCollection();
- continue;
- }
- if (beginCollection(childIterators.tos().query()))
- return true;
- }
- }
- void finishCollection()
- {
- collections.pop();
- childIterators.pop();
- }
- bool checkSubGraph()
- {
- if (!filter)
- return true;
- IPropertyTree & curSubGraph = subgraphIter->query();
- curStat->creatorType = queryCreatorType(curSubGraph.queryProp("@c"));
- curStat->creator.set(curSubGraph.queryProp("@creator"));
- return filter->matches(curStat->creatorType, curStat->creator, SSTall, NULL, SMeasureAll, StKindAll);
- }
- bool checkScope()
- {
- if (!filter)
- return true;
- IStatisticCollection * collection = &collections.tos();
- curStat->scopeType = collection->queryScopeType();
- collection->getFullScope(curStat->scope.clear());
- return filter->matches(SCTall, NULL, curStat->scopeType, curStat->scope, SMeasureAll, StKindAll);
- }
- bool checkStatistic()
- {
- IStatisticCollection & collection = collections.tos();
- collection.getStatistic(curStat->kind, curStat->value, curStatIndex);
- curStat->measure = queryMeasure(curStat->kind);
- if (!filter)
- return true;
- if (!filter->matches(SCTall, NULL, SSTall, NULL, curStat->measure, curStat->kind))
- return false;
- return true;
- }
- void ensureUniqueStatistic()
- {
- //If something else has linked this statistic, clone a unique one.
- if (curStat->IsShared())
- curStat.setown(new ExtractedStatistic(*curStat));
- }
- private:
- Owned<IRemoteConnection> conn;
- Owned<ExtractedStatistic> curStat;
- const IStatisticsFilter * filter;
- StringArray scopes;
- StringBuffer rootPath;
- Owned<IPropertyTreeIterator> graphIter;
- Owned<IPropertyTreeIterator> subgraphIter;
- IArrayOf<IStatisticCollection> collections;
- IArrayOf<IStatisticCollectionIterator> childIterators;
- MemoryBuffer compressed;
- MemoryBuffer serialized;
- unsigned numStats;
- unsigned curStatIndex;
- bool valid;
- };
- //--------------------------------------------------------------------------------------------------------------------
- mapEnums states[] = {
- { WUStateUnknown, "unknown" },
- { WUStateCompiled, "compiled" },
- { WUStateRunning, "running" },
- { WUStateCompleted, "completed" },
- { WUStateFailed, "failed" },
- { WUStateArchived, "archived" },
- { WUStateAborting, "aborting" },
- { WUStateAborted, "aborted" },
- { WUStateBlocked, "blocked" },
- { WUStateSubmitted, "submitted" },
- { WUStateScheduled, "scheduled" },
- { WUStateCompiling, "compiling" },
- { WUStateWait, "wait" },
- { WUStateUploadingFiles, "uploading_files" },
- { WUStateDebugPaused, "debugging" },
- { WUStateDebugRunning, "debug_running" },
- { WUStatePaused, "paused" },
- { WUStateSize, NULL }
- };
- mapEnums actions[] = {
- { WUActionUnknown, "unknown" },
- { WUActionCompile, "compile" },
- { WUActionCheck, "check" },
- { WUActionRun, "run" },
- { WUActionExecuteExisting, "execute" },
- { WUActionPause, "pause" },
- { WUActionPauseNow, "pausenow" },
- { WUActionResume, "resume" },
- { WUActionSize, NULL },
- };
- mapEnums priorityClasses[] = {
- { PriorityClassUnknown, "unknown" },
- { PriorityClassLow, "low" },
- { PriorityClassNormal, "normal" },
- { PriorityClassHigh, "high" },
- { PriorityClassSize, NULL },
- };
- const char * getWorkunitStateStr(WUState state)
- {
- dbgassertex(state < WUStateSize);
- return states[state].str; // MORE - should be using getEnumText, or need to take steps to ensure values remain contiguous and in order.
- }
- void setEnum(IPropertyTree *p, const char *propname, int value, const mapEnums *map)
- {
- const char *defval = map->str;
- while (map->str)
- {
- if (value==map->val)
- {
- p->setProp(propname, map->str);
- return;
- }
- map++;
- }
- assertex(!"Unexpected value in setEnum");
- p->setProp(propname, defval);
- }
- static int getEnum(const char *v, const mapEnums *map)
- {
- if (v)
- {
- while (map->str)
- {
- if (stricmp(v, map->str)==0)
- return map->val;
- map++;
- }
- assertex(!"Unexpected value in getEnum");
- }
- return 0;
- }
- static int getEnum(const IPropertyTree *p, const char *propname, const mapEnums *map)
- {
- return getEnum(p->queryProp(propname),map);
- }
- const char * getWorkunitActionStr(WUAction action)
- {
- return getEnumText(action, actions);
- }
- WUAction getWorkunitAction(const char *actionStr)
- {
- return (WUAction) getEnum(actionStr, actions);
- }
- //==========================================================================================
- class CLightweightWorkunitInfo : public CInterfaceOf<IConstWorkUnitInfo>
- {
- public:
- CLightweightWorkunitInfo(IPropertyTree &p)
- {
- wuid.set(p.queryName());
- user.set(p.queryProp("@submitID"));
- jobName.set(p.queryProp("@jobName"));
- clusterName.set(p.queryProp("@clusterName"));
- timeScheduled.set(p.queryProp("@timeScheduled"));
- state = (WUState) getEnum(&p, "@state", states);
- action = (WUAction) getEnum(&p, "Action", actions);
- priority = (WUPriorityClass) getEnum(&p, "@priorityClass", priorityClasses);
- priorityLevel = calcPriorityValue(&p);
- wuscope.set(p.queryProp("@scope"));
- appvalues.load(&p,"Application/*");
- totalThorTime = (unsigned)nanoToMilli(extractTimeCollatable(p.queryProp("@totalThorTime"), false));
- _isProtected = p.getPropBool("@protected", false);
- }
- virtual const char *queryWuid() const { return wuid.str(); }
- virtual const char *queryUser() const { return user.str(); }
- virtual const char *queryJobName() const { return jobName.str(); }
- virtual const char *queryClusterName() const { return clusterName.str(); }
- virtual const char *queryWuScope() const { return wuscope.str(); }
- virtual WUState getState() const { return state; }
- virtual const char *queryStateDesc() const { return getEnumText(state, states); }
- virtual WUAction getAction() const { return action; }
- virtual const char *queryActionDesc() const { return getEnumText(action, actions); }
- virtual WUPriorityClass getPriority() const { return priority; }
- virtual const char *queryPriorityDesc() const { return getEnumText(priority, priorityClasses); }
- virtual int getPriorityLevel() const { return priorityLevel; }
- virtual bool isProtected() const { return _isProtected; }
- virtual IJlibDateTime & getTimeScheduled(IJlibDateTime & val) const
- {
- if (timeScheduled.length())
- val.setGmtString(timeScheduled.str());
- return val;
- }
- virtual unsigned getTotalThorTime() const { return totalThorTime; };
- virtual IConstWUAppValueIterator & getApplicationValues() const { return *new CArrayIteratorOf<IConstWUAppValue,IConstWUAppValueIterator> (appvalues, 0, (IConstWorkUnitInfo *) this); };
- protected:
- StringAttr wuid, user, jobName, clusterName, timeScheduled, wuscope;
- mutable CachedTags<CLocalWUAppValue,IConstWUAppValue> appvalues;
- unsigned totalThorTime;
- WUState state;
- WUAction action;
- WUPriorityClass priority;
- int priorityLevel;
- bool _isProtected;
- };
- extern IConstWorkUnitInfo *createConstWorkUnitInfo(IPropertyTree &p)
- {
- return new CLightweightWorkunitInfo(p);
- }
- class CDaliWuGraphStats : public CWuGraphStats
- {
- public:
- CDaliWuGraphStats(IRemoteConnection *_conn, StatisticCreatorType _creatorType, const char * _creator, const char * _rootScope, unsigned _id)
- : CWuGraphStats(LINK(_conn->queryRoot()), _creatorType, _creator, _rootScope, _id), conn(_conn)
- {
- }
- protected:
- Owned<IRemoteConnection> conn;
- };
- CWorkUnitWatcher::CWorkUnitWatcher(IWorkUnitSubscriber *_subscriber, WUSubscribeOptions flags, const char *wuid) : subscriber(_subscriber)
- {
- abortId = 0;
- stateId = 0;
- actionId = 0;
- assertex((flags & ~SubscribeOptionAbort) == 0);
- if (flags & SubscribeOptionAbort)
- {
- VStringBuffer xpath("/WorkUnitAborts/%s", wuid);
- abortId = querySDS().subscribe(xpath.str(), *this);
- }
- }
- CWorkUnitWatcher::~CWorkUnitWatcher()
- {
- assertex(abortId==0 && stateId==0 && actionId==0);
- }
- void CWorkUnitWatcher::unsubscribe()
- {
- CriticalBlock b(crit);
- if (abortId)
- querySDS().unsubscribe(abortId);
- if (stateId)
- querySDS().unsubscribe(stateId);
- if (actionId)
- querySDS().unsubscribe(actionId);
- abortId = 0;
- stateId = 0;
- actionId = 0;
- }
- void CWorkUnitWatcher::notify(SubscriptionId id, const char *xpath, SDSNotifyFlags flags, unsigned valueLen, const void *valueData)
- {
- CriticalBlock b(crit);
- if (id==stateId)
- subscriber->notify(SubscribeOptionState);
- else if (id==actionId)
- subscriber->notify(SubscribeOptionAction);
- else if (id==abortId)
- subscriber->notify(SubscribeOptionAbort);
- }
- class CDaliWorkUnitWatcher : public CWorkUnitWatcher
- {
- public:
- CDaliWorkUnitWatcher(IWorkUnitSubscriber *_subscriber, WUSubscribeOptions flags, const char *wuid)
- : CWorkUnitWatcher(_subscriber, (WUSubscribeOptions) (flags & SubscribeOptionAbort), wuid)
- {
- if (flags & SubscribeOptionState)
- {
- VStringBuffer xpath("/WorkUnits/%s/State", wuid);
- stateId = querySDS().subscribe(xpath.str(), *this);
- }
- if (flags & SubscribeOptionAction)
- {
- VStringBuffer xpath("/WorkUnits/%s/Action", wuid);
- actionId = querySDS().subscribe(xpath.str(), *this);
- }
- }
- };
- void CPersistedWorkUnit::subscribe(WUSubscribeOptions options)
- {
- CriticalBlock block(crit);
- assertex(options==SubscribeOptionAbort);
- if (!abortWatcher)
- {
- abortWatcher.setown(new CWorkUnitWatcher(this, SubscribeOptionAbort, p->queryName()));
- abortDirty = true;
- }
- }
- void CPersistedWorkUnit::unsubscribe()
- {
- CriticalBlock block(crit);
- if (abortWatcher)
- {
- abortWatcher->unsubscribe();
- abortWatcher.clear();
- }
- }
- bool CPersistedWorkUnit::aborting() const
- {
- CriticalBlock block(crit);
- if (abortDirty)
- {
- StringBuffer apath;
- apath.append("/WorkUnitAborts/").append(p->queryName());
- Owned<IRemoteConnection> acon = querySDS().connect(apath.str(), myProcessSession(), 0, SDS_LOCK_TIMEOUT);
- if (acon)
- abortState = acon->queryRoot()->getPropInt(NULL) != 0;
- else
- abortState = false;
- abortDirty = false;
- }
- return abortState;
- }
- class CDaliWorkUnit : public CPersistedWorkUnit
- {
- public:
- CDaliWorkUnit(IRemoteConnection *_conn, ISecManager *secmgr, ISecUser *secuser)
- : connection(_conn), CPersistedWorkUnit(secmgr, secuser)
- {
- loadPTree(connection->getRoot());
- }
- ~CDaliWorkUnit()
- {
- // NOTE - order is important - we need to construct connection before p and (especially) destroy after p
- // We use the beforeDispose() in base class to help ensure this
- p.clear();
- }
- IConstWUGraphProgress *getGraphProgress(const char *graphName) const
- {
- Owned<IRemoteConnection> conn = getProgressConnection();
- if (conn)
- {
- IPTree *progress = conn->queryRoot()->queryPropTree(graphName);
- if (progress)
- return new CConstGraphProgress(p->queryName(), graphName, progress);
- }
- return NULL;
- }
- virtual WUGraphState queryGraphState(const char *graphName) const
- {
- Owned<IRemoteConnection> conn = getProgressConnection();
- if (conn)
- {
- IPTree *progress = conn->queryRoot()->queryPropTree(graphName);
- if (progress)
- return (WUGraphState) progress->getPropInt("@_state", (unsigned) WUGraphUnknown);
- }
- return WUGraphUnknown;
- }
- virtual WUGraphState queryNodeState(const char *graphName, WUGraphIDType nodeId) const
- {
- Owned<IRemoteConnection> conn = getProgressConnection();
- if (conn)
- {
- IPTree *progress = conn->queryRoot()->queryPropTree(graphName);
- if (progress)
- {
- StringBuffer path;
- // NOTE - the node state info still uses the old graph layout, even when the stats are using the new...
- path.append("node[@id=\"").append(nodeId).append("\"]/@_state");
- return (WUGraphState) progress->getPropInt(path, (unsigned) WUGraphUnknown);
- }
- }
- return WUGraphUnknown;
- }
- virtual void clearGraphProgress() const
- {
- CriticalBlock block(crit);
- progressConnection.clear(); // Make sure nothing is locking for read or we won't be able to lock for write
- StringBuffer path("/GraphProgress/");
- path.append(p->queryName());
- Owned<IRemoteConnection> delconn = querySDS().connect(path.str(), myProcessSession(), RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT);
- if (delconn)
- delconn->close(true);
- }
- virtual bool getRunningGraph(IStringVal &graphName, WUGraphIDType &subId) const
- {
- Owned<IRemoteConnection> conn = getProgressConnection();
- if (!conn)
- return false;
- const char *name = conn->queryRoot()->queryProp("Running/@graph");
- if (name)
- {
- graphName.set(name);
- subId = conn->queryRoot()->getPropInt64("Running/@subId");
- return true;
- }
- else
- return false;
- }
- virtual void forceReload()
- {
- synchronized sync(locked); // protect locked workunits (uncommitted writes) from reload
- CriticalBlock block(crit);
- clearCached(true);
- connection->reload();
- progressConnection.clear();
- abortDirty = true;
- p.setown(connection->getRoot());
- }
- virtual void cleanupAndDelete(bool deldll, bool deleteOwned, const StringArray *deleteExclusions)
- {
- CPersistedWorkUnit::cleanupAndDelete(deldll, deleteOwned, deleteExclusions);
- clearGraphProgress();
- connection->close(true);
- connection.clear();
- }
- virtual void commit()
- {
- CPersistedWorkUnit::commit();
- if (connection)
- connection->commit();
- }
- virtual void _lockRemote()
- {
- StringBuffer wuRoot;
- getXPath(wuRoot, p->queryName());
- if (connection)
- connection->changeMode(RTM_LOCK_WRITE,SDS_LOCK_TIMEOUT);
- else
- connection.setown(querySDS().connect(wuRoot.str(), myProcessSession(), RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT));
- if (!connection)
- throw MakeStringException(WUERR_LockFailed, "Failed to get connection for xpath %s", wuRoot.str());
- clearCached(true);
- p.setown(connection->getRoot());
- }
- virtual void _unlockRemote()
- {
- if (connection)
- {
- try
- {
- try
- {
- connection->commit();
- }
- catch (IException *e)
- {
- EXCLOG(e, "Error during workunit commit");
- connection->rollback();
- connection->changeMode(0, SDS_LOCK_TIMEOUT);
- throw;
- }
- connection->changeMode(0, SDS_LOCK_TIMEOUT);
- }
- catch (IException *E)
- {
- StringBuffer s;
- PrintLog("Failed to release write lock on workunit: %s", E->errorMessage(s).str());
- throw;
- }
- }
- }
- virtual void setGraphState(const char *graphName, WUGraphState state) const
- {
- Owned<IRemoteConnection> conn = getWritableProgressConnection(graphName);
- conn->queryRoot()->setPropInt("@_state", state);
- }
- virtual void setNodeState(const char *graphName, WUGraphIDType nodeId, WUGraphState state) const
- {
- CriticalBlock block(crit);
- progressConnection.clear(); // Make sure nothing is locking for read or we won't be able to lock for write
- VStringBuffer path("/GraphProgress/%s", queryWuid());
- Owned<IRemoteConnection> conn = querySDS().connect(path, myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT);
- IPTree *progress = ensurePTree(conn->queryRoot(), graphName);
- // NOTE - the node state info still uses the old graph layout, even when the stats are using the new...
- path.clear().append("node[@id=\"").append(nodeId).append("\"]");
- IPropertyTree *node = progress->queryPropTree(path.str());
- if (!node)
- {
- node = progress->addPropTree("node", createPTree());
- node->setPropInt64("@id", nodeId);
- }
- node->setPropInt("@_state", (unsigned)state);
- switch (state)
- {
- case WUGraphRunning:
- {
- IPropertyTree *running = conn->queryRoot()->setPropTree("Running", createPTree());
- running->setProp("@graph", graphName);
- running->setPropInt64("@subId", nodeId);
- break;
- }
- case WUGraphComplete:
- {
- conn->queryRoot()->removeProp("Running"); // only one thing running at any given time and one thing with lockWrite access
- break;
- }
- }
- }
- virtual IWUGraphStats *updateStats(const char *graphName, StatisticCreatorType creatorType, const char * creator, unsigned subgraph) const
- {
- return new CDaliWuGraphStats(getWritableProgressConnection(graphName), creatorType, creator, graphName, subgraph);
- }
- protected:
- IRemoteConnection *getProgressConnection() const
- {
- CriticalBlock block(crit);
- if (!progressConnection)
- {
- VStringBuffer path("/GraphProgress/%s", queryWuid());
- progressConnection.setown(querySDS().connect(path, myProcessSession(), 0, SDS_LOCK_TIMEOUT)); // Note - we don't lock. The writes are atomic.
- }
- return progressConnection.getLink();
- }
- IRemoteConnection *getWritableProgressConnection(const char *graphName) const
- {
- CriticalBlock block(crit);
- progressConnection.clear(); // Make sure subsequent reads from this workunit get the changes I am making
- VStringBuffer path("/GraphProgress/%s/%s", queryWuid(), graphName);
- return querySDS().connect(path, myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT);
- }
- IPropertyTree *getGraphProgressTree() const
- {
- Owned<IRemoteConnection> conn = getProgressConnection();
- if (conn)
- {
- Owned<IPropertyTree> tmp = createPTree("GraphProgress");
- mergePTree(tmp,conn->queryRoot());
- return tmp.getClear();
- }
- return NULL;
- }
- Owned<IRemoteConnection> connection;
- mutable Owned<IRemoteConnection> progressConnection;
- };
- class CLockedWorkUnit : implements ILocalWorkUnit, implements IExtendedWUInterface, public CInterface
- {
- public:
- Owned<CLocalWorkUnit> c;
- IMPLEMENT_IINTERFACE;
- CLockedWorkUnit(CLocalWorkUnit *_c) : c(_c) {}
- ~CLockedWorkUnit()
- {
- if (workUnitTraceLevel > 1)
- PrintLog("Releasing locked workunit %s", queryWuid());
- if (c)
- c->unlockRemote();
- }
- virtual IConstWorkUnit * unlock()
- {
- c->unlockRemote();
- return c.getClear();
- }
- virtual bool aborting() const
- { return c->aborting(); }
- virtual void forceReload()
- { UNIMPLEMENTED; }
- virtual WUAction getAction() const
- { return c->getAction(); }
- virtual const char *queryActionDesc() const
- { return c->queryActionDesc(); }
- virtual IStringVal & getApplicationValue(const char * application, const char * propname, IStringVal & str) const
- { return c->getApplicationValue(application, propname, str); }
- virtual int getApplicationValueInt(const char * application, const char * propname, int defVal) const
- { return c->getApplicationValueInt(application, propname, defVal); }
- virtual IConstWUAppValueIterator & getApplicationValues() const
- { return c->getApplicationValues(); }
- virtual bool hasWorkflow() const
- { return c->hasWorkflow(); }
- virtual unsigned queryEventScheduledCount() const
- { return c->queryEventScheduledCount(); }
- virtual IPropertyTree * queryWorkflowTree() const
- { return c->queryWorkflowTree(); }
- virtual IConstWorkflowItemIterator * getWorkflowItems() const
- { return c->getWorkflowItems(); }
- virtual IWorkflowItemArray * getWorkflowClone() const
- { return c->getWorkflowClone(); }
- virtual bool requiresLocalFileUpload() const
- { return c->requiresLocalFileUpload(); }
- virtual IConstLocalFileUploadIterator * getLocalFileUploads() const
- { return c->getLocalFileUploads(); }
- virtual bool getIsQueryService() const
- { return c->getIsQueryService(); }
- virtual bool getCloneable() const
- { return c->getCloneable(); }
- virtual IUserDescriptor * queryUserDescriptor() const
- { return c->queryUserDescriptor(); }
- virtual const char *queryClusterName() const
- { return c->queryClusterName(); }
- virtual unsigned getCodeVersion() const
- { return c->getCodeVersion(); }
- virtual unsigned getWuidVersion() const
- { return c->getWuidVersion(); }
- virtual void getBuildVersion(IStringVal & buildVersion, IStringVal & eclVersion) const
- { c->getBuildVersion(buildVersion, eclVersion); }
- virtual bool hasDebugValue(const char * propname) const
- { return c->hasDebugValue(propname); }
- virtual IStringVal & getDebugValue(const char * propname, IStringVal & str) const
- { return c->getDebugValue(propname, str); }
- virtual int getDebugValueInt(const char * propname, int defVal) const
- { return c->getDebugValueInt(propname, defVal); }
- virtual __int64 getDebugValueInt64(const char * propname, __int64 defVal) const
- { return c->getDebugValueInt64(propname, defVal); }
- virtual bool getDebugValueBool(const char * propname, bool defVal) const
- { return c->getDebugValueBool(propname, defVal); }
- virtual IStringIterator & getDebugValues() const
- { return c->getDebugValues(NULL); }
- virtual IStringIterator & getDebugValues(const char *prop) const
- { return c->getDebugValues(prop); }
- virtual unsigned getExceptionCount() const
- { return c->getExceptionCount(); }
- virtual IConstWUExceptionIterator & getExceptions() const
- { return c->getExceptions(); }
- virtual unsigned getGraphCount() const
- { return c->getGraphCount(); }
- virtual unsigned getSourceFileCount() const
- { return c->getSourceFileCount(); }
- virtual unsigned getResultCount() const
- { return c->getResultCount(); }
- virtual unsigned getVariableCount() const
- { return c->getVariableCount(); }
- virtual unsigned getApplicationValueCount() const
- { return c->getApplicationValueCount(); }
- virtual IConstWUGraphIterator & getGraphs(WUGraphType type) const
- { return c->getGraphs(type); }
- virtual IConstWUGraphMetaIterator & getGraphsMeta(WUGraphType type) const
- { return c->getGraphsMeta(type); }
- virtual IConstWUGraph * getGraph(const char *name) const
- { return c->getGraph(name); }
- virtual IConstWUGraphProgress * getGraphProgress(const char * name) const
- { return c->getGraphProgress(name); }
- virtual const char *queryJobName() const
- { return c->queryJobName(); }
- virtual IConstWUPlugin * getPluginByName(const char * name) const
- { return c->getPluginByName(name); }
- virtual IConstWUPluginIterator & getPlugins() const
- { return c->getPlugins(); }
- virtual IConstWULibrary* getLibraryByName(const char *name) const
- { return c->getLibraryByName(name); }
- virtual IConstWULibraryIterator & getLibraries() const
- { return c->getLibraries(); }
- virtual WUPriorityClass getPriority() const
- { return c->getPriority(); }
- virtual const char *queryPriorityDesc() const
- { return c->queryPriorityDesc(); }
- virtual int getPriorityLevel() const
- { return c->getPriorityLevel(); }
- virtual int getPriorityValue() const
- { return c->getPriorityValue(); }
- virtual IConstWUQuery * getQuery() const
- { return c->getQuery(); }
- virtual IConstWUWebServicesInfo * getWebServicesInfo() const
- { return c->getWebServicesInfo(); }
- virtual bool getRescheduleFlag() const
- { return c->getRescheduleFlag(); }
- virtual IConstWUResult * getResultByName(const char * name) const
- { return c->getResultByName(name); }
- virtual IConstWUResult * getResultBySequence(unsigned seq) const
- { return c->getResultBySequence(seq); }
- virtual unsigned getResultLimit() const
- { return c->getResultLimit(); }
- virtual IConstWUResultIterator & getResults() const
- { return c->getResults(); }
- virtual IStringVal & getScope(IStringVal & str) const
- { return c->getScope(str); }
- virtual IStringVal & getSecurityToken(IStringVal & str) const
- { return c->getSecurityToken(str); }
- virtual WUState getState() const
- { return c->getState(); }
- virtual IStringVal & getStateEx(IStringVal & str) const
- { return c->getStateEx(str); }
- virtual __int64 getAgentSession() const
- { return c->getAgentSession(); }
- virtual unsigned getAgentPID() const
- { return c->getAgentPID(); }
- virtual const char *queryStateDesc() const
- { return c->queryStateDesc(); }
- virtual bool getRunningGraph(IStringVal & graphName, WUGraphIDType & subId) const
- { return c->getRunningGraph(graphName, subId); }
- virtual IConstWUStatisticIterator & getStatistics(const IStatisticsFilter * filter) const
- { return c->getStatistics(filter); }
- virtual IConstWUStatistic * getStatistic(const char * creator, const char * scope, StatisticKind kind) const
- { return c->getStatistic(creator, scope, kind); }
- virtual IStringVal & getSnapshot(IStringVal & str) const
- { return c->getSnapshot(str); }
- virtual const char *queryUser() const
- { return c->queryUser(); }
- virtual ErrorSeverity getWarningSeverity(unsigned code, ErrorSeverity defaultSeverity) const
- { return c->getWarningSeverity(code, defaultSeverity); }
- virtual const char *queryWuScope() const
- { return c->queryWuScope(); }
- virtual const char *queryWuid() const
- { return c->queryWuid(); }
- virtual IConstWUResult * getGlobalByName(const char * name) const
- { return c->getGlobalByName(name); }
- virtual IConstWUResult * getTemporaryByName(const char * name) const
- { return c->getTemporaryByName(name); }
- virtual IConstWUResultIterator & getTemporaries() const
- { return c->getTemporaries(); }
- virtual IConstWUResult * getVariableByName(const char * name) const
- { return c->getVariableByName(name); }
- virtual IConstWUResultIterator & getVariables() const
- { return c->getVariables(); }
- virtual bool isProtected() const
- { return c->isProtected(); }
- virtual bool isPausing() const
- { return c->isPausing(); }
- virtual IWorkUnit & lock()
- { ((CInterface *)this)->Link(); return (IWorkUnit &) *this; }
- virtual bool reload()
- { UNIMPLEMENTED; }
- virtual void subscribe(WUSubscribeOptions options)
- { c->subscribe(options); }
- virtual void requestAbort()
- { c->requestAbort(); }
- virtual unsigned calculateHash(unsigned prevHash)
- { return queryExtendedWU(c)->calculateHash(prevHash); }
- virtual void copyWorkUnit(IConstWorkUnit *cached, bool all)
- { queryExtendedWU(c)->copyWorkUnit(cached, all); }
- virtual IPropertyTree *queryPTree() const
- { return queryExtendedWU(c)->queryPTree(); }
- virtual IPropertyTree *getUnpackedTree(bool includeProgress) const
- { return queryExtendedWU(c)->getUnpackedTree(includeProgress); }
- virtual bool archiveWorkUnit(const char *base,bool del,bool deldll,bool deleteOwned,bool exportAssociatedFiles)
- { return queryExtendedWU(c)->archiveWorkUnit(base,del,deldll,deleteOwned,exportAssociatedFiles); }
- virtual unsigned queryFileUsage(const char *filename) const
- { return c->queryFileUsage(filename); }
- virtual IConstWUFileUsageIterator * getFieldUsage() const
- { return c->getFieldUsage(); }
- virtual bool getFieldUsageArray(StringArray & filenames, StringArray & columnnames, const char * clusterName) const
- { return c->getFieldUsageArray(filenames, columnnames, clusterName); }
- virtual IJlibDateTime & getTimeScheduled(IJlibDateTime &val) const
- { return c->getTimeScheduled(val); }
- virtual unsigned getDebugAgentListenerPort() const
- { return c->getDebugAgentListenerPort(); }
- virtual IStringVal & getDebugAgentListenerIP(IStringVal &ip) const
- { return c->getDebugAgentListenerIP(ip); }
- virtual IStringVal & getXmlParams(IStringVal & params, bool hidePasswords) const
- { return c->getXmlParams(params, hidePasswords); }
- virtual const IPropertyTree *getXmlParams() const
- { return c->getXmlParams(); }
- virtual unsigned __int64 getHash() const
- { return c->getHash(); }
- virtual IStringIterator *getLogs(const char *type, const char *instance) const
- { return c->getLogs(type, instance); }
- virtual IStringIterator *getProcesses(const char *type) const
- { return c->getProcesses(type); }
- virtual IPropertyTreeIterator* getProcesses(const char *type, const char *instance) const
- { return c->getProcesses(type, instance); }
- virtual unsigned getTotalThorTime() const
- { return c->getTotalThorTime(); }
- virtual WUGraphState queryGraphState(const char *graphName) const
- { return c->queryGraphState(graphName); }
- virtual WUGraphState queryNodeState(const char *graphName, WUGraphIDType nodeId) const
- { return c->queryNodeState(graphName, nodeId); }
- virtual void setGraphState(const char *graphName, WUGraphState state) const
- { c->setGraphState(graphName, state); }
- virtual void setNodeState(const char *graphName, WUGraphIDType nodeId, WUGraphState state) const
- { c->setNodeState(graphName, nodeId, state); }
- virtual IWUGraphStats *updateStats(const char *graphName, StatisticCreatorType creatorType, const char * creator, unsigned subgraph) const
- { return c->updateStats(graphName, creatorType, creator, subgraph); }
- virtual void clearGraphProgress() const
- { c->clearGraphProgress(); }
- virtual IStringVal & getAbortBy(IStringVal & str) const
- { return c->getAbortBy(str); }
- virtual unsigned __int64 getAbortTimeStamp() const
- { return c->getAbortTimeStamp(); }
- virtual void clearExceptions()
- { c->clearExceptions(); }
- virtual void commit()
- { c->commit(); }
- virtual IWUException * createException()
- { return c->createException(); }
- virtual void addProcess(const char *type, const char *instance, unsigned pid, const char *log)
- { c->addProcess(type, instance, pid, log); }
- virtual void protect(bool protectMode)
- { c->protect(protectMode); }
- virtual void setAction(WUAction action)
- { c->setAction(action); }
- virtual void setApplicationValue(const char * application, const char * propname, const char * value, bool overwrite)
- { c->setApplicationValue(application, propname, value, overwrite); }
- virtual void setApplicationValueInt(const char * application, const char * propname, int value, bool overwrite)
- { c->setApplicationValueInt(application, propname, value, overwrite); }
- virtual void incEventScheduledCount()
- { c->incEventScheduledCount(); }
- virtual void setIsQueryService(bool value)
- { c->setIsQueryService(value); }
- virtual void setCloneable(bool value)
- { c->setCloneable(value); }
- virtual void setIsClone(bool value)
- { c->setIsClone(value); }
- virtual void setClusterName(const char * value)
- { c->setClusterName(value); }
- virtual void setCodeVersion(unsigned version, const char * buildVersion, const char * eclVersion)
- { c->setCodeVersion(version, buildVersion, eclVersion); }
- virtual void setDebugValue(const char * propname, const char * value, bool overwrite)
- { c->setDebugValue(propname, value, overwrite); }
- virtual void setDebugValueInt(const char * propname, int value, bool overwrite)
- { c->setDebugValueInt(propname, value, overwrite); }
- virtual void setJobName(const char * value)
- { c->setJobName(value); }
- virtual void setPriority(WUPriorityClass cls)
- { c->setPriority(cls); }
- virtual void setPriorityLevel(int level)
- { c->setPriorityLevel(level); }
- virtual void setRescheduleFlag(bool value)
- { c->setRescheduleFlag(value); }
- virtual void setResultLimit(unsigned value)
- { c->setResultLimit(value); }
- virtual void setSecurityToken(const char *value)
- { c->setSecurityToken(value); }
- virtual void setState(WUState state)
- { c->setState(state); }
- virtual void setStateEx(const char * text)
- { c->setStateEx(text); }
- virtual void setAgentSession(__int64 sessionId)
- { c->setAgentSession(sessionId); }
- 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)
- { c->setStatistic(creatorType, creator, scopeType, scope, kind, optDescription, value, count, maxValue, mergeAction); }
- virtual void setTracingValue(const char * propname, const char * value)
- { c->setTracingValue(propname, value); }
- virtual void setTracingValueInt(const char * propname, int value)
- { c->setTracingValueInt(propname, value); }
- virtual void setTracingValueInt64(const char * propname, __int64 value)
- { c->setTracingValueInt64(propname, value); }
- virtual void setUser(const char * value)
- { c->setUser(value); }
- virtual void setWuScope(const char * value)
- { c->setWuScope(value); }
- virtual IWorkflowItem* addWorkflowItem(unsigned wfid, WFType type, WFMode mode, unsigned success, unsigned failure, unsigned recovery, unsigned retriesAllowed, unsigned contingencyFor)
- { return c->addWorkflowItem(wfid, type, mode, success, failure, recovery, retriesAllowed, contingencyFor); }
- virtual void syncRuntimeWorkflow(IWorkflowItemArray * array)
- { c->syncRuntimeWorkflow(array); }
- virtual IWorkflowItemIterator * updateWorkflowItems()
- { return c->updateWorkflowItems(); }
- virtual void resetWorkflow()
- { c->resetWorkflow(); }
- virtual void schedule()
- { c->schedule(); }
- virtual void deschedule()
- { c->deschedule(); }
- virtual unsigned addLocalFileUpload(LocalFileUploadType type, char const * source, char const * destination, char const * eventTag)
- { return c->addLocalFileUpload(type, source, destination, eventTag); }
- virtual IWUResult * updateGlobalByName(const char * name)
- { return c->updateGlobalByName(name); }
- virtual void createGraph(const char * name, const char *label, WUGraphType type, IPropertyTree *xgmml)
- { c->createGraph(name, label, type, xgmml); }
- virtual IWUQuery * updateQuery()
- { return c->updateQuery(); }
- virtual IWUWebServicesInfo * updateWebServicesInfo(bool create)
- { return c->updateWebServicesInfo(create); }
- virtual IWUPlugin * updatePluginByName(const char * name)
- { return c->updatePluginByName(name); }
- virtual IWULibrary * updateLibraryByName(const char * name)
- { return c->updateLibraryByName(name); }
- virtual IWUResult * updateResultByName(const char * name)
- { return c->updateResultByName(name); }
- virtual IWUResult * updateResultBySequence(unsigned seq)
- { return c->updateResultBySequence(seq); }
- virtual IWUResult * updateTemporaryByName(const char * name)
- { return c->updateTemporaryByName(name); }
- virtual IWUResult * updateVariableByName(const char * name)
- { return c->updateVariableByName(name); }
- virtual void addFile(const char *fileName, StringArray *clusters, unsigned usageCount, WUFileKind fileKind, const char *graphOwner)
- { c->addFile(fileName, clusters, usageCount, fileKind, graphOwner); }
- virtual void noteFileRead(IDistributedFile *file)
- { c->noteFileRead(file); }
- virtual void noteFieldUsage(IPropertyTree * usage)
- { c->noteFieldUsage(usage); }
- virtual void releaseFile(const char *fileName)
- { c->releaseFile(fileName); }
- virtual void resetBeforeGeneration()
- { c->resetBeforeGeneration(); }
- virtual void deleteTempFiles(const char *graph, bool deleteOwned, bool deleteJobOwned)
- { c->deleteTempFiles(graph, deleteOwned, deleteJobOwned); }
- virtual void deleteTemporaries()
- { c->deleteTemporaries(); }
- virtual void addDiskUsageStats(__int64 avgNodeUsage, unsigned minNode, __int64 minNodeUsage, unsigned maxNode, __int64 maxNodeUsage, __int64 graphId)
- { c->addDiskUsageStats(avgNodeUsage, minNode, minNodeUsage, maxNode, maxNodeUsage, graphId); }
- virtual IPropertyTree * getDiskUsageStats()
- { return c->getDiskUsageStats(); }
- virtual IPropertyTreeIterator & getFileIterator() const
- { return c->getFileIterator(); }
- virtual IPropertyTreeIterator & getFilesReadIterator() const
- { return c->getFilesReadIterator(); }
- virtual void setSnapshot(const char * value)
- { c->setSnapshot(value); }
- virtual void setWarningSeverity(unsigned code, ErrorSeverity severity)
- { c->setWarningSeverity(code, severity); }
- virtual void setTimeScheduled(const IJlibDateTime &val)
- { c->setTimeScheduled(val); }
- virtual void setDebugAgentListenerPort(unsigned port)
- { c->setDebugAgentListenerPort(port); }
- virtual void setDebugAgentListenerIP(const char * ip)
- { c->setDebugAgentListenerIP(ip); }
- virtual void setXmlParams(const char *params)
- { c->setXmlParams(params); }
- virtual void setXmlParams(IPropertyTree *tree)
- { c->setXmlParams(tree); }
- virtual void setHash(unsigned __int64 hash)
- { c->setHash(hash); }
- // ILocalWorkUnit - used for debugging etc
- virtual void serialize(MemoryBuffer &tgt)
- { c->serialize(tgt); }
- virtual void deserialize(MemoryBuffer &src)
- { c->deserialize(src); }
- virtual bool switchThorQueue(const char *cluster, IQueueSwitcher *qs)
- { return c->switchThorQueue(cluster,qs); }
- virtual void setAllowedClusters(const char *value)
- { c->setAllowedClusters(value); }
- virtual IStringVal& getAllowedClusters(IStringVal &str) const
- { return c->getAllowedClusters(str); }
- virtual void remoteCheckAccess(IUserDescriptor *user, bool writeaccess) const
- { c->remoteCheckAccess(user,writeaccess); }
- virtual void setAllowAutoQueueSwitch(bool val)
- { c->setAllowAutoQueueSwitch(val); }
- virtual bool getAllowAutoQueueSwitch() const
- { return c->getAllowAutoQueueSwitch(); }
- virtual void setLibraryInformation(const char * name, unsigned interfaceHash, unsigned definitionHash)
- { c->setLibraryInformation(name, interfaceHash, definitionHash); }
- virtual void setResultInt(const char * name, unsigned sequence, __int64 val)
- { c->setResultInt(name, sequence, val); }
- virtual void setResultUInt(const char * name, unsigned sequence, unsigned __int64 val)
- { c->setResultUInt(name, sequence, val); }
- virtual void setResultReal(const char *name, unsigned sequence, double val)
- { c->setResultReal(name, sequence, val); }
- virtual void setResultVarString(const char * stepname, unsigned sequence, const char *val)
- { c->setResultVarString(stepname, sequence, val); }
- virtual void setResultVarUnicode(const char * stepname, unsigned sequence, UChar const *val)
- { c->setResultVarUnicode(stepname, sequence, val); }
- virtual void setResultString(const char * stepname, unsigned sequence, int len, const char *val)
- { c->setResultString(stepname, sequence, len, val); }
- virtual void setResultData(const char * stepname, unsigned sequence, int len, const void *val)
- { c->setResultData(stepname, sequence, len, val); }
- virtual void setResultRaw(const char * name, unsigned sequence, int len, const void *val)
- { c->setResultRaw(name, sequence, len, val); }
- virtual void setResultSet(const char * name, unsigned sequence, bool isAll, size32_t len, const void *val, ISetToXmlTransformer *xform)
- { c->setResultSet(name, sequence, isAll, len, val, xform); }
- virtual void setResultUnicode(const char * name, unsigned sequence, int len, UChar const * val)
- { c->setResultUnicode(name, sequence, len, val); }
- virtual void setResultBool(const char *name, unsigned sequence, bool val)
- { c->setResultBool(name, sequence, val); }
- virtual void setResultDecimal(const char *name, unsigned sequence, int len, int precision, bool isSigned, const void *val)
- { c->setResultDecimal(name, sequence, len, precision, isSigned, val); }
- virtual void setResultDataset(const char * name, unsigned sequence, size32_t len, const void *val, unsigned numRows, bool extend)
- { c->setResultDataset(name, sequence, len, val, numRows, extend); }
- };
- class CLocalWUAssociated : implements IConstWUAssociatedFile, public CInterface
- {
- Owned<IPropertyTree> p;
- public:
- IMPLEMENT_IINTERFACE;
- CLocalWUAssociated(IPropertyTree *p);
- virtual WUFileType getType() const;
- virtual IStringVal & getDescription(IStringVal & ret) const;
- virtual IStringVal & getIp(IStringVal & ret) const;
- virtual IStringVal & getName(IStringVal & ret) const;
- virtual IStringVal & getNameTail(IStringVal & ret) const;
- virtual unsigned getCrc() const;
- virtual unsigned getMinActivityId() const;
- virtual unsigned getMaxActivityId() const;
- };
- class CLocalWUQuery : implements IWUQuery, public CInterface
- {
- Owned<IPropertyTree> p;
- mutable IArrayOf<IConstWUAssociatedFile> associated;
- mutable CriticalSection crit;
- mutable bool associatedCached;
- private:
- void addSpecialCaseAssociated(WUFileType type, const char * propname, unsigned crc) const;
- void loadAssociated() const;
- public:
- IMPLEMENT_IINTERFACE;
- CLocalWUQuery(IPropertyTree *p);
- virtual WUQueryType getQueryType() const;
- virtual IStringVal& getQueryText(IStringVal &str) const;
- virtual IStringVal& getQueryShortText(IStringVal &str) const;
- virtual IStringVal& getQueryName(IStringVal &str) const;
- virtual IStringVal & getQueryMainDefinition(IStringVal & str) const;
- virtual IStringVal& getQueryDllName(IStringVal &str) const;
- virtual unsigned getQueryDllCrc() const;
- virtual IStringVal& getQueryCppName(IStringVal &str) const;
- virtual IStringVal& getQueryResTxtName(IStringVal &str) const;
- virtual IConstWUAssociatedFile * getAssociatedFile(WUFileType type, unsigned index) const;
- virtual IConstWUAssociatedFileIterator& getAssociatedFiles() const;
- virtual bool isArchive() const;
- virtual void setQueryType(WUQueryType qt);
- virtual void setQueryText(const char *pstr);
- virtual void setQueryName(const char *);
- virtual void setQueryMainDefinition(const char * str);
- virtual void addAssociatedFile(WUFileType type, const char * name, const char * ip, const char * desc, unsigned crc, unsigned minActivity, unsigned maxActivity);
- virtual void removeAssociatedFiles();
- virtual void removeAssociatedFile(WUFileType type, const char * name, const char * desc);
- };
- class CLocalWUWebServicesInfo : implements IWUWebServicesInfo, public CInterface
- {
- Owned<IPropertyTree> p;
- mutable CriticalSection crit;
- private:
-
- public:
- IMPLEMENT_IINTERFACE;
- CLocalWUWebServicesInfo(IPropertyTree *p);
- virtual IStringVal& getModuleName(IStringVal &str) const;
- virtual IStringVal& getAttributeName(IStringVal &str) const;
- virtual IStringVal& getDefaultName(IStringVal &str) const;
- virtual IStringVal& getInfo(const char *name, IStringVal &str) const;
- virtual IStringVal& getText(const char *name, IStringVal &str) const;
- virtual unsigned getWebServicesCRC() const;
-
- virtual void setModuleName(const char *);
- virtual void setAttributeName(const char *);
- virtual void setDefaultName(const char *);
- virtual void setInfo(const char *name, const char *info);
- virtual void setText(const char *name, const char *info);
- virtual void setWebServicesCRC(unsigned);
- };
- class CLocalWUResult : implements IWUResult, public CInterface
- {
- friend class CLocalWorkUnit;
- mutable CriticalSection crit;
- Owned<IPropertyTree> p;
- Owned<IProperties> xmlns;
- public:
- IMPLEMENT_IINTERFACE;
- CLocalWUResult(IPropertyTree *props);
- ~CLocalWUResult() { try { p.clear(); } catch (IException *E) {E->Release();}}
- virtual WUResultStatus getResultStatus() const;
- virtual IStringVal& getResultName(IStringVal &str) const;
- virtual int getResultSequence() const;
- virtual bool isResultScalar() const;
- virtual IStringVal& getResultXml(IStringVal &str, bool hidePasswords) const;
- virtual unsigned getResultFetchSize() const;
- virtual __int64 getResultTotalRowCount() const;
- virtual __int64 getResultRowCount() const;
- virtual void getResultDataset(IStringVal & ecl, IStringVal & defs) const;
- virtual IStringVal& getResultLogicalName(IStringVal &ecl) const;
- virtual IStringVal& getResultKeyField(IStringVal& ecl) const;
- virtual unsigned getResultRequestedRows() const;
- virtual __int64 getResultInt() const;
- virtual bool getResultBool() const;
- virtual double getResultReal() const;
- virtual IStringVal& getResultString(IStringVal & str, bool hidePassword) const;
- virtual IDataVal& getResultRaw(IDataVal & data, IXmlToRawTransformer * xmlTransformer, ICsvToRawTransformer * csvTransformer) const;
- virtual IDataVal& getResultUnicode(IDataVal & data) const;
- virtual void getResultDecimal(void * val, unsigned length, unsigned precision, bool isSigned) const;
- virtual IStringVal& getResultEclSchema(IStringVal & str) const;
- virtual __int64 getResultRawSize(IXmlToRawTransformer * xmlTransformer, ICsvToRawTransformer * csvTransformer) const;
- virtual IDataVal& getResultRaw(IDataVal & data, __int64 from, __int64 length, IXmlToRawTransformer * xmlTransformer, ICsvToRawTransformer * csvTransformer) const;
- virtual IStringVal& getResultRecordSizeEntry(IStringVal & str) const;
- virtual IStringVal& getResultTransformerEntry(IStringVal & str) const;
- virtual __int64 getResultRowLimit() const;
- virtual IStringVal& getResultFilename(IStringVal & str) const;
- virtual WUResultFormat getResultFormat() const;
- virtual unsigned getResultHash() const;
- virtual bool getResultIsAll() const;
- virtual IProperties *queryResultXmlns();
- virtual IStringVal& getResultFieldOpt(const char *name, IStringVal &str) const;
- virtual void getSchema(IArrayOf<ITypeInfo> &types, StringAttrArray &names, IStringVal * ecl=NULL) const;
- // interface IWUResult
- virtual void setResultStatus(WUResultStatus status);
- virtual void setResultName(const char *name);
- virtual void setResultSequence(unsigned seq);
- virtual void setResultSchemaRaw(unsigned len, const void *schema);
- virtual void setResultScalar(bool isScalar);
- virtual void setResultRaw(unsigned len, const void *xml, WUResultFormat format);
- virtual void setResultFetchSize(unsigned rows); // 0 means file-loaded
- virtual void setResultTotalRowCount(__int64 rows); // -1 means unknown
- virtual void setResultRowCount(__int64 rows);
- virtual void setResultDataset(const char *ecl, const char *defs);
- virtual void setResultLogicalName(const char *logicalName);
- virtual void setResultKeyField(const char * name);
- virtual void setResultRequestedRows(unsigned req);
- virtual void setResultRecordSizeEntry(const char * val);
- virtual void setResultTransformerEntry(const char * val);
- virtual void setResultInt(__int64 val);
- virtual void setResultReal(double val);
- virtual void setResultBool(bool val);
- virtual void setResultString(const char * val, unsigned length);
- virtual void setResultUnicode(const void * val, unsigned length);
- virtual void setResultData(const void * val, unsigned length);
- virtual void setResultDecimal(const void * val, unsigned length);
- virtual void addResultRaw(unsigned len, const void * data, WUResultFormat format);
- virtual void setResultRowLimit(__int64 value);
- virtual void setResultFilename(const char * name);
- virtual void setResultUInt(unsigned __int64 val);
- virtual void setResultIsAll(bool value);
- virtual void setResultFormat(WUResultFormat format);
- virtual void setResultXML(const char *val);
- virtual void setResultRow(unsigned len, const void * data);
- virtual void setResultXmlns(const char *prefix, const char *uri);
- virtual void setResultFieldOpt(const char *name, const char *value);
- virtual IPropertyTree *queryPTree() { return p; }
- };
- class CLocalWUPlugin : implements IWUPlugin, public CInterface
- {
- Owned<IPropertyTree> p;
- public:
- IMPLEMENT_IINTERFACE;
- CLocalWUPlugin(IPropertyTree *p);
- virtual IStringVal& getPluginName(IStringVal &str) const;
- virtual IStringVal& getPluginVersion(IStringVal &str) const;
- virtual void setPluginName(const char *str);
- virtual void setPluginVersion(const char *str);
- };
- class CLocalWULibrary : implements IWULibrary, public CInterface
- {
- Owned<IPropertyTree> p;
- public:
- IMPLEMENT_IINTERFACE;
- CLocalWULibrary(IPropertyTree *p);
- virtual IStringVal & getName(IStringVal & str) const;
- virtual void setName(const char * str);
- };
- class CLocalWUException : implements IWUException, public CInterface
- {
- Owned<IPropertyTree> p;
- public:
- IMPLEMENT_IINTERFACE;
- CLocalWUException(IPropertyTree *p);
- virtual IStringVal& getExceptionSource(IStringVal &str) const;
- virtual IStringVal& getExceptionMessage(IStringVal &str) const;
- virtual unsigned getExceptionCode() const;
- virtual ErrorSeverity getSeverity() const;
- virtual IStringVal & getTimeStamp(IStringVal & dt) const;
- virtual IStringVal & getExceptionFileName(IStringVal & str) const;
- virtual unsigned getExceptionLineNo() const;
- virtual unsigned getExceptionColumn() const;
- virtual unsigned getSequence() const;
- virtual void setExceptionSource(const char *str);
- virtual void setExceptionMessage(const char *str);
- virtual void setExceptionCode(unsigned code);
- virtual void setSeverity(ErrorSeverity level);
- virtual void setTimeStamp(const char * dt);
- virtual void setExceptionFileName(const char *str);
- virtual void setExceptionLineNo(unsigned r);
- virtual void setExceptionColumn(unsigned c);
- };
- //==========================================================================================
- extern WORKUNIT_API bool isSpecialResultSequence(unsigned sequence)
- {
- switch ((int) sequence)
- {
- case ResultSequenceInternal:
- case ResultSequenceOnce:
- case ResultSequencePersist:
- case ResultSequenceStored:
- return true;
- default:
- assertex(sequence <= INT_MAX);
- return false;
- }
- }
- class CConstWUArrayIterator : implements IConstWorkUnitIterator, public CInterface
- {
- unsigned curTreeNum;
- IArrayOf<IPropertyTree> trees;
- Owned<IConstWorkUnitInfo> cur;
- void setCurrent()
- {
- cur.setown(new CLightweightWorkunitInfo(trees.item(curTreeNum)));
- }
- public:
- IMPLEMENT_IINTERFACE;
- CConstWUArrayIterator(IArrayOf<IPropertyTree> &_trees)
- {
- ForEachItemIn(t, _trees)
- trees.append(*LINK(&_trees.item(t)));
- curTreeNum = 0;
- }
- bool first()
- {
- curTreeNum = 0;
- return next();
- }
- bool isValid()
- {
- return (NULL != cur.get());
- }
- bool next()
- {
- if (curTreeNum >= trees.ordinality())
- {
- cur.clear();
- return false;
- }
- setCurrent();
- ++curTreeNum;
- return true;
- }
- IConstWorkUnitInfo & query() { return *cur; }
- };
- class CLocalWUFieldUsage : public CInterface, implements IConstWUFieldUsage
- {
- Owned<IPropertyTree> p;
- public:
- IMPLEMENT_IINTERFACE;
- CLocalWUFieldUsage(IPropertyTree& _p) { p.setown(&_p); }
- virtual const char * queryName() const { return p->queryProp("@name"); }
- };
- class CConstWUFieldUsageIterator : public CInterface, implements IConstWUFieldUsageIterator
- {
- public:
- IMPLEMENT_IINTERFACE;
- CConstWUFieldUsageIterator(IPropertyTreeIterator * tree) { iter.setown(tree); }
- bool first() override { return iter->first(); }
- bool isValid() override { return iter->isValid(); }
- bool next() override { return iter->next(); }
- IConstWUFieldUsage * get() const override { return new CLocalWUFieldUsage(iter->get()); }
- private:
- Owned<IPropertyTreeIterator> iter;
- };
- class CLocalWUFileUsage : public CInterface, implements IConstWUFileUsage
- {
- Owned<IPropertyTree> p;
- public:
- IMPLEMENT_IINTERFACE;
- CLocalWUFileUsage(IPropertyTree& _p) { p.setown(&_p); }
- virtual const char * queryName() const { return p->queryProp("@name"); }
- virtual const char * queryType() const { return p->queryProp("@type"); }
- virtual unsigned getNumFields() const { return p->getPropInt("@numFields"); }
- virtual unsigned getNumFieldsUsed() const { return p->getPropInt("@numFieldsUsed"); }
- virtual IConstWUFieldUsageIterator * getFields() const { return new CConstWUFieldUsageIterator(p->getElements("fields/field")); }
- };
- class CConstWUFileUsageIterator : public CInterface, implements IConstWUFileUsageIterator
- {
- public:
- IMPLEMENT_IINTERFACE;
- CConstWUFileUsageIterator(IPropertyTreeIterator * tree) { iter.setown(tree); }
- bool first() override { return iter->first(); }
- bool isValid() override { return iter->isValid(); }
- bool next() override { return iter->next(); }
- IConstWUFileUsage * get() const override { return new CLocalWUFileUsage(iter->get()); }
- private:
- Owned<IPropertyTreeIterator> iter;
- };
- //==========================================================================================
- class CStringArrayIterator : implements IStringIterator, public CInterface
- {
- unsigned idx;
- StringArray strings;
- public:
- IMPLEMENT_IINTERFACE;
- CStringArrayIterator() { idx = 0; };
- void append(const char *str) { strings.append(str); }
- virtual bool first() { idx = 0; return strings.isItem(idx); }
- virtual bool next() { idx ++; return strings.isItem(idx); }
- virtual bool isValid() { return strings.isItem(idx); }
- virtual IStringVal & str(IStringVal &s) { s.set(strings.item(idx)); return s; }
- };
- class CCachedJobNameIterator : implements IStringIterator, public CInterface
- {
- Owned<IPropertyTreeIterator> it;
- public:
- IMPLEMENT_IINTERFACE;
- CCachedJobNameIterator(IPropertyTreeIterator *p) : it(p) {};
- virtual bool first() { return it->first(); }
- virtual bool next() { return it->next(); }
- virtual bool isValid() { return it->isValid(); }
- virtual IStringVal & str(IStringVal &s) { s.set(it->query().queryName()+1); return s; }
- };
- class CEmptyStringIterator : implements IStringIterator, public CInterface
- {
- public:
- IMPLEMENT_IINTERFACE;
- virtual bool first() { return false; }
- virtual bool next() { return false; }
- virtual bool isValid() { return false; }
- virtual IStringVal & str(IStringVal &s) { s.clear(); return s; }
- };
- mapEnums workunitSortFields[] =
- {
- { WUSFuser, "@submitID" },
- { WUSFcluster, "@clusterName" },
- { WUSFjob, "@jobName" },
- { WUSFstate, "@state" },
- { WUSFpriority, "@priorityClass" },
- { WUSFprotected, "@protected" },
- { WUSFwuid, "@" },
- { WUSFecl, "Query/Text" },
- { WUSFfileread, "FilesRead/File/@name" },
- { WUSFtotalthortime, "@totalThorTime|"
- "Statistics/Statistic[@c='summary'][@creator='thor'][@kind='TimeElapsed']/@value|"
- "Statistics/Statistic[@c='summary'][@creator='hthor'][@kind='TimeElapsed']/@value|"
- "Statistics/Statistic[@c='summary'][@creator='roxie'][@kind='TimeElapsed']/@value|"
- "Statistics/Statistic[@desc='Total thor time']/@value|"
- "Timings/Timing[@name='Total thor time']/@duration" //Use Statistics first. If not found, use Timings
- },
- { WUSFwuidhigh, "@" },
- { WUSFwildwuid, "@" },
- { WUSFappvalue, "Application" },
- { WUSFfilewritten, "Files/File/@name" },
- { WUSFterm, NULL }
- };
- extern const char *queryFilterXPath(WUSortField field)
- {
- return getEnumText(field, workunitSortFields);
- }
- mapEnums querySortFields[] =
- {
- { WUQSFId, "@id" },
- { WUQSFwuid, "@wuid" },
- { WUQSFname, "@name" },
- { WUQSFdll, "@dll" },
- { WUQSFmemoryLimit, "@memoryLimit" },
- { WUQSFmemoryLimitHi, "@memoryLimit" },
- { WUQSFtimeLimit, "@timeLimit" },
- { WUQSFtimeLimitHi, "@timeLimit" },
- { WUQSFwarnTimeLimit, "@warnTimeLimit" },
- { WUQSFwarnTimeLimitHi, "@warnTimeLimit" },
- { WUQSFpriority, "@priority" },
- { WUQSFpriorityHi, "@priority" },
- { WUQSFQuerySet, "@querySetId" },
- { WUQSFActivited, "@activated" },
- { WUQSFSuspendedByUser, "@suspended" },
- { WUQSFLibrary, "Library"},
- { WUQSFPublishedBy, "@publishedBy" },
- { WUQSFterm, NULL }
- };
- class asyncRemoveDllWorkItem: public CInterface, implements IWorkQueueItem // class only used in asyncRemoveDll
- {
- StringAttr name;
- public:
- IMPLEMENT_IINTERFACE;
- asyncRemoveDllWorkItem(const char * _name) : name(_name)
- {
- }
- void execute()
- {
- PROGLOG("WU removeDll %s", name.get());
- queryDllServer().removeDll(name, true, true); // <name>, removeDlls=true, removeDirectory=true
- }
- };
- class asyncRemoveRemoteFileWorkItem: public CInterface, implements IWorkQueueItem // class only used in asyncRemoveFile
- {
- RemoteFilename name;
- public:
- IMPLEMENT_IINTERFACE;
- asyncRemoveRemoteFileWorkItem(const char * _ip, const char * _name)
- {
- SocketEndpoint ep(_ip);
- name.setPath(ep, _name);
- }
- void execute()
- {
- Owned<IFile> file = createIFile(name);
- PROGLOG("WU removeDll %s",file->queryFilename());
- file->remove();
- }
- };
- //==========================================================================================
- class CConstQuerySetQueryIterator : implements IConstQuerySetQueryIterator, public CInterface
- {
- unsigned index;
- IArrayOf<IPropertyTree> trees;
- public:
- IMPLEMENT_IINTERFACE;
- CConstQuerySetQueryIterator(IArrayOf<IPropertyTree> &_trees)
- {
- ForEachItemIn(t, _trees)
- trees.append(*LINK(&_trees.item(t)));
- index = 0;
- }
- ~CConstQuerySetQueryIterator()
- {
- trees.kill();
- }
- bool first()
- {
- index = 0;
- return (trees.ordinality()!=0);
- }
- bool next()
- {
- index++;
- return (index<trees.ordinality());
- }
- bool isValid()
- {
- return (index<trees.ordinality());
- }
- IPropertyTree &query()
- {
- return trees.item(index);
- }
- };
- class CSecurityCache
- {
- };
- class CConstWUIterator : implements IConstWorkUnitIterator, public CInterface
- {
- public:
- IMPLEMENT_IINTERFACE;
- CConstWUIterator(IPropertyTreeIterator *_ptreeIter)
- : ptreeIter(_ptreeIter)
- {
- }
- bool first()
- {
- if (!ptreeIter->first())
- {
- cur.clear();
- return false;
- }
- cur.setown(new CLightweightWorkunitInfo(ptreeIter->query()));
- return true;
- }
- bool isValid()
- {
- return (NULL != cur.get());
- }
- bool next()
- {
- if (!ptreeIter->next())
- {
- cur.clear();
- return false;
- }
- cur.setown(new CLightweightWorkunitInfo(ptreeIter->query()));
- return true;
- }
- IConstWorkUnitInfo & query() { return *cur; }
- private:
- Owned<IConstWorkUnitInfo> cur;
- Owned<IPropertyTreeIterator> ptreeIter;
- };
- class CSecureConstWUIterator : public CInterfaceOf<IConstWorkUnitIterator>
- {
- public:
- CSecureConstWUIterator(IConstWorkUnitIterator *_parent, ISecManager *_secmgr=NULL, ISecUser *_secuser=NULL)
- : parent(_parent), secmgr(_secmgr), secuser(_secuser)
- {
- assertex(_secuser && _secmgr);
- }
- bool first()
- {
- if (!parent->first())
- return false;
- return getNext();
- }
- bool next()
- {
- if (!parent->next())
- return false;
- return getNext();
- }
- virtual bool isValid()
- {
- return parent->isValid();
- }
- virtual IConstWorkUnitInfo &query()
- {
- return parent->query();
- }
- private:
- Owned<IConstWorkUnitIterator> parent;
- MapStringTo<int> scopePermissions;
- Linked<ISecManager> secmgr;
- Linked<ISecUser> secuser;
- bool getNext() // scan for a workunit with permissions
- {
- do
- {
- const char *scopeName = parent->query().queryWuScope();
- if (!scopeName || !*scopeName || checkScope(scopeName))
- return true;
- } while (parent->next());
- return false;
- }
- bool checkScope(const char *scopeName)
- {
- int *perms = scopePermissions.getValue(scopeName);
- SecAccessFlags perm;
- if (!perms)
- {
- perm = secuser.get() ? secmgr->authorizeWorkunitScope(*secuser, scopeName) : SecAccess_Unavailable;
- scopePermissions.setValue(scopeName, perm);
- }
- else
- perm = (SecAccessFlags)*perms;
- return perm >= SecAccess_Read;
- }
- };
- CWorkUnitFactory::CWorkUnitFactory()
- {
- }
- CWorkUnitFactory::~CWorkUnitFactory()
- {
- }
- IWorkUnit* CWorkUnitFactory::createNamedWorkUnit(const char *wuid, const char *app, const char *scope, ISecManager *secmgr, ISecUser *secuser)
- {
- checkWuScopeSecAccess(scope, secmgr, secuser, SecAccess_Write, "Create", true, true);
- Owned<CLocalWorkUnit> cw = _createWorkUnit(wuid, secmgr, secuser);
- if (scope)
- 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...
- IWorkUnit* ret = &cw->lockRemote(false); // Note - this may throw exception if user does not have rights.
- ret->setDebugValue("CREATED_BY", app, true);
- ret->setDebugValue("CREATED_FOR", scope, true);
- return ret;
- }
- IWorkUnit* CWorkUnitFactory::createWorkUnit(const char *app, const char *scope, ISecManager *secmgr, ISecUser *secuser)
- {
- StringBuffer wuid("W");
- char result[32];
- time_t ltime;
- time( <ime );
- tm *today = localtime( <ime ); // MORE - this is not threadsafe. But I probably don't care that much!
- strftime(result, sizeof(result), "%Y%m%d-%H%M%S", today);
- wuid.append(result);
- if (workUnitTraceLevel > 1)
- PrintLog("createWorkUnit created %s", wuid.str());
- IWorkUnit* ret = createNamedWorkUnit(wuid.str(), app, scope, secmgr, secuser);
- if (workUnitTraceLevel > 1)
- PrintLog("createWorkUnit created %s", ret->queryWuid());
- addTimeStamp(ret, SSTglobal, NULL, StWhenCreated);
- return ret;
- }
- bool CWorkUnitFactory::deleteWorkUnit(const char * wuid, ISecManager *secmgr, ISecUser *secuser)
- {
- if (workUnitTraceLevel > 1)
- PrintLog("deleteWorkUnit %s", wuid);
- StringBuffer wuRoot;
- getXPath(wuRoot, wuid);
- Owned<CLocalWorkUnit> cw = _updateWorkUnit(wuid, secmgr, secuser);
- if (!checkWuSecAccess(*cw.get(), secmgr, secuser, SecAccess_Full, "delete", true, true))
- return false;
- try
- {
- cw->cleanupAndDelete(true, true);
- }
- catch (IException *E)
- {
- StringBuffer s;
- LOG(MCexception(E, MSGCLS_warning), E, s.append("Exception during deleteWorkUnit: ").append(wuid).str());
- E->Release();
- return false;
- }
- removeWorkUnitFromAllQueues(wuid); //known active workunits wouldn't make it this far
- return true;
- }
- IConstWorkUnit* CWorkUnitFactory::openWorkUnit(const char *wuid, ISecManager *secmgr, ISecUser *secuser)
- {
- StringBuffer wuidStr(wuid);
- wuidStr.trim();
- if (wuidStr.length() && ('w' == wuidStr.charAt(0)))
- wuidStr.setCharAt(0, 'W');
- if (!wuidStr.length() || ('W' != wuidStr.charAt(0)))
- {
- if (workUnitTraceLevel > 1)
- PrintLog("openWorkUnit %s invalid WUID", nullText(wuidStr.str()));
- return NULL;
- }
- if (workUnitTraceLevel > 1)
- PrintLog("openWorkUnit %s", wuidStr.str());
- Owned<IConstWorkUnit> wu = _openWorkUnit(wuid, secmgr, secuser);
- if (wu)
- {
- if (!checkWuSecAccess(*wu, secmgr, secuser, SecAccess_Read, "opening", true, true))
- return NULL; // Actually throws exception on failure, so won't reach here
- return wu.getClear();
- }
- else
- {
- if (workUnitTraceLevel > 0)
- PrintLog("openWorkUnit %s not found", wuidStr.str());
- return NULL;
- }
- }
- IWorkUnit* CWorkUnitFactory::updateWorkUnit(const char *wuid, ISecManager *secmgr, ISecUser *secuser)
- {
- if (workUnitTraceLevel > 1)
- PrintLog("updateWorkUnit %s", wuid);
- Owned<CLocalWorkUnit> wu = _updateWorkUnit(wuid, secmgr, secuser);
- if (wu)
- {
- if (!checkWuSecAccess(*wu.get(), secmgr, secuser, SecAccess_Write, "updating", true, true))
- return NULL;
- return &wu->lockRemote(false);
- }
- else
- {
- if (workUnitTraceLevel > 0)
- PrintLog("updateWorkUnit %s not found", wuid);
- return NULL;
- }
- }
- IPropertyTree * pruneBranch(IPropertyTree * from, char const * xpath)
- {
- Owned<IPropertyTree> ret;
- IPropertyTree * branch = from->queryPropTree(xpath);
- if(branch)
- {
- ret.setown(createPTreeFromIPT(branch));
- from->removeTree(branch);
- }
- return ret.getClear();
- }
- bool CWorkUnitFactory::restoreWorkUnit(const char *base, const char *wuid, bool restoreAssociated)
- {
- StringBuffer path(base);
- addPathSepChar(path).append(wuid).append(".xml");
- Owned<IPTree> pt = createPTreeFromXMLFile(path);
- if (!pt)
- return false;
- CDateTime dt;
- dt.setNow();
- StringBuffer dts;
- dt.getString(dts);
- pt->setProp("@restoredDate", dts.str());
- Owned<IPropertyTree> generatedDlls = pruneBranch(pt, "GeneratedDlls[1]");
- Owned<IPropertyTree> associatedFiles;
- IPropertyTree *srcAssociated = pt->queryPropTree("Query/Associated");
- if (srcAssociated)
- associatedFiles.setown(createPTreeFromIPT(srcAssociated));
- // The updating of the repo is implementation specific...
- if (!_restoreWorkUnit(pt.getClear(), wuid))
- return false;
- // now kludge back GeneratedDlls
- if (generatedDlls)
- {
- Owned<IPropertyTreeIterator> dlls = generatedDlls->getElements("GeneratedDll");
- for(dlls->first(); dlls->isValid(); dlls->next())
- {
- IPropertyTree & dll = dlls->query();
- char const * name = dll.queryProp("@name");
- char const * kind = dll.queryProp("@kind");
- char const * location = dll.queryProp("@location");
- Owned<IDllEntry> got = queryDllServer().getEntry(name);
- if (!got)
- {
- RemoteFilename dstRfn;
- dstRfn.setRemotePath(location);
- StringBuffer srcPath(base);
- addPathSepChar(srcPath);
- dstRfn.getTail(srcPath);
- OwnedIFile srcFile = createIFile(srcPath);
- OwnedIFile dstFile = createIFile(dstRfn);
- copyFile(dstFile, srcFile);
- queryDllServer().registerDll(name, kind, location);
- }
- }
- }
- if (associatedFiles)
- {
- Owned<IPropertyTreeIterator> associated = associatedFiles->getElements("*");
- ForEach(*associated)
- {
- IPropertyTree &file = associated->query();
- const char *filename = file.queryProp("@filename");
- SocketEndpoint ep(file.queryProp("@ip"));
- RemoteFilename rfn;
- rfn.setPath(ep, filename);
- OwnedIFile dstFile = createIFile(rfn);
- StringBuffer srcPath(base), name;
- addPathSepChar(srcPath);
- rfn.getTail(name);
- srcPath.append(name);
- if (generatedDlls)
- {
- VStringBuffer gDllPath("GeneratedDll[@name=\"%s\"]", name.str());
- if (generatedDlls->hasProp(gDllPath))
- continue; // generated dlls handled separately - see above
- }
- OwnedIFile srcFile = createIFile(srcPath);
- if (srcFile->exists())
- {
- try
- {
- copyFile(dstFile, srcFile);
- }
- catch (IException *e)
- {
- VStringBuffer msg("Failed to restore associated file '%s' to destination '%s'", srcFile->queryFilename(), dstFile->queryFilename());
- EXCLOG(e, msg.str());
- e->Release();
- }
- }
- }
- }
- return true;
- }
- int CWorkUnitFactory::setTracingLevel(int newLevel)
- {
- if (newLevel)
- PrintLog("Setting workunit trace level to %d", newLevel);
- int level = workUnitTraceLevel;
- workUnitTraceLevel = newLevel;
- return level;
- }
- void CWorkUnitFactory::descheduleAllWorkUnits(ISecManager *secmgr, ISecUser *secuser)
- {
- Owned<IRemoteConnection> conn = querySDS().connect("/Schedule", myProcessSession(), RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT);
- if(!conn) return;
- Owned<IPropertyTree> root(conn->queryRoot()->getBranch("."));
- KeptAtomTable entries;
- Owned<IPropertyTreeIterator> iter(root->getElements("*/*/*/*"));
- StringBuffer wuid;
- for(iter->first(); iter->isValid(); iter->next())
- {
- char const * entry = iter->query().queryName();
- if(!entries.find(entry))
- {
- entries.addAtom(entry);
- ncnameUnescape(entry, wuid.clear());
- Owned<IWorkUnit> wu = updateWorkUnit(wuid, secmgr, secuser);
- if(wu && (wu->getState() == WUStateWait))
- wu->setState(WUStateCompleted);
- }
- }
- bool more;
- do more = root->removeProp("*"); while(more);
- }
- IConstQuerySetQueryIterator* CWorkUnitFactory::getQuerySetQueriesSorted( WUQuerySortField *sortorder, // list of fields to sort by (terminated by WUSFterm)
- WUQuerySortField *filters, // NULL or list of fields to filter on (terminated by WUSFterm)
- const void *filterbuf, // (appended) string values for filters
- unsigned startoffset,
- unsigned maxnum,
- __int64 *cachehint,
- unsigned *total,
- const MapStringTo<bool> *_subset)
- {
- struct PostFilters
- {
- WUQueryFilterBoolean activatedFilter;
- WUQueryFilterBoolean suspendedByUserFilter;
- PostFilters()
- {
- activatedFilter = WUQFSAll;
- suspendedByUserFilter = WUQFSAll;
- };
- } postFilters;
- class CQuerySetQueriesPager : public CSimpleInterface, implements IElementsPager
- {
- StringAttr querySet;
- StringAttr xPath;
- StringAttr sortOrder;
- PostFilters postFilters;
- StringArray unknownAttributes;
- const MapStringTo<bool> *subset;
- void populateQueryTree(const IPropertyTree* querySetTree, IPropertyTree* queryTree)
- {
- const char* querySetId = querySetTree->queryProp("@id");
- VStringBuffer path("Query%s", xPath.get());
- Owned<IPropertyTreeIterator> iter = querySetTree->getElements(path.str());
- ForEach(*iter)
- {
- IPropertyTree &query = iter->query();
- bool activated = false;
- const char* queryId = query.queryProp("@id");
- if (queryId && *queryId)
- {
- if (subset)
- {
- VStringBuffer match("%s/%s", querySetId, queryId);
- if (!subset->getValue(match))
- continue;
- }
- VStringBuffer aliasXPath("Alias[@id='%s']", queryId);
- IPropertyTree *alias = querySetTree->queryPropTree(aliasXPath.str());
- if (alias)
- activated = true;
- }
- if (activated && (postFilters.activatedFilter == WUQFSNo))
- continue;
- if (!activated && (postFilters.activatedFilter == WUQFSYes))
- continue;
- if ((postFilters.suspendedByUserFilter == WUQFSNo) && query.hasProp(getEnumText(WUQSFSuspendedByUser,querySortFields)))
- continue;
- if ((postFilters.suspendedByUserFilter == WUQFSYes) && !query.hasProp(getEnumText(WUQSFSuspendedByUser,querySortFields)))
- continue;
- IPropertyTree *queryWithSetId = queryTree->addPropTree("Query", createPTreeFromIPT(&query));
- queryWithSetId->setProp("@querySetId", querySetId);
- queryWithSetId->setPropBool("@activated", activated);
- }
- }
- IRemoteConnection* populateQueryTree(IPropertyTree* queryTree)
- {
- StringBuffer querySetXPath("QuerySets");
- if (!querySet.isEmpty())
- querySetXPath.appendf("/QuerySet[@id=\"%s\"]", querySet.get());
- Owned<IRemoteConnection> conn = querySDS().connect(querySetXPath.str(), myProcessSession(), 0, SDS_LOCK_TIMEOUT);
- if (!conn)
- return NULL;
- if (querySet.isEmpty())
- {
- Owned<IPropertyTreeIterator> querySetIter = conn->queryRoot()->getElements("*");
- ForEach(*querySetIter)
- populateQueryTree(&querySetIter->query(), queryTree);
- }
- else
- populateQueryTree(conn->queryRoot(), queryTree);
- return conn.getClear();
- }
- public:
- IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
- CQuerySetQueriesPager(const char* _querySet, const char* _xPath, const char *_sortOrder, PostFilters& _postFilters, StringArray& _unknownAttributes, const MapStringTo<bool> *_subset)
- : querySet(_querySet), xPath(_xPath), sortOrder(_sortOrder), subset(_subset)
- {
- postFilters.activatedFilter = _postFilters.activatedFilter;
- postFilters.suspendedByUserFilter = _postFilters.suspendedByUserFilter;
- ForEachItemIn(x, _unknownAttributes)
- unknownAttributes.append(_unknownAttributes.item(x));
- }
- virtual IRemoteConnection* getElements(IArrayOf<IPropertyTree> &elements)
- {
- Owned<IPropertyTree> elementTree = createPTree("Queries");
- Owned<IRemoteConnection> conn = populateQueryTree(elementTree);
- if (!conn)
- return NULL;
- Owned<IPropertyTreeIterator> iter = elementTree->getElements("*");
- if (!iter)
- return NULL;
- sortElements(iter, sortOrder.get(), NULL, NULL, unknownAttributes, elements);
- return conn.getClear();
- }
- virtual bool allMatchingElementsReceived() { return true; } //For now, dali always returns all of matched Queries.
- };
- StringAttr querySet;
- StringBuffer xPath;
- StringBuffer so;
- StringArray unknownAttributes;
- if (filters)
- {
- const char *fv = (const char *)filterbuf;
- for (unsigned i=0;filters[i]!=WUQSFterm;i++) {
- int fmt = filters[i];
- int subfmt = (fmt&0xff);
- if (subfmt==WUQSFQuerySet)
- querySet.set(fv);
- else if ((subfmt==WUQSFmemoryLimit) || (subfmt==WUQSFtimeLimit) || (subfmt==WUQSFwarnTimeLimit) || (subfmt==WUQSFpriority))
- xPath.append('[').append(getEnumText(subfmt,querySortFields)).append(">=").append(fv).append("]");
- else if ((subfmt==WUQSFmemoryLimitHi) || (subfmt==WUQSFtimeLimitHi) || (subfmt==WUQSFwarnTimeLimitHi) || (subfmt==WUQSFpriorityHi))
- xPath.append('[').append(getEnumText(subfmt,querySortFields)).append("<=").append(fv).append("]");
- else if (subfmt==WUQSFActivited)
- postFilters.activatedFilter = (WUQueryFilterBoolean) atoi(fv);
- else if (subfmt==WUQSFSuspendedByUser)
- postFilters.suspendedByUserFilter = (WUQueryFilterBoolean) atoi(fv);
- else if (!fv || !*fv)
- unknownAttributes.append(getEnumText(subfmt,querySortFields));
- else {
- xPath.append('[').append(getEnumText(subfmt,querySortFields)).append('=');
- if (fmt&WUQSFnocase)
- xPath.append('?');
- if (fmt&WUQSFnumeric)
- xPath.append('#');
- if (fmt&WUQSFwild)
- xPath.append('~');
- xPath.append('"').append(fv).append("\"]");
- }
- fv = fv + strlen(fv)+1;
- }
- }
- if (sortorder) {
- for (unsigned i=0;sortorder[i]!=WUQSFterm;i++) {
- if (so.length())
- so.append(',');
- int fmt = sortorder[i];
- if (fmt&WUQSFreverse)
- so.append('-');
- if (fmt&WUQSFnocase)
- so.append('?');
- if (fmt&WUQSFnumeric)
- so.append('#');
- so.append(getEnumText(fmt&0xff,querySortFields));
- }
- }
- IArrayOf<IPropertyTree> results;
- Owned<IElementsPager> elementsPager = new CQuerySetQueriesPager(querySet.get(), xPath.str(), so.length()?so.str():NULL, postFilters, unknownAttributes, _subset);
- Owned<IRemoteConnection> conn=getElementsPaged(elementsPager,startoffset,maxnum,NULL,"",cachehint,results,total,NULL);
- return new CConstQuerySetQueryIterator(results);
- }
- bool CWorkUnitFactory::isAborting(const char *wuid) const
- {
- VStringBuffer apath("/WorkUnitAborts/%s", wuid);
- try
- {
- Owned<IRemoteConnection> acon = querySDS().connect(apath.str(), myProcessSession(), 0, SDS_LOCK_TIMEOUT);
- if (acon)
- return acon->queryRoot()->getPropInt(NULL) != 0;
- }
- catch (IException *E)
- {
- EXCLOG(E);
- E->Release();
- }
- return false;
- }
- void CWorkUnitFactory::clearAborting(const char *wuid)
- {
- VStringBuffer apath("/WorkUnitAborts/%s", wuid);
- try
- {
- Owned<IRemoteConnection> acon = querySDS().connect(apath.str(), myProcessSession(), RTM_LOCK_WRITE|RTM_LOCK_SUB, SDS_LOCK_TIMEOUT);
- if (acon)
- acon->close(true);
- }
- catch (IException *E)
- {
- EXCLOG(E);
- E->Release();
- }
- }
- void CWorkUnitFactory::reportAbnormalTermination(const char *wuid, WUState &state, SessionId agent)
- {
- WARNLOG("reportAbnormalTermination: session stopped unexpectedly: %" I64F "d state: %d", (__int64) agent, (int) state);
- bool isEcl = false;
- switch (state)
- {
- case WUStateAborting:
- state = WUStateAborted;
- break;
- case WUStateCompiling:
- isEcl = true;
- // drop into
- default:
- state = WUStateFailed;
- }
- Owned<IWorkUnit> wu = updateWorkUnit(wuid, NULL, NULL);
- wu->setState(state);
- Owned<IWUException> e = wu->createException();
- e->setExceptionCode(isEcl ? 1001 : 1000);
- e->setExceptionMessage(isEcl ? "EclServer terminated unexpectedly" : "Workunit terminated unexpectedly");
- }
- static CriticalSection deleteDllLock;
- static Owned<IWorkQueueThread> deleteDllWorkQ;
- static void asyncRemoveDll(const char * name)
- {
- CriticalBlock b(deleteDllLock);
- if (!deleteDllWorkQ)
- deleteDllWorkQ.setown(createWorkQueueThread());
- deleteDllWorkQ->post(new asyncRemoveDllWorkItem(name));
- }
- static void asyncRemoveFile(const char * ip, const char * name)
- {
- CriticalBlock b(deleteDllLock);
- if (!deleteDllWorkQ)
- deleteDllWorkQ.setown(createWorkQueueThread());
- deleteDllWorkQ->post(new asyncRemoveRemoteFileWorkItem(ip, name));
- }
- class CDaliWorkUnitFactory : public CWorkUnitFactory, implements IDaliClientShutdown
- {
- public:
- IMPLEMENT_IINTERFACE_USING(CWorkUnitFactory);
- CDaliWorkUnitFactory()
- {
- // Assumes dali client configuration has already been done
- sdsManager = &querySDS();
- session = myProcessSession();
- addShutdownHook(*this);
- }
- ~CDaliWorkUnitFactory()
- {
- removeShutdownHook(*this);
- }
- virtual bool initializeStore()
- {
- throwUnexpected(); // Used when loading a plugin factory - not applicable here
- }
- virtual IWorkUnitWatcher *getWatcher(IWorkUnitSubscriber *subscriber, WUSubscribeOptions options, const char *wuid) const
- {
- return new CDaliWorkUnitWatcher(subscriber, options, wuid);
- }
- virtual unsigned validateRepository(bool fixErrors)
- {
- return 0;
- }
- virtual void deleteRepository(bool recreate)
- {
- Owned<IRemoteConnection> conn = sdsManager->connect("/WorkUnits", session, RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT);
- if (conn)
- conn->close(true);
- conn.setown(sdsManager->connect("/GraphProgress", session, RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT));
- if (conn)
- conn->close(true);
- }
- virtual void createRepository()
- {
- // Nothing to do
- }
- virtual const char *queryStoreType() const
- {
- return "Dali";
- }
- virtual CLocalWorkUnit *_createWorkUnit(const char *wuid, ISecManager *secmgr, ISecUser *secuser)
- {
- StringBuffer wuRoot;
- getXPath(wuRoot, wuid);
- IRemoteConnection *conn;
- conn = sdsManager->connect(wuRoot.str(), session, RTM_LOCK_WRITE|RTM_CREATE_UNIQUE, SDS_LOCK_TIMEOUT);
- conn->queryRoot()->setProp("@xmlns:xsi", "http://www.w3.org/1999/XMLSchema-instance");
- conn->queryRoot()->setPropInt("@wuidVersion", WUID_VERSION);
- return new CDaliWorkUnit(conn, secmgr, secuser);
- }
- virtual CLocalWorkUnit* _openWorkUnit(const char *wuid, ISecManager *secmgr, ISecUser *secuser)
- {
- StringBuffer wuRoot;
- getXPath(wuRoot, wuid);
- IRemoteConnection* conn = sdsManager->connect(wuRoot.str(), session, 0, SDS_LOCK_TIMEOUT);
- if (conn)
- return new CDaliWorkUnit(conn, secmgr, secuser);
- else
- return NULL;
- }
- virtual bool _restoreWorkUnit(IPTree *_pt, const char *wuid)
- {
- Owned<IPTree> pt(_pt);
- Owned<IPropertyTree> gprogress = pruneBranch(pt, "GraphProgress[1]");
- StringBuffer wuRoot;
- getXPath(wuRoot, wuid);
- Owned<IRemoteConnection> conn = sdsManager->connect(wuRoot.str(), myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT);
- if (!conn)
- {
- ERRLOG("restoreWorkUnit could not create to %s", wuRoot.str());
- return false;
- }
- IPropertyTree *root = conn->queryRoot();
- if (root->hasChildren())
- {
- ERRLOG("restoreWorkUnit WUID %s already exists", wuid);
- return false;
- }
- root->setPropTree(NULL, pt.getClear());
- conn.clear();
- // now kludge back GraphProgress
- if (gprogress)
- {
- VStringBuffer xpath("/GraphProgress/%s", wuid);
- conn.setown(querySDS().connect(xpath, myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT));
- if (conn)
- {
- IPropertyTree *groot = conn->queryRoot();
- if (groot->hasChildren())
- WARNLOG("restoreWorkUnit WUID %s graphprogress already exists, replacing",wuid);
- groot->setPropTree(NULL, gprogress.getClear());
- }
- }
- return true;
- }
- virtual CLocalWorkUnit* _updateWorkUnit(const char *wuid, ISecManager *secmgr, ISecUser *secuser)
- {
- StringBuffer wuRoot;
- getXPath(wuRoot, wuid);
- IRemoteConnection* conn = sdsManager->connect(wuRoot.str(), session, RTM_LOCK_WRITE|RTM_LOCK_SUB, SDS_LOCK_TIMEOUT);
- if (conn)
- return new CDaliWorkUnit(conn, secmgr, secuser);
- else
- return NULL;
- }
- virtual IWorkUnit* getGlobalWorkUnit(ISecManager *secmgr, ISecUser *secuser)
- {
- // MORE - should it check security?
- StringBuffer wuRoot;
- getXPath(wuRoot, GLOBAL_WORKUNIT);
- IRemoteConnection* conn = sdsManager->connect(wuRoot.str(), session, RTM_LOCK_WRITE|RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT);
- conn->queryRoot()->setProp("@xmlns:xsi", "http://www.w3.org/1999/XMLSchema-instance");
- Owned<CLocalWorkUnit> cw = new CDaliWorkUnit(conn, (ISecManager *) NULL, NULL);
- return &cw->lockRemote(false);
- }
- virtual IConstWorkUnitIterator* getWorkUnitsByOwner(const char * owner, ISecManager *secmgr, ISecUser *secuser)
- {
- StringBuffer path("*");
- if (owner && *owner)
- path.append("[@submitID=?~\"").append(owner).append("\"]");
- return _getWorkUnitsByXPath(path.str(), secmgr, secuser);
- }
- IConstWorkUnitIterator* getScheduledWorkUnits(ISecManager *secmgr, ISecUser *secuser)
- {
- StringBuffer path("*");
- path.append("[@state=\"").append(getEnumText(WUStateScheduled, states)).append("\"]");
- return _getWorkUnitsByXPath(path.str(), secmgr, secuser);
- }
- virtual void clientShutdown();
- virtual unsigned numWorkUnits()
- {
- Owned<IRemoteConnection> conn = sdsManager->connect("/WorkUnits", session, 0, SDS_LOCK_TIMEOUT);
- if (!conn)
- return 0;
- IPropertyTree *root = conn->queryRoot();
- return root->numChildren();
- }
- IConstWorkUnitIterator* getWorkUnitsSorted( WUSortField sortorder, // field to sort by (and flags for desc sort etc)
- WUSortField *filters, // NULL or list of fields to filter on (terminated by WUSFterm)
- const void *filterbuf, // (appended) string values for filters
- unsigned startoffset,
- unsigned maxnum,
- __int64 *cachehint,
- unsigned *total,
- ISecManager *secmgr,
- ISecUser *secuser)
- {
- class CWorkUnitsPager : public CSimpleInterface, implements IElementsPager
- {
- StringAttr xPath;
- StringAttr sortOrder;
- StringAttr nameFilterLo;
- StringAttr nameFilterHi;
- StringArray unknownAttributes;
- public:
- IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
- CWorkUnitsPager(const char* _xPath, const char *_sortOrder, const char* _nameFilterLo, const char* _nameFilterHi, StringArray& _unknownAttributes)
- : xPath(_xPath), sortOrder(_sortOrder), nameFilterLo(_nameFilterLo), nameFilterHi(_nameFilterHi)
- {
- ForEachItemIn(x, _unknownAttributes)
- unknownAttributes.append(_unknownAttributes.item(x));
- }
- virtual IRemoteConnection* getElements(IArrayOf<IPropertyTree> &elements)
- {
- Owned<IRemoteConnection> conn = querySDS().connect("WorkUnits", myProcessSession(), 0, SDS_LOCK_TIMEOUT);
- if (!conn)
- return NULL;
- Owned<IPropertyTreeIterator> iter = conn->getElements(xPath);
- if (!iter)
- return NULL;
- sortElements(iter, sortOrder.get(), nameFilterLo.get(), nameFilterHi.get(), unknownAttributes, elements);
- return conn.getClear();
- }
- virtual bool allMatchingElementsReceived() { return true; }//For now, dali always returns all of matched WUs.
- };
- class CScopeChecker : public CSimpleInterface, implements ISortedElementsTreeFilter
- {
- UniqueScopes done;
- ISecManager *secmgr;
- ISecUser *secuser;
- CriticalSection crit;
- public:
- IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
- CScopeChecker(ISecManager *_secmgr,ISecUser *_secuser)
- {
- secmgr = _secmgr;
- secuser = _secuser;
- }
- bool isOK(IPropertyTree &tree)
- {
- const char *scopename = tree.queryProp("@scope");
- if (!scopename||!*scopename)
- return true;
- {
- CriticalBlock block(crit);
- const bool *b = done.getValue(scopename);
- if (b)
- return *b;
- }
- bool ret = checkWuScopeSecAccess(scopename,secmgr,secuser,SecAccess_Read,"iterating",false,false);
- {
- // conceivably could have already been checked and added, but ok.
- CriticalBlock block(crit);
- done.setValue(scopename,ret);
- }
- return ret;
- }
- };
- Owned<ISortedElementsTreeFilter> sc = new CScopeChecker(secmgr,secuser);
- StringBuffer query;
- StringBuffer so;
- StringAttr namefilter("*");
- StringAttr namefilterlo;
- StringAttr namefilterhi;
- StringArray unknownAttributes;
- if (filters)
- {
- const char *fv = (const char *) filterbuf;
- for (unsigned i=0;filters[i]!=WUSFterm;i++)
- {
- assertex(fv);
- int fmt = filters[i];
- int subfmt = (fmt&0xff);
- if (subfmt==WUSFwuid)
- namefilterlo.set(fv);
- else if (subfmt==WUSFwuidhigh)
- namefilterhi.set(fv);
- else if (subfmt==WUSFwildwuid)
- namefilter.set(fv);
- else if (subfmt==WUSFappvalue)
- {
- const char *app = fv;
- fv = fv + strlen(fv)+1;
- query.append("[Application/").append(app);
- if (*fv)
- query.append("=?~\"").append(fv).append('\"');
- query.append("]");
- }
- else if (!*fv)
- {
- unknownAttributes.append(getEnumText(subfmt,workunitSortFields));
- if (subfmt==WUSFtotalthortime)
- sortorder = (WUSortField) (sortorder & ~WUSFnumeric);
- }
- else
- {
- query.append('[').append(getEnumText(subfmt,workunitSortFields)).append('=');
- if (fmt&WUSFnocase)
- query.append('?');
- if (fmt&WUSFwild)
- query.append('~');
- query.append('"').append(fv).append("\"]");
- }
- fv = fv + strlen(fv)+1;
- }
- }
- if ((sortorder&0xff)==WUSFtotalthortime)
- sortorder = (WUSortField) (sortorder & ~WUSFnumeric);
- query.insert(0, namefilter.get());
- if (sortorder)
- {
- if (so.length())
- so.append(',');
- if (sortorder & WUSFreverse)
- so.append('-');
- if (sortorder & WUSFnocase)
- so.append('?');
- if (sortorder & WUSFnumeric)
- so.append('#');
- so.append(getEnumText(sortorder&0xff,workunitSortFields));
- }
- IArrayOf<IPropertyTree> results;
- Owned<IElementsPager> elementsPager = new CWorkUnitsPager(query.str(), so.length()?so.str():NULL, namefilterlo.get(), namefilterhi.get(), unknownAttributes);
- Owned<IRemoteConnection> conn=getElementsPaged(elementsPager,startoffset,maxnum,secmgr?sc:NULL,"",cachehint,results,total,NULL);
- return new CConstWUArrayIterator(results);
- }
- virtual WUState waitForWorkUnit(const char * wuid, unsigned timeout, bool compiled, bool returnOnWaitState)
- {
- Owned<WorkUnitWaiter> waiter = new WorkUnitWaiter(wuid, SubscribeOptionState);
- LocalIAbortHandler abortHandler(*waiter);
- WUState ret = WUStateUnknown;
- StringBuffer wuRoot;
- getXPath(wuRoot, wuid);
- Owned<IRemoteConnection> conn = sdsManager->connect(wuRoot.str(), session, 0, SDS_LOCK_TIMEOUT);
- if (conn)
- {
- SessionId agent = -1;
- bool agentSessionStopped = false;
- unsigned start = msTick();
- loop
- {
- ret = (WUState) getEnum(conn->queryRoot(), "@state", states);
- switch (ret)
- {
- case WUStateCompiled:
- case WUStateUploadingFiles:
- if (!compiled)
- break;
- // fall into
- case WUStateCompleted:
- case WUStateFailed:
- case WUStateAborted:
- return ret;
- case WUStateWait:
- if(returnOnWaitState)
- {
- return ret;
- }
- break;
- case WUStateCompiling:
- case WUStateRunning:
- case WUStateDebugPaused:
- case WUStateDebugRunning:
- case WUStateBlocked:
- case WUStateAborting:
- if (agentSessionStopped)
- {
- reportAbnormalTermination(wuid, ret, agent);
- return ret;
- }
- if (queryDaliServerVersion().compare("2.1")>=0)
- {
- agent = conn->queryRoot()->getPropInt64("@agentSession", -1);
- if((agent>0) && querySessionManager().sessionStopped(agent, 0))
- {
- agentSessionStopped = true;
- conn->reload();
- continue;
- }
- }
- break;
- }
- agentSessionStopped = false; // reset for state changes such as WUStateWait then WUStateRunning again
- unsigned waited = msTick() - start;
- if (timeout==-1)
- {
- waiter->wait(20000); // recheck state every 20 seconds even if no timeout, in case eclagent has crashed.
- if (waiter->aborted)
- {
- ret = WUStateUnknown; // MORE - throw an exception?
- break;
- }
- }
- else if (waited > timeout || !waiter->wait(timeout-waited))
- {
- ret = WUStateUnknown; // MORE - throw an exception?
- break;
- }
- conn->reload();
- }
- }
- return ret;
- }
- virtual WUAction waitForWorkUnitAction(const char * wuid, WUAction original)
- {
- Owned<WorkUnitWaiter> waiter = new WorkUnitWaiter(wuid, SubscribeOptionAction);
- LocalIAbortHandler abortHandler(*waiter);
- WUAction ret = WUActionUnknown;
- StringBuffer wuRoot;
- getXPath(wuRoot, wuid);
- Owned<IRemoteConnection> conn = sdsManager->connect(wuRoot.str(), session, 0, SDS_LOCK_TIMEOUT);
- if (conn)
- {
- unsigned start = msTick();
- loop
- {
- ret = (WUAction) getEnum(conn->queryRoot(), "Action", actions);
- if (ret != original)
- break;
- unsigned waited = msTick() - start;
- waiter->wait(20000); // recheck state every 20 seconds even if no timeout, in case eclagent has crashed.
- if (waiter->aborted)
- {
- ret = WUActionUnknown; // MORE - throw an exception?
- break;
- }
- conn->reload();
- }
- }
- waiter->unsubscribe();
- return ret;
- }
- protected:
- IConstWorkUnitIterator * _getWorkUnitsByXPath(const char *xpath, ISecManager *secmgr, ISecUser *secuser)
- {
- Owned<IRemoteConnection> conn = sdsManager->connect("/WorkUnits", session, 0, SDS_LOCK_TIMEOUT);
- if (conn)
- {
- CDaliVersion serverVersionNeeded("3.2");
- Owned<IPropertyTreeIterator> iter(queryDaliServerVersion().compare(serverVersionNeeded) < 0 ?
- conn->queryRoot()->getElements(xpath) :
- conn->getElements(xpath));
- return createSecureConstWUIterator(iter.getClear(), secmgr, secuser);
- }
- else
- return NULL;
- }
- ISDSManager *sdsManager;
- SessionId session;
- };
- extern WORKUNIT_API IConstWorkUnitIterator *createSecureConstWUIterator(IConstWorkUnitIterator *iter, ISecManager *secmgr, ISecUser *secuser)
- {
- if (secmgr)
- return new CSecureConstWUIterator(iter, secmgr, secuser);
- else
- return iter;
- }
- extern WORKUNIT_API IConstWorkUnitIterator *createSecureConstWUIterator(IPropertyTreeIterator *iter, ISecManager *secmgr, ISecUser *secuser)
- {
- if (secmgr)
- return new CSecureConstWUIterator(new CConstWUIterator(iter), secmgr, secuser);
- else
- return new CConstWUIterator(iter);
- }
- static CriticalSection factoryCrit;
- static Owned<IWorkUnitFactory> factory;
- void CDaliWorkUnitFactory::clientShutdown()
- {
- CriticalBlock b(factoryCrit);
- factory.clear();
- }
- void clientShutdownWorkUnit()
- {
- CriticalBlock b(factoryCrit);
- factory.clear();
- }
- extern WORKUNIT_API void setWorkUnitFactory(IWorkUnitFactory * _factory)
- {
- CriticalBlock b(factoryCrit);
- factory.setown(_factory);
- }
- extern WORKUNIT_API IWorkUnitFactory * getWorkUnitFactory()
- {
- if (!factory)
- {
- CriticalBlock b(factoryCrit);
- 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.
- {
- const char *forceEnv = getenv("FORCE_DALI_WORKUNITS");
- bool forceDali = forceEnv && !strieq(forceEnv, "off") && !strieq(forceEnv, "0");
- Owned<IRemoteConnection> env = querySDS().connect("/Environment", myProcessSession(), 0, SDS_LOCK_TIMEOUT);
- IPropertyTree *pluginInfo = NULL;
- if (env)
- {
- SocketEndpoint targetDali = queryCoven().queryGroup().queryNode(0).endpoint();
- IPropertyTree *daliInfo = findDaliProcess(env->queryRoot(), targetDali);
- if (daliInfo)
- {
- const char *daliName = daliInfo->queryProp("@name");
- if (daliName)
- {
- VStringBuffer xpath("Software/DaliServerPlugin[@type='WorkunitServer'][@daliServers='%s']", daliName);
- pluginInfo = env->queryRoot()->queryPropTree(xpath);
- }
- if (!pluginInfo)
- pluginInfo = daliInfo->queryPropTree("Plugin[@type='WorkunitServer']"); // Compatibility with early betas of 6.0 ...
- }
- }
- if (pluginInfo && !forceDali)
- factory.setown( (IWorkUnitFactory *) loadPlugin(pluginInfo));
- else
- factory.setown(new CDaliWorkUnitFactory());
- }
- }
- return factory.getLink();
- }
- extern WORKUNIT_API IWorkUnitFactory * getDaliWorkUnitFactory()
- {
- if (!factory)
- {
- CriticalBlock b(factoryCrit);
- 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.
- factory.setown(new CDaliWorkUnitFactory());
- }
- return factory.getLink();
- }
- // A SecureWorkUnitFactory allows the security params to be supplied once to the factory rather than being supplied to each call.
- // They can still be supplied if you want...
- class CSecureWorkUnitFactory : implements IWorkUnitFactory, public CInterface
- {
- public:
- IMPLEMENT_IINTERFACE;
- CSecureWorkUnitFactory(IWorkUnitFactory *_baseFactory, ISecManager *_secMgr, ISecUser *_secUser)
- : baseFactory(_baseFactory), defaultSecMgr(_secMgr), defaultSecUser(_secUser)
- {
- }
- virtual bool initializeStore()
- {
- throwUnexpected(); // Used when loading a plugin factory - not applicable here
- }
- virtual IWorkUnitWatcher *getWatcher(IWorkUnitSubscriber *subscriber, WUSubscribeOptions options, const char *wuid) const
- {
- return baseFactory->getWatcher(subscriber, options, wuid);
- }
- virtual unsigned validateRepository(bool fix)
- {
- return baseFactory->validateRepository(fix);
- }
- virtual void deleteRepository(bool recreate)
- {
- return baseFactory->deleteRepository(recreate);
- }
- virtual void createRepository()
- {
- return baseFactory->createRepository();
- }
- virtual const char *queryStoreType() const
- {
- return baseFactory->queryStoreType();
- }
- virtual StringArray &getUniqueValues(WUSortField field, const char *prefix, StringArray &result) const
- {
- return baseFactory->getUniqueValues(field, prefix, result);
- }
- virtual IWorkUnit* createNamedWorkUnit(const char *wuid, const char *app, const char *user, ISecManager *secMgr, ISecUser *secUser)
- {
- if (!secMgr) secMgr = defaultSecMgr.get();
- if (!secUser) secUser = defaultSecUser.get();
- return baseFactory->createNamedWorkUnit(wuid, app, user, secMgr, secUser);
- }
- virtual IWorkUnit* createWorkUnit(const char *app, const char *user, ISecManager *secMgr, ISecUser *secUser)
- {
- if (!secMgr) secMgr = defaultSecMgr.get();
- if (!secUser) secUser = defaultSecUser.get();
- return baseFactory->createWorkUnit(app, user, secMgr, secUser);
- }
- virtual bool deleteWorkUnit(const char * wuid, ISecManager *secMgr, ISecUser *secUser)
- {
- if (!secMgr) secMgr = defaultSecMgr.get();
- if (!secUser) secUser = defaultSecUser.get();
- return baseFactory->deleteWorkUnit(wuid, secMgr, secUser);
- }
- virtual IConstWorkUnit* openWorkUnit(const char *wuid, ISecManager *secMgr, ISecUser *secUser)
- {
- if (!secMgr) secMgr = defaultSecMgr.get();
- if (!secUser) secUser = defaultSecUser.get();
- return baseFactory->openWorkUnit(wuid, secMgr, secUser);
- }
- virtual IWorkUnit* updateWorkUnit(const char *wuid, ISecManager *secMgr, ISecUser *secUser)
- {
- if (!secMgr) secMgr = defaultSecMgr.get();
- if (!secUser) secUser = defaultSecUser.get();
- return baseFactory->updateWorkUnit(wuid, secMgr, secUser);
- }
- virtual bool restoreWorkUnit(const char *base, const char *wuid, bool restoreAssociated)
- {
- return baseFactory->restoreWorkUnit(base, wuid, restoreAssociated);
- }
- virtual IWorkUnit * getGlobalWorkUnit(ISecManager *secMgr, ISecUser *secUser)
- {
- if (!secMgr) secMgr = defaultSecMgr.get();
- if (!secUser) secUser = defaultSecUser.get();
- return baseFactory->getGlobalWorkUnit(secMgr, secUser);
- }
- virtual IConstWorkUnitIterator * getWorkUnitsByOwner(const char * owner, ISecManager *secMgr, ISecUser *secUser)
- {
- if (!secMgr) secMgr = defaultSecMgr.get();
- if (!secUser) secUser = defaultSecUser.get();
- return baseFactory->getWorkUnitsByOwner(owner, secMgr, secUser);
- }
- virtual IConstWorkUnitIterator * getScheduledWorkUnits(ISecManager *secMgr, ISecUser *secUser)
- {
- if (!secMgr) secMgr = defaultSecMgr.get();
- if (!secUser) secUser = defaultSecUser.get();
- return baseFactory->getScheduledWorkUnits(secMgr, secUser);
- }
- virtual void descheduleAllWorkUnits(ISecManager *secMgr, ISecUser *secUser)
- {
- if (!secMgr) secMgr = defaultSecMgr.get();
- if (!secUser) secUser = defaultSecUser.get();
- baseFactory->descheduleAllWorkUnits(secMgr, secUser);
- }
- virtual int setTracingLevel(int newLevel)
- {
- return baseFactory->setTracingLevel(newLevel);
- }
- virtual IConstWorkUnitIterator* getWorkUnitsSorted( WUSortField sortorder, // field to sort by
- WUSortField *filters, // NULL or list of fields to filter on (terminated by WUSFterm)
- const void *filterbuf, // (appended) string values for filters
- unsigned startoffset,
- unsigned maxnum,
- __int64 *cachehint,
- unsigned *total,
- ISecManager *secMgr, ISecUser *secUser)
- {
- if (!secMgr) secMgr = defaultSecMgr.get();
- if (!secUser) secUser = defaultSecUser.get();
- return baseFactory->getWorkUnitsSorted(sortorder,filters,filterbuf,startoffset,maxnum,cachehint, total, secMgr, secUser);
- }
- virtual IConstQuerySetQueryIterator* getQuerySetQueriesSorted( WUQuerySortField *sortorder,
- WUQuerySortField *filters,
- const void *filterbuf,
- unsigned startoffset,
- unsigned maxnum,
- __int64 *cachehint,
- unsigned *total,
- const MapStringTo<bool> *subset)
- {
- // MORE - why no security?
- return baseFactory->getQuerySetQueriesSorted(sortorder,filters,filterbuf,startoffset,maxnum,cachehint,total,subset);
- }
- virtual unsigned numWorkUnits()
- {
- return baseFactory->numWorkUnits();
- }
- virtual bool isAborting(const char *wuid) const
- {
- return baseFactory->isAborting(wuid);
- }
- virtual void clearAborting(const char *wuid)
- {
- baseFactory->clearAborting(wuid);
- }
- virtual WUState waitForWorkUnit(const char * wuid, unsigned timeout, bool compiled, bool returnOnWaitState)
- {
- return baseFactory->waitForWorkUnit(wuid, timeout, compiled, returnOnWaitState);
- }
- virtual WUAction waitForWorkUnitAction(const char * wuid, WUAction original)
- {
- return baseFactory->waitForWorkUnitAction(wuid, original);
- }
- private:
- Owned<IWorkUnitFactory> baseFactory;
- Linked<ISecManager> defaultSecMgr;
- Linked<ISecUser> defaultSecUser;
- };
- extern WORKUNIT_API IWorkUnitFactory * getWorkUnitFactory(ISecManager *secmgr, ISecUser *secuser)
- {
- if (secmgr && secuser)
- return new CSecureWorkUnitFactory(getWorkUnitFactory(), secmgr, secuser);
- else
- return getWorkUnitFactory();
- }
- //==========================================================================================
- class CStringPTreeIterator : implements IStringIterator, public CInterface
- {
- Owned<IPropertyTreeIterator> it;
- public:
- IMPLEMENT_IINTERFACE;
- CStringPTreeIterator(IPropertyTreeIterator *p) : it(p) {};
- virtual bool first() { return it->first(); }
- virtual bool next() { return it->next(); }
- virtual bool isValid() { return it->isValid(); }
- virtual IStringVal & str(IStringVal &s) { s.set(it->query().queryProp(NULL)); return s; }
- };
- class CStringPTreeTagIterator : implements IStringIterator, public CInterface
- {
- Owned<IPropertyTreeIterator> it;
- public:
- IMPLEMENT_IINTERFACE;
- CStringPTreeTagIterator(IPropertyTreeIterator *p) : it(p) {};
- virtual bool first() { return it->first(); }
- virtual bool next() { return it->next(); }
- virtual bool isValid() { return it->isValid(); }
- virtual IStringVal & str(IStringVal &s) { s.set(it->query().queryName()); return s; }
- };
- class CStringPTreeAttrIterator : implements IStringIterator, public CInterface
- {
- Owned<IPropertyTreeIterator> it;
- StringAttr name;
- public:
- IMPLEMENT_IINTERFACE;
- CStringPTreeAttrIterator(IPropertyTreeIterator *p, const char *_name) : it(p), name(_name) {};
- virtual bool first() { return it->first(); }
- virtual bool next() { return it->next(); }
- virtual bool isValid() { return it->isValid(); }
- virtual IStringVal & str(IStringVal &s) { s.set(it->query().queryProp(name)); return s; }
- };
- //==========================================================================================
- CLocalWorkUnit::CLocalWorkUnit(ISecManager *secmgr, ISecUser *secuser)
- {
- clearCached(false);
- secMgr.set(secmgr);
- secUser.set(secuser);
- workflowIteratorCached = false;
- resultsCached = false;
- graphsCached = false;
- temporariesCached = false;
- variablesCached = false;
- exceptionsCached = false;
- pluginsCached = false;
- librariesCached = false;
- activitiesCached = false;
- webServicesInfoCached = false;
- roxieQueryInfoCached = false;
- }
- void CLocalWorkUnit::clearCached(bool clearTree)
- {
- query.clear();
- webServicesInfo.clear();
- workflowIterator.clear();
- graphs.kill();
- results.kill();
- variables.kill();
- plugins.kill();
- libraries.kill();
- exceptions.kill();
- temporaries.kill();
- statistics.kill();
- appvalues.kill();
- if (clearTree)
- p.clear();
- workflowIteratorCached = false;
- resultsCached = false;
- graphsCached = false;
- temporariesCached = false;
- variablesCached = false;
- exceptionsCached = false;
- pluginsCached = false;
- librariesCached = false;
- activitiesCached = false;
- webServicesInfoCached = false;
- roxieQueryInfoCached = false;
- }
- void CLocalWorkUnit::loadPTree(IPropertyTree *ptree)
- {
- clearCached(false);
- p.setown(ptree);
- }
- void CLocalWorkUnit::beforeDispose()
- {
- try
- {
- unsubscribe();
- clearCached(true);
- userDesc.clear();
- secMgr.clear();
- secUser.clear();
- }
- catch (IException *E) { LOG(MCexception(E, MSGCLS_warning), E, "Exception during ~CLocalWorkUnit"); E->Release(); }
- }
- void CLocalWorkUnit::cleanupAndDelete(bool deldll, bool deleteOwned, const StringArray *deleteExclusions)
- {
- MTIME_SECTION(queryActiveTimer(), "WUDELETE cleanupAndDelete total");
- // Delete any related things in SDS etc that might otherwise be forgotten
- if (p->getPropBool("@protected", false))
- throw MakeStringException(WUERR_WorkunitProtected, "%s: Workunit is protected",p->queryName());
- switch (getState())
- {
- case WUStateAborted:
- case WUStateCompleted:
- case WUStateFailed:
- case WUStateArchived:
- break;
- case WUStateCompiled:
- if (getAction()==WUActionRun || getAction()==WUActionUnknown)
- throw MakeStringException(WUERR_WorkunitActive, "%s: Workunit is active. Please abort before deleting this workunit.",p->queryName());
- break;
- case WUStateWait:
- throw MakeStringException(WUERR_WorkunitScheduled, "%s: Workunit is scheduled",p->queryName());
- default:
- throw MakeStringException(WUERR_WorkunitActive, "%s: Workunit is active. Please abort before deleting this workunit.",p->queryName());
- break;
- }
- if (getIsQueryService())
- {
- Owned<IPropertyTree> registry = getQueryRegistryRoot();
- if (registry)
- {
- VStringBuffer xpath("QuerySet/Query[@wuid='%s']", p->queryName());
- if (registry->hasProp(xpath.str()))
- throw MakeStringException(WUERR_WorkunitPublished, "%s: Workunit is published",p->queryName());
- }
- }
- try
- {
- if (deldll && !p->getPropBool("@isClone", false))
- {
- Owned<IConstWUQuery> q = getQuery();
- if (q)
- {
- Owned<IConstWUAssociatedFileIterator> iter = &q->getAssociatedFiles();
- SCMStringBuffer name;
- ForEach(*iter)
- {
- IConstWUAssociatedFile & cur = iter->query();
- cur.getNameTail(name);
- if (!deleteExclusions || (NotFound == deleteExclusions->find(name.str())))
- {
- Owned<IDllEntry> entry = queryDllServer().getEntry(name.str());
- if (entry.get())
- asyncRemoveDll(name.str());
- else
- {
- SCMStringBuffer ip, localPath;
- cur.getName(localPath);
- cur.getIp(ip);
- asyncRemoveFile(ip.str(), localPath.str());
- }
- }
- }
- }
- }
- factory->clearAborting(queryWuid());
- deleteTempFiles(NULL, deleteOwned, true); // all, any remaining.
- }
- catch(IException *E)
- {
- StringBuffer s;
- LOG(MCexception(E, MSGCLS_warning), E, s.append("Exception during cleanupAndDelete: ").append(p->queryName()).str());
- E->Release();
- }
- catch (...)
- {
- WARNLOG("Unknown exception during cleanupAndDelete: %s", p->queryName());
- }
- }
- void CLocalWorkUnit::setTimeScheduled(const IJlibDateTime &val)
- {
- SCMStringBuffer strval;
- val.getGmtString(strval);
- p->setProp("@timescheduled",strval.str());
- }
- IJlibDateTime & CLocalWorkUnit::getTimeScheduled(IJlibDateTime &val) const
- {
- StringBuffer str;
- p->getProp("@timescheduled",str);
- if(str.length())
- val.setGmtString(str.str());
- return val;
- }
- bool modifyAndWriteWorkUnitXML(char const * wuid, StringBuffer & buf, StringBuffer & extra, IFileIO * fileio)
- {
- // kludge in extra chunks of XML such as GraphProgress and GeneratedDlls
- if(extra.length())
- {
- size32_t l = (size32_t)strlen(wuid);
- size32_t p = buf.length()-l-4; // bit of a kludge
- assertex(memcmp(buf.str()+p+2,wuid,l)==0);
- StringAttr tail(buf.str()+p);
- buf.setLength(p);
- buf.append(extra);
- buf.append(tail);
- }
- return (fileio->write(0,buf.length(),buf.str()) == buf.length());
- }
- bool CLocalWorkUnit::archiveWorkUnit(const char *base, bool del, bool ignoredllerrors, bool deleteOwned, bool exportAssociatedFiles)
- {
- CriticalBlock block(crit);
- StringBuffer path(base);
- if (!p)
- return false;
- const char *wuid = p->queryName();
- if (!wuid||!*wuid)
- return false;
- addPathSepChar(path).append(wuid).append(".xml");
- Owned<IFile> file = createIFile(path.str());
- if (!file)
- return false;
- Owned<IFileIO> fileio = file->open(IFOcreate);
- if (!fileio)
- return false;
- StringBuffer buf;
- exportWorkUnitToXML(this, buf, false, false, true);
- StringBuffer extraWorkUnitXML;
- Owned<IPTree> graphProgress = getGraphProgressTree();
- if (graphProgress)
- {
- toXML(graphProgress,extraWorkUnitXML,1,XML_Format);
- graphProgress.clear();
- }
- Owned<IConstWUQuery> q = getQuery();
- if (!q)
- {
- if (!modifyAndWriteWorkUnitXML(wuid, buf, extraWorkUnitXML, fileio))
- return false;
- if (del)
- {
- if (getState()==WUStateUnknown)
- setState(WUStateArchived); // to allow delete
- cleanupAndDelete(false,deleteOwned); // no query, may as well delete
- }
- return false;
- }
- StringArray deleteExclusions; // associated files not to delete, added if failure to copy
- Owned<IConstWUAssociatedFileIterator> iter = &q->getAssociatedFiles();
- Owned<IPropertyTree> generatedDlls = createPTree("GeneratedDlls");
- ForEach(*iter)
- {
- IConstWUAssociatedFile & cur = iter->query();
- SCMStringBuffer name;
- cur.getNameTail(name);
- if (name.length())
- {
- Owned<IDllEntry> entry = queryDllServer().getEntry(name.str());
- SCMStringBuffer curPath, curIp;
- cur.getName(curPath);
- cur.getIp(curIp);
- SocketEndpoint curEp(curIp.str());
- RemoteFilename curRfn;
- curRfn.setPath(curEp, curPath.str());
- StringBuffer dst(base);
- addPathSepChar(dst);
- curRfn.getTail(dst);
- Owned<IFile> dstFile = createIFile(dst.str());
- if (entry.get())
- {
- Owned<IException> exception;
- Owned<IDllLocation> loc;
- Owned<IPropertyTree> generatedDllBranch = createPTree();
- generatedDllBranch->setProp("@name", entry->queryName());
- generatedDllBranch->setProp("@kind", entry->queryKind());
- if (exportAssociatedFiles)
- {
- try
- {
- loc.setown(entry->getBestLocation()); //throws exception if no readable locations
- }
- catch(IException * e)
- {
- exception.setown(e);
- loc.setown(entry->getBestLocationCandidate()); //this will be closest of the unreadable locations
- }
- RemoteFilename filename;
- loc->getDllFilename(filename);
- if (!exception)
- {
- Owned<IFile> srcfile = createIFile(filename);
- try
- {
- if (dstFile->exists())
- {
- if (streq(srcfile->queryFilename(), dstFile->queryFilename()))
- deleteExclusions.append(name.str()); // restored workunit, referencing archive location for query dll (no longer true post HPCC-11191 fix)
- // still want to delete if already archived but there are source file copies
- }
- else
- copyFile(dstFile, srcfile);
- }
- catch(IException * e)
- {
- exception.setown(e);
- }
- }
- if (exception)
- {
- if (ignoredllerrors)
- {
- EXCLOG(exception.get(), "archiveWorkUnit (copying associated file)");
- //copy failed, so don't delete the registered dll files
- deleteExclusions.append(name.str());
- }
- else
- throw exception.getClear();
- }
- }
- // Record Associated path to restore back to
- StringBuffer restorePath;
- curRfn.getRemotePath(restorePath);
- generatedDllBranch->setProp("@location", restorePath.str());
- generatedDlls->addPropTree("GeneratedDll", generatedDllBranch.getClear());
- }
- else if (exportAssociatedFiles) // no generated dll entry
- {
- Owned<IFile> srcFile = createIFile(curRfn);
- try
- {
- copyFile(dstFile, srcFile);
- }
- catch (IException *e)
- {
- VStringBuffer msg("Failed to archive associated file '%s' to destination '%s'", srcFile->queryFilename(), dstFile->queryFilename());
- EXCLOG(e, msg.str());
- e->Release();
- deleteExclusions.append(name.str());
- }
- }
- }
- }
- iter.clear();
- if (generatedDlls->numChildren())
- toXML(generatedDlls, extraWorkUnitXML, 1, XML_Format);
- if (!modifyAndWriteWorkUnitXML(wuid, buf, extraWorkUnitXML, fileio))
- return false;
- if (del)
- {
- //setState(WUStateArchived); // this isn't useful as about to delete it!
- q.clear();
- cleanupAndDelete(true, deleteOwned, &deleteExclusions);
- }
- return true;
- }
- void CLocalWorkUnit::loadXML(const char *xml)
- {
- CriticalBlock block(crit);
- clearCached(true);
- assertex(xml);
- p.setown(createPTreeFromXMLString(xml));
- }
- void CLocalWorkUnit::serialize(MemoryBuffer &tgt)
- {
- CriticalBlock block(crit);
- StringBuffer x;
- tgt.append(exportWorkUnitToXML(this, x, false, false, false).str());
- }
- void CLocalWorkUnit::deserialize(MemoryBuffer &src)
- {
- CriticalBlock block(crit);
- StringAttr value;
- src.read(value);
- loadXML(value);
- }
- void CLocalWorkUnit::requestAbort()
- {
- CriticalBlock block(crit);
- abortWorkUnit(p->queryName());
- }
- void CLocalWorkUnit::unlockRemote()
- {
- CriticalBlock block(crit);
- locked.unlock();
- _unlockRemote();
- }
- IWorkUnit &CLocalWorkUnit::lockRemote(bool commit)
- {
- if (secMgr)
- checkWuSecAccess(*this, secMgr.get(), secUser.get(), SecAccess_Write, "write lock", true, true);
- locked.lock();
- CriticalBlock block(crit);
- if (commit)
- {
- try
- {
- _lockRemote();
- }
- catch (IException *E)
- {
- StringBuffer s;
- PrintLog("Failed to get write lock on workunit: %s", E->errorMessage(s).str());
- locked.unlock();
- throw;
- }
- }
- return *new CLockedWorkUnit(LINK(this));
- }
- void CLocalWorkUnit::commit()
- {
- // Nothing to do if not backed by a persistent store
- }
- IWorkUnit& CLocalWorkUnit::lock()
- {
- return lockRemote(true);
- }
- const char *CLocalWorkUnit::queryWuid() const
- {
- CriticalBlock block(crit);
- return p->queryName();
- }
- unsigned CLocalWorkUnit::getDebugAgentListenerPort() const
- {
- CriticalBlock block(crit);
- return p->getPropInt("@DebugListenerPort", 0);
- }
- unsigned CLocalWorkUnit::getTotalThorTime() const
- {
- CriticalBlock block(crit);
- return (unsigned)nanoToMilli(extractTimeCollatable(p->queryProp("@totalThorTime"), false));
- }
- void CLocalWorkUnit::setDebugAgentListenerPort(unsigned port)
- {
- CriticalBlock block(crit);
- p->setPropInt("@DebugListenerPort", port);
- }
- IStringVal& CLocalWorkUnit::getDebugAgentListenerIP(IStringVal &ip) const
- {
- CriticalBlock block(crit);
- ip.set(p->queryProp("@DebugListenerIP"));
- return ip;
- }
- void CLocalWorkUnit::setDebugAgentListenerIP(const char * ip)
- {
- CriticalBlock block(crit);
- p->setProp("@DebugListenerIP", ip);
- }
- IStringVal& CLocalWorkUnit::getSecurityToken(IStringVal &str) const
- {
- CriticalBlock block(crit);
- str.set(p->queryProp("@token"));
- return str;
- }
- void CLocalWorkUnit::setSecurityToken(const char *value)
- {
- CriticalBlock block(crit);
- p->setProp("@token", value);
- }
- bool CLocalWorkUnit::getRunningGraph(IStringVal &graphName, WUGraphIDType &subId) const
- {
- // Only implemented in derived classes
- return false;
- }
- void CLocalWorkUnit::setJobName(const char *value)
- {
- CriticalBlock block(crit);
- p->setProp("@jobName", value);
- }
- const char *CLocalWorkUnit::queryJobName() const
- {
- CriticalBlock block(crit);
- const char *ret = p->queryProp("@jobName");
- if (!ret)
- ret = "";
- return ret;
- }
- void CLocalWorkUnit::setClusterName(const char *value)
- {
- CriticalBlock block(crit);
- p->setProp("@clusterName", value);
- }
- const char *CLocalWorkUnit::queryClusterName() const
- {
- CriticalBlock block(crit);
- const char *ret = p->queryProp("@clusterName");
- if (!ret)
- ret = "";
- return ret;
- }
- void CLocalWorkUnit::setAllowedClusters(const char *value)
- {
- setDebugValue("allowedclusters",value, true);
- }
- IStringVal& CLocalWorkUnit::getAllowedClusters(IStringVal &str) const
- {
- CriticalBlock block(crit);
- getDebugValue("allowedclusters",str);
- if (str.length()!=0)
- return str;
- str.set(p->queryProp("@clusterName"));
- return str;
- }
- void CLocalWorkUnit::setAllowAutoQueueSwitch(bool val)
- {
- setDebugValueInt("allowautoqueueswitch",val?1:0,true);
- }
-
- bool CLocalWorkUnit::getAllowAutoQueueSwitch() const
- {
- CriticalBlock block(crit);
- return getDebugValueBool("allowautoqueueswitch",false);
- }
- void CLocalWorkUnit::setLibraryInformation(const char * name, unsigned interfaceHash, unsigned definitionHash)
- {
- StringBuffer suffix;
- if (name && *name)
- setApplicationValue("LibraryModule", "name", name, true);
- setApplicationValueInt("LibraryModule", "interfaceHash", interfaceHash, true);
- setApplicationValueInt("LibraryModule", "definitionHash", definitionHash, true);
- setApplicationValue("LibraryModule", "platform", appendLibrarySuffix(suffix).str(), true);
- }
- void CLocalWorkUnit::remoteCheckAccess(IUserDescriptor *user, bool writeaccess) const
- {
- unsigned auditflags = DALI_LDAP_AUDIT_REPORT|DALI_LDAP_READ_WANTED;
- if (writeaccess)
- auditflags |= DALI_LDAP_WRITE_WANTED;
- SecAccessFlags perm = SecAccess_Full;
- const char *scopename = p->queryProp("@scope");
- if (scopename&&*scopename) {
- if (!user)
- user = queryUserDescriptor();
- perm = querySessionManager().getPermissionsLDAP("workunit",scopename,user,auditflags);
- if (perm<0) {
- if (perm == SecAccess_Unavailable)
- perm = SecAccess_Full;
- else
- perm = SecAccess_None;
- }
- }
- if (!HASREADPERMISSION(perm))
- throw MakeStringException(WUERR_WorkunitAccessDenied, "Read access denied for workunit %s", queryWuid());
- if (writeaccess && !HASWRITEPERMISSION(perm))
- throw MakeStringException(WUERR_WorkunitAccessDenied, "Write access denied for workunit %s", queryWuid());
- }
- void CLocalWorkUnit::setUser(const char * value)
- {
- CriticalBlock block(crit);
- p->setProp("@submitID", value);
- }
- const char *CLocalWorkUnit::queryUser() const
- {
- CriticalBlock block(crit);
- const char *ret = p->queryProp("@submitID");
- if (!ret)
- ret = "";
- return ret;
- }
- void CLocalWorkUnit::setWuScope(const char * value)
- {
- if (value && *value)
- {
- if (checkWuScopeSecAccess(value, secMgr.get(), secUser.get(), SecAccess_Write, "Change Scope", true, true))
- {
- CriticalBlock block(crit);
- p->setProp("@scope", value);
- }
- }
- }
- const char *CLocalWorkUnit::queryWuScope() const
- {
- CriticalBlock block(crit);
- const char *ret = p->queryProp("@scope");
- if (!ret)
- ret = "";
- return ret;
- }
- void CLocalWorkUnit::setPriority(WUPriorityClass cls)
- {
- CriticalBlock block(crit);
- setEnum(p, "@priorityClass", cls, priorityClasses);
- }
- WUPriorityClass CLocalWorkUnit::getPriority() const
- {
- CriticalBlock block(crit);
- return (WUPriorityClass) getEnum(p, "@priorityClass", priorityClasses);
- }
- const char *CLocalWorkUnit::queryPriorityDesc() const
- {
- return getEnumText(getPriority(), priorityClasses);
- }
- void CLocalWorkUnit::setState(WUState value)
- {
- if (value==WUStateAborted || value==WUStatePaused || value==WUStateCompleted || value==WUStateFailed || value==WUStateSubmitted || value==WUStateWait)
- {
- if (factory)
- factory->clearAborting(queryWuid());
- }
- CriticalBlock block(crit);
- setEnum(p, "@state", value, states); // For historical reasons, we use state to store the state
- setEnum(p, "State", value, states); // But we can only subscribe to elements, not attributes
- if (getDebugValueBool("monitorWorkunit", false))
- {
- switch(value)
- {
- case WUStateAborted:
- FLLOG(MCoperatorWarning, "Workunit %s aborted", p->queryName());
- break;
- case WUStateCompleted:
- FLLOG(MCoperatorProgress, "Workunit %s completed", p->queryName());
- break;
- case WUStateFailed:
- FLLOG(MCoperatorProgress, "Workunit %s failed", p->queryName());
- break;
- }
- }
- p->removeProp("@stateEx");
- }
- void CLocalWorkUnit::setStateEx(const char * text)
- {
- CriticalBlock block(crit);
- p->setProp("@stateEx", text);
- }
- void CLocalWorkUnit::setAgentSession(__int64 sessionId)
- {
- CriticalBlock block(crit);
- p->setPropInt64("@agentSession", sessionId);
- }
- bool CLocalWorkUnit::getIsQueryService() const
- {
- CriticalBlock block(crit);
- return p->getPropBool("@isQueryService", false);
- }
- void CLocalWorkUnit::setIsQueryService(bool value)
- {
- CriticalBlock block(crit);
- p->setPropBool("@isQueryService", value);
- }
- void CLocalWorkUnit::checkAgentRunning(WUState & state)
- {
- if (queryDaliServerVersion().compare("2.1")<0)
- return;
- switch(state)
- {
- case WUStateRunning:
- case WUStateDebugPaused:
- case WUStateDebugRunning:
- case WUStateBlocked:
- case WUStateAborting:
- case WUStateCompiling:
- case WUStatePaused:
- {
- SessionId agent = getAgentSession();
- if((agent>0) && querySessionManager().sessionStopped(agent, 0))
- {
- forceReload();
- state = (WUState) getEnum(p, "@state", states);
- bool isecl=state==WUStateCompiling;
- if (aborting())
- state = WUStateAborted;
- else if (state==WUStateRunning || state==WUStatePaused || state==WUStateDebugPaused || state==WUStateDebugRunning || state==WUStateBlocked || state==WUStateCompiling)
- state = WUStateFailed;
- else
- return;
- WARNLOG("checkAgentRunning terminated: %" I64F "d state = %d",(__int64)agent,(int)state);
- Owned<IWorkUnit> w = &lock();
- w->setState(state);
- Owned<IWUException> e = w->createException();
- WUAction action = w->getAction();
- switch (action)
- {
- case WUActionPause:
- case WUActionPauseNow:
- case WUActionResume:
- w->setAction(WUActionUnknown);
- }
- if(isecl)
- {
- e->setExceptionCode(1001);
- e->setExceptionMessage("EclServer terminated unexpectedly");
- }
- else
- {
- e->setExceptionCode(1000);
- e->setExceptionMessage("Workunit terminated unexpectedly");
- }
- }
- }
- }
- }
- WUState CLocalWorkUnit::getState() const
- {
- CriticalBlock block(crit);
- WUState state = (WUState) getEnum(p, "@state", states);
- switch (state)
- {
- case WUStateRunning:
- case WUStateDebugPaused:
- case WUStateDebugRunning:
- case WUStateBlocked:
- case WUStateCompiling:
- if (aborting())
- state = WUStateAborting;
- break;
- case WUStateSubmitted:
- if (aborting())
- state = WUStateAborted;
- break;
- }
- const_cast<CLocalWorkUnit *>(this)->checkAgentRunning(state); //need const_cast as will change state if agent has died
- return state;
- }
- IStringVal& CLocalWorkUnit::getStateEx(IStringVal & str) const
- {
- CriticalBlock block(crit);
- str.set(p->queryProp("@stateEx"));
- return str;
- }
- __int64 CLocalWorkUnit::getAgentSession() const
- {
- CriticalBlock block(crit);
- return p->getPropInt64("@agentSession", -1);
- }
- unsigned CLocalWorkUnit::getAgentPID() const
- {
- CriticalBlock block(crit);
- return p->getPropInt("@agentPID", -1);
- }
- const char * CLocalWorkUnit::queryStateDesc() const
- {
- // MORE - not sure about this - may prefer a separate interface
- CriticalBlock block(crit);
- try
- {
- return getEnumText(getState(), states);
- }
- catch (...)
- {
- return "???";
- }
- }
- void CLocalWorkUnit::setAction(WUAction value)
- {
- CriticalBlock block(crit);
- setEnum(p, "Action", value, actions);
- }
- WUAction CLocalWorkUnit::getAction() const
- {
- CriticalBlock block(crit);
- return (WUAction) getEnum(p, "Action", actions);
- }
- const char *CLocalWorkUnit::queryActionDesc() const
- {
- CriticalBlock block(crit);
- return p->queryProp("Action");
- }
- IStringVal& CLocalWorkUnit::getApplicationValue(const char *app, const char *propname, IStringVal &str) const
- {
- CriticalBlock block(crit);
- StringBuffer prop("Application/");
- prop.append(app).append('/').append(propname);
- str.set(p->queryProp(prop.str()));
- return str;
- }
- int CLocalWorkUnit::getApplicationValueInt(const char *app, const char *propname, int defVal) const
- {
- CriticalBlock block(crit);
- StringBuffer prop("Application/");
- prop.append(app).append('/').append(propname);
- return p->getPropInt(prop.str(), defVal);
- }
- IConstWUAppValueIterator& CLocalWorkUnit::getApplicationValues() const
- {
- CriticalBlock block(crit);
- appvalues.load(p,"Application/*");
- return *new CArrayIteratorOf<IConstWUAppValue,IConstWUAppValueIterator> (appvalues, 0, (IConstWorkUnit *) this);
- }
- void CLocalWorkUnit::setApplicationValue(const char *app, const char *propname, const char *value, bool overwrite)
- {
- CriticalBlock block(crit);
- StringBuffer prop("Application/");
- prop.append(app).append('/').append(propname);
- if (overwrite || !p->hasProp(prop.str()))
- {
- StringBuffer sp;
- p->setProp(sp.append("Application").str(), "");
- p->setProp(sp.append('/').append(app).str(), "");
- p->setProp(prop.str(), value);
- }
- }
- void CLocalWorkUnit::setApplicationValueInt(const char *app, const char *propname, int value, bool overwrite)
- {
- VStringBuffer s("%d", value);
- setApplicationValue(app, propname, s, overwrite);
- }
- void CLocalWorkUnit::setPriorityLevel(int level)
- {
- CriticalBlock block(crit);
- p->setPropInt("PriorityFlag", level);
- }
- int CLocalWorkUnit::getPriorityLevel() const
- {
- CriticalBlock block(crit);
- return p->getPropInt("PriorityFlag");
- }
- int calcPriorityValue(const IPropertyTree * p)
- {
- int priority = p->getPropInt("PriorityFlag");
- switch((WUPriorityClass) getEnum(p, "@priorityClass", priorityClasses))
- {
- case PriorityClassLow:
- priority -= 100;
- break;
- case PriorityClassHigh:
- priority += 100;
- break;
- }
- return priority;
- }
- int CLocalWorkUnit::getPriorityValue() const
- {
- CriticalBlock block(crit);
- return calcPriorityValue(p);
- }
- void CLocalWorkUnit::setRescheduleFlag(bool value)
- {
- CriticalBlock block(crit);
- p->setPropInt("RescheduleFlag", (int) value);
- }
- bool CLocalWorkUnit::getRescheduleFlag() const
- {
- CriticalBlock block(crit);
- return p->getPropInt("RescheduleFlag") != 0;
- }
- class NullIStringIterator : implements IStringIterator, public CInterface
- {
- public:
- IMPLEMENT_IINTERFACE;
- bool first() { return false; }
- bool next() { return false; }
- bool isValid() { return false; }
- IStringVal & str(IStringVal & str) { return str; }
- };
- ClusterType getClusterType(const char * platform, ClusterType dft)
- {
- if (stricmp(platform, "thor") == 0)
- return ThorLCRCluster;
- if (stricmp(platform, "thorlcr") == 0)
- return ThorLCRCluster;
- if (stricmp(platform, "hthor") == 0)
- return HThorCluster;
- if (stricmp(platform, "roxie") == 0)
- return RoxieCluster;
- return dft;
- }
- const char *clusterTypeString(ClusterType clusterType, bool lcrSensitive)
- {
- switch (clusterType)
- {
- case ThorLCRCluster:
- if (lcrSensitive)
- return "thorlcr";
- return "thor";
- case RoxieCluster:
- return "roxie";
- case HThorCluster:
- return "hthor";
- }
- throwUnexpected();
- }
- IPropertyTree *queryRoxieProcessTree(IPropertyTree *environment, const char *process)
- {
- if (!process || !*process)
- return NULL;
- VStringBuffer xpath("Software/RoxieCluster[@name=\"%s\"]", process);
- return environment->queryPropTree(xpath.str());
- }
- void getRoxieProcessServers(IPropertyTree *roxie, SocketEndpointArray &endpoints)
- {
- if (!roxie)
- return;
- Owned<IPropertyTreeIterator> servers = roxie->getElements("RoxieServerProcess");
- ForEach(*servers)
- {
- IPropertyTree &server = servers->query();
- const char *netAddress = server.queryProp("@netAddress");
- if (netAddress && *netAddress)
- {
- SocketEndpoint ep(netAddress, server.getPropInt("@port", 9876));
- endpoints.append(ep);
- }
- }
- }
- void getRoxieProcessServers(const char *process, SocketEndpointArray &servers)
- {
- Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
- Owned<IConstEnvironment> env = factory->openEnvironment();
- if (!env)
- return;
- Owned<IPropertyTree> root = &env->getPTree();
- getRoxieProcessServers(queryRoxieProcessTree(root, process), servers);
- }
- class CEnvironmentClusterInfo: implements IConstWUClusterInfo, public CInterface
- {
- StringAttr name;
- StringAttr alias;
- StringAttr serverQueue;
- StringAttr agentQueue;
- StringAttr roxieProcess;
- SocketEndpointArray roxieServers;
- StringAttr thorQueue;
- StringArray thorProcesses;
- StringArray primaryThorProcesses;
- StringAttr prefix;
- StringAttr ldapUser;
- StringBuffer ldapPassword;
- ClusterType platform;
- unsigned clusterWidth;
- unsigned roxieRedundancy;
- unsigned channelsPerNode;
- int roxieReplicateOffset;
- public:
- IMPLEMENT_IINTERFACE;
- CEnvironmentClusterInfo(const char *_name, const char *_prefix, const char *_alias, IPropertyTree *agent, IArrayOf<IPropertyTree> &thors, IPropertyTree *roxie)
- : name(_name), prefix(_prefix), alias(_alias), roxieRedundancy(0), channelsPerNode(0), roxieReplicateOffset(1)
- {
- StringBuffer queue;
- if (thors.ordinality())
- {
- thorQueue.set(getClusterThorQueueName(queue.clear(), name));
- clusterWidth = 0;
- bool isMultiThor = (thors.length() > 1);
- ForEachItemIn(i,thors)
- {
- IPropertyTree &thor = thors.item(i);
- const char* thorName = thor.queryProp("@name");
- thorProcesses.append(thorName);
- if (!isMultiThor)
- primaryThorProcesses.append(thorName);
- else
- {
- const char *nodeGroup = thor.queryProp("@nodeGroup");
- if (!nodeGroup || strieq(nodeGroup, thorName))
- primaryThorProcesses.append(thorName);
- }
- unsigned nodes = thor.getCount("ThorSlaveProcess");
- if (!nodes)
- throw MakeStringException(WUERR_MismatchClusterSize,"CEnvironmentClusterInfo: Thor cluster can not have 0 slave processes");
- unsigned slavesPerNode = thor.getPropInt("@slavesPerNode", 1);
- unsigned channelsPerSlave = thor.getPropInt("@channelsPerSlave", 1);
- unsigned ts = nodes * slavesPerNode * channelsPerSlave;
- if (clusterWidth && (ts!=clusterWidth))
- throw MakeStringException(WUERR_MismatchClusterSize,"CEnvironmentClusterInfo: mismatched thor sizes in cluster");
- clusterWidth = ts;
- bool islcr = !thor.getPropBool("@Legacy");
- if (!islcr)
- throw MakeStringException(WUERR_MismatchThorType,"CEnvironmentClusterInfo: Legacy Thor no longer supported");
- }
- platform = ThorLCRCluster;
- }
- else if (roxie)
- {
- roxieProcess.set(roxie->queryProp("@name"));
- platform = RoxieCluster;
- getRoxieProcessServers(roxie, roxieServers);
- clusterWidth = roxieServers.length();
- ldapUser.set(roxie->queryProp("@ldapUser"));
- StringBuffer encPassword = roxie->queryProp("@ldapPassword");
- if (encPassword.length())
- decrypt(ldapPassword, encPassword);
- const char *redundancyMode = roxie->queryProp("@slaveConfig");
- if (redundancyMode && *redundancyMode)
- {
- unsigned dataCopies = roxie->getPropInt("@numDataCopies", 1);
- if (strieq(redundancyMode, "overloaded"))
- channelsPerNode = roxie->getPropInt("@channelsPernode", 1);
- else if (strieq(redundancyMode, "full redundancy"))
- {
- roxieRedundancy = dataCopies-1;
- roxieReplicateOffset = 0;
- }
- else if (strieq(redundancyMode, "cyclic redundancy"))
- {
- roxieRedundancy = dataCopies-1;
- channelsPerNode = dataCopies;
- roxieReplicateOffset = roxie->getPropInt("@cyclicOffset", 1);
- }
- }
- }
- else
- {
- clusterWidth = 1;
- platform = HThorCluster;
- }
- if (agent)
- {
- assertex(!roxie);
- agentQueue.set(getClusterEclAgentQueueName(queue.clear(), name));
- }
- else if (roxie)
- agentQueue.set(getClusterRoxieQueueName(queue.clear(), name));
- // MORE - does this need to be conditional?
- serverQueue.set(getClusterEclCCServerQueueName(queue.clear(), name));
- }
- IStringVal & getName(IStringVal & str) const
- {
- str.set(name.get());
- return str;
- }
- const char *getAlias() const
- {
- return alias;
- }
- IStringVal & getScope(IStringVal & str) const
- {
- str.set(prefix.get());
- return str;
- }
- IStringVal & getAgentQueue(IStringVal & str) const
- {
- str.set(agentQueue);
- return str;
- }
- virtual IStringVal & getServerQueue(IStringVal & str) const
- {
- str.set(serverQueue);
- return str;
- }
- IStringVal & getThorQueue(IStringVal & str) const
- {
- str.set(thorQueue);
- return str;
- }
- unsigned getSize() const
- {
- return clusterWidth;
- }
- virtual ClusterType getPlatform() const
- {
- return platform;
- }
- IStringVal & getRoxieProcess(IStringVal & str) const
- {
- str.set(roxieProcess.get());
- return str;
- }
- const StringArray & getThorProcesses() const
- {
- return thorProcesses;
- }
- const StringArray & getPrimaryThorProcesses() const
- {
- return primaryThorProcesses;
- }
- const SocketEndpointArray & getRoxieServers() const
- {
- return roxieServers;
- }
- unsigned getRoxieRedundancy() const
- {
- return roxieRedundancy;
- }
- unsigned getChannelsPerNode() const
- {
- return channelsPerNode;
- }
- int getRoxieReplicateOffset() const
- {
- return roxieReplicateOffset;
- }
- const char *getLdapUser() const
- {
- return ldapUser.get();
- }
- virtual const char *getLdapPassword() const
- {
- return ldapPassword.str();
- }
- };
- IStringVal &getProcessQueueNames(IStringVal &ret, const char *process, const char *type, const char *suffix)
- {
- if (process)
- {
- Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
- Owned<IConstEnvironment> env = factory->openEnvironment();
- if (env)
- {
- Owned<IPropertyTree> root = &env->getPTree();
- StringBuffer queueNames;
- StringBuffer xpath;
- xpath.appendf("%s[@process=\"%s\"]", type, process);
- Owned<IPropertyTreeIterator> targets = root->getElements("Software/Topology/Cluster");
- ForEach(*targets)
- {
- IPropertyTree &target = targets->query();
- if (target.hasProp(xpath))
- {
- if (queueNames.length())
- queueNames.append(',');
- queueNames.append(target.queryProp("@name")).append(suffix);
- }
- }
- ret.set(queueNames);
- }
- }
- return ret;
- }
- #define ROXIE_QUEUE_EXT ".roxie"
- #define THOR_QUEUE_EXT ".thor"
- #define ECLCCSERVER_QUEUE_EXT ".eclserver"
- #define ECLSERVER_QUEUE_EXT ECLCCSERVER_QUEUE_EXT
- #define ECLSCHEDULER_QUEUE_EXT ".eclscheduler"
- #define ECLAGENT_QUEUE_EXT ".agent"
- extern WORKUNIT_API IStringVal &getEclCCServerQueueNames(IStringVal &ret, const char *process)
- {
- return getProcessQueueNames(ret, process, "EclCCServerProcess", ECLCCSERVER_QUEUE_EXT);
- }
- extern WORKUNIT_API IStringVal &getEclServerQueueNames(IStringVal &ret, const char *process)
- {
- return getProcessQueueNames(ret, process, "EclServerProcess", ECLSERVER_QUEUE_EXT); // shares queue name with EclCCServer
- }
- extern WORKUNIT_API IStringVal &getEclSchedulerQueueNames(IStringVal &ret, const char *process)
- {
- return getProcessQueueNames(ret, process, "EclSchedulerProcess", ECLSCHEDULER_QUEUE_EXT); // Shares deployment/config with EclCCServer
- }
- extern WORKUNIT_API IStringVal &getAgentQueueNames(IStringVal &ret, const char *process)
- {
- return getProcessQueueNames(ret, process, "EclAgentProcess", ECLAGENT_QUEUE_EXT);
- }
- extern WORKUNIT_API IStringVal &getRoxieQueueNames(IStringVal &ret, const char *process)
- {
- return getProcessQueueNames(ret, process, "RoxieCluster", ROXIE_QUEUE_EXT);
- }
- extern WORKUNIT_API IStringVal &getThorQueueNames(IStringVal &ret, const char *process)
- {
- return getProcessQueueNames(ret, process, "ThorCluster", THOR_QUEUE_EXT);
- }
- extern WORKUNIT_API StringBuffer &getClusterThorQueueName(StringBuffer &ret, const char *cluster)
- {
- return ret.append(cluster).append(THOR_QUEUE_EXT);
- }
- extern WORKUNIT_API StringBuffer &getClusterThorGroupName(StringBuffer &ret, const char *cluster)
- {
- Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
- Owned<IConstEnvironment> env = factory->openEnvironment();
- if (env)
- {
- Owned<IPropertyTree> root = &env->getPTree();
- StringBuffer path;
- path.append("Software/ThorCluster[@name=\"").append(cluster).append("\"]");
- IPropertyTree * child = root->queryPropTree(path);
- if (child)
- getClusterGroupName(*child, ret);
- }
- return ret;
- }
- extern WORKUNIT_API StringBuffer &getClusterRoxieQueueName(StringBuffer &ret, const char *cluster)
- {
- return ret.append(cluster).append(ROXIE_QUEUE_EXT);
- }
- extern WORKUNIT_API StringBuffer &getClusterEclCCServerQueueName(StringBuffer &ret, const char *cluster)
- {
- return ret.append(cluster).append(ECLCCSERVER_QUEUE_EXT);
- }
- extern WORKUNIT_API StringBuffer &getClusterEclServerQueueName(StringBuffer &ret, const char *cluster)
- {
- return ret.append(cluster).append(ECLSERVER_QUEUE_EXT);
- }
- extern WORKUNIT_API StringBuffer &getClusterEclAgentQueueName(StringBuffer &ret, const char *cluster)
- {
- return ret.append(cluster).append(ECLAGENT_QUEUE_EXT);
- }
- extern WORKUNIT_API IStringIterator *getTargetClusters(const char *processType, const char *processName)
- {
- Owned<CStringArrayIterator> ret = new CStringArrayIterator;
- Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
- Owned<IConstEnvironment> env = factory->openEnvironment();
- if (env)
- {
- Owned<IPropertyTree> root = &env->getPTree();
- StringBuffer xpath;
- xpath.appendf("%s", processType ? processType : "*");
- if (processName && *processName)
- xpath.appendf("[@process=\"%s\"]", processName);
- Owned<IPropertyTreeIterator> targets = root->getElements("Software/Topology/Cluster");
- ForEach(*targets)
- {
- IPropertyTree &target = targets->query();
- if (target.hasProp(xpath))
- {
- ret->append(target.queryProp("@name"));
- }
- }
- }
- return ret.getClear();
- }
- extern WORKUNIT_API bool isProcessCluster(const char *process)
- {
- if (!process || !*process)
- return false;
- Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
- Owned<IConstEnvironment> env = factory->openEnvironment();
- if (!env)
- return false;
- Owned<IPropertyTree> root = &env->getPTree();
- VStringBuffer xpath("Software/*Cluster[@name=\"%s\"]", process);
- return root->hasProp(xpath.str());
- }
- extern WORKUNIT_API bool isProcessCluster(const char *remoteDali, const char *process)
- {
- if (!remoteDali || !*remoteDali)
- return isProcessCluster(process);
- if (!process || !*process)
- return false;
- Owned<INode> remote = createINode(remoteDali, 7070);
- if (!remote)
- return false;
- //Cannot use getEnvironmentFactory() since it is using a remotedali
- VStringBuffer xpath("Environment/Software/*Cluster[@name=\"%s\"]/@name", process);
- try
- {
- Owned<IPropertyTreeIterator> clusters = querySDS().getElementsRaw(xpath, remote, 1000*60*1);
- return clusters->first();
- }
- catch (IException *E)
- {
- StringBuffer msg;
- E->errorMessage(msg);
- DBGLOG("Exception validating cluster %s/%s: %s", remoteDali, xpath.str(), msg.str());
- E->Release();
- }
- return true;
- }
- IConstWUClusterInfo* getTargetClusterInfo(IPropertyTree *environment, IPropertyTree *cluster)
- {
- const char *clustname = cluster->queryProp("@name");
- // MORE - at the moment configenf specifies eclagent and thor queues by (in effect) placing an 'example' thor or eclagent in the topology
- // that uses the queue that will be used.
- // We should and I hope will change that, at which point the code below gets simpler
- StringBuffer prefix(cluster->queryProp("@prefix"));
- prefix.toLowerCase();
- StringBuffer xpath;
- StringBuffer querySetName;
-
- IPropertyTree *agent = NULL;
- const char *agentName = cluster->queryProp("EclAgentProcess/@process");
- if (agentName)
- {
- xpath.clear().appendf("Software/EclAgentProcess[@name=\"%s\"]", agentName);
- agent = environment->queryPropTree(xpath.str());
- }
- Owned<IPropertyTreeIterator> ti = cluster->getElements("ThorCluster");
- IArrayOf<IPropertyTree> thors;
- ForEach(*ti)
- {
- const char *thorName = ti->query().queryProp("@process");
- if (thorName)
- {
- xpath.clear().appendf("Software/ThorCluster[@name=\"%s\"]", thorName);
- thors.append(*environment->getPropTree(xpath.str()));
- }
- }
- const char *roxieName = cluster->queryProp("RoxieCluster/@process");
- return new CEnvironmentClusterInfo(clustname, prefix, cluster->queryProp("@alias"), agent, thors, queryRoxieProcessTree(environment, roxieName));
- }
- IPropertyTree* getTopologyCluster(Owned<IPropertyTree> &envRoot, const char *clustname)
- {
- if (!clustname || !*clustname)
- return NULL;
- Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
- Owned<IConstEnvironment> env = factory->openEnvironment();
- if (!env)
- return NULL;
- envRoot.setown(&env->getPTree());
- StringBuffer xpath;
- xpath.appendf("Software/Topology/Cluster[@name=\"%s\"]", clustname);
- return envRoot->getPropTree(xpath.str());
- }
- bool validateTargetClusterName(const char *clustname)
- {
- Owned<IPropertyTree> envRoot;
- Owned<IPropertyTree> cluster = getTopologyCluster(envRoot, clustname);
- return (cluster.get()!=NULL);
- }
- IConstWUClusterInfo* getTargetClusterInfo(const char *clustname)
- {
- Owned<IPropertyTree> envRoot;
- Owned<IPropertyTree> cluster = getTopologyCluster(envRoot, clustname);
- if (!cluster)
- return NULL;
- return getTargetClusterInfo(envRoot, cluster);
- }
- unsigned getEnvironmentClusterInfo(CConstWUClusterInfoArray &clusters)
- {
- Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
- Owned<IConstEnvironment> env = factory->openEnvironment();
- if (!env)
- return 0;
- Owned<IPropertyTree> root = &env->getPTree();
- return getEnvironmentClusterInfo(root, clusters);
- }
- unsigned getEnvironmentClusterInfo(IPropertyTree* environmentRoot, CConstWUClusterInfoArray &clusters)
- {
- if (!environmentRoot)
- return 0;
- Owned<IPropertyTreeIterator> clusterIter = environmentRoot->getElements("Software/Topology/Cluster");
- ForEach(*clusterIter)
- {
- IPropertyTree &node = clusterIter->query();
- Owned<IConstWUClusterInfo> cluster = getTargetClusterInfo(environmentRoot, &node);
- clusters.append(*cluster.getClear());
- }
- return clusters.ordinality();
- }
- const char *getTargetClusterComponentName(const char *clustname, const char *processType, StringBuffer &name)
- {
- if (!clustname)
- return NULL;
- Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
- Owned<IConstEnvironment> env = factory->openEnvironment();
- if (!env)
- return NULL;
- Owned<IPropertyTree> root = &env->getPTree();
- StringBuffer xpath;
- xpath.appendf("Software/Topology/Cluster[@name=\"%s\"]", clustname);
- Owned<IPropertyTree> cluster = root->getPropTree(xpath.str());
- if (!cluster)
- return NULL;
- StringBuffer xpath1;
- xpath1.appendf("%s/@process", processType);
- name.append(cluster->queryProp(xpath1.str()));
- return name.str();
- }
- unsigned getEnvironmentThorClusterNames(StringArray &thorNames, StringArray &groupNames, StringArray &targetNames, StringArray &queueNames)
- {
- Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
- Owned<IConstEnvironment> env = factory->openEnvironment();
- if (!env)
- return 0;
- Owned<IPropertyTree> root = &env->getPTree();
- Owned<IPropertyTreeIterator> allTargets = root->getElements("Software/Topology/Cluster");
- ForEach(*allTargets)
- {
- IPropertyTree &target = allTargets->query();
- const char *targetName = target.queryProp("@name");
- if (targetName && *targetName)
- {
- Owned<IPropertyTreeIterator> thorClusters = target.getElements("ThorCluster");
- ForEach(*thorClusters)
- {
- const char *thorName = thorClusters->query().queryProp("@process");
- VStringBuffer query("Software/ThorCluster[@name=\"%s\"]",thorName);
- IPropertyTree *thorCluster = root->queryPropTree(query.str());
- if (thorCluster)
- {
- const char *groupName = thorCluster->queryProp("@nodeGroup");
- if (!groupName||!*groupName)
- groupName = thorName;
- thorNames.append(thorName);
- groupNames.append(groupName);
- targetNames.append(targetName);
- StringBuffer queueName(targetName);
- queueNames.append(queueName.append(THOR_QUEUE_EXT));
- }
- }
- }
- }
- return thorNames.ordinality();
- }
- unsigned getEnvironmentHThorClusterNames(StringArray &eclAgentNames, StringArray &groupNames, StringArray &targetNames)
- {
- Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
- Owned<IConstEnvironment> env = factory->openEnvironment();
- if (!env)
- return 0;
- Owned<IPropertyTree> root = &env->getPTree();
- Owned<IPropertyTreeIterator> allEclAgents = root->getElements("Software/EclAgentProcess");
- ForEach(*allEclAgents)
- {
- IPropertyTree &eclAgent = allEclAgents->query();
- const char *eclAgentName = eclAgent.queryProp("@name");
- if (eclAgentName && *eclAgentName)
- {
- Owned<IPropertyTreeIterator> allTargets = root->getElements("Software/Topology/Cluster");
- ForEach(*allTargets)
- {
- IPropertyTree &target = allTargets->query();
- const char *targetName = target.queryProp("@name");
- if (targetName && *targetName)
- {
- StringBuffer xpath;
- xpath.appendf("EclAgentProcess[@process=\"%s\"]", eclAgentName);
- if (target.hasProp(xpath) && !target.hasProp("ThorCluster"))
- {
- StringBuffer groupName("hthor__");
- groupName.append(eclAgentName);
- groupNames.append(groupName);
- eclAgentNames.append(eclAgentName);
- targetNames.append(targetName);
- }
- }
- }
- }
- }
- return eclAgentNames.ordinality();
- }
- IStringVal& CLocalWorkUnit::getScope(IStringVal &str) const
- {
- CriticalBlock block(crit);
- if (p->hasProp("Debug/ForceScope"))
- {
- StringBuffer prefix(p->queryProp("Debug/ForceScope"));
- str.set(prefix.toLowerCase().str());
- }
- else
- {
- Owned <IConstWUClusterInfo> ci = getTargetClusterInfo(p->queryProp("@clusterName"));
- if (ci)
- ci->getScope(str);
- else
- str.clear();
- }
- return str;
- }
- //Queries
- void CLocalWorkUnit::setCodeVersion(unsigned codeVersion, const char * buildVersion, const char * eclVersion)
- {
- CriticalBlock block(crit);
- p->setPropInt("@codeVersion", codeVersion);
- p->setProp("@buildVersion", buildVersion);
- p->setProp("@eclVersion", eclVersion);
- }
- unsigned CLocalWorkUnit::getCodeVersion() const
- {
- CriticalBlock block(crit);
- return p->getPropInt("@codeVersion");
- }
- unsigned CLocalWorkUnit::getWuidVersion() const
- {
- CriticalBlock block(crit);
- return p->getPropInt("@wuidVersion");
- }
- void CLocalWorkUnit::getBuildVersion(IStringVal & buildVersion, IStringVal & eclVersion) const
- {
- CriticalBlock block(crit);
- buildVersion.set(p->queryProp("@buildVersion"));
- eclVersion.set(p->queryProp("@eclVersion"));
- }
- void CLocalWorkUnit::setCloneable(bool value)
- {
- CriticalBlock block(crit);
- p->setPropInt("@cloneable", value);
- }
- void CLocalWorkUnit::setIsClone(bool value)
- {
- CriticalBlock block(crit);
- p->setPropInt("@isClone", value);
- }
- bool CLocalWorkUnit::getCloneable() const
- {
- CriticalBlock block(crit);
- return p->getPropBool("@cloneable", false);
- }
- IUserDescriptor *CLocalWorkUnit::queryUserDescriptor() const
- {
- CriticalBlock block(crit);
- if (!userDesc)
- {
- SCMStringBuffer token, user, password;
- getSecurityToken(token);
- extractToken(token.str(), queryWuid(), user, password);
- userDesc.setown(createUserDescriptor());
- userDesc->set(user.str(), password.str());
- }
- return userDesc;
- }
- bool CLocalWorkUnit::isProtected() const
- {
- CriticalBlock block(crit);
- return p->getPropBool("@protected", false);
- }
- bool CLocalWorkUnit::isPausing() const
- {
- CriticalBlock block(crit);
- if (WUActionPause == getAction())
- {
- switch (getState())
- {
- case WUStateRunning:
- case WUStateAborting:
- return true;
- }
- }
- return false;
- }
- void CLocalWorkUnit::protect(bool protectMode)
- {
- CriticalBlock block(crit);
- p->setPropBool("@protected", protectMode);
- }
- void CLocalWorkUnit::setResultLimit(unsigned value)
- {
- CriticalBlock block(crit);
- p->setPropInt("resultLimit", value);
- }
- unsigned CLocalWorkUnit::getResultLimit() const
- {
- CriticalBlock block(crit);
- return p->getPropInt("resultLimit");
- }
- IStringVal & CLocalWorkUnit::getSnapshot(IStringVal & str) const
- {
- CriticalBlock block(crit);
- str.set(p->queryProp("SNAPSHOT"));
- return str;
- }
- void CLocalWorkUnit::setSnapshot(const char * val)
- {
- CriticalBlock block(crit);
- p->setProp("SNAPSHOT", val);
- }
- const static mapEnums warningSeverityMap[] =
- {
- { SeverityInformation, "info" },
- { SeverityWarning, "warning" },
- { SeverityError, "error" },
- { SeverityAlert, "alert" },
- { SeverityIgnore, "ignore" },
- { SeverityFatal, "fatal" },
- { SeverityUnknown, NULL }
- };
- ErrorSeverity CLocalWorkUnit::getWarningSeverity(unsigned code, ErrorSeverity defaultSeverity) const
- {
- StringBuffer xpath;
- xpath.append("OnWarnings/OnWarning[@code='").append(code).append("']");
- CriticalBlock block(crit);
- IPropertyTree * mapping = p->queryPropTree(xpath);
- if (mapping)
- return (ErrorSeverity) getEnum(mapping, "@severity", warningSeverityMap);
- return defaultSeverity;
- }
- void CLocalWorkUnit::setWarningSeverity(unsigned code, ErrorSeverity severity)
- {
- StringBuffer xpath;
- xpath.append("OnWarnings/OnWarning[@code='").append(code).append("']");
- CriticalBlock block(crit);
- IPropertyTree * mapping = p->queryPropTree(xpath);
- if (!mapping)
- {
- IPropertyTree * onWarnings = ensurePTree(p, "OnWarnings");
- mapping = onWarnings->addPropTree("OnWarning", createPTree());
- mapping->setPropInt("@code", code);
- }
- setEnum(mapping, "@severity", severity, warningSeverityMap);
- }
- static int comparePropTrees(IInterface * const *ll, IInterface * const *rr)
- {
- IPropertyTree *l = (IPropertyTree *) *ll;
- IPropertyTree *r = (IPropertyTree *) *rr;
- return stricmp(l->queryName(), r->queryName());
- };
- unsigned CLocalWorkUnit::calculateHash(unsigned crc)
- {
- // Any other values in the WU that could affect generated code should be crc'ed here
- IPropertyTree *tree = p->queryBranch("Debug");
- if (tree)
- {
- Owned<IPropertyTreeIterator> sub = tree->getElements("*");
- ICopyArrayOf<IPropertyTree> subs;
- for(sub->first(); sub->isValid(); sub->next())
- subs.append(sub->query());
- subs.sort(comparePropTrees);
- ForEachItemIn(idx, subs)
- {
- const char *name = subs.item(idx).queryName();
- const char *val = subs.item(idx).queryProp(NULL);
- crc = crc32(name, (size32_t)strlen(name), crc);
- if (val)
- crc = crc32(val, (size32_t)strlen(val), crc);
- }
- }
- Owned<IConstWUPluginIterator> plugins = &getPlugins();
- for (plugins->first();plugins->isValid();plugins->next())
- {
- IConstWUPlugin &thisplugin = plugins->query();
- SCMStringBuffer version;
- thisplugin.getPluginVersion(version);
- crc = crc32(version.str(), version.length(), crc);
- }
- return crc;
- }
- static void updateProp(IPropertyTree * to, const IPropertyTree * from, const char * xpath)
- {
- if (!to->hasProp(xpath) && from->hasProp(xpath))
- to->setProp(xpath, from->queryProp(xpath));
- }
- static void setProp(IPropertyTree * to, const IPropertyTree * from, const char * xpath)
- {
- if (from->hasProp(xpath))
- to->setProp(xpath, from->queryProp(xpath));
- }
- static void copyTree(IPropertyTree * to, const IPropertyTree * from, const char * xpath)
- {
- IPropertyTree * match = from->getBranch(xpath);
- if (match)
- to->setPropTree(xpath, match);
- }
- IPropertyTree *CLocalWorkUnit::queryPTree() const
- {
- return p;
- }
- void CLocalWorkUnit::copyWorkUnit(IConstWorkUnit *cached, bool all)
- {
- CLocalWorkUnit *from = QUERYINTERFACE(cached, CLocalWorkUnit);
- if (!from)
- {
- CLockedWorkUnit *fl = QUERYINTERFACE(cached, CLockedWorkUnit);
- if (!fl)
- throw MakeStringException(WUERR_InternalUnknownImplementation, "Cached workunit not created using workunit dll");
- from = fl->c;
- }
- // Need to copy the query, the results, and the graphs from the cached query.
- // The cache is made before the query is executed so there is no need to clear them.
- if (!cached->getCloneable())
- throw MakeStringException(WUERR_CannotCloneWorkunit, "Source work unit not marked as clonable");
- const IPropertyTree * fromP = from->p;
- IPropertyTree *pt;
- CriticalBlock block(crit);
- clearCached(false);
- query.clear();
- updateProp(p, fromP, "@jobName");
- copyTree(p, fromP, "Query");
- pt = fromP->getBranch("Application/LibraryModule");
- if (pt)
- {
- ensurePTree(p, "Application");
- p->setPropTree("Application/LibraryModule", pt);
- }
- pt = fromP->queryBranch("Debug");
- if (pt)
- {
- IPropertyTree *curDebug = p->queryPropTree("Debug");
- if (curDebug)
- {
- Owned<IPropertyTreeIterator> elems = pt->getElements("*");
- ForEach(*elems)
- {
- IPropertyTree *elem = &elems->query();
- if (!curDebug->hasProp(elem->queryName()))
- curDebug->setPropTree(elem->queryName(),LINK(elem));
- }
- }
- else
- p->setPropTree("Debug", LINK(pt));
- }
- copyTree(p, fromP, "OnWarnings");
- copyTree(p, fromP, "Plugins");
- copyTree(p, fromP, "Libraries");
- copyTree(p, fromP, "Results");
- copyTree(p, fromP, "Graphs");
- copyTree(p, fromP, "Workflow");
- copyTree(p, fromP, "WebServicesInfo");
- if (all)
- {
- // 'all' mode is used when setting up a dali WU from the embedded wu in a workunit dll
- // Merge timing info from both branches
- pt = fromP->getBranch("Timings");
- if (pt)
- {
- IPropertyTree *tgtTimings = ensurePTree(p, "Timings");
- mergePTree(tgtTimings, pt);
- pt->Release();
- }
- pt = fromP->getBranch("Statistics");
- if (pt)
- {
- IPropertyTree *tgtStatistics = ensurePTree(p, "Statistics");
- mergePTree(tgtStatistics, pt);
- pt->Release();
- }
- }
- updateProp(p, fromP, "@clusterName");
- updateProp(p, fromP, "allowedclusters");
- updateProp(p, fromP, "@submitID");
- updateProp(p, fromP, "SNAPSHOT");
- setProp(p, fromP, "@eventScheduledCount");
- //MORE: This is very adhoc. All options that should be cloned should really be in a common branch
- if (all)
- {
- setProp(p, fromP, "PriorityFlag");
- setProp(p, fromP, "@priorityClass");
- setProp(p, fromP, "@protected");
- setProp(p, fromP, "@clusterName");
- updateProp(p, fromP, "@scope");
- }
- //Variables may have been set up as parameters to the query - so need to preserve any values that were supplied.
- pt = fromP->getBranch("Variables");
- if (pt)
- {
- IPropertyTree *ptTgtVariables = ensurePTree(p, "Variables");
- Owned<IPropertyTreeIterator> ptiVariable = pt->getElements("Variable");
- for (ptiVariable->first(); ptiVariable->isValid(); ptiVariable->next())
- {
- IPropertyTree *ptSrcVariable = &ptiVariable->query();
- const char *name = ptSrcVariable->queryProp("@name");
- assertex(name);
- StringBuffer xpath;
- xpath.append("Variable[@name='").append(name).append("']");
- IPropertyTree *ptTgtVariable = ptTgtVariables->queryPropTree(xpath.str());
- IPropertyTree *merged = createPTreeFromIPT(ptSrcVariable); // clone entire source info...
- merged->removeProp("Value"); // except value and status
- merged->setProp("@status", "undefined");
- if (!merged->getPropBool("@isScalar"))
- merged->removeProp("totalRowCount");
- merged->removeProp("rowCount");
- // If there are any other fields that get set ONLY by eclagent, strip them out here...
- if (ptTgtVariable)
- {
- // copy status and Value from what is already set in target
- merged->setProp("@status", ptTgtVariable->queryProp("@status"));
- MemoryBuffer value;
- if (ptTgtVariable->getPropBin("Value", value))
- merged->setPropBin("Value", value.length(), value.toByteArray());
- ptTgtVariable->removeProp(xpath.str());
- // If there are any other fields in a variable that get set by ws_ecl before submitting, copy them across here...
- }
- ptTgtVariables->addPropTree("Variable", merged);
- }
- pt->Release();
- }
- p->setProp("@codeVersion", fromP->queryProp("@codeVersion"));
- p->setProp("@buildVersion", fromP->queryProp("@buildVersion"));
- p->setProp("@eclVersion", fromP->queryProp("@eclVersion"));
- p->setProp("@hash", fromP->queryProp("@hash"));
- p->setPropBool("@cloneable", true);
- p->setPropBool("@isClone", true);
- resetWorkflow(); // the source Workflow section may have had some parts already executed...
- Owned<IPropertyTreeIterator> results = p->getElements("Results/Result");
- ForEach(*results)
- {
- CLocalWUResult result(LINK(&results->query()));
- result.setResultStatus(ResultStatusUndefined);
- }
- copyTree(p, fromP, "usedsources"); // field usage
- }
- bool CLocalWorkUnit::hasDebugValue(const char *propname) const
- {
- StringBuffer lower;
- lower.append(propname).toLowerCase();
- CriticalBlock block(crit);
- StringBuffer prop("Debug/");
- return p->hasProp(prop.append(lower));
- }
- IStringVal& CLocalWorkUnit::getDebugValue(const char *propname, IStringVal &str) const
- {
- StringBuffer lower;
- lower.append(propname).toLowerCase();
- CriticalBlock block(crit);
- StringBuffer prop("Debug/");
- str.set(p->queryProp(prop.append(lower).str()));
- return str;
- }
- IStringIterator& CLocalWorkUnit::getDebugValues() const
- {
- return getDebugValues(NULL);
- }
- IStringIterator& CLocalWorkUnit::getDebugValues(const char *prop) const
- {
- CriticalBlock block(crit);
- StringBuffer path("Debug/");
- if (prop)
- {
- StringBuffer lower;
- lower.append(prop).toLowerCase();
- path.append(lower);
- }
- else
- path.append("*");
- return *new CStringPTreeTagIterator(p->getElements(path.str()));
- }
- int CLocalWorkUnit::getDebugValueInt(const char *propname, int defVal) const
- {
- StringBuffer lower;
- lower.append(propname).toLowerCase();
- CriticalBlock block(crit);
- StringBuffer prop("Debug/");
- prop.append(lower);
- return p->getPropInt(prop.str(), defVal);
- }
- __int64 CLocalWorkUnit::getDebugValueInt64(const char *propname, __int64 defVal) const
- {
- StringBuffer lower;
- lower.append(propname).toLowerCase();
- CriticalBlock block(crit);
- StringBuffer prop("Debug/");
- prop.append(lower);
- return p->getPropInt64(prop.str(), defVal);
- }
- bool CLocalWorkUnit::getDebugValueBool(const char * propname, bool defVal) const
- {
- StringBuffer lower;
- lower.append(propname).toLowerCase();
- CriticalBlock block(crit);
- StringBuffer prop("Debug/");
- prop.append(lower);
- return p->getPropBool(prop.str(), defVal);
- }
- IStringIterator *CLocalWorkUnit::getLogs(const char *type, const char *instance) const
- {
- VStringBuffer xpath("Process/%s/", type);
- if (instance)
- xpath.append(instance);
- else
- xpath.append("*");
- CriticalBlock block(crit);
- if (p->getPropInt("@wuidVersion") < 1) // legacy wuid
- {
- // NB: instance unused
- if (streq("EclAgent", type))
- return new CStringPTreeIterator(p->getElements("Debug/eclagentlog"));
- else if (streq("Thor", type))
- return new CStringPTreeIterator(p->getElements("Debug/thorlog*"));
- VStringBuffer xpath("Debug/%s", type);
- return new CStringPTreeIterator(p->getElements(xpath.str()));
- }
- else
- return new CStringPTreeAttrIterator(p->getElements(xpath.str()), "@log");
- }
- IPropertyTreeIterator* CLocalWorkUnit::getProcesses(const char *type, const char *instance) const
- {
- VStringBuffer xpath("Process/%s/", type);
- if (instance)
- xpath.append(instance);
- else
- xpath.append("*");
- CriticalBlock block(crit);
- return p->getElements(xpath.str());
- }
- IStringIterator *CLocalWorkUnit::getProcesses(const char *type) const
- {
- VStringBuffer xpath("Process/%s/*", type);
- CriticalBlock block(crit);
- return new CStringPTreeTagIterator(p->getElements(xpath.str()));
- }
- void CLocalWorkUnit::addProcess(const char *type, const char *instance, unsigned pid, const char *log)
- {
- VStringBuffer processType("Process/%s", type);
- VStringBuffer xpath("%s/%s", processType.str(), instance);
- if (log)
- xpath.appendf("[@log=\"%s\"]", log);
- CriticalBlock block(crit);
- if (!p->hasProp(xpath))
- {
- IPropertyTree *node = ensurePTree(p, processType.str());
- node = node->addPropTree(instance, createPTree());
- node->setProp("@log", log);
- node->setPropInt("@pid", pid);
- }
- }
- void CLocalWorkUnit::setDebugValue(const char *propname, const char *value, bool overwrite)
- {
- StringBuffer lower;
- lower.append(propname).toLowerCase();
- CriticalBlock block(crit);
- StringBuffer prop("Debug/");
- prop.append(lower);
- if (overwrite || !p->hasProp(prop.str()))
- {
- // MORE - not sure this line should be needed....
- p->setProp("Debug", "");
- p->setProp(prop.str(), value);
- }
- }
- void CLocalWorkUnit::setDebugValueInt(const char *propname, int value, bool overwrite)
- {
- StringBuffer lower;
- lower.append(propname).toLowerCase();
- CriticalBlock block(crit);
- StringBuffer prop("Debug/");
- prop.append(lower);
- if (overwrite || !p->hasProp(prop.str()))
- {
- // MORE - not sure this line should be needed....
- p->setProp("Debug", "");
- p->setPropInt(prop.str(), value);
- }
- }
- void CLocalWorkUnit::setTracingValue(const char *propname, const char *value)
- {
- CriticalBlock block(crit);
- // MORE - not sure this line should be needed....
- p->setProp("Tracing", "");
- StringBuffer prop("Tracing/");
- p->setProp(prop.append(propname).str(), value);
- }
- void CLocalWorkUnit::setTracingValueInt(const char *propname, int value)
- {
- CriticalBlock block(crit);
- StringBuffer prop("Tracing/");
- p->setPropInt(prop.append(propname).str(), value);
- }
- void CLocalWorkUnit::setTracingValueInt64(const char *propname, __int64 value)
- {
- CriticalBlock block(crit);
- VStringBuffer prop("Tracing/%s", propname);
- p->setPropInt64(prop.str(), value);
- }
- IConstWUQuery* CLocalWorkUnit::getQuery() const
- {
- // For this to be legally called, we must have the read-able interface. So we are already locked for (at least) read.
- CriticalBlock block(crit);
- if (!query)
- {
- IPropertyTree *s = p->getPropTree("Query");
- if (s)
- query.setown(new CLocalWUQuery(s)); // NB takes ownership of 's'
- }
- return query.getLink();
- }
- IWUQuery* CLocalWorkUnit::updateQuery()
- {
- // For this to be legally called, we must have the write-able interface. So we are already locked for write.
- CriticalBlock block(crit);
- if (!query)
- {
- IPropertyTree *s = p->queryPropTree("Query");
- if (!s)
- s = p->addPropTree("Query", createPTreeFromXMLString("<Query fetchEntire='1'/>")); // Is this really desirable (the fetchEntire) ?
- s->Link();
- query.setown(new CLocalWUQuery(s));
- }
- return query.getLink();
- }
- void CLocalWorkUnit::loadPlugins() const
- {
- CriticalBlock block(crit);
- if (!pluginsCached)
- {
- assertex(plugins.length() == 0);
- Owned<IPropertyTreeIterator> r = p->getElements("Plugins/Plugin");
- for (r->first(); r->isValid(); r->next())
- {
- IPropertyTree *rp = &r->query();
- rp->Link();
- plugins.append(*new CLocalWUPlugin(rp));
- }
- pluginsCached = true;
- }
- }
- IConstWUPluginIterator& CLocalWorkUnit::getPlugins() const
- {
- CriticalBlock block(crit);
- loadPlugins();
- return *new CArrayIteratorOf<IConstWUPlugin,IConstWUPluginIterator> (plugins, 0, (IConstWorkUnit *) this);
- }
- void CLocalWorkUnit::loadLibraries() const
- {
- CriticalBlock block(crit);
- if (!librariesCached)
- {
- assertex(libraries.length() == 0);
- Owned<IPropertyTreeIterator> r = p->getElements("Libraries/Library");
- ForEach(*r)
- {
- IPropertyTree *rp = &r->query();
- rp->Link();
- libraries.append(*new CLocalWULibrary(rp));
- }
- librariesCached = true;
- }
- }
- IConstWULibraryIterator& CLocalWorkUnit::getLibraries() const
- {
- CriticalBlock block(crit);
- loadLibraries();
- return *new CArrayIteratorOf<IConstWULibrary,IConstWULibraryIterator> (libraries, 0, (IConstWorkUnit *) this);
- }
- IConstWULibrary * CLocalWorkUnit::getLibraryByName(const char * search) const
- {
- CriticalBlock block(crit);
- loadLibraries();
- ForEachItemIn(idx, libraries)
- {
- SCMStringBuffer name;
- IConstWULibrary &cur = libraries.item(idx);
- cur.getName(name);
- if (stricmp(name.str(), search)==0)
- return &OLINK(cur);
- }
- return NULL;
- }
- StringBuffer &formatGraphTimerLabel(StringBuffer &str, const char *graphName, unsigned subGraphNum, unsigned __int64 subId)
- {
- str.append("Graph ").append(graphName);
- if (subGraphNum) str.append(" - ").append(subGraphNum).append(" (").append(subId).append(")");
- else if (subId) str.append(" - id(").append(subId).append(")");
- return str;
- }
- StringBuffer &formatGraphTimerScope(StringBuffer &str, const char *graphName, unsigned subGraphNum, unsigned __int64 subId)
- {
- str.append(graphName);
- if (subId) str.append(":sg").append(subId);
- return str;
- }
- bool parseGraphTimerLabel(const char *label, StringAttr &graphName, unsigned & graphNum, unsigned &subGraphNum, unsigned &subId)
- {
- // expects format: "Graph <graphname>[ - <subgraphnum> (<subgraphid>)]"
- unsigned len = (size32_t)strlen(label);
- if (len < 6 || (0 != memcmp(label, "Graph ", 6)))
- return false;
- graphNum = 0;
- subGraphNum = 0;
- subId = 0;
- const char *finger = label+6;
- const char *finger2 = strchr(finger, '-');
- if (NULL == finger2) // just graphName
- graphName.set(finger);
- else
- {
- graphName.set(finger, (size32_t)((finger2-1)-finger));
- finger = finger2+2; // skip '-' and space
- finger2 = strchr(finger, ' ');
- if (finger2)
- {
- subGraphNum = atoi_l(finger, (size32_t)(finger2-finger));
- finger = finger2+2; // skip space and '('
- finger2 = strchr(finger, ')');
- if (finger2)
- subId = atoi_l(finger, (size32_t)(finger2-finger));
- }
- else if (((len-(finger-label))>3) && 0 == memcmp(finger, "id(", 3)) // subgraph id only, new format.
- {
- finger += 3;
- finger2 = strchr(finger, ')');
- if (finger2)
- subId = atoi_l(finger, (size32_t)(finger2-finger));
- }
- }
- if (graphName && !memicmp(graphName, "graph", 5))
- graphNum = atoi(graphName + 5);
- return true;
- }
- bool parseGraphScope(const char *scope, StringAttr &graphName, unsigned & graphNum, unsigned &subGraphId)
- {
- if (!MATCHES_CONST_PREFIX(scope, GraphScopePrefix))
- return false;
- graphNum = atoi(scope + CONST_STRLEN(GraphScopePrefix));
- subGraphId = 0;
- const char * colon = strchr(scope, ':');
- if (!colon)
- {
- graphName.set(scope);
- return true;
- }
- const char * subgraph = colon+1;
- graphName.set(scope, (size32_t)(colon - scope));
- if (MATCHES_CONST_PREFIX(subgraph, SubGraphScopePrefix))
- subGraphId = atoi(subgraph+CONST_STRLEN(SubGraphScopePrefix));
- return true;
- }
- class WorkUnitStatisticsIterator : public CArrayIteratorOf<IConstWUStatistic,IConstWUStatisticIterator>
- {
- typedef CArrayIteratorOf<IConstWUStatistic,IConstWUStatisticIterator> PARENT;
- public:
- WorkUnitStatisticsIterator(const IArray &a, aindex_t start, IInterface *owner, const IStatisticsFilter * _filter)
- : PARENT(a,start, owner), filter(_filter)
- {
- }
- virtual bool first()
- {
- if (!PARENT::first())
- return false;
- if (matchesFilter())
- return true;
- return next();
- }
- virtual bool next()
- {
- loop
- {
- if (!PARENT::next())
- return false;
- if (matchesFilter())
- return true;
- }
- }
- protected:
- bool matchesFilter()
- {
- if (!filter)
- return true;
- return query().matches(filter);
- }
- protected:
- Linked<const IStatisticsFilter> filter;
- };
- 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)
- {
- if (!scope || !*scope) scope = GLOBAL_SCOPE;
- const char * kindName = queryStatisticName(kind);
- StatisticMeasure measure = queryMeasure(kind);
- //creator. scope and name must all be present, and must not contain semi colons.
- assertex(creator && scope);
- CriticalBlock block(crit);
- IPropertyTree * stats = p->queryPropTree("Statistics");
- if (!stats)
- stats = p->addPropTree("Statistics", createPTree("Statistics"));
- IPropertyTree * statTree = NULL;
- if (mergeAction != StatsMergeAppend)
- {
- StringBuffer xpath;
- xpath.append("Statistic[@creator='").append(creator).append("'][@scope='").append(scope).append("'][@kind='").append(kindName).append("']");
- statTree = stats->queryPropTree(xpath.str());
- }
- if (!statTree)
- {
- statTree = stats->addPropTree("Statistic", createPTree("Statistic"));
- statTree->setProp("@creator", creator);
- statTree->setProp("@scope", scope);
- statTree->setProp("@kind", kindName);
- //These items are primarily here to facilitate filtering.
- statTree->setProp("@unit", queryMeasureName(measure));
- statTree->setProp("@c", queryCreatorTypeName(creatorType));
- statTree->setProp("@s", queryScopeTypeName(scopeType));
- statTree->setPropInt64("@ts", getTimeStampNowValue());
- if (optDescription)
- statTree->setProp("@desc", optDescription);
- if (statistics.cached)
- statistics.append(LINK(statTree));
- mergeAction = StatsMergeAppend;
- }
- if (mergeAction != StatsMergeAppend) // RKC->GH Is this right??
- {
- unsigned __int64 oldValue = statTree->getPropInt64("@value", 0);
- unsigned __int64 oldCount = statTree->getPropInt64("@count", 0);
- unsigned __int64 oldMax = statTree->getPropInt64("@max", 0);
- if (oldMax < oldValue)
- oldMax = oldValue;
- statTree->setPropInt64("@value", mergeStatisticValue(oldValue, value, mergeAction));
- statTree->setPropInt64("@count", count + oldCount);
- if (maxValue > oldMax)
- statTree->setPropInt64("@max", maxValue);
- }
- else
- {
- statTree->setPropInt64("@value", value);
- statTree->setPropInt64("@count", count);
- if (maxValue)
- statTree->setPropInt64("@max", maxValue);
- else
- statTree->removeProp("@max");
- }
- if (creatorType==SCTsummary && kind==StTimeElapsed && strsame(scope, GLOBAL_SCOPE))
- {
- StringBuffer t;
- formatTimeCollatable(t, value, false);
- p->setProp("@totalThorTime", t);
- }
- }
- void CLocalWorkUnit::_loadStatistics() const
- {
- statistics.load(p,"Statistics/*");
- }
- IConstWUStatisticIterator& CLocalWorkUnit::getStatistics(const IStatisticsFilter * filter) const
- {
- CriticalBlock block(crit);
- //This should be deleted in version 6.0 when support for 4.x is no longer required
- legacyTimings.load(p,"Timings/*");
- if (legacyTimings.ordinality())
- return *new WorkUnitStatisticsIterator(legacyTimings, 0, (IConstWorkUnit *) this, filter);
- statistics.load(p,"Statistics/*");
- Owned<IConstWUStatisticIterator> localStats = new WorkUnitStatisticsIterator(statistics, 0, (IConstWorkUnit *) this, filter);
- const char * wuid = p->queryName();
- Owned<IConstWUStatisticIterator> graphStats = new CConstGraphProgressStatisticsIterator(wuid, filter);
- return * new CCompoundIteratorOf<IConstWUStatisticIterator, IConstWUStatistic>(localStats, graphStats);
- }
- IConstWUStatistic * CLocalWorkUnit::getStatistic(const char * creator, const char * scope, StatisticKind kind) const
- {
- //MORE: Optimize this....
- StatisticsFilter filter;
- filter.setCreator(creator);
- filter.setScope(scope);
- filter.setKind(kind);
- Owned<IConstWUStatisticIterator> stats = &getStatistics(&filter);
- if (stats->first())
- return LINK(&stats->query());
- return NULL;
- }
- IWUPlugin* CLocalWorkUnit::updatePluginByName(const char *qname)
- {
- CriticalBlock block(crit);
- IConstWUPlugin *existing = getPluginByName(qname);
- if (existing)
- return (IWUPlugin *) existing;
- if (!plugins.length())
- p->addPropTree("Plugins", createPTree("Plugins"));
- IPropertyTree *pl = p->queryPropTree("Plugins");
- IPropertyTree *s = pl->addPropTree("Plugin", createPTree("Plugin"));
- s->Link();
- IWUPlugin* q = new CLocalWUPlugin(s);
- q->Link();
- plugins.append(*q);
- q->setPluginName(qname);
- return q;
- }
- IConstWUPlugin* CLocalWorkUnit::getPluginByName(const char *qname) const
- {
- CriticalBlock block(crit);
- loadPlugins();
- ForEachItemIn(idx, plugins)
- {
- SCMStringBuffer name;
- IConstWUPlugin &cur = plugins.item(idx);
- cur.getPluginName(name);
- if (stricmp(name.str(), qname)==0)
- {
- cur.Link();
- return &cur;
- }
- }
- return NULL;
- }
- IWULibrary* CLocalWorkUnit::updateLibraryByName(const char *qname)
- {
- CriticalBlock block(crit);
- IConstWULibrary *existing = getLibraryByName(qname);
- if (existing)
- return (IWULibrary *) existing;
- if (!libraries.length())
- p->addPropTree("Libraries", createPTree("Libraries"));
- IPropertyTree *pl = p->queryPropTree("Libraries");
- IPropertyTree *s = pl->addPropTree("Library", createPTree("Library"));
- s->Link();
- IWULibrary* q = new CLocalWULibrary(s);
- q->Link();
- libraries.append(*q);
- q->setName(qname);
- return q;
- }
- void CLocalWorkUnit::_loadExceptions() const
- {
- assertex(exceptions.length() == 0);
- Owned<IPropertyTreeIterator> r = p->getElements("Exceptions/Exception");
- for (r->first(); r->isValid(); r->next())
- {
- IPropertyTree *rp = &r->query();
- rp->Link();
- exceptions.append(*new CLocalWUException(rp));
- }
- }
- void CLocalWorkUnit::loadExceptions() const
- {
- CriticalBlock block(crit);
- if (!exceptionsCached)
- {
- _loadExceptions();
- exceptionsCached = true;
- }
- }
- IConstWUExceptionIterator& CLocalWorkUnit::getExceptions() const
- {
- CriticalBlock block(crit);
- loadExceptions();
- return *new CArrayIteratorOf<IConstWUException,IConstWUExceptionIterator> (exceptions, 0, (IConstWorkUnit *) this);
- }
- unsigned CLocalWorkUnit::getExceptionCount() const
- {
- CriticalBlock block(crit);
- loadExceptions();
- return exceptions.length();
- }
- void CLocalWorkUnit::clearExceptions()
- {
- CriticalBlock block(crit);
- // For this to be legally called, we must have the write-able interface. So we are already locked for write.
- exceptions.kill();
- exceptionsCached = true;
- p->removeProp("Exceptions");
- }
- IWUException* CLocalWorkUnit::createException()
- {
- CriticalBlock block(crit);
- // For this to be legally called, we must have the write-able interface. So we are already locked for write.
- loadExceptions();
- if (!exceptions.length())
- p->addPropTree("Exceptions", createPTree("Exceptions"));
- IPropertyTree *r = p->queryPropTree("Exceptions");
- IPropertyTree *s = r->addPropTree("Exception", createPTree("Exception"));
- s->setPropInt("@sequence", exceptions.ordinality());
- IWUException* q = new CLocalWUException(LINK(s));
- exceptions.append(*LINK(q));
- Owned<IJlibDateTime> now = createDateTimeNow();
- SCMStringBuffer temp;
- now->getString(temp);
- q->setTimeStamp(temp.str());
- return q;
- }
- IConstWUWebServicesInfo* CLocalWorkUnit::getWebServicesInfo() const
- {
- // For this to be legally called, we must have the read-able interface. So we are already locked for (at least) read.
- CriticalBlock block(crit);
- if (!webServicesInfoCached)
- {
- assertex(!webServicesInfo);
- IPropertyTree *s = p->getPropTree("WebServicesInfo");
- if (s)
- webServicesInfo.setown(new CLocalWUWebServicesInfo(s)); // NB takes ownership of 's'
- webServicesInfoCached = true;
- }
- return webServicesInfo.getLink();
- }
- IWUWebServicesInfo* CLocalWorkUnit::updateWebServicesInfo(bool create)
- {
- // For this to be legally called, we must have the write-able interface. So we are already locked for write.
- CriticalBlock block(crit);
- if (!webServicesInfoCached)
- {
- IPropertyTree *s = p->queryPropTree("WebServicesInfo");
- if (!s)
- {
- if (create)
- s = p->addPropTree("WebServicesInfo", createPTreeFromXMLString("<WebServicesInfo />"));
- else
- return NULL;
- }
- s->Link();
- webServicesInfo.setown(new CLocalWUWebServicesInfo(s));
- webServicesInfoCached = true;
- }
- return webServicesInfo.getLink();
- }
- static int compareResults(IInterface * const *ll, IInterface * const *rr)
- {
- CLocalWUResult *l = (CLocalWUResult *) *ll;
- CLocalWUResult *r = (CLocalWUResult *) *rr;
- return l->getResultSequence() - r->getResultSequence();
- }
- void CLocalWorkUnit::_loadResults() const
- {
- Owned<IPropertyTreeIterator> r = p->getElements("Results/Result");
- for (r->first(); r->isValid(); r->next())
- {
- IPropertyTree *rp = &r->query();
- rp->Link();
- results.append(*new CLocalWUResult(rp));
- }
- }
- void CLocalWorkUnit::loadResults() const
- {
- if (!resultsCached)
- {
- assertex(results.length() == 0);
- _loadResults();
- results.sort(compareResults);
- resultsCached = true;
- }
- }
- void CLocalWorkUnit::_loadVariables() const
- {
- Owned<IPropertyTreeIterator> r = p->getElements("Variables/Variable");
- for (r->first(); r->isValid(); r->next())
- {
- IPropertyTree *rp = &r->query();
- rp->Link();
- variables.append(*new CLocalWUResult(rp));
- }
- }
- void CLocalWorkUnit::loadVariables() const
- {
- if (!variablesCached)
- {
- assertex(variables.length() == 0);
- _loadVariables();
- variablesCached = true;
- }
- }
- void CLocalWorkUnit::_loadTemporaries() const
- {
- Owned<IPropertyTreeIterator> r = p->getElements("Temporaries/Variable");
- for (r->first(); r->isValid(); r->next())
- {
- IPropertyTree *rp = &r->query();
- rp->Link();
- temporaries.append(*new CLocalWUResult(rp));
- }
- }
- void CLocalWorkUnit::loadTemporaries() const
- {
- if (!temporariesCached)
- {
- assertex(temporaries.length() == 0);
- _loadTemporaries();
- temporariesCached = true;
- }
- }
- void CLocalWorkUnit::deleteTemporaries()
- {
- CriticalBlock block(crit);
- if (temporariesCached)
- {
- temporaries.kill();
- temporariesCached = false;
- }
- p->removeProp("Temporaries");
- }
- IWUResult* CLocalWorkUnit::createResult()
- {
- CriticalBlock block(crit);
- // For this to be legally called, we must have the write-able interface. So we are already locked for write.
- loadResults();
- if (!results.length())
- p->addPropTree("Results", createPTree("Results"));
- IPropertyTree *r = p->queryPropTree("Results");
- IPropertyTree *s = r->addPropTree("Result", createPTree());
- s->Link();
- IWUResult* q = new CLocalWUResult(s);
- q->Link();
- results.append(*q);
- return q;
- }
- IWUResult* CLocalWorkUnit::updateResultByName(const char *qname)
- {
- CriticalBlock block(crit);
- IConstWUResult *existing = getResultByName(qname);
- if (existing)
- return (IWUResult *) existing;
- IWUResult* q = createResult();
- q->setResultName(qname);
- return q;
- }
- IWUResult* CLocalWorkUnit::updateResultBySequence(unsigned seq)
- {
- CriticalBlock block(crit);
- IConstWUResult *existing = getResultBySequence(seq);
- if (existing)
- return (IWUResult *) existing;
- IWUResult* q = createResult();
- q->setResultSequence(seq);
- return q;
- }
- IConstWUResultIterator& CLocalWorkUnit::getResults() const
- {
- CriticalBlock block(crit);
- loadResults();
- return *new CArrayIteratorOf<IConstWUResult,IConstWUResultIterator> (results, 0, (IConstWorkUnit *) this);
- }
- IConstWUResult* CLocalWorkUnit::getResultByName(const char *qname) const
- {
- CriticalBlock block(crit);
- loadResults();
- ForEachItemIn(idx, results)
- {
- SCMStringBuffer name;
- IConstWUResult &cur = results.item(idx);
- cur.getResultName(name);
- if (stricmp(name.str(), qname)==0)
- {
- cur.Link();
- return &cur;
- }
- }
- return NULL;
- }
- IConstWUResult* CLocalWorkUnit::getResultBySequence(unsigned seq) const
- {
- CriticalBlock block(crit);
- loadResults();
- ForEachItemIn(idx, results)
- {
- IConstWUResult &cur = results.item(idx);
- if (cur.getResultSequence() == seq)
- {
- cur.Link();
- return &cur;
- }
- }
- return NULL;
- }
- IConstWUResultIterator& CLocalWorkUnit::getVariables() const
- {
- CriticalBlock block(crit);
- loadVariables();
- return *new CArrayIteratorOf<IConstWUResult,IConstWUResultIterator> (variables, 0, (IConstWorkUnit *) this);
- }
- IConstWUResult* CLocalWorkUnit::getGlobalByName(const char *qname) const
- {
- CriticalBlock block(crit);
- if (strcmp(p->queryName(), GLOBAL_WORKUNIT)==0)
- return getVariableByName(qname);
- Owned <IWorkUnit> global = factory->getGlobalWorkUnit(secMgr, secUser);
- return global->getVariableByName(qname);
- }
- IWUResult* CLocalWorkUnit::updateGlobalByName(const char *qname)
- {
- CriticalBlock block(crit);
- if (strcmp(p->queryName(), GLOBAL_WORKUNIT)==0)
- return updateVariableByName(qname);
- Owned <IWorkUnit> global = factory->getGlobalWorkUnit(secMgr, secUser);
- return global->updateVariableByName(qname);
- }
- IConstWUResult* CLocalWorkUnit::getVariableByName(const char *qname) const
- {
- CriticalBlock block(crit);
- loadVariables();
- ForEachItemIn(idx, variables)
- {
- SCMStringBuffer name;
- IConstWUResult &cur = variables.item(idx);
- cur.getResultName(name);
- if (stricmp(name.str(), qname)==0)
- {
- cur.Link();
- return &cur;
- }
- }
- return NULL;
- }
- IConstWUResult* CLocalWorkUnit::getTemporaryByName(const char *qname) const
- {
- CriticalBlock block(crit);
- loadTemporaries();
- ForEachItemIn(idx, temporaries)
- {
- SCMStringBuffer name;
- IConstWUResult &cur = temporaries.item(idx);
- cur.getResultName(name);
- if (stricmp(name.str(), qname)==0)
- {
- cur.Link();
- return &cur;
- }
- }
- return NULL;
- }
- IConstWUResultIterator& CLocalWorkUnit::getTemporaries() const
- {
- CriticalBlock block(crit);
- loadTemporaries();
- return *new CArrayIteratorOf<IConstWUResult,IConstWUResultIterator> (temporaries, 0, (IConstWorkUnit *) this);
- }
- IWUResult* CLocalWorkUnit::updateTemporaryByName(const char *qname)
- {
- CriticalBlock block(crit);
- IConstWUResult *existing = getTemporaryByName(qname);
- if (existing)
- return (IWUResult *) existing;
- if (!temporaries.length())
- p->addPropTree("Temporaries", createPTree("Temporaries"));
- IPropertyTree *vars = p->queryPropTree("Temporaries");
- IPropertyTree *s = vars->addPropTree("Variable", createPTree("Variable"));
- s->Link();
- IWUResult* q = new CLocalWUResult(s);
- q->Link();
- temporaries.append(*q);
- q->setResultName(qname);
- q->setResultSequence(ResultSequenceInternal);
- return q;
- }
- IWUResult* CLocalWorkUnit::updateVariableByName(const char *qname)
- {
- CriticalBlock block(crit);
- IConstWUResult *existing = getVariableByName(qname);
- if (existing)
- return (IWUResult *) existing;
- if (!variables.length())
- p->addPropTree("Variables", createPTree("Variables"));
- IPropertyTree *vars = p->queryPropTree("Variables");
- IPropertyTree *s = vars->addPropTree("Variable", createPTree("Variable"));
- s->Link();
- IWUResult* q = new CLocalWUResult(s);
- q->Link();
- variables.append(*q);
- q->setResultName(qname);
- q->setResultSequence(ResultSequenceStored);
- return q;
- }
- void CLocalWorkUnit::deleteTempFiles(const char *graph, bool deleteOwned, bool deleteJobOwned)
- {
- CriticalBlock block(crit);
- IPropertyTree *files = p->queryPropTree("Files");
- if (!files) return;
- Owned<IPropertyTreeIterator> iter = files->getElements("File");
- ICopyArrayOf<IPropertyTree> toRemove;
- ForEach (*iter)
- {
- IPropertyTree &file = iter->query();
- WUFileKind fileKind = (WUFileKind) file.getPropInt("@kind", WUFileStandard);
- if(file.getPropBool("@temporary")) fileKind = WUFileTemporary; // @temporary, legacy check
- bool needDelete;
- switch(fileKind)
- {
- case WUFileTemporary:
- if(graph==NULL)
- needDelete = true;
- else
- {
- const char *graphOwner = file.queryProp("@graph");
- needDelete = ((graphOwner==NULL) || (strcmp(graph, graphOwner)==0));
- }
- break;
- case WUFileJobOwned:
- needDelete = ((graph==NULL) && deleteJobOwned);
- break;
- case WUFileOwned:
- needDelete = ((graph==NULL) && deleteOwned);
- break;
- default:
- needDelete = false;
- }
- if(needDelete)
- {
- const char *name = file.queryProp("@name");
- LOG(MCdebugProgress, unknownJob, "Removing workunit file %s from DFS", name);
- queryDistributedFileDirectory().removeEntry(name, queryUserDescriptor());
- toRemove.append(file);
- }
- }
- ForEachItemIn(r, toRemove) files->removeTree(&toRemove.item(r));
- }
- static void _noteFileRead(IDistributedFile *file, IPropertyTree *filesRead)
- {
- IDistributedSuperFile *super = file->querySuperFile();
- StringBuffer fname;
- file->getLogicalName(fname);
- if (fname.length())
- {
- StringBuffer path("File[@name=\"");
- path.append(fname).append("\"]");
- IPropertyTree *fileTree = filesRead->queryPropTree(path.str());
- if (fileTree)
- fileTree->setPropInt("@useCount", fileTree->getPropInt("@useCount")+1);
- else
- {
- StringBuffer cluster;
- file->getClusterName(0,cluster);
- fileTree = createPTree();
- fileTree->setProp("@name", fname.str());
- fileTree->setProp("@cluster", cluster.str());
- fileTree->setPropInt("@useCount", 1);
- fileTree = filesRead->addPropTree("File", fileTree);
- }
- if (super)
- {
- fileTree->setPropBool("@super", true);
- Owned<IDistributedFileIterator> iter = super->getSubFileIterator(false);
- ForEach (*iter)
- {
- IDistributedFile &file = iter->query();
- StringBuffer fname;
- file.getLogicalName(fname);
- Owned<IPropertyTree> subfile = createPTree();
- subfile->setProp("@name", fname.str());
- fileTree->addPropTree("Subfile", subfile.getClear());
- _noteFileRead(&file, filesRead);
- }
- }
- }
- }
- void CLocalWorkUnit::_loadFilesRead() const
- {
- // Nothing to do
- }
- void CLocalWorkUnit::noteFileRead(IDistributedFile *file)
- {
- if (file)
- {
- CriticalBlock block(crit);
- IPropertyTree *files = p->queryPropTree("FilesRead");
- if (!files)
- files = p->addPropTree("FilesRead", createPTree());
- _noteFileRead(file, files);
- }
- }
- void CLocalWorkUnit::noteFieldUsage(IPropertyTree * fieldUsage)
- {
- if (fieldUsage)
- {
- CriticalBlock block(crit);
- p->addPropTree("usedsources", fieldUsage);
- }
- }
- void CLocalWorkUnit::_loadFilesWritten() const
- {
- // Nothing to do
- }
- static void addFile(IPropertyTree *files, const char *fileName, const char *cluster, unsigned usageCount, WUFileKind fileKind, const char *graphOwner)
- {
- StringBuffer path("File[@name=\"");
- path.append(fileName).append("\"]");
- if (cluster)
- path.append("[@cluster=\"").append(cluster).append("\"]");
- IPropertyTree *file = files->queryPropTree(path.str());
- if (file) files->removeTree(file);
- file = createPTree();
- file->setProp("@name", fileName);
- if (cluster)
- file->setProp("@cluster", cluster);
- if (graphOwner)
- file->setProp("@graph", graphOwner);
- file->setPropInt("@kind", (unsigned)fileKind);
- if (WUFileTemporary == fileKind)
- file->setPropInt("@usageCount", usageCount);
- files->addPropTree("File", file);
- }
- void CLocalWorkUnit::addFile(const char *fileName, StringArray *clusters, unsigned usageCount, WUFileKind fileKind, const char *graphOwner)
- {
- CriticalBlock block(crit);
- IPropertyTree *files = p->queryPropTree("Files");
- if (!files)
- files = p->addPropTree("Files", createPTree());
- if (!clusters)
- ::addFile(files, fileName, NULL, usageCount, fileKind, graphOwner);
- else
- {
- ForEachItemIn(c, *clusters)
- ::addFile(files, fileName, clusters->item(c), usageCount, fileKind, graphOwner);
- }
- }
- void CLocalWorkUnit::releaseFile(const char *fileName)
- {
- StringBuffer path("File[@name=\"");
- path.append(fileName).append("\"]");
- CriticalBlock block(crit);
- IPropertyTree *files = p->queryPropTree("Files");
- if (!files) return;
- Owned<IPropertyTreeIterator> fiter = files->getElements(path.str());
- ForEach (*fiter)
- {
- IPropertyTree *file = &fiter->query();
- unsigned usageCount = file->getPropInt("@usageCount");
- if (usageCount > 1)
- file->setPropInt("@usageCount", usageCount-1);
- else
- {
- StringAttr name(file->queryProp("@name"));
- files->removeTree(file);
- if (!name.isEmpty()&&(1 == usageCount))
- {
- if (queryDistributedFileDirectory().removeEntry(fileName, queryUserDescriptor()))
- LOG(MCdebugProgress, unknownJob, "Removed (released) file %s from DFS", name.get());
- }
- }
- }
- }
- void CLocalWorkUnit::clearGraphProgress() const
- {
- }
- void CLocalWorkUnit::resetBeforeGeneration()
- {
- CriticalBlock block(crit);
- //Remove all associated files
- Owned<IWUQuery> q = updateQuery();
- q->removeAssociatedFiles();
- //Remove any pre-existing workflow information
- workflowIterator.clear();
- p->removeProp("Workflow");
- }
- unsigned CLocalWorkUnit::queryFileUsage(const char *fileName) const
- {
- StringBuffer path("Files/File[@name=\"");
- path.append(fileName).append("\"]/@usageCount");
- CriticalBlock block(crit);
- return p->getPropInt(path.str());
- }
- IConstWUFileUsageIterator * CLocalWorkUnit::getFieldUsage() const
- {
- CriticalBlock block(crit);
- IPropertyTree* fieldUsageTree = p->queryPropTree("usedsources");
- if (!fieldUsageTree)
- return NULL;
- IPropertyTreeIterator* iter = fieldUsageTree->getElements("*");
- return new CConstWUFileUsageIterator(iter);
- }
- bool isFilenameResolved(StringBuffer& filename)
- {
- size32_t length = filename.length();
- // With current implementation, if filename is surrounded by single quotes, it means that the filename was resolved at compile time.
- if (filename.length() >= 2 && filename.charAt(0) == '\'' && filename.charAt(length-1) == '\'')
- return true;
- else
- return false;
- }
- bool CLocalWorkUnit::getFieldUsageArray(StringArray & filenames, StringArray & columnnames, const char * clusterName) const
- {
- bool scopeLoaded = false;
- SCMStringBuffer defaultScope;
- Owned<IConstWUFileUsageIterator> files = getFieldUsage();
- if (!files)
- return false; // this query was not compiled with recordFieldUsage option.
- ForEach(*files)
- {
- Owned<IConstWUFileUsage> file = files->get();
- StringBuffer filename = file->queryName();
- size32_t length = filename.length();
-
- if (length == 0)
- throw MakeStringException(WUERR_InvalidFieldUsage, "Invalid FieldUsage found in WU. Cannot enforce view security.");
- StringBuffer normalizedFilename;
-
- // Two cases to handle:
- // 1. Filename was known at compile time, and is surrounded in single quotes (i.e. 'filename').
- // 2. Filename could not be resolved at compile time (i.e. filename is an input to a query),
- // and is a raw expression WITHOUT surrounding single quotes (i.e. STORED('input_filename')).
- if (isFilenameResolved(filename))
- {
- // filename cannot be empty (i.e. empty single quotes '')
- if (length == 2)
- throw MakeStringException(WUERR_InvalidFieldUsage, "Invalid FieldUsage found in WU. Cannot enforce view security.");
-
- // Remove surrounding single quotes
- StringAttr cleanFilename(filename.str()+1, length-2);
- // When a filename doesn't start with a tilde (~), it means scope is omitted and is relying on a default scope.
- // We need to load a default scope from config and prefix the filename with it.
- if (cleanFilename.str()[0] != '~')
- {
- // loading a default scope from config is expensive, and should be only done once and be reused later.
- if (!scopeLoaded)
- {
- Owned<IConstWUClusterInfo> clusterInfo = getTargetClusterInfo(clusterName);
- if (!clusterInfo)
- throw MakeStringException(WUERR_InvalidCluster, "Unknown cluster %s", clusterName);
- clusterInfo->getScope(defaultScope);
- scopeLoaded = true;
- }
- normalizedFilename.append(defaultScope.str());
- normalizedFilename.append(cleanFilename.str());
- }
- else
- {
- normalizedFilename.append(cleanFilename);
- }
- }
- else
- {
- // When filename is an unresolved expression, simply treat the expression as a "non-existent" filename.
- // It will have an effect of this query accessing a non-existent filename, and will be denied access unconditionally.
- normalizedFilename.append(filename.str());
- }
- Owned<IConstWUFieldUsageIterator> fields = file->getFields();
- ForEach(*fields)
- {
- Owned<IConstWUFieldUsage> field = fields->get();
- filenames.append(normalizedFilename.str());
- columnnames.append(field->queryName());
- }
- }
- return true;
- }
- IPropertyTree *CLocalWorkUnit::getDiskUsageStats()
- {
- return p->getPropTree("DiskUsageStats");
- }
- void CLocalWorkUnit::addDiskUsageStats(__int64 _avgNodeUsage, unsigned _minNode, __int64 _minNodeUsage, unsigned _maxNode, __int64 _maxNodeUsage, __int64 _graphId)
- {
- IPropertyTree *stats = p->queryPropTree("DiskUsageStats");
- offset_t maxNodeUsage;
- if (stats)
- maxNodeUsage = stats->getPropInt64("@maxNodeUsage");
- else
- {
- stats = p->addPropTree("DiskUsageStats", createPTree());
- maxNodeUsage = 0;
- }
- if ((offset_t)_maxNodeUsage > maxNodeUsage)
- {
- // record all details at time of max node usage.
- stats->setPropInt("@minNode", _minNode);
- stats->setPropInt("@maxNode", _maxNode);
- stats->setPropInt64("@minNodeUsage", _minNodeUsage);
- stats->setPropInt64("@maxNodeUsage", _maxNodeUsage);
- stats->setPropInt64("@graphId", _graphId);
- if (_avgNodeUsage)
- {
- unsigned _skewHi = (unsigned)((100 * (_maxNodeUsage-_avgNodeUsage))/_avgNodeUsage);
- unsigned _skewLo = (unsigned)((100 * (_avgNodeUsage-_minNodeUsage))/_avgNodeUsage);
- stats->setPropInt("@skewHi", _skewHi);
- stats->setPropInt("@skewLo", _skewLo);
- }
- }
- }
- IPropertyTreeIterator & CLocalWorkUnit::getFileIterator() const
- {
- CriticalBlock block(crit);
- _loadFilesWritten();
- return * p->getElements("Files/File");
- }
- IPropertyTreeIterator & CLocalWorkUnit::getFilesReadIterator() const
- {
- CriticalBlock block(crit);
- _loadFilesRead();
- return * p->getElements("FilesRead/File");
- }
- //=================================================================================================
- bool CLocalWorkUnit::switchThorQueue(const char *cluster, IQueueSwitcher *qs)
- {
- CriticalBlock block(crit);
- if (qs->isAuto()&&!getAllowAutoQueueSwitch())
- return false;
- Owned<IConstWUClusterInfo> newci = getTargetClusterInfo(cluster);
- if (!newci)
- return false;
- StringBuffer currentcluster;
- if (!p->getProp("@clusterName",currentcluster))
- return false;
- Owned<IConstWUClusterInfo> curci = getTargetClusterInfo(currentcluster.str());
- if (!curci)
- return false;
- SCMStringBuffer curqname;
- curci->getThorQueue(curqname);
- const char *wuid = p->queryName();
- void *qi = qs->getQ(curqname.str(),wuid);
- if (!qi)
- return false;
- setClusterName(cluster);
- SCMStringBuffer newqname;
- newci->getThorQueue(newqname);
- qs->putQ(newqname.str(),wuid,qi);
- return true;
- }
- //=================================================================================================
- IPropertyTree *CLocalWorkUnit::getUnpackedTree(bool includeProgress) const
- {
- Owned<IPropertyTree> ret = createPTreeFromIPT(p);
- Owned<IConstWUGraphIterator> graphIter = &getGraphs(GraphTypeAny);
- ForEach(*graphIter)
- {
- IConstWUGraph &graph = graphIter->query();
- Owned<IPropertyTree> graphTree = graph.getXGMMLTree(includeProgress);
- SCMStringBuffer gName;
- graph.getName(gName);
- StringBuffer xpath("Graphs/Graph[@name=\"");
- xpath.append(gName.s).append("\"]/xgmml");
- IPropertyTree *xgmml = ret->queryPropTree(xpath.str());
- if (xgmml) // don't know of any reason it shouldn't exist
- {
- xgmml->removeProp("graphBin");
- xgmml->setPropTree("graph", graphTree.getClear());
- }
- }
- return ret.getClear();
- }
- void CLocalWorkUnit::_loadGraphs(bool heavy) const
- {
- Owned<IPropertyTreeIterator> iter = p->getElements("Graphs/Graph");
- ForEach(*iter)
- {
- IPropertyTree &graph = iter->query();
- graphs.append(*new CLocalWUGraph(*this, LINK(&graph)));
- }
- }
- void CLocalWorkUnit::loadGraphs(bool heavy) const
- {
- if (graphsCached < (heavy ? 2 : 1))
- {
- graphs.kill();
- _loadGraphs(heavy);
- graphsCached = (heavy ? 2 : 1);
- }
- }
- mapEnums graphTypes[] = {
- { GraphTypeAny, "unknown" },
- { GraphTypeProgress, "progress" },
- { GraphTypeEcl, "ECL" },
- { GraphTypeActivities, "activities" },
- { GraphTypeSubProgress, "subgraph" },
- { GraphTypeSize, NULL },
- };
- WUGraphType getGraphTypeFromString(const char* type)
- {
- return (WUGraphType) getEnum(type, graphTypes);
- }
- CLocalWUGraph::CLocalWUGraph(const CLocalWorkUnit &_owner, IPropertyTree *props) : p(props), owner(_owner)
- {
- wuidVersion = owner.getWuidVersion();
- }
- IStringVal& CLocalWUGraph::getName(IStringVal &str) const
- {
- str.set(p->queryProp("@name"));
- return str;
- }
- IStringVal& CLocalWUGraph::getLabel(IStringVal &str) const
- {
- if (wuidVersion >= 2)
- {
- str.set(p->queryProp("@label"));
- return str;
- }
- else
- {
- Owned<IPropertyTree> xgmml = getXGMMLTree(false);
- str.set(xgmml->queryProp("@label"));
- return str;
- }
- }
- WUGraphState CLocalWUGraph::getState() const
- {
- return owner.queryGraphState(p->queryProp("@name"));
- }
- IStringVal& CLocalWUGraph::getXGMML(IStringVal &str, bool mergeProgress) const
- {
- Owned<IPropertyTree> xgmml = getXGMMLTree(mergeProgress);
- if (xgmml)
- {
- StringBuffer x;
- toXML(xgmml, x);
- str.set(x.str());
- }
- return str;
- }
- unsigned CLocalWorkUnit::getGraphCount() const
- {
- CriticalBlock block(crit);
- if (p->hasProp("Graphs"))
- {
- return p->queryPropTree("Graphs")->numChildren();
- }
- return 0;
- }
- unsigned CLocalWorkUnit::getSourceFileCount() const
- {
- CriticalBlock block(crit);
- _loadFilesRead();
- if (p->hasProp("FilesRead"))
- {
- return p->queryPropTree("FilesRead")->numChildren();
- }
- return 0;
-
- }
- unsigned CLocalWorkUnit::getResultCount() const
- {
- CriticalBlock block(crit);
- if (p->hasProp("Results"))
- {
- return p->queryPropTree("Results")->numChildren();
- }
- return 0;
-
- }
- unsigned CLocalWorkUnit::getVariableCount() const
- {
- CriticalBlock block(crit);
- if (p->hasProp("Variables"))
- {
- return p->queryPropTree("Variables")->numChildren();
- }
- return 0;
-
- }
- unsigned CLocalWorkUnit::getApplicationValueCount() const
- {
- CriticalBlock block(crit);
- if (p->hasProp("Application"))
- {
- return p->queryPropTree("Application")->numChildren();
- }
- return 0;
-
- }
- StringBuffer &appendPTreeOpenTag(StringBuffer &s, IPropertyTree *tree, const char *name, unsigned indent)
- {
- appendXMLOpenTag(s, name, NULL, false);
- Owned<IAttributeIterator> attrs = tree->getAttributes(true);
- if (attrs->first())
- {
- unsigned attributeindent = indent + (size32_t) strlen(name);
- unsigned count = attrs->count();
- bool doindent = false;
- ForEach(*attrs)
- {
- if (doindent)
- s.append('\n').appendN(attributeindent, ' ');
- else if (count > 3)
- doindent = true;
- appendXMLAttr(s, attrs->queryName()+1, attrs->queryValue());
- }
- }
- s.append('>');
- return s;
- }
- IStringVal &CLocalWorkUnit::getXmlParams(IStringVal &str, bool hidePasswords) const
- {
- CriticalBlock block(crit);
- IPropertyTree *paramTree = p->queryPropTree("Parameters");
- if (!paramTree)
- return str;
- StringBuffer xml;
- if (!hidePasswords)
- toXML(paramTree, xml);
- else
- {
- appendPTreeOpenTag(xml.append(' '), paramTree, "Parameters", 0).append('\n');
- Owned<IPropertyTreeIterator> elems = paramTree->getElements("*");
- ForEach(*elems)
- {
- const char *paramname = elems->query().queryName();
- VStringBuffer xpath("Variables/Variable[@name='%s']/Format/@password", paramname);
- if (p->getPropBool(xpath))
- appendXMLTag(xml.append(" "), paramname, "***").append('\n');
- else
- toXML(&elems->query(), xml, 2);
- }
- appendXMLCloseTag(xml.append(' '), "Parameters").append('\n');
- }
- str.set(xml);
- return str;
- }
- const IPropertyTree *CLocalWorkUnit::getXmlParams() const
- {
- CriticalBlock block(crit);
- return p->getPropTree("Parameters");
- }
- void CLocalWorkUnit::setXmlParams(const char *params)
- {
- CriticalBlock block(crit);
- p->setPropTree("Parameters", createPTreeFromXMLString(params));
- }
- void CLocalWorkUnit::setXmlParams(IPropertyTree *tree)
- {
- CriticalBlock block(crit);
- p->setPropTree("Parameters", tree);
- }
- unsigned __int64 CLocalWorkUnit::getHash() const
- {
- CriticalBlock block(crit);
- return p->getPropInt64("@hash");
- }
- void CLocalWorkUnit::setHash(unsigned __int64 hash)
- {
- CriticalBlock block(crit);
- p->setPropInt64("@hash", hash);
- }
- // getGraphs / getGraphsMeta
- // These are basically the same except for the amount of preloading they do, and the type of the iterator they return...
- // If a type other than any is requested, a postfilter is needed.
- template <class T, class U> class CFilteredGraphIteratorOf : public CInterfaceOf<T>
- {
- WUGraphType type;
- Owned<T> base;
- bool match()
- {
- return base->query().getType()==type;
- }
- public:
- CFilteredGraphIteratorOf<T,U>(T *_base, WUGraphType _type)
- : base(_base), type(_type)
- {
- }
- bool first()
- {
- if (!base->first())
- return false;
- if (match())
- return true;
- return next();
- }
- bool next()
- {
- while (base->next())
- if (match())
- return true;
- return false;
- }
- virtual bool isValid()
- {
- return base->isValid();
- }
- U & query()
- {
- return base->query();
- }
- };
- IConstWUGraphMetaIterator& CLocalWorkUnit::getGraphsMeta(WUGraphType type) const
- {
- /* NB: this method should be 'cheap', loadGraphs() creates IConstWUGraph interfaces to the graphs
- * it does not actually pull the graph data. We only use IConstWUGraphMeta here, which never probes the xgmml.
- */
- CriticalBlock block(crit);
- loadGraphs(false);
- IConstWUGraphMetaIterator *giter = new CArrayIteratorOf<IConstWUGraph,IConstWUGraphMetaIterator> (graphs, 0, (IConstWorkUnit *) this);
- if (type!=GraphTypeAny)
- giter = new CFilteredGraphIteratorOf<IConstWUGraphMetaIterator, IConstWUGraphMeta>(giter,type);
- return *giter;
- }
- IConstWUGraphIterator& CLocalWorkUnit::getGraphs(WUGraphType type) const
- {
- CriticalBlock block(crit);
- loadGraphs(true);
- IConstWUGraphIterator *giter = new CArrayIteratorOf<IConstWUGraph,IConstWUGraphIterator> (graphs, 0, (IConstWorkUnit *) this);
- if (type!=GraphTypeAny)
- giter = new CFilteredGraphIteratorOf<IConstWUGraphIterator, IConstWUGraph>(giter, type);
- return *giter;
- }
- IConstWUGraph* CLocalWorkUnit::getGraph(const char *qname) const
- {
- CriticalBlock block(crit);
- VStringBuffer xpath("Graphs/Graph[@name='%s']", qname);
- // NOTE - this would go wrong if we had other graphs of same name but different type. Ignore for now.
- IPTree *graph = p->queryPropTree(xpath);
- if (graph)
- return new CLocalWUGraph(*this, LINK(graph));
- return NULL;
- }
- void CLocalWorkUnit::createGraph(const char * name, const char *label, WUGraphType type, IPropertyTree *xgmml)
- {
- CriticalBlock block(crit);
- if (!graphs.length())
- p->addPropTree("Graphs", createPTree("Graphs"));
- IPropertyTree *r = p->queryPropTree("Graphs");
- IPropertyTree *s = r->addPropTree("Graph", createPTree());
- CLocalWUGraph *q = new CLocalWUGraph(*this, LINK(s));
- q->setName(name);
- q->setLabel(label);
- q->setType(type);
- q->setXGMMLTree(xgmml);
- graphs.append(*q);
- }
- IConstWUGraphProgress *CLocalWorkUnit::getGraphProgress(const char *name) const
- {
- /* Owned<IRemoteConnection> conn = getProgressConnection();
- if (conn)
- {
- IPTree *progress = conn->queryRoot()->queryPropTree(graphName);
- if (progress)
- return new CConstGraphProgress(p->queryName(), graphName, progress);
- }
- */
- return NULL;
- }
- WUGraphState CLocalWorkUnit::queryGraphState(const char *graphName) const
- {
- throwUnexpected(); // Should only be used for persisted workunits
- }
- WUGraphState CLocalWorkUnit::queryNodeState(const char *graphName, WUGraphIDType nodeId) const
- {
- throwUnexpected(); // Should only be used for persisted workunits
- }
- void CLocalWorkUnit::setGraphState(const char *graphName, WUGraphState state) const
- {
- throwUnexpected(); // Should only be used for persisted workunits
- }
- void CLocalWorkUnit::setNodeState(const char *graphName, WUGraphIDType nodeId, WUGraphState state) const
- {
- throwUnexpected(); // Should only be used for persisted workunits
- }
- IWUGraphStats *CLocalWorkUnit::updateStats(const char *graphName, StatisticCreatorType creatorType, const char * creator, unsigned subgraph) const
- {
- return new CWuGraphStats(LINK(p), creatorType, creator, graphName, subgraph);
- }
- void CLocalWUGraph::setName(const char *str)
- {
- p->setProp("@name", str);
- }
- void CLocalWUGraph::setLabel(const char *str)
- {
- p->setProp("@label", str);
- }
- void CLocalWUGraph::setXGMML(const char *str)
- {
- setXGMMLTree(createPTreeFromXMLString(str));
- }
- void CLocalWUGraph::setXGMMLTree(IPropertyTree *_graph)
- {
- assertex(strcmp(_graph->queryName(), "graph")==0);
- IPropertyTree *xgmml = p->setPropTree("xgmml", createPTree());
- MemoryBuffer mb;
- _graph->serialize(mb);
- // Note - we could compress further but that would introduce compatibility concerns, so don't bother
- // Cassandra workunit code actually lzw compresses the parent anyway
- xgmml->setPropBin("graphBin", mb.length(), mb.toByteArray());
- graph.setown(_graph);
- }
- static void expandAttributes(IPropertyTree & targetNode, IPropertyTree & progressNode)
- {
- Owned<IAttributeIterator> aIter = progressNode.getAttributes();
- ForEach (*aIter)
- {
- const char *aName = aIter->queryName()+1;
- if (0 != stricmp("id", aName)) // "id" reserved.
- {
- IPropertyTree *att = targetNode.addPropTree("att", createPTree());
- att->setProp("@name", aName);
- att->setProp("@value", aIter->queryValue());
- }
- }
- }
- void CLocalWUGraph::mergeProgress(IPropertyTree &rootNode, IPropertyTree &progressTree, const unsigned &progressV) const
- {
- IPropertyTree *graphNode = rootNode.queryPropTree("att/graph");
- if (!graphNode) return;
- unsigned nodeId = rootNode.getPropInt("@id");
- StringBuffer progressNodePath("node[@id=\"");
- progressNodePath.append(nodeId).append("\"]");
- IPropertyTree *progressNode = progressTree.queryPropTree(progressNodePath.str());
- if (progressNode)
- {
- expandAttributes(*graphNode, *progressNode);
- Owned<IPropertyTreeIterator> edges = progressNode->getElements("edge");
- ForEach (*edges)
- {
- IPropertyTree &edge = edges->query();
- StringBuffer edgePath("edge[@id=\"");
- edgePath.append(edge.queryProp("@id")).append("\"]");
- IPropertyTree *graphEdge = graphNode->queryPropTree(edgePath.str());
- if (graphEdge)
- {
- if (progressV < 1)
- mergePTree(graphEdge, &edge);
- else
- { // must translate to XGMML format
- expandAttributes(*graphEdge, edge);
- // 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)
- Owned<IPropertyTreeIterator> iter = edge.getElements("*");
- ForEach (*iter)
- {
- IPropertyTree &t = iter->query();
- IPropertyTree *att = graphEdge->addPropTree("att", createPTree());
- att->setProp("@name", t.queryName());
- att->setProp("@value", t.queryProp(NULL));
- }
- }
- }
- }
- Owned<IPropertyTreeIterator> nodes = progressNode->getElements("node");
- ForEach (*nodes)
- {
- IPropertyTree &node = nodes->query();
- StringBuffer nodePath("node[@id=\"");
- nodePath.append(node.queryProp("@id")).append("\"]");
- IPropertyTree *_node = graphNode->queryPropTree(nodePath.str());
- if (_node)
- {
- if (progressV < 1)
- mergePTree(_node, &node);
- else
- { // must translate to XGMML format
- expandAttributes(*_node, node);
- }
- }
- }
- }
- Owned<IPropertyTreeIterator> iter = graphNode->getElements("node");
- ForEach (*iter)
- mergeProgress(iter->query(), progressTree, progressV);
- }
- IPropertyTree * CLocalWUGraph::getXGMMLTreeRaw() const
- {
- return p->getPropTree("xgmml");
- }
- IPropertyTree * CLocalWUGraph::getXGMMLTree(bool doMergeProgress) const
- {
- if (!graph)
- {
- // NB: although graphBin introduced in wuidVersion==2,
- // daliadmin can retrospectively compress existing graphs, so need to check for all versions
- MemoryBuffer mb;
- if (p->getPropBin("xgmml/graphBin", mb))
- graph.setown(createPTree(mb));
- else
- graph.setown(p->getBranch("xgmml/graph"));
- if (!graph)
- return NULL;
- }
- if (!doMergeProgress)
- return graph.getLink();
- else
- {
- Owned<IPropertyTree> copy = createPTreeFromIPT(graph);
- Owned<IConstWUGraphProgress> progress = owner.getGraphProgress(p->queryProp("@name"));
- if (progress)
- {
- //MORE: Eventually this should directly access the new stats structure
- unsigned progressV = progress->queryFormatVersion();
- Owned<IPropertyTree> progressTree = progress->getProgressTree();
- Owned<IPropertyTreeIterator> nodeIterator = copy->getElements("node");
- ForEach (*nodeIterator)
- mergeProgress(nodeIterator->query(), *progressTree, progressV);
- }
- return copy.getClear();
- }
- }
- WUGraphType CLocalWUGraph::getType() const
- {
- return (WUGraphType) getEnum(p, "@type", graphTypes);
- }
- IStringVal & CLocalWUGraph::getTypeName(IStringVal &str) const
- {
- str.set(p->queryProp("@type"));
- if (!str.length())
- str.set("unknown");
- return str;
- }
- void CLocalWUGraph::setType(WUGraphType _type)
- {
- setEnum(p, "@type", _type, graphTypes);
- }
- //=================================================================================================
- mapEnums queryFileTypes[] = {
- { FileTypeCpp, "cpp" },
- { FileTypeDll, "dll" },
- { FileTypeResText, "res" },
- { FileTypeHintXml, "hint" },
- { FileTypeXml, "xml" },
- { FileTypeSize, NULL },
- };
- CLocalWUAssociated::CLocalWUAssociated(IPropertyTree *props) : p(props)
- {
- }
- WUFileType CLocalWUAssociated::getType() const
- {
- return (WUFileType)getEnum(p, "@type", queryFileTypes);
- }
- IStringVal & CLocalWUAssociated::getDescription(IStringVal & str) const
- {
- str.set(p->queryProp("@desc"));
- return str;
- }
- IStringVal & CLocalWUAssociated::getIp(IStringVal & str) const
- {
- str.set(p->queryProp("@ip"));
- return str;
- }
- IStringVal & CLocalWUAssociated::getName(IStringVal & str) const
- {
- str.set(p->queryProp("@filename"));
- return str;
- }
- IStringVal & CLocalWUAssociated::getNameTail(IStringVal & str) const
- {
- str.set(pathTail(p->queryProp("@filename")));
- return str;
- }
- unsigned CLocalWUAssociated::getCrc() const
- {
- return p->getPropInt("@crc", 0);
- }
- unsigned CLocalWUAssociated::getMinActivityId() const
- {
- return p->getPropInt("@minActivity", 0);
- }
- unsigned CLocalWUAssociated::getMaxActivityId() const
- {
- return p->getPropInt("@maxActivity", 0);
- }
- //=================================================================================================
- CLocalWUQuery::CLocalWUQuery(IPropertyTree *props) : p(props)
- {
- associatedCached = false;
- }
- mapEnums queryTypes[] = {
- { QueryTypeUnknown, "unknown" },
- { QueryTypeEcl, "ECL" },
- { QueryTypeSql, "SQL" },
- { QueryTypeXml, "XML" },
- { QueryTypeAttribute, "Attribute" },
- { QueryTypeSize, NULL },
- };
- WUQueryType CLocalWUQuery::getQueryType() const
- {
- return (WUQueryType) getEnum(p, "@type", queryTypes);
- }
- void CLocalWUQuery::setQueryType(WUQueryType qt)
- {
- setEnum(p, "@type", qt, queryTypes);
- }
- IStringVal& CLocalWUQuery::getQueryText(IStringVal &str) const
- {
- str.set(p->queryProp("Text"));
- return str;
- }
- IStringVal& CLocalWUQuery::getQueryShortText(IStringVal &str) const
- {
- const char * text = p->queryProp("ShortText");
- if (text)
- str.set(text);
- else
- {
- text = p->queryProp("Text");
- if (isArchiveQuery(text))
- {
- Owned<IPropertyTree> xml = createPTreeFromXMLString(text, ipt_caseInsensitive);
- const char * path = xml->queryProp("Query/@attributePath");
- if (path)
- {
- IPropertyTree * resolved = resolveDefinitionInArchive(xml, path);
- if (resolved)
- str.set(resolved->queryProp(NULL));
- }
- else
- str.set(xml->queryProp("Query"));
- }
- else
- str.set(text);
- }
- return str;
- }
- bool CLocalWUQuery::isArchive() const
- {
- if (p->hasProp("@isArchive"))
- return p->getPropBool("@isArchive");
- const char *text = p->queryProp("Text");
- return isArchiveQuery(text);
- }
- IStringVal& CLocalWUQuery::getQueryName(IStringVal &str) const
- {
- str.set(p->queryProp("@name"));
- return str;
- }
- IStringVal & CLocalWUQuery::getQueryMainDefinition(IStringVal & str) const
- {
- str.set(p->queryProp("@main"));
- return str;
- }
- IStringVal& CLocalWUQuery::getQueryDllName(IStringVal &str) const
- {
- Owned<IConstWUAssociatedFile> entry = getAssociatedFile(FileTypeDll, 0);
- if (entry)
- entry->getNameTail(str);
- return str;
- }
- IStringVal& CLocalWUQuery::getQueryCppName(IStringVal &str) const
- {
- Owned<IConstWUAssociatedFile> entry = getAssociatedFile(FileTypeCpp, 0);
- if (entry)
- entry->getName(str);
- return str;
- }
- IStringVal& CLocalWUQuery::getQueryResTxtName(IStringVal &str) const
- {
- Owned<IConstWUAssociatedFile> entry = getAssociatedFile(FileTypeResText, 0);
- if (entry)
- entry->getName(str);
- return str;
- }
- unsigned CLocalWUQuery::getQueryDllCrc() const
- {
- Owned<IConstWUAssociatedFile> entry = getAssociatedFile(FileTypeDll, 0);
- if (entry)
- return entry->getCrc();
- return 0;
- }
- void CLocalWUQuery::setQueryText(const char *text)
- {
- p->setProp("Text", text);
- bool isArchive = isArchiveQuery(text);
- if (isArchive)
- {
- Owned<IPropertyTree> xml = createPTreeFromXMLString(text, ipt_caseInsensitive);
- const char * path = xml->queryProp("Query/@attributePath");
- if (path)
- {
- IPropertyTree * resolved = resolveDefinitionInArchive(xml, path);
- if (resolved)
- p->setProp("ShortText", resolved->queryProp(NULL));
- }
- else
- p->setProp("ShortText", xml->queryProp("Query"));
- }
- p->setPropBool("@isArchive", isArchive);
- }
- void CLocalWUQuery::setQueryName(const char *qname)
- {
- p->setProp("@name", qname);
- }
- void CLocalWUQuery::setQueryMainDefinition(const char * str)
- {
- p->setProp("@main", str);
- }
- void CLocalWUQuery::addAssociatedFile(WUFileType type, const char * name, const char * ip, const char * desc, unsigned crc, unsigned minActivity, unsigned maxActivity)
- {
- CriticalBlock block(crit);
- loadAssociated();
- if (!associated.length())
- p->addPropTree("Associated", createPTree("Associated"));
- IPropertyTree *pl = p->queryPropTree("Associated");
- IPropertyTree *s = pl->addPropTree("File", createPTree("File"));
- setEnum(s, "@type", type, queryFileTypes);
- s->setProp("@filename", name);
- s->setProp("@ip", ip);
- s->setProp("@desc", desc);
- if (crc)
- s->setPropInt("@crc", crc);
- if (minActivity)
- s->setPropInt("@minActivity", minActivity);
- if (maxActivity)
- s->setPropInt("@maxActivity", maxActivity);
- IConstWUAssociatedFile * q = new CLocalWUAssociated(LINK(s));
- associated.append(*q);
- }
- void CLocalWUQuery::removeAssociatedFile(WUFileType type, const char * name, const char * desc)
- {
- CriticalBlock block(crit);
- associatedCached = false;
- associated.kill();
- StringBuffer xpath;
- xpath.append("Associated/File");
- if (type)
- xpath.append("[@type=\"").append(getEnumText(type, queryFileTypes)).append("\"]");
- if (name)
- xpath.append("[@filename=\"").append(name).append("\"]");
- if (desc)
- xpath.append("[@desc=\"").append(desc).append("\"]");
- p->removeProp(xpath.str());
- }
- void CLocalWUQuery::removeAssociatedFiles()
- {
- associatedCached = false;
- associated.kill();
- p->removeProp("Associated");
- }
- IConstWUAssociatedFile * CLocalWUQuery::getAssociatedFile(WUFileType type, unsigned index) const
- {
- CriticalBlock block(crit);
- loadAssociated();
- ForEachItemIn(idx, associated)
- {
- CLocalWUAssociated &cur = static_cast<CLocalWUAssociated &>(associated.item(idx));
- if (cur.getType() == type)
- {
- if (index-- == 0)
- return &OLINK(cur);
- }
- }
- return NULL;
- }
- void CLocalWUQuery::addSpecialCaseAssociated(WUFileType type, const char * propname, unsigned crc) const
- {
- const char * name = p->queryProp(propname);
- if (name)
- {
- IPropertyTree *s = createPTree("File");
- setEnum(s, "@type", type, queryFileTypes);
- s->setProp("@filename", name);
- if (crc)
- s->setPropInt("@crc", crc);
- associated.append(*new CLocalWUAssociated(s));
- }
- }
- void CLocalWUQuery::loadAssociated() const
- {
- CriticalBlock block(crit);
- if (!associatedCached)
- {
- assertex(associated.length() == 0);
- addSpecialCaseAssociated(FileTypeDll, "DllName", p->getPropInt("DllCrc", 0));
- addSpecialCaseAssociated(FileTypeCpp, "CppName", 0);
- addSpecialCaseAssociated(FileTypeResText, "ResTxtName", 0);
- Owned<IPropertyTreeIterator> r = p->getElements("Associated/File");
- for (r->first(); r->isValid(); r->next())
- {
- IPropertyTree *rp = &r->query();
- rp->Link();
- associated.append(*new CLocalWUAssociated(rp));
- }
- associatedCached = true;
- }
- }
- IConstWUAssociatedFileIterator& CLocalWUQuery::getAssociatedFiles() const
- {
- CriticalBlock block(crit);
- loadAssociated();
- return *new CArrayIteratorOf<IConstWUAssociatedFile,IConstWUAssociatedFileIterator> (associated, 0, (IConstWUQuery *) this);
- }
- //========================================================================================
- CLocalWUWebServicesInfo::CLocalWUWebServicesInfo(IPropertyTree *props) : p(props)
- {
- }
- IStringVal& CLocalWUWebServicesInfo::getModuleName(IStringVal &str) const
- {
- str.set(p->queryProp("@module"));
- return str;
- }
- IStringVal& CLocalWUWebServicesInfo::getAttributeName(IStringVal &str) const
- {
- str.set(p->queryProp("@attribute"));
- return str;
- }
- IStringVal& CLocalWUWebServicesInfo::getDefaultName(IStringVal &str) const
- {
- str.set(p->queryProp("@defaultName"));
- return str;
- }
- unsigned CLocalWUWebServicesInfo::getWebServicesCRC() const
- {
- return (unsigned) p->getPropInt("@crc");
- }
- IStringVal& CLocalWUWebServicesInfo::getInfo(const char *name, IStringVal &str) const
- {
- if (!name)
- {
- StringBuffer ws_info;
- ws_info.appendf("<%s ", p->queryName());
- Owned<IAttributeIterator> attrs = p->getAttributes();
- for(attrs->first(); attrs->isValid(); attrs->next())
- {
- const char *name = attrs->queryName()+1;
- const char *value = attrs->queryValue();
- ws_info.appendf("%s='%s' ", name, value);
- }
- ws_info.append("> \n");
- Owned<IPropertyTreeIterator> info = p->getElements("*");
- ForEach(*info)
- {
- IPropertyTree &item = info->query();
- const char *name = item.queryName();
- if (name)
- {
- MemoryBuffer mb;
- bool isbin = p->isBinary(name);
- if (isbin)
- {
- p->getPropBin(name,mb);
- if (mb.length())
- {
- unsigned len = 0;
- mb.read(len);
- StringBuffer encodedString;
- StringBuffer val(len, (const char *) mb.readDirect(len));
- encodeXML(val, encodedString);
- ws_info.appendf("<%s>%s</%s>", name, encodedString.str(), name);
- }
- }
- else
- {
- StringBuffer tmp;
- toXML(&item, tmp);
- ws_info.append(tmp.str());
- }
- }
- }
- ws_info.appendf("</%s>", p->queryName());
- str.setLen(ws_info.str(), ws_info.length());
- }
- else
- {
- MemoryBuffer mb;
- p->getPropBin(name,mb);
- if (mb.length())
- {
- unsigned len;
- mb.read(len);
- str.setLen((const char *) mb.readDirect(len), len);
- }
- }
- return str;
- }
- IStringVal& CLocalWUWebServicesInfo::getText(const char *name, IStringVal &str) const
- {
- str.set(p->queryProp(name));
- return str;
- }
- void CLocalWUWebServicesInfo::setModuleName(const char *mname)
- {
- p->setProp("@module", mname);
- }
- void CLocalWUWebServicesInfo::setAttributeName(const char *aname)
- {
- p->setProp("@attribute", aname);
- }
- void CLocalWUWebServicesInfo::setDefaultName(const char *dname)
- {
- p->setProp("@defaultName", dname);
- }
- void CLocalWUWebServicesInfo::setWebServicesCRC(unsigned crc)
- {
- p->setPropInt("@crc", crc);
- }
- void CLocalWUWebServicesInfo::setInfo(const char *name, const char *info)
- {
- MemoryBuffer m;
- unsigned len = (size32_t)strlen(info);
- serializeLPString(len, info, m);
- p->setPropBin(name, m.length(), m.toByteArray());
- }
- void CLocalWUWebServicesInfo::setText(const char *name, const char *info)
- {
- p->setProp(name, info);
- }
- //========================================================================================
- CLocalWUResult::CLocalWUResult(IPropertyTree *props) : p(props)
- {
- }
- mapEnums resultStatuses[] = {
- { ResultStatusUndefined, "undefined" },
- { ResultStatusCalculated, "calculated" },
- { ResultStatusSupplied, "supplied" },
- { ResultStatusFailed, "failed" },
- { ResultStatusPartial, "partial" },
- { ResultStatusSize, NULL }
- };
- WUResultStatus CLocalWUResult::getResultStatus() const
- {
- return (WUResultStatus ) getEnum(p, "@status", resultStatuses);
- }
- IStringVal& CLocalWUResult::getResultName(IStringVal &str) const
- {
- str.set(p->queryProp("@name"));
- return str;
- }
- int CLocalWUResult::getResultSequence() const
- {
- return p->getPropInt("@sequence", -1);
- }
- bool CLocalWUResult::isResultScalar() const
- {
- return p->getPropInt("@isScalar", 1) != 0;
- }
- bool findSize(int size, IntArray &sizes)
- {
- ForEachItemIn(idx, sizes)
- {
- if (sizes.item(idx)==size)
- return true;
- }
- return false;
- }
- void CLocalWUResult::getSchema(IArrayOf<ITypeInfo> &types, StringAttrArray &names, IStringVal * eclText) const
- {
- MemoryBuffer schema;
- p->getPropBin("SchemaRaw", schema);
- if (schema.length())
- {
- for (;;)
- {
- StringAttr name;
- schema.read(name);
- if (*schema.readDirect(0)==type_void)
- break;
- names.append(*new StringAttrItem(name));
- types.append(*deserializeType(schema)); // MORE - nested records!
- }
- schema.skip(1);
- if (schema.length() != schema.getPos())
- {
- unsigned eclLen;
- schema.read(eclLen);
- const char * schemaData = (const char *)schema.readDirect(eclLen);
- if (eclText)
- {
- eclText->setLen(schemaData, eclLen);
- if ((eclLen == 0) && names.ordinality())
- {
- const char * firstName = names.item(0).text;
- StringBuffer temp;
- temp.append("RECORD ");
- types.item(0).getECLType(temp);
- temp.append(" value{NAMED('").append(firstName).append("')}").append("; END;");
- eclText->set(temp.str());
- }
- }
- }
- }
- }
- void readRow(StringBuffer &out, MemoryBuffer &in, TypeInfoArray &types, StringAttrArray &names)
- {
- ForEachItemIn(idx, types)
- {
- StringAttrItem &name = names.item(idx);
- ITypeInfo &type = types.item(idx);
- unsigned size = type.getSize();
- switch(type.getTypeCode())
- {
- case type_data:
- if (size==UNKNOWN_LENGTH)
- {
- if (in.remaining() < sizeof(int))
- throw MakeStringException(WUERR_CorruptResult, "corrupt workunit information");
- in.read(size);
- }
- outputXmlData(size, in.readDirect(size), name.text, out);
- break;
- case type_string:
- if (size==UNKNOWN_LENGTH)
- {
- if (in.remaining() < sizeof(int))
- throw MakeStringException(WUERR_CorruptResult, "corrupt workunit information");
- in.read(size);
- }
- outputXmlString(size, (const char *) in.readDirect(size), name.text, out);
- break;
- case type_varstring:
- {
- if (size == UNKNOWN_LENGTH)
- size = (size32_t)strlen((const char *) in.readDirect(0))+1;
- const char * text = (const char *) in.readDirect(size);
- outputXmlString((size32_t)strlen(text), text, name.text, out);
- break;
- }
- case type_unicode:
- {
- unsigned len = type.getStringLen();
- if (size==UNKNOWN_LENGTH)
- in.read(len);
- outputXmlUnicode(len, (UChar const *) in.readDirect(len*2), name.text, out);
- }
- break;
- case type_utf8:
- {
- unsigned len = type.getStringLen();
- if (size==UNKNOWN_LENGTH)
- {
- in.read(len);
- size = rtlUtf8Size(len, in.readDirect(0));
- }
- outputXmlUtf8(len, (const char *) in.readDirect(size), name.text, out);
- }
- break;
- case type_qstring:
- {
- unsigned len = type.getStringLen();
- if (size==UNKNOWN_LENGTH)
- in.read(len);
- unsigned outlen;
- char *outstr;
- rtlQStrToStrX(outlen, outstr, len, (const char *) in.readDirect(rtlQStrSize(len)));
- outputXmlString(outlen, outstr, name.text, out);
- free(outstr);
- break;
- }
- case type_int:
- case type_swapint:
- if (type.isSigned())
- {
- const unsigned char *raw = (const unsigned char *) in.readDirect(size);
- unsigned __int64 cval8 = 0;
- //MORE: I think this is wrong - swapped doesn't mean little/big/
- if (type.isSwappedEndian())
- {
- unsigned idx = 0;
- if (raw[idx] & 0x80)
- cval8 = (__int64)-1;
- while (size--)
- cval8 = (cval8 << 8) | raw[idx++];
- }
- else
- {
- if (raw[size-1] & 0x80)
- cval8 = (__int64)-1;
- while (size--)
- cval8 = (cval8 << 8) | raw[size];
- }
- outputXmlInt((__int64) cval8, name.text, out);
- }
- else
- {
- const unsigned char *raw = (const unsigned char *) in.readDirect(size);
- unsigned __int64 cval8 = 0;
- if (type.isSwappedEndian())
- {
- unsigned idx = 0;
- while (size--)
- cval8 = (cval8 << 8) | raw[idx++];
- }
- else
- {
- while (size--)
- cval8 = (cval8 << 8) | raw[size];
- }
- outputXmlUInt(cval8, name.text, out);
- }
- break;
- case type_boolean:
- bool cvalb;
- in.read(cvalb);
- outputXmlBool(cvalb, name.text, out);
- break;
- case type_decimal:
- if (type.isSigned())
- outputXmlDecimal(in.readDirect(size), size, type.getPrecision(), name.text, out);
- else
- outputXmlUDecimal(in.readDirect(size), size, type.getPrecision(), name.text, out);
- break;
- case type_real:
- double cvald;
- switch(size)
- {
- case 4:
- float cvalf;
- in.read(cvalf);
- cvald = cvalf;
- break;
- case 8:
- in.read(cvald);
- break;
- }
- outputXmlReal(cvald, name.text, out);
- break;
- default:
- assertex(!"unexpected type in raw record");
- break;
- }
- }
- }
- IStringVal& CLocalWUResult::getResultXml(IStringVal &str, bool hidePassword) const
- {
- TypeInfoArray types;
- StringAttrArray names;
- getSchema(types, names);
- StringBuffer xml;
- const char * name = p->queryProp("@name");
- if (name)
- xml.appendf("<Dataset name=\'%s\'>\n", name);
- else
- xml.append("<Dataset>\n");
- if (hidePassword && p->getPropBool("Format/@password"))
- {
- xml.append(" <Row>");
- appendXMLTag(xml, name, "****");
- xml.append("</Row>\n");
- }
- else if (p->hasProp("Value"))
- {
- MemoryBuffer raw;
- p->getPropBin("Value", raw);
- unsigned __int64 numrows = getResultRowCount();
- while (numrows--)
- {
- xml.append(" <Row>");
- readRow(xml, raw, types, names);
- xml.append("</Row>\n");
- }
- }
- else if (p->hasProp("xmlValue"))
- {
- xml.append(" <Row>");
- appendXMLTag(xml, name, p->queryProp("xmlValue"));
- xml.append("</Row>\n");
- }
- xml.append("</Dataset>\n");
- str.set(xml.str());
- return str;
- }
- IProperties *CLocalWUResult::queryResultXmlns()
- {
- CriticalBlock block(crit);
- if (xmlns)
- return xmlns;
- xmlns.setown(createProperties());
- Owned<IAttributeIterator> it = p->getAttributes();
- unsigned prefixLen = strlen("@xmlns");
- ForEach(*it)
- {
- const char *name = it->queryName();
- if (!strncmp("@xmlns", name, prefixLen))
- {
- if (name[prefixLen]==':') //normal case
- xmlns->setProp(name+prefixLen+1, it->queryValue());
- else if (!name[prefixLen]) //special case, unprefixed namespace
- xmlns->setProp("xmlns", it->queryValue());
- }
- }
- return xmlns;
- }
- unsigned CLocalWUResult::getResultFetchSize() const
- {
- return p->getPropInt("fetchSize", 100);
- }
- __int64 CLocalWUResult::getResultTotalRowCount() const
- {
- return p->getPropInt64("totalRowCount", -1);
- }
- __int64 CLocalWUResult::getResultRowCount() const
- {
- return p->getPropInt64("rowCount", 0);
- }
- void CLocalWUResult::getResultDataset(IStringVal & ecl, IStringVal & defs) const
- {
- ecl.set(p->queryProp("datasetEcl"));
- defs.set(p->queryProp("datasetEclDefs"));
- }
- IStringVal& CLocalWUResult::getResultLogicalName(IStringVal & val) const
- {
- val.set(p->queryProp("logicalName"));
- return val;
- }
- IStringVal& CLocalWUResult::getResultKeyField(IStringVal & ecl) const
- {
- ecl.set(p->queryProp("keyField"));
- return ecl;
- }
- unsigned CLocalWUResult::getResultRequestedRows() const
- {
- return p->getPropInt("requestedRows", 1);
- }
- IStringVal& CLocalWUResult::getResultEclSchema(IStringVal & str) const
- {
- TypeInfoArray types;
- StringAttrArray names;
- getSchema(types, names, &str);
- return str;
- }
- IStringVal& CLocalWUResult::getResultRecordSizeEntry(IStringVal & str) const
- {
- str.set(p->queryProp("@recordSizeEntry"));
- return str;
- }
- IStringVal& CLocalWUResult::getResultTransformerEntry(IStringVal & str) const
- {
- str.set(p->queryProp("@transformerEntry"));
- return str;
- }
- __int64 CLocalWUResult::getResultRowLimit() const
- {
- return p->getPropInt64("@rowLimit");
- }
- IStringVal& CLocalWUResult::getResultFilename(IStringVal & str) const
- {
- str.set(p->queryProp("@tempFilename"));
- return str;
- }
- IStringVal& CLocalWUResult::getResultFieldOpt(const char *name, IStringVal &str) const
- {
- str.clear();
- if (!name || !*name)
- return str;
- IPropertyTree *format = p->queryPropTree("Format");
- if (!format)
- return str;
- VStringBuffer xpath("@%s", name);
- str.set(format->queryProp(xpath));
- return str;
- }
- void CLocalWUResult::setResultStatus(WUResultStatus status)
- {
- setEnum(p, "@status", status, resultStatuses);
- if (status==ResultStatusUndefined)
- {
- p->removeProp("Value");
- p->removeProp("totalRowCount");
- p->removeProp("rowCount");
- p->removeProp("@format");
- p->removeProp("@tempFileNmae");
- p->removeProp("logicalName");
- }
- }
- void CLocalWUResult::setResultName(const char *s)
- {
- p->setProp("@name", s);
- }
- void CLocalWUResult::setResultSequence(unsigned seq)
- {
- p->setPropInt("@sequence", seq);
- }
- void CLocalWUResult::setResultSchemaRaw(unsigned size, const void *schema)
- {
- p->setPropBin("SchemaRaw", size, schema);
- }
- void CLocalWUResult::setResultXmlns(const char *prefix, const char *uri)
- {
- StringBuffer xpath("@xmlns");
- if (prefix && *prefix)
- xpath.append(':').append(prefix);
- p->setProp(xpath, uri);
- }
- void CLocalWUResult::setResultFieldOpt(const char *name, const char *value)
- {
- if (!name || !*name)
- return;
- IPropertyTree *format = ensurePTree(p, "Format");
- VStringBuffer xpath("@%s", name);
- format->setProp(xpath, value);
- }
- void CLocalWUResult::setResultScalar(bool isScalar)
- {
- p->setPropInt("@isScalar", (int) isScalar);
- if (isScalar)
- setResultTotalRowCount(1);
- }
- void CLocalWUResult::setResultRaw(unsigned len, const void *data, WUResultFormat format)
- {
- p->setPropBin("Value", len, data);
- setResultStatus(ResultStatusSupplied);
- setResultFormat(format);
- }
- void CLocalWUResult::setResultFormat(WUResultFormat format)
- {
- switch (format)
- {
- case ResultFormatXml:
- p->setProp("@format","xml");
- break;
- case ResultFormatXmlSet:
- p->setProp("@format","xmlSet");
- break;
- case ResultFormatCsv:
- p->setProp("@format","csv");
- break;
- default:
- p->removeProp("@format");
- break;
- }
- }
- void CLocalWUResult::setResultXML(const char *val)
- {
- p->setProp("xmlValue", val);
- }
- void CLocalWUResult::addResultRaw(unsigned len, const void *data, WUResultFormat format)
- {
- p->appendPropBin("Value", len, data);
- setResultStatus(ResultStatusPartial);
- const char *existingFormat = p->queryProp("@format");
- const char *formatStr = NULL;
- switch (format)
- {
- case ResultFormatXml:
- formatStr = "xml";
- break;
- case ResultFormatXmlSet:
- formatStr = "xmlSet";
- break;
- case ResultFormatCsv:
- formatStr = "csv";
- break;
- default:
- p->removeProp("@format");
- break;
- }
- if (format)
- {
- if (existingFormat)
- {
- if (0 != stricmp(formatStr, existingFormat))
- throw MakeStringException(WUERR_ResultFormatMismatch, "addResult format %s, does not match existing format %s", formatStr, existingFormat);
- }
- else
- p->setProp("@format", formatStr);
- }
- }
- void CLocalWUResult::setResultFetchSize(unsigned rows)
- {
- p->setPropInt("fetchSize", rows);
- }
- void CLocalWUResult::setResultTotalRowCount(__int64 rows)
- {
- p->setPropInt64("totalRowCount", rows);
- }
- void CLocalWUResult::setResultRowCount(__int64 rows)
- {
- p->setPropInt64("rowCount", rows);
- }
- void CLocalWUResult::setResultDataset(const char *ecl, const char *defs)
- {
- p->setProp("datasetEcl", ecl);
- p->setProp("datasetEclDefs", defs);
- }
- void CLocalWUResult::setResultLogicalName(const char *logicalName)
- {
- p->setProp("logicalName", logicalName);
- }
- void CLocalWUResult::setResultKeyField(const char *ecl)
- {
- p->setProp("keyField", ecl);
- }
- void CLocalWUResult::setResultRequestedRows(unsigned rows)
- {
- p->setPropInt("requestedRows", rows);
- }
- void CLocalWUResult::setResultRecordSizeEntry(const char * entry)
- {
- p->setProp("@recordSizeEntry", entry);
- }
- void CLocalWUResult::setResultTransformerEntry(const char * entry)
- {
- p->setProp("@transformerEntry", entry);
- }
- void CLocalWUResult::setResultRowLimit(__int64 value)
- {
- p->setPropInt64("@rowLimit", value);
- }
- void CLocalWUResult::setResultFilename(const char * name)
- {
- p->setProp("@tempFilename", name);
- }
- // MORE - it's an undetected error if we call getResult... of a type that does not match schema
- __int64 CLocalWUResult::getResultInt() const
- {
- __int64 result = 0;
- MemoryBuffer s;
- p->getPropBin("Value", s);
- if (s.length())
- s.read(result);
- else
- result = p->getPropInt64("xmlValue");
- return result;
- }
- bool CLocalWUResult::getResultBool() const
- {
- bool result = false;
- MemoryBuffer s;
- p->getPropBin("Value", s);
- if (s.length())
- s.read(result);
- else
- result = p->getPropBool("xmlValue");
- return result;
- }
- double CLocalWUResult::getResultReal() const
- {
- double result = 0;
- MemoryBuffer s;
- p->getPropBin("Value", s);
- if (s.length())
- s.read(result);
- else
- {
- const char *xmlVal = p->queryProp("xmlValue");
- if (xmlVal)
- result = atof(xmlVal);
- }
- return result;
- }
- void CLocalWUResult::getResultDecimal(void * val, unsigned len, unsigned precision, bool isSigned) const
- {
- MemoryBuffer s;
- p->getPropBin("Value", s);
- if (s.length())
- {
- assertex(s.length() == len);
- s.read(len, val);
- }
- else
- {
- const char *xmlVal = p->queryProp("xmlValue");
- if (xmlVal)
- {
- Decimal d;
- d.setString(strlen(xmlVal), xmlVal);
- if (isSigned)
- d.getDecimal(len, precision, val);
- else
- d.getUDecimal(len, precision, val);
- }
- else
- memset(val, 0, len);
- }
- }
- IStringVal& CLocalWUResult::getResultString(IStringVal & str, bool hidePassword) const
- {
- if (hidePassword && p->getPropBool("@password"))
- {
- str.set("****");
- return str;
- }
- MemoryBuffer s;
- p->getPropBin("Value", s);
- if (s.length())
- {
- unsigned len;
- s.read(len);
- str.setLen((const char *) s.readDirect(len), len);
- }
- else
- {
- p->getPropBin("xmlValue", s);
- if (p->isBinary("xmlValue"))
- str.setLen(s.toByteArray(), s.length());
- else
- {
- char *ascii = rtlUtf8ToVStr(rtlUtf8Length(s.length(), s.toByteArray()), s.toByteArray());
- str.set(ascii);
- rtlFree(ascii);
- }
- }
- return str;
- }
- WUResultFormat CLocalWUResult::getResultFormat() const
- {
- const char * format = p->queryProp("@format");
- if (!format)
- return ResultFormatRaw;
- else if (strcmp(format, "xml") == 0)
- return ResultFormatXml;
- else if (strcmp(format, "xmlSet") == 0)
- return ResultFormatXmlSet;
- else if (strcmp(format, "csv") == 0)
- return ResultFormatCsv;
- else
- throw MakeStringException(WUERR_InvalidResultFormat, "Unrecognised result format %s", format);
- }
- IDataVal& CLocalWUResult::getResultRaw(IDataVal & data, IXmlToRawTransformer * xmlTransformer, ICsvToRawTransformer * csvTransformer) const
- {
- MemoryBuffer s;
- p->getPropBin("Value", s);
- unsigned len = s.length();
- if (len)
- {
- WUResultFormat format = getResultFormat();
- if (format == ResultFormatXml || format == ResultFormatXmlSet)
- {
- if (!xmlTransformer)
- throw MakeStringException(WUERR_MissingFormatTranslator, "No transformer supplied to translate XML format result");
- xmlTransformer->transform(data, len, s.readDirect(len), format == ResultFormatXml);
- }
- else if (format == ResultFormatCsv)
- {
- if (!csvTransformer)
- throw MakeStringException(WUERR_MissingFormatTranslator, "No transformer supplied to translate Csv format result");
- csvTransformer->transform(data, len, s.readDirect(len), true);
- }
- else
- data.setLen(s.readDirect(len), len);
- }
- else
- data.clear();
- return data;
- }
- unsigned CLocalWUResult::getResultHash() const
- {
- MemoryBuffer s;
- p->getPropBin("Value", s);
- unsigned len = s.length();
- const byte * data = (const byte *)s.toByteArray();
- return ~hashc(data, len, ~0);
- }
- IDataVal& CLocalWUResult::getResultUnicode(IDataVal & data) const
- {
- MemoryBuffer s;
- p->getPropBin("Value", s);
- if (s.length())
- {
- unsigned len;
- s.read(len);
- data.setLen(s.readDirect(len*2), len*2);
- }
- else
- {
- StringBuffer utf8;
- if (p->getProp("xmlValue", utf8))
- {
- unsigned outlen;
- UChar *out;
- rtlUtf8ToUnicodeX(outlen, out, utf8.length(), utf8.str());
- data.setLen(out, outlen*2);
- rtlFree(out);
- }
- else
- data.clear();
- }
- return data;
- }
- __int64 CLocalWUResult::getResultRawSize(IXmlToRawTransformer * xmlTransformer, ICsvToRawTransformer * csvTransformer) const
- {
- WUResultFormat format = getResultFormat();
- if (format == ResultFormatRaw)
- {
- //MORE: This should not load the whole property...
- MemoryBuffer s;
- p->getPropBin("Value", s);
- return s.length();
- }
- else
- {
- MemoryBuffer temp;
- MemoryBuffer2IDataVal adaptor(temp);
- getResultRaw(adaptor, xmlTransformer, csvTransformer);
- return temp.length();
- }
- }
- IDataVal& CLocalWUResult::getResultRaw(IDataVal & data, __int64 from, __int64 length, IXmlToRawTransformer * xmlTransformer, ICsvToRawTransformer * csvTransformer) const
- {
- WUResultFormat format = getResultFormat();
- if (format != ResultFormatRaw)
- {
- MemoryBuffer temp;
- MemoryBuffer2IDataVal adaptor(temp);
- getResultRaw(adaptor, xmlTransformer, csvTransformer);
- unsigned len = temp.length();
- if (from > len) from = len;
- if (from + length > len) length = len - from;
- data.setLen(temp.readDirect(len) + from, (size32_t)length);
- return data;
- }
- else
- {
- //MORE: This should not load the whole property, and should be different from the code above...
- MemoryBuffer s;
- p->getPropBin("Value", s);
- unsigned len = s.length();
- if (from > len) from = len;
- if (from + length > len) length = len - from;
- data.setLen(s.readDirect(len) + from, (size32_t)length);
- return data;
- }
- }
- bool CLocalWUResult::getResultIsAll() const
- {
- return p->getPropBool("@isAll", false);
- }
- // MORE - it's an undetected error if we call setResult... of a type that does not match schema
- void CLocalWUResult::setResultInt(__int64 val)
- {
- // Note: we always serialize scalar integer results as int8, and schema must reflect this
- MemoryBuffer m;
- serializeInt8(val, m);
- p->setPropBin("Value", m.length(), m.toByteArray());
- setResultRowCount(1);
- setResultTotalRowCount(1);
- }
- void CLocalWUResult::setResultUInt(unsigned __int64 val)
- {
- setResultInt((__int64) val);
- }
- void CLocalWUResult::setResultReal(double val)
- {
- // Note: we always serialize scalar real results as real8, and schema must reflect this
- MemoryBuffer m;
- serializeReal8(val, m);
- p->setPropBin("Value", m.length(), m.toByteArray());
- setResultRowCount(1);
- setResultTotalRowCount(1);
- }
- void CLocalWUResult::setResultBool(bool val)
- {
- MemoryBuffer m;
- serializeBool(val, m);
- p->setPropBin("Value", m.length(), m.toByteArray());
- setResultRowCount(1);
- setResultTotalRowCount(1);
- }
- void CLocalWUResult::setResultString(const char *val, unsigned len)
- {
- // Note: we always serialize scalar strings with length prefix, and schema must reflect this
- MemoryBuffer m;
- serializeLPString(len, val, m);
- p->setPropBin("Value", m.length(), m.toByteArray());
- setResultRowCount(1);
- setResultTotalRowCount(1);
- }
- void CLocalWUResult::setResultUnicode(const void *val, unsigned len)
- {
- // Note: we always serialize scalar strings with length prefix, and schema must reflect this
- MemoryBuffer m;
- m.append(len).append(len*2, val);
- p->setPropBin("Value", m.length(), m.toByteArray());
- setResultRowCount(1);
- setResultTotalRowCount(1);
- }
- void CLocalWUResult::setResultData(const void *val, unsigned len)
- {
- // Note: we always serialize scalar data with length prefix, and schema must reflect this
- MemoryBuffer m;
- serializeLPString(len, (const char *)val, m);
- p->setPropBin("Value", m.length(), m.toByteArray());
- setResultRowCount(1);
- setResultTotalRowCount(1);
- }
- void CLocalWUResult::setResultDecimal(const void *val, unsigned len)
- {
- // Note: serialized as data but with length known from schema
- MemoryBuffer m;
- serializeFixedData(len, val, m);
- p->setPropBin("Value", m.length(), m.toByteArray());
- setResultRowCount(1);
- setResultTotalRowCount(1);
- }
- void CLocalWUResult::setResultRow(unsigned len, const void * data)
- {
- p->setPropBin("Value", len, data);
- setResultRowCount(1);
- setResultTotalRowCount(1);
- setResultFormat(ResultFormatRaw);
- }
- void CLocalWUResult::setResultIsAll(bool value)
- {
- p->setPropBool("@isAll", value);
- }
- //==========================================================================================
- CLocalWUPlugin::CLocalWUPlugin(IPropertyTree *props) : p(props)
- {
- }
- IStringVal& CLocalWUPlugin::getPluginName(IStringVal &str) const
- {
- str.set(p->queryProp("@dllname"));
- return str;
- }
- IStringVal& CLocalWUPlugin::getPluginVersion(IStringVal &str) const
- {
- str.set(p->queryProp("@version"));
- return str;
- }
- void CLocalWUPlugin::setPluginName(const char *str)
- {
- p->setProp("@dllname", str);
- }
- void CLocalWUPlugin::setPluginVersion(const char *str)
- {
- p->setProp("@version", str);
- }
- //==========================================================================================
- CLocalWULibrary::CLocalWULibrary(IPropertyTree *props) : p(props)
- {
- }
- IStringVal& CLocalWULibrary::getName(IStringVal &str) const
- {
- str.set(p->queryProp("@name"));
- return str;
- }
- void CLocalWULibrary::setName(const char *str)
- {
- p->setProp("@name", str);
- }
- //==========================================================================================
- CLocalWUException::CLocalWUException(IPropertyTree *props) : p(props)
- {
- }
- IStringVal& CLocalWUException::getExceptionSource(IStringVal &str) const
- {
- str.set(p->queryProp("@source"));
- return str;
- }
- IStringVal& CLocalWUException::getExceptionMessage(IStringVal &str) const
- {
- str.set(p->queryProp(NULL));
- return str;
- }
- unsigned CLocalWUException::getExceptionCode() const
- {
- return p->getPropInt("@code", 0);
- }
- ErrorSeverity CLocalWUException::getSeverity() const
- {
- return (ErrorSeverity)p->getPropInt("@severity", SeverityError);
- }
- IStringVal & CLocalWUException::getTimeStamp(IStringVal & dt) const
- {
- dt.set(p->queryProp("@time"));
- return dt;
- }
- IStringVal & CLocalWUException::getExceptionFileName(IStringVal & str) const
- {
- str.set(p->queryProp("@filename"));
- return str;
- }
- unsigned CLocalWUException::getExceptionLineNo() const
- {
- return p->getPropInt("@row", 0);
- }
- unsigned CLocalWUException::getExceptionColumn() const
- {
- return p->getPropInt("@col", 0);
- }
- unsigned CLocalWUException::getSequence() const
- {
- return p->getPropInt("@sequence", 0);
- }
- void CLocalWUException::setExceptionSource(const char *str)
- {
- p->setProp("@source", str);
- }
- void CLocalWUException::setExceptionMessage(const char *str)
- {
- p->setProp(NULL, str);
- }
- void CLocalWUException::setExceptionCode(unsigned code)
- {
- p->setPropInt("@code", code);
- }
- void CLocalWUException::setSeverity(ErrorSeverity level)
- {
- p->setPropInt("@severity", level);
- }
- void CLocalWUException::setTimeStamp(const char *str)
- {
- p->setProp("@time", str);
- }
- void CLocalWUException::setExceptionFileName(const char *str)
- {
- p->setProp("@filename", str);
- }
- void CLocalWUException::setExceptionLineNo(unsigned r)
- {
- p->setPropInt("@row", r);
- }
- void CLocalWUException::setExceptionColumn(unsigned c)
- {
- p->setPropInt("@col", c);
- }
- //==========================================================================================
- CLocalWUAppValue::CLocalWUAppValue(IPropertyTree *props, unsigned child) : p(props)
- {
- StringAttrBuilder propPath(prop);
- propPath.append("*[").append(child).append("]");
- }
- const char * CLocalWUAppValue::queryApplication() const
- {
- return p->queryName();
- }
- const char * CLocalWUAppValue::queryName() const
- {
- IPropertyTree* val=p->queryPropTree(prop.str());
- if(val)
- return val->queryName();
- return ""; // Should not happen in normal usage
- }
- const char * CLocalWUAppValue::queryValue() const
- {
- return p->queryProp(prop.str());
- }
- //==========================================================================================
- CLocalWUStatistic::CLocalWUStatistic(IPropertyTree *props) : p(props)
- {
- }
- IStringVal & CLocalWUStatistic::getCreator(IStringVal & str) const
- {
- const char * creator = p->queryProp("@creator");
- str.set(creator);
- return str;
- }
- IStringVal & CLocalWUStatistic::getDescription(IStringVal & str, bool createDefault) const
- {
- const char * desc = p->queryProp("@desc");
- if (desc)
- {
- str.set(desc); // legacy and in case it is overridden
- }
- else if (createDefault)
- {
- StatisticKind kind = getKind();
- assertex(kind != StKindNone);
- const char * scope = p->queryProp("@scope");
- assertex(scope);
- //Clean up the format of the scope when converting it to a description
- StringBuffer descriptionText;
- if (streq(scope, GLOBAL_SCOPE))
- {
- const char * creator = p->queryProp("@creator");
- descriptionText.append(creator).append(":");
- queryLongStatisticName(descriptionText, kind);
- }
- else
- {
- loop
- {
- char c = *scope++;
- if (!c)
- break;
- if (c == ':')
- descriptionText.append(": ");
- else
- descriptionText.append(c);
- }
- if (kind != StTimeElapsed)
- queryLongStatisticName(descriptionText.append(": "), kind);
- }
- str.set(descriptionText);
- }
- else
- str.clear();
- return str;
- }
- IStringVal & CLocalWUStatistic::getType(IStringVal & str) const
- {
- StatisticKind kind = getKind();
- if (kind != StKindNone)
- str.set(queryStatisticName(kind));
- return str;
- }
- IStringVal & CLocalWUStatistic::getFormattedValue(IStringVal & str) const
- {
- StringBuffer formatted;
- formatStatistic(formatted, getValue(), getMeasure());
- str.set(formatted);
- return str;
- }
- StatisticCreatorType CLocalWUStatistic::getCreatorType() const
- {
- return queryCreatorType(p->queryProp("@c"));
- }
- StatisticScopeType CLocalWUStatistic::getScopeType() const
- {
- return queryScopeType(p->queryProp("@s"));
- }
- StatisticKind CLocalWUStatistic::getKind() const
- {
- return queryStatisticKind(p->queryProp("@kind"));
- }
- IStringVal & CLocalWUStatistic::getScope(IStringVal & str) const
- {
- const char * scope = p->queryProp("@scope");
- str.set(scope);
- return str;
- }
- StatisticMeasure CLocalWUStatistic::getMeasure() const
- {
- return queryMeasure(p->queryProp("@unit"));
- }
- unsigned __int64 CLocalWUStatistic::getValue() const
- {
- return p->getPropInt64("@value", 0);
- }
- unsigned __int64 CLocalWUStatistic::getCount() const
- {
- return p->getPropInt64("@count", 0);
- }
- unsigned __int64 CLocalWUStatistic::getMax() const
- {
- return p->getPropInt64("@max", 0);
- }
- unsigned __int64 CLocalWUStatistic::getTimestamp() const
- {
- return p->getPropInt64("@ts", 0);
- }
- bool CLocalWUStatistic::matches(const IStatisticsFilter * filter) const
- {
- if (!filter)
- return true;
- const char * creator = p->queryProp("@creator");
- const char * scope = p->queryProp("@scope");
- return filter->matches(getCreatorType(), creator, getScopeType(), scope, getMeasure(), getKind());
- }
- //==========================================================================================
- CLocalWULegacyTiming::CLocalWULegacyTiming(IPropertyTree *props) : p(props)
- {
- }
- IStringVal & CLocalWULegacyTiming::getCreator(IStringVal & str) const
- {
- str.clear();
- return str;
- }
- IStringVal & CLocalWULegacyTiming::getDescription(IStringVal & str, bool createDefault) const
- {
- str.set(p->queryProp("@name"));
- return str;
- }
- IStringVal & CLocalWULegacyTiming::getType(IStringVal & str) const
- {
- str.set(queryStatisticName(StTimeElapsed));
- return str;
- }
- IStringVal & CLocalWULegacyTiming::getFormattedValue(IStringVal & str) const
- {
- StringBuffer formatted;
- formatStatistic(formatted, getValue(), getMeasure());
- str.set(formatted);
- return str;
- }
- StatisticCreatorType CLocalWULegacyTiming::getCreatorType() const
- {
- return SCTunknown;
- }
- StatisticScopeType CLocalWULegacyTiming::getScopeType() const
- {
- return SSTnone;
- }
- StatisticKind CLocalWULegacyTiming::getKind() const
- {
- return StTimeElapsed;
- }
- IStringVal & CLocalWULegacyTiming::getScope(IStringVal & str) const
- {
- str.clear();
- return str;
- }
- StatisticMeasure CLocalWULegacyTiming::getMeasure() const
- {
- return SMeasureTimeNs;
- }
- unsigned __int64 CLocalWULegacyTiming::getValue() const
- {
- return p->getPropInt64("@duration", 0) * 1000000;
- }
- unsigned __int64 CLocalWULegacyTiming::getCount() const
- {
- return p->getPropInt64("@count", 0);
- }
- unsigned __int64 CLocalWULegacyTiming::getMax() const
- {
- return p->getPropInt64("@max", 0);
- }
- unsigned __int64 CLocalWULegacyTiming::getTimestamp() const
- {
- return 0;
- }
- bool CLocalWULegacyTiming::matches(const IStatisticsFilter * filter) const
- {
- if (!filter)
- return true;
- const char * creator = p->queryProp("@creator");
- const char * scope = p->queryProp("@scope");
- return filter->matches(SCTall, NULL, SSTall, NULL, getMeasure(), getKind());
- }
- //==========================================================================================
- extern WORKUNIT_API ILocalWorkUnit * createLocalWorkUnit(const char *xml)
- {
- Owned<CLocalWorkUnit> cw = new CLocalWorkUnit((ISecManager *) NULL, NULL);
- if (xml)
- cw->loadPTree(createPTreeFromXMLString(xml));
- else
- {
- Owned<IPropertyTree> p = createPTree("W_LOCAL");
- p->setProp("@xmlns:xsi", "http://www.w3.org/1999/XMLSchema-instance");
- cw->loadPTree(p.getClear());
- }
- ILocalWorkUnit* ret = QUERYINTERFACE(&cw->lockRemote(false), ILocalWorkUnit);
- return ret;
- }
- void exportWorkUnitToXMLWithHiddenPasswords(IPropertyTree *p, IIOStream &out, unsigned extraXmlFlags)
- {
- const char *name = p->queryName();
- if (!name)
- name = "__unnamed__";
- StringBuffer temp;
- writeStringToStream(out, appendPTreeOpenTag(temp, p, name, 1));
- Owned<IPropertyTreeIterator> elems = p->getElements("*", iptiter_sort);
- ForEach(*elems)
- {
- IPropertyTree &elem = elems->query();
- if (streq(elem.queryName(), "Parameters"))
- {
- writeStringToStream(out, appendPTreeOpenTag(temp.clear().append(' '), &elem, "Parameters", 2).append('\n'));
- Owned<IPropertyTreeIterator> params = elem.getElements("*", iptiter_sort);
- ForEach(*params)
- {
- IPropertyTree ¶m = params->query();
- const char *paramname = param.queryName();
- VStringBuffer xpath("Variables/Variable[@name='%s']/Format/@password", paramname);
- if (p->getPropBool(xpath))
- writeStringToStream(out, appendXMLTag(temp.clear().append(" "), paramname, "****").append('\n'));
- else
- {
- toXML(¶m, out, 2, XML_Format|XML_SortTags|extraXmlFlags);
- }
- }
- writeStringToStream(out, appendXMLCloseTag(temp.clear().append(' '), "Parameters").append('\n'));
- }
- else if (streq(elem.queryName(), "Variables"))
- {
- writeStringToStream(out, appendPTreeOpenTag(temp.clear().append(' '), &elem, "Variables", 2).append('\n'));
- Owned<IPropertyTreeIterator> vars = elem.getElements("*", iptiter_sort);
- ForEach(*vars)
- {
- Owned<IPropertyTree> var = LINK(&vars->query());
- if (var->getPropBool("Format/@password"))
- {
- var.setown(createPTreeFromIPT(var)); //copy and remove password values
- var->removeProp("Value");
- var->removeProp("xmlValue");
- }
- toXML(var, out, 2, XML_Format|XML_SortTags|extraXmlFlags);
- }
- writeStringToStream(out, appendXMLCloseTag(temp.clear().append(' '), "Variables").append('\n'));
- }
- else
- toXML(&elem, out, 1, XML_Format|XML_SortTags|extraXmlFlags);
- }
- writeStringToStream(out, appendXMLCloseTag(temp.clear(), name));
- }
- StringBuffer &exportWorkUnitToXMLWithHiddenPasswords(IPropertyTree *p, StringBuffer &str)
- {
- class CAdapter : public CInterface, implements IIOStream
- {
- StringBuffer &out;
- public:
- IMPLEMENT_IINTERFACE;
- CAdapter(StringBuffer &_out) : out(_out) { }
- virtual void flush() { }
- virtual size32_t read(size32_t len, void * data) { UNIMPLEMENTED; return 0; }
- virtual size32_t write(size32_t len, const void * data) { out.append(len, (const char *)data); return len; }
- } adapter(str);
- exportWorkUnitToXMLWithHiddenPasswords(p->queryBranch(NULL), adapter, 0);
- return str;
- }
- void exportWorkUnitToXMLFileWithHiddenPasswords(IPropertyTree *p, const char *filename, unsigned extraXmlFlags)
- {
- OwnedIFile ifile = createIFile(filename);
- OwnedIFileIO ifileio = ifile->open(IFOcreate);
- Owned<IIOStream> stream = createIOStream(ifileio);
- exportWorkUnitToXMLWithHiddenPasswords(p->queryBranch(NULL), *stream, extraXmlFlags);
- }
- extern WORKUNIT_API StringBuffer &exportWorkUnitToXML(const IConstWorkUnit *wu, StringBuffer &str, bool unpack, bool includeProgress, bool hidePasswords)
- {
- // MORE - queryPTree isn't really safe without holding CLocalWorkUnit::crit - really need to move these functions into CLocalWorkunit
- const IExtendedWUInterface *ewu = queryExtendedWU(wu);
- if (ewu)
- {
- Linked<IPropertyTree> p;
- if (unpack||includeProgress)
- p.setown(ewu->getUnpackedTree(includeProgress));
- else
- p.set(ewu->queryPTree());
- if (hidePasswords && p->hasProp("Variables/Variable[Format/@password]"))
- return exportWorkUnitToXMLWithHiddenPasswords(p, str);
- toXML(p, str, 0, XML_Format|XML_SortTags);
- }
- else
- str.append("Unrecognized workunit format");
- return str;
- }
- extern WORKUNIT_API void exportWorkUnitToXMLFile(const IConstWorkUnit *wu, const char * filename, unsigned extraXmlFlags, bool unpack, bool includeProgress, bool hidePasswords)
- {
- const IExtendedWUInterface *ewu = queryExtendedWU(wu);
- if (ewu)
- {
- Linked<IPropertyTree> p;
- if (unpack||includeProgress)
- p.setown(ewu->getUnpackedTree(includeProgress));
- else
- p.set(ewu->queryPTree());
- if (hidePasswords && p->hasProp("Variables/Variable[Format/@password]"))
- return exportWorkUnitToXMLFileWithHiddenPasswords(p, filename, extraXmlFlags);
- saveXML(filename, p, 0, XML_Format|XML_SortTags|extraXmlFlags);
- }
- else
- throw makeStringException(0, "Unrecognized workunit format");
- }
- extern WORKUNIT_API void submitWorkUnit(const char *wuid, const char *username, const char *password)
- {
- MemoryBuffer buffer;
- Owned<INamedQueueConnection> conn = createNamedQueueConnection(0); // MORE - security token?
- Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
- Owned<IWorkUnit> workunit = factory->updateWorkUnit(wuid);
- assertex(workunit);
- SCMStringBuffer token;
- createToken(wuid, username, password, token);
- workunit->setSecurityToken(token.str());
- StringAttr clusterName(workunit->queryClusterName());
- if (!clusterName.length())
- throw MakeStringException(WUERR_InvalidCluster, "No target cluster specified");
- workunit->commit();
- workunit.clear();
- Owned<IConstWUClusterInfo> clusterInfo = getTargetClusterInfo(clusterName.str());
- if (!clusterInfo)
- throw MakeStringException(WUERR_InvalidCluster, "Unknown cluster %s", clusterName.str());
- SCMStringBuffer serverQueue;
- clusterInfo->getServerQueue(serverQueue);
- assertex(serverQueue.length());
- Owned<IJobQueue> queue = createJobQueue(serverQueue.str());
- if (!queue.get())
- throw MakeStringException(WUERR_InvalidQueue, "Could not create workunit queue");
- IJobQueueItem *item = createJobQueueItem(wuid);
- queue->enqueue(item);
- }
- extern WORKUNIT_API void abortWorkUnit(const char *wuid)
- {
- StringBuffer xpath("/WorkUnitAborts/");
- xpath.append(wuid);
- Owned<IRemoteConnection> acon = querySDS().connect(xpath.str(), myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE, SDS_LOCK_TIMEOUT);
- acon->queryRoot()->setPropInt(NULL, 1);
- }
- extern WORKUNIT_API void secSubmitWorkUnit(const char *wuid, ISecManager &secmgr, ISecUser &secuser)
- {
- if (checkWuSecAccess(wuid, &secmgr, &secuser, SecAccess_Write, "Submit", true, true))
- submitWorkUnit(wuid, secuser.getName(), secuser.credentials().getPassword());
- }
- extern WORKUNIT_API void secAbortWorkUnit(const char *wuid, ISecManager &secmgr, ISecUser &secuser)
- {
- if (!checkWuSecAccess(wuid, &secmgr, &secuser, SecAccess_Write, "Submit", true, true))
- return;
- abortWorkUnit(wuid);
- Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid);
- if(!cw)
- return;
- WorkunitUpdate wu(&cw->lock());
- const char *abortBy = secuser.getName();
- if (abortBy && *abortBy)
- wu->setTracingValue("AbortBy", abortBy);
- wu->setTracingValueInt64("AbortTimeStamp", getTimeStampNowValue());
- }
- extern WORKUNIT_API void submitWorkUnit(const char *wuid, ISecManager *secmgr, ISecUser *secuser)
- {
- if (secmgr && secuser)
- return secSubmitWorkUnit(wuid, *secmgr, *secuser);
- if (secuser)
- return submitWorkUnit(wuid, secuser->getName(), secuser->credentials().getPassword());
- submitWorkUnit(wuid, "", "");
- }
- extern WORKUNIT_API void abortWorkUnit(const char *wuid, ISecManager *secmgr, ISecUser *secuser)
- {
- if (secmgr && secuser)
- return secAbortWorkUnit(wuid, *secmgr, *secuser);
- abortWorkUnit(wuid);
- }
- bool CLocalWorkUnit::hasWorkflow() const
- {
- return p->hasProp("Workflow");
- }
- unsigned CLocalWorkUnit::queryEventScheduledCount() const
- {
- CriticalBlock block(crit);
- if (p->hasProp("@eventScheduledCount"))
- return p->getPropInt("@eventScheduledCount", 0);
- else
- return p->getPropInt("Workflow/@eventScheduledCount", 0); // Legacy location for this setting
- }
- void CLocalWorkUnit::incEventScheduledCount()
- {
- CriticalBlock block(crit);
- p->setPropInt("@eventScheduledCount", queryEventScheduledCount()+1);
- }
- IPropertyTree * CLocalWorkUnit::queryWorkflowTree() const
- {
- CriticalBlock block(crit);
- return p->queryPropTree("Workflow");
- }
- IConstWorkflowItemIterator* CLocalWorkUnit::getWorkflowItems() const
- {
- // For this to be legally called, we must have the read-able interface. So we are already locked for (at least) read.
- CriticalBlock block(crit);
- if(!workflowIteratorCached)
- {
- assertex(!workflowIterator);
- Owned<IPropertyTree> s = p->getPropTree("Workflow");
- if(s)
- workflowIterator.setown(createWorkflowItemIterator(s));
- workflowIteratorCached = true;
- }
- return workflowIterator.getLink();
- }
- IWorkflowItemArray * CLocalWorkUnit::getWorkflowClone() const
- {
- unsigned count = 0;
- Owned<IConstWorkflowItemIterator> iter = getWorkflowItems();
- for(iter->first(); iter->isValid(); iter->next())
- count++;
- Owned<IWorkflowItemArray> array = createWorkflowItemArray(count);
- for(iter->first(); iter->isValid(); iter->next())
- array->addClone(iter->query());
- return array.getLink();
- }
- IWorkflowItem * CLocalWorkUnit::addWorkflowItem(unsigned wfid, WFType type, WFMode mode, unsigned success, unsigned failure, unsigned recovery, unsigned retriesAllowed, unsigned contingencyFor)
- {
- // For this to be legally called, we must have the write-able interface. So we are already locked for write.
- CriticalBlock block(crit);
- workflowIterator.clear();
- workflowIteratorCached = false;
- IPropertyTree * s = p->queryPropTree("Workflow");
- if(!s)
- s = p->addPropTree("Workflow", createPTree("Workflow"));
- return createWorkflowItem(s, wfid, type, mode, success, failure, recovery, retriesAllowed, contingencyFor);
- }
- IWorkflowItemIterator * CLocalWorkUnit::updateWorkflowItems()
- {
- // For this to be legally called, we must have the write-able interface. So we are already locked for write.
- CriticalBlock block(crit);
- if(!workflowIterator)
- {
- IPropertyTree * s = p->queryPropTree("Workflow");
- if(!s)
- s = p->addPropTree("Workflow", createPTree("Workflow"));
- workflowIterator.setown(createWorkflowItemIterator(s));
- workflowIteratorCached = true;
- }
- return workflowIterator.getLink();
- }
- void CLocalWorkUnit::syncRuntimeWorkflow(IWorkflowItemArray * array)
- {
- Owned<IWorkflowItemIterator> iter = updateWorkflowItems();
- Owned<IWorkflowItem> item;
- for(iter->first(); iter->isValid(); iter->next())
- {
- item.setown(iter->get());
- item->syncRuntimeData(array->queryWfid(item->queryWfid()));
- }
- workflowIterator.clear();
- workflowIteratorCached = false;
- }
- void CLocalWorkUnit::resetWorkflow()
- {
- if (hasWorkflow())
- {
- Owned<IWorkflowItemIterator> iter = updateWorkflowItems();
- Owned<IWorkflowItem> wf;
- for(iter->first(); iter->isValid(); iter->next())
- {
- wf.setown(iter->get());
- wf->reset();
- }
- workflowIterator.clear();
- workflowIteratorCached = false;
- }
- }
- void CLocalWorkUnit::schedule()
- {
- CriticalBlock block(crit);
- if(queryEventScheduledCount() == 0) return;
- switch(getState())
- {
- case WUStateCompleted:
- setState(WUStateWait);
- break;
- case WUStateFailed:
- case WUStateArchived:
- case WUStateAborting:
- case WUStateAborted:
- case WUStateScheduled:
- throw MakeStringException(WUERR_CannotSchedule, "Cannot schedule workunit in this state");
- }
- StringBuffer rootPath;
- rootPath.append("/Schedule/").append(queryClusterName());
- Owned<IRemoteConnection> conn = querySDS().connect(rootPath.str(), myProcessSession(), RTM_LOCK_WRITE | RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT);
- Owned<IPropertyTree> root = conn->getRoot();
- if(!root->hasChildren())
- {
- StringBuffer addPath;
- addPath.append("/Schedulers/").append(queryClusterName());
- Owned<IRemoteConnection> addConn = querySDS().connect(addPath.str(), myProcessSession(), RTM_LOCK_WRITE | RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT);
- }
- char const * wuid = p->queryName();
- StringBuffer xpath("*/*/");
- ncnameEscape(wuid, xpath);
- bool more;
- do more = root->removeProp(xpath.str()); while(more);
-
- Owned<IConstWorkflowItemIterator> iter = getWorkflowItems();
- Owned<IWorkflowEvent> event;
- Owned<IPropertyTree> branch1, branch2;
- for(iter->first(); iter->isValid(); iter->next())
- {
- event.setown(iter->query()->getScheduleEvent());
- if(!event) continue;
- ncnameEscape(event->queryName(), xpath.clear());
- ensurePTree(root, xpath.str());
- branch1.setown(root->getPropTree(xpath.str()));
- ncnameEscape(event->queryText(), xpath.clear());
- ensurePTree(branch1, xpath.str());
- branch2.setown(branch1->getPropTree(xpath.str()));
- ncnameEscape(wuid, xpath.clear());
- ensurePTree(branch2, xpath.str());
- }
- }
- void CLocalWorkUnit::deschedule()
- {
- if(queryEventScheduledCount() == 0) return;
- if(getState() == WUStateWait)
- setState(WUStateCompleted);
- doDescheduleWorkkunit(p->queryName());
- }
- mapEnums localFileUploadTypes[] = {
- { UploadTypeFileSpray, "FileSpray" },
- { UploadTypeWUResult, "WUResult" },
- { UploadTypeWUResultCsv, "WUResultCsv" },
- { UploadTypeWUResultXml, "WUResultXml" },
- { UploadTypeSize, NULL }
- };
- class CLocalFileUpload : public CInterface, implements IConstLocalFileUpload
- {
- public:
- CLocalFileUpload(IPropertyTree * _tree) : tree(_tree) {}
- CLocalFileUpload(unsigned id, LocalFileUploadType type, char const * source, char const * destination, char const * eventTag)
- {
- tree.setown(createPTree());
- tree->setPropInt("@id", id);
- setEnum(tree, "@type", type, localFileUploadTypes);
- tree->setProp("@source", source);
- tree->setProp("@destination", destination);
- if (eventTag)
- tree->setProp("@eventTag", eventTag);
- }
- IMPLEMENT_IINTERFACE;
- IPropertyTree * getTree() { return tree.getLink(); }
- virtual unsigned queryID() const { return tree->getPropInt("@id"); }
- virtual LocalFileUploadType queryType() const { return (LocalFileUploadType)getEnum(tree, "@type", localFileUploadTypes); }
- virtual IStringVal & getSource(IStringVal & ret) const { ret.set(tree->queryProp("@source")); return ret; }
- virtual IStringVal & getDestination(IStringVal & ret) const { ret.set(tree->queryProp("@destination")); return ret; }
- virtual IStringVal & getEventTag(IStringVal & ret) const { if(tree->hasProp("@eventTag")) ret.set(tree->queryProp("@eventTag")); else ret.clear(); return ret; }
- private:
- Owned<IPropertyTree> tree;
- };
- class CLocalFileUploadIterator : public CInterface, implements IConstLocalFileUploadIterator
- {
- public:
- CLocalFileUploadIterator(IPropertyTree * _tree) : tree(_tree), iter(tree->getElements("LocalFileUpload")) {}
- IMPLEMENT_IINTERFACE;
- bool first() { return iter->first(); }
- bool isValid() { return iter->isValid(); }
- bool next() { return iter->next(); }
- IConstLocalFileUpload * get() { return new CLocalFileUpload(&iter->get()); }
- private:
- Owned<IPropertyTree> tree;
- Owned<IPropertyTreeIterator> iter;
- };
- IConstLocalFileUploadIterator * CLocalWorkUnit::getLocalFileUploads() const
- {
- // For this to be legally called, we must have the read-able interface. So we are already locked for (at least) read.
- CriticalBlock block(crit);
- Owned<IPropertyTree> s = p->getPropTree("LocalFileUploads");
- if(s)
- return new CLocalFileUploadIterator(s.getClear());
- else
- return NULL;
- }
- bool CLocalWorkUnit::requiresLocalFileUpload() const
- {
- SCMStringBuffer dest;
- Owned<IConstWUResult> result;
- Owned<IConstLocalFileUploadIterator> iter(getLocalFileUploads());
- if(!iter)
- return false;
- for(iter->first(); iter->isValid(); iter->next())
- {
- Owned<IConstLocalFileUpload> upload(iter->get());
- switch(upload->queryType())
- {
- case UploadTypeWUResult:
- case UploadTypeWUResultCsv:
- case UploadTypeWUResultXml:
- upload->getDestination(dest);
- result.setown(getResultByName(dest.str()));
- if(!result)
- return true;
- break;
- default:
- throw MakeStringException(WUERR_InvalidUploadFormat, "Unsupported local file upload type %s", getEnumText(upload->queryType(), localFileUploadTypes));
- }
- }
- return false;
- }
- unsigned CLocalWorkUnit::addLocalFileUpload(LocalFileUploadType type, char const * source, char const * destination, char const * eventTag)
- {
- // For this to be legally called, we must have the write-able interface. So we are already locked for write.
- CriticalBlock block(crit);
- IPropertyTree * s = p->queryPropTree("LocalFileUploads");
- if(!s)
- s = p->addPropTree("LocalFileUploads", createPTree());
- unsigned id = s->numChildren();
- Owned<CLocalFileUpload> upload = new CLocalFileUpload(id, type, source, destination, eventTag);
- s->addPropTree("LocalFileUpload", upload->getTree());
- return id;
- }
- IStringVal & CLocalWorkUnit::getAbortBy(IStringVal & str) const
- {
- CriticalBlock block(crit);
- str.set(p->queryProp("Tracing/AbortBy"));
- return str;
- }
- unsigned __int64 CLocalWorkUnit::getAbortTimeStamp() const
- {
- CriticalBlock block(crit);
- return p->getPropInt64("Tracing/AbortTimeStamp", 0);
- }
- #if 0
- void testConstWorkflow(IConstWorkflowItem * cwf, bool * okay, bool * dep)
- {
- DBGLOG("Test workflow const iface %u", cwf->queryWfid());
- unsigned deps = 0;
- Owned<IWorkflowDependencyIterator> diter;
- switch(cwf->queryWfid())
- {
- case 1:
- assertex(!cwf->isScheduled());
- assertex(cwf->queryType() == WFTypeNormal);
- assertex(cwf->queryState() == WFStateNull);
- diter.setown(cwf->getDependencies());
- for(diter->first(); diter->isValid(); diter->next())
- deps++;
- assertex(deps==0);
- okay[0] = true;
- break;
- case 2:
- assertex(!cwf->isScheduled());
- assertex(cwf->queryType() == WFTypeRecovery);
- assertex(cwf->queryState() == WFStateSkip);
- okay[1] = true;
- break;
- case 3:
- assertex(cwf->queryContingencyFor() == 4);
- okay[2] = true;
- break;
- case 4:
- assertex(cwf->isScheduled());
- assertex(cwf->queryType() == WFTypeNormal);
- assertex(cwf->queryState() == WFStateReqd);
- assertex(cwf->querySuccess() == 0);
- assertex(cwf->queryFailure() == 3);
- assertex(cwf->queryRecovery() == 2);
- assertex(cwf->queryRetriesAllowed() == 10);
- assertex(cwf->queryRetriesRemaining() == 10);
- diter.setown(cwf->getDependencies());
- for(diter->first(); diter->isValid(); diter->next())
- {
- dep[diter->query()-1] = true;
- deps++;
- }
- assertex(deps==2);
- assertex(dep[0]);
- assertex(dep[1]);
- okay[3] = true;
- break;
- case 5:
- assertex(cwf->isScheduled());
- assertex(!cwf->isScheduledNow());
- assertex(cwf->querySchedulePriority() == 75);
- assertex(cwf->queryScheduleCount() == 5);
- assertex(cwf->queryScheduleCountRemaining() == 5);
- okay[4] = true;
- break;
- case 6:
- assertex(cwf->isScheduled());
- assertex(!cwf->isScheduledNow());
- assertex(cwf->querySchedulePriority() == 25);
- assertex(!cwf->hasScheduleCount());
- okay[5] = true;
- break;
- default:
- assertex(!"unknown wfid in test");
- }
- }
- void testRuntimeWorkflow(IRuntimeWorkflowItem * rwf, bool * okay)
- {
- DBGLOG("Test workflow runtime iface %u", rwf->queryWfid());
- switch(rwf->queryWfid())
- {
- case 1:
- case 2:
- case 3:
- okay[rwf->queryWfid()-1] = true;
- break;
- case 4:
- {
- unsigned tries = 0;
- while(rwf->testAndDecRetries())
- tries++;
- assertex(tries == 10);
- assertex(rwf->queryRetriesRemaining() == 0);
- rwf->setState(WFStateFail);
- assertex(rwf->queryState() == WFStateFail);
- rwf->reset();
- assertex(rwf->queryRetriesRemaining() == 10);
- assertex(rwf->queryState() == WFStateReqd);
- }
- okay[3] = true;
- break;
- case 5:
- {
- assertex(rwf->queryScheduleCountRemaining() == 5);
- unsigned count = 0;
- do count++; while(rwf->decAndTestScheduleCountRemaining());
- assertex(count == 5);
- assertex(rwf->queryScheduleCountRemaining() == 0);
- rwf->reset();
- assertex(rwf->queryScheduleCountRemaining() == 5);
- }
- okay[4] = true;
- break;
- case 6:
- {
- assertex(!rwf->hasScheduleCount());
- unsigned count;
- for(count=0; count<20; count++)
- assertex(rwf->decAndTestScheduleCountRemaining());
- }
- okay[5] = true;
- break;
- default:
- assertex(!"unknown wfid in test");
- }
- }
- void testWorkflow()
- {
- DBGLOG("workunit.cpp : testWorkflow");
- CLocalWorkUnit wu("W-WF-TEST", 0, 0, 0);
- Owned<IWorkflowItem> wf;
- wf.setown(wu.addWorkflowItem(1, WFTypeNormal, 0, 0, 0, 0, 0));
- wf.setown(wu.addWorkflowItem(2, WFTypeRecovery, 0, 0, 0, 0, 0));
- wf.setown(wu.addWorkflowItem(3, WFTypeFailure, 0, 0, 0, 0, 4));
- wf.setown(wu.addWorkflowItem(4, WFTypeNormal, 0, 3, 2, 10, 0));
- wf->setScheduledNow();
- wf->addDependency(1);
- wf.setown(wu.addWorkflowItem(5, WFTypeNormal, 0, 0, 0, 0, 0));
- wf->setScheduledOn("test", "foo*");
- wf->setSchedulePriority(75);
- wf->setScheduleCount(5);
- wf.setown(wu.addWorkflowItem(6, WFTypeNormal, 0, 0, 0, 0, 0));
- wf->setScheduledOn("test", "bar*");
- wf->setSchedulePriority(25);
- unsigned const n = 6;
- bool okay[n];
- bool dep[n];
- unsigned i;
- for(i=0; i<n; i++)
- okay[i] = dep[i] = 0;
- Owned<IConstWorkflowItemIterator> citer(wu.getWorkflowItems());
- for(citer->first(); citer->isValid(); citer->next())
- testConstWorkflow(citer->query(), okay, dep);
- for(i=0; i<n; i++)
- {
- assertex(okay[i]);
- okay[i] = false;
- }
- Owned<IWorkflowItemIterator> miter(wu.updateWorkflowItems());
- for(miter->first(); miter->isValid(); miter->next())
- {
- Owned<IRuntimeWorkflowItem> rwf(miter->get());
- testRuntimeWorkflow(rwf, okay);
- }
- for(i=0; i<n; i++)
- {
- assertex(okay[i]);
- okay[i] = dep[i] = false;
- }
- Owned<IWorkflowItemArray> array(wu.getWorkflowClone());
- unsigned wfid;
- for(wfid = 1; array->isValid(wfid); wfid++)
- testConstWorkflow(&array->queryWfid(wfid), okay, dep);
- for(i=0; i<n; i++)
- {
- assertex(okay[i]);
- okay[i] = false;
- }
- for(wfid = 1; array->isValid(wfid); wfid++)
- testRuntimeWorkflow(&array->queryWfid(wfid), okay);
- for(i=0; i<n; i++)
- {
- assertex(okay[i]);
- okay[i] = false;
- }
- }
- #endif
- //------------------------------------------------------------------------------------------
- extern WUState waitForWorkUnitToComplete(const char * wuid, int timeout, bool returnOnWaitState)
- {
- return factory->waitForWorkUnit(wuid, (unsigned) timeout, false, returnOnWaitState);
- }
- extern WORKUNIT_API WUState secWaitForWorkUnitToComplete(const char * wuid, ISecManager &secmgr, ISecUser &secuser, int timeout, bool returnOnWaitState)
- {
- if (checkWuSecAccess(wuid, &secmgr, &secuser, SecAccess_Read, "Wait for Complete", false, true))
- return waitForWorkUnitToComplete(wuid, timeout, returnOnWaitState);
- return WUStateUnknown;
- }
- extern bool waitForWorkUnitToCompile(const char * wuid, int timeout)
- {
- switch(factory->waitForWorkUnit(wuid, (unsigned) timeout, true, true))
- {
- case WUStateCompiled:
- case WUStateCompleted:
- case WUStateWait:
- case WUStateUploadingFiles:
- return true;
- default:
- return false;
- }
- }
- extern WORKUNIT_API bool secWaitForWorkUnitToCompile(const char * wuid, ISecManager &secmgr, ISecUser &secuser, int timeout)
- {
- if (checkWuSecAccess(wuid, &secmgr, &secuser, SecAccess_Read, "Wait for Compile", false, true))
- return waitForWorkUnitToCompile(wuid, timeout);
- return false;
- }
- extern WORKUNIT_API bool secDebugWorkunit(const char * wuid, ISecManager &secmgr, ISecUser &secuser, const char *command, StringBuffer &response)
- {
- if (strnicmp(command, "<debug:", 7) == 0 && checkWuSecAccess(wuid, &secmgr, &secuser, SecAccess_Read, "Debug", false, true))
- {
- Owned<IConstWorkUnit> wu = factory->openWorkUnit(wuid, &secmgr, &secuser);
- SCMStringBuffer ip;
- unsigned port;
- port = wu->getDebugAgentListenerPort();
- wu->getDebugAgentListenerIP(ip);
- SocketEndpoint debugEP(ip.str(), port);
- Owned<ISocket> socket = ISocket::connect_timeout(debugEP, 1000);
- unsigned len = (size32_t)strlen(command);
- unsigned revlen = len;
- _WINREV(revlen);
- socket->write(&revlen, sizeof(revlen));
- socket->write(command, len);
- for (;;)
- {
- socket->read(&len, sizeof(len));
- _WINREV(len);
- if (len == 0)
- break;
- if (len & 0x80000000)
- {
- throwUnexpected();
- }
- char * mem = (char*) response.reserve(len);
- socket->read(mem, len);
- }
- return true;
- }
- return false;
- }
- void getSimpleResultType(IWUResult *r, Owned<ITypeInfo> &type)
- {
- TypeInfoArray types;
- StringAttrArray names;
- r->getSchema(types, names, NULL);
- if (types.ordinality()==1)
- type.set(&types.item(0));
- }
- bool isSuppliedParamScalar(IWUResult *r, IPropertyTree &curVal, Owned<ITypeInfo> &type)
- {
- if (!r->isResultScalar())
- return false;
- if (!curVal.hasChildren())
- return true;
- getSimpleResultType(r, type);
- return type && type->isScalar();
- }
- void updateSuppliedXmlParams(IWorkUnit * w)
- {
- Owned<const IPropertyTree> params = w->getXmlParams();
- if (!params)
- return;
- Owned<IPropertyTreeIterator> elems = params->getElements("*");
- ForEach(*elems)
- {
- IPropertyTree & curVal = elems->query();
- const char *name = curVal.queryName();
- Owned<IWUResult> r = updateWorkUnitResult(w, name, -1);
- if (r)
- {
- Owned<ITypeInfo> type;
- StringBuffer s;
- if (isSuppliedParamScalar(r, curVal, type))
- {
- curVal.getProp(".", s);
- r->setResultXML(s);
- r->setResultStatus(ResultStatusSupplied);
- }
- else
- {
- toXML(&curVal, s);
- if (!type)
- getSimpleResultType(r, type);
- bool isSet = (type && type->getTypeCode()==type_set);
- r->setResultRaw(s.length(), s.str(), isSet ? ResultFormatXmlSet : ResultFormatXml);
- }
- }
- else
- DBGLOG("WARNING: no matching variable in workunit for input parameter %s", name);
- }
- }
- IWUResult * updateWorkUnitResult(IWorkUnit * w, const char *name, unsigned sequence)
- {
- switch ((int)sequence)
- {
- case ResultSequenceStored:
- return w->updateVariableByName(name);
- case ResultSequencePersist:
- return w->updateGlobalByName(name);
- case ResultSequenceInternal:
- case ResultSequenceOnce:
- return w->updateTemporaryByName(name);
- default:
- return w->updateResultBySequence(sequence);
- }
- }
- IConstWUResult * getWorkUnitResult(IConstWorkUnit * w, const char *name, unsigned sequence)
- {
- switch ((int)sequence)
- {
- case ResultSequenceStored:
- return w->getVariableByName(name);
- case ResultSequencePersist:
- return w->getGlobalByName(name);
- case ResultSequenceInternal:
- case ResultSequenceOnce:
- return w->getTemporaryByName(name);
- default:
- if (name && name[0])
- return w->getResultByName(name);//name takes precedence over sequence
- else
- return w->getResultBySequence(sequence);
- }
- }
- extern WORKUNIT_API bool getWorkUnitCreateTime(const char *wuid,CDateTime &time)
- {
- if (wuid) {
- char prefchar;
- unsigned year,month,day,hour,min,sec;
- if (sscanf(wuid, "%c%4u%2u%2u-%2u%2u%2u", &prefchar, &year, &month, &day, &hour, &min, &sec)==7) {
- time.set(year, month, day, hour, min, sec, 0, true);
- // time.setDate(year, month, day);
- // time.setTime(hour, min, sec, 0, true); // for some reason time is local
- return true;
- }
- }
- return false;
- }
- extern WORKUNIT_API IStringVal& createToken(const char *wuid, const char *user, const char *password, IStringVal &str)
- {
- StringBuffer wu, token("X");
- wu.append(wuid).append(';').append(user).append(';').append(password);
- encrypt(token,wu.str());
- str.set(token.str());
- return str;
- }
- // This will be replaced by something more secure!
- extern WORKUNIT_API void extractToken(const char *token, const char *wuid, IStringVal &user, IStringVal &password)
- {
- if (token && *token)
- {
- StringBuffer wu;
- decrypt(wu, token+1);
- const char *finger = strchr(wu.str(),';');
- if (finger && strnicmp(wuid, wu.str(), finger-wu.str())==0)
- {
- const char *finger1 = strchr(++finger,';');
- if(finger1)
- {
- user.setLen(finger, (size32_t)(finger1-finger));
- finger1++;
- password.setLen(finger1, (size32_t)(wu.str() + wu.length() - finger1));
- return;
- }
- }
- throw MakeStringException(WUERR_InvalidSecurityToken, "Invalid call to extractToken");
- }
- }
- extern WORKUNIT_API WUState getWorkUnitState(const char* state)
- {
- return (WUState) getEnum(state, states);
- }
- const LogMsgCategory MCschedconn = MCprogress(1000); // Category used to inform about schedule synchronization
- class CWorkflowScheduleConnection : implements IWorkflowScheduleConnection, public CInterface
- {
- public:
- CWorkflowScheduleConnection(char const * wuid)
- {
- basexpath.append("/WorkflowSchedule/").append(wuid);
- flagxpath.append(basexpath.str()).append("/Active");
- }
- IMPLEMENT_IINTERFACE;
- virtual void lock()
- {
- LOG(MCschedconn, "Locking base schedule connection");
- baseconn.setown(querySDS().connect(basexpath.str(), myProcessSession(), RTM_CREATE_QUERY | RTM_LOCK_WRITE, INFINITE));
- if(!baseconn)
- throw MakeStringException(WUERR_ScheduleLockFailed, "Could not get base workflow schedule lock");
- }
- virtual void unlock()
- {
- LOG(MCschedconn, "Unlocking base schedule connection");
- baseconn.clear();
- }
- virtual void setActive()
- {
- LOG(MCschedconn, "Setting active flag in schedule connection");
- flagconn.setown(querySDS().connect(flagxpath.str(), myProcessSession(), RTM_CREATE | RTM_LOCK_WRITE | RTM_DELETE_ON_DISCONNECT, INFINITE));
- if(!flagconn)
- throw MakeStringException(WUERR_ScheduleLockFailed, "Could not get active workflow schedule lock");
- }
- virtual void resetActive()
- {
- LOG(MCschedconn, "Resetting active flag in schedule connection");
- flagconn.clear();
- }
- virtual bool queryActive()
- {
- return baseconn->queryRoot()->hasProp("Active");
- }
- virtual bool pull(IWorkflowItemArray * workflow)
- {
- assertex(baseconn);
- Owned<IPropertyTree> root = baseconn->getRoot();
- Owned<IPropertyTree> eventQueue = root->getPropTree("EventQueue");
- if(!eventQueue) return false;
- if(!eventQueue->hasProp("Item")) return false;
- {
- Owned<IPropertyTreeIterator> eventItems = eventQueue->getElements("Item");
- Owned<IPropertyTree> eventItem;
- Owned<IRuntimeWorkflowItemIterator> wfItems = workflow->getSequenceIterator();
- Owned<IRuntimeWorkflowItem> wfItem;
- for(eventItems->first(); eventItems->isValid(); eventItems->next())
- {
- eventItem.setown(&eventItems->get());
- const char * eventName = eventItem->queryProp("@name");
- const char * eventText = eventItem->queryProp("@text");
- for(wfItems->first(); wfItems->isValid(); wfItems->next())
- {
- wfItem.setown(wfItems->get());
- if(wfItem->queryState() != WFStateWait)
- continue;
- Owned<IWorkflowEvent> targetEvent = wfItem->getScheduleEvent();
- if(!targetEvent || !targetEvent->matches(eventName, eventText))
- continue;
- wfItem->setEvent(eventName, eventText);
- wfItem->setState(WFStateReqd);
- resetDependentsState(workflow, *wfItem);
- }
- }
- }
- bool more;
- do
- more = eventQueue->removeProp("Item");
- while(more);
- return true;
- }
- virtual void push(char const * name, char const * text)
- {
- assertex(baseconn);
- Owned<IPropertyTree> root = baseconn->getRoot();
- ensurePTree(root, "EventQueue");
- Owned<IPropertyTree> eventQueue = root->getPropTree("EventQueue");
- Owned<IPropertyTree> eventItem = createPTree();
- eventItem->setProp("@name", name);
- eventItem->setProp("@text", text);
- eventQueue->addPropTree("Item", eventItem.getLink());
- }
- virtual void remove()
- {
- if (baseconn)
- {
- baseconn->close(true);
- baseconn.clear();
- }
- }
- private:
- void resetItemStateAndDependents(IWorkflowItemArray * workflow, unsigned wfid) const
- {
- if (wfid)
- resetItemStateAndDependents(workflow, workflow->queryWfid(wfid));
- }
- void resetItemStateAndDependents(IWorkflowItemArray * workflow, IRuntimeWorkflowItem & item) const
- {
- switch(item.queryState())
- {
- case WFStateDone:
- case WFStateFail:
- {
- item.setState(WFStateNull);
- resetItemStateAndDependents(workflow, item.queryPersistWfid());
- resetDependentsState(workflow, item);
- break;
- }
- }
- }
- void resetDependentsState(IWorkflowItemArray * workflow, IRuntimeWorkflowItem & item) const
- {
- Owned<IWorkflowDependencyIterator> iter(item.getDependencies());
- for(iter->first(); iter->isValid(); iter->next())
- {
- IRuntimeWorkflowItem & dep = workflow->queryWfid(iter->query());
- resetItemStateAndDependents(workflow, dep);
- }
- }
- private:
- StringBuffer basexpath;
- StringBuffer flagxpath;
- Owned<IRemoteConnection> baseconn;
- Owned<IRemoteConnection> flagconn;
- };
- extern WORKUNIT_API IWorkflowScheduleConnection * getWorkflowScheduleConnection(char const * wuid)
- {
- return new CWorkflowScheduleConnection(wuid);
- }
- extern WORKUNIT_API IExtendedWUInterface * queryExtendedWU(IConstWorkUnit * wu)
- {
- return QUERYINTERFACE(wu, IExtendedWUInterface);
- }
- extern WORKUNIT_API const IExtendedWUInterface * queryExtendedWU(const IConstWorkUnit * wu)
- {
- return QUERYINTERFACE(wu, const IExtendedWUInterface);
- }
- extern WORKUNIT_API void addExceptionToWorkunit(IWorkUnit * wu, ErrorSeverity severity, const char * source, unsigned code, const char * text, const char * filename, unsigned lineno, unsigned column)
- {
- Owned<IWUException> we = wu->createException();
- we->setSeverity(severity);
- we->setExceptionMessage(text);
- if (source)
- we->setExceptionSource(source);
- if (code)
- we->setExceptionCode(code);
- if (filename)
- we->setExceptionFileName(filename);
- if (lineno)
- {
- we->setExceptionLineNo(lineno);
- if (column)
- we->setExceptionColumn(lineno);
- }
- }
- const char * skipLeadingXml(const char * text)
- {
- if (!text)
- return NULL;
- //skip utf8 BOM, probably excessive
- if (memcmp(text, UTF8_BOM, 3) == 0)
- text += 3;
- loop
- {
- if (isspace(*text))
- text++;
- else if (text[0] == '<' && text[1] == '?')
- {
- text += 2;
- loop
- {
- if (!*text) break;
- if (text[0] == '?' && text[1] == '>')
- {
- text += 2;
- break;
- }
- text++;
- }
- }
- else if (text[0] == '<' && text[1] == '!' && text[2] == '-' && text[3] == '-')
- {
- text += 4;
- loop
- {
- if (!*text) break;
- if (text[0] == '-' && text[1] == '-' && text[2] == '>')
- {
- text += 3;
- break;
- }
- text++;
- }
- }
- else
- break;
- }
- return text;
- }
- extern WORKUNIT_API bool isArchiveQuery(const char * text)
- {
- text = skipLeadingXml(text);
- if (!text)
- return false;
- const char * archivePrefix = "<Archive";
- return memicmp(text, archivePrefix, strlen(archivePrefix)) == 0;
- }
- extern WORKUNIT_API bool isQueryManifest(const char * text)
- {
- text = skipLeadingXml(text);
- if (!text)
- return false;
- const char * manifestPrefix = "<Manifest";
- return memicmp(text, manifestPrefix, strlen(manifestPrefix)) == 0;
- }
- //------------------------------------------------------------------------------
- // Named Alias helper function
- static IPropertyTree * resolveQueryByDll(IPropertyTree * queryRegistry, const char * dll)
- {
- StringBuffer xpath;
- xpath.append("Query[@dll=\"").append(dll).append("\"]");
- return queryRegistry->getPropTree(xpath);
- }
- static IPropertyTree * resolveQueryByWuid(IPropertyTree * queryRegistry, const char * wuid)
- {
- StringBuffer xpath;
- xpath.append("Query[@wuid=\"").append(wuid).append("\"]");
- return queryRegistry->getPropTree(xpath);
- }
- static void clearAliases(IPropertyTree * queryRegistry, const char * id)
- {
- StringBuffer lcId(id);
- lcId.toLowerCase();
- StringBuffer xpath;
- xpath.append("Alias[@id=\"").append(lcId).append("\"]");
- Owned<IPropertyTreeIterator> iter = queryRegistry->getElements(xpath);
- ForEach(*iter)
- {
- queryRegistry->removeProp(xpath.str());
- }
- }
- IPropertyTree * addNamedQuery(IPropertyTree * queryRegistry, const char * name, const char * wuid, const char * dll, bool library, const char *userid, const char *snapshot)
- {
- StringBuffer lcName(name);
- lcName.toLowerCase();
- StringBuffer xpath;
- xpath.append("Query[@name=\"").append(lcName.str()).append("\"]");
- Owned<IPropertyTreeIterator> iter = queryRegistry->getElements(xpath);
- unsigned seq = 1;
- ForEach(*iter)
- {
- IPropertyTree &item = iter->query();
- const char *thisWuid = item.queryProp("@wuid");
- if (strieq(wuid, thisWuid))
- return &item;
- unsigned thisSeq = item.getPropInt("@seq");
- if (thisSeq >= seq)
- seq = thisSeq + 1;
- }
- StringBuffer id;
- id.append(lcName).append(".").append(seq);
- IPropertyTree * newEntry = createPTree("Query", ipt_caseInsensitive);
- newEntry->setProp("@name", lcName);
- newEntry->setProp("@wuid", wuid);
- newEntry->setProp("@dll", dll);
- newEntry->setProp("@id", id);
- newEntry->setPropInt("@seq", seq);
- if (library)
- newEntry->setPropBool("@isLibrary", true);
- if (userid && *userid)
- newEntry->setProp("@publishedBy", userid);
- if (snapshot && *snapshot)
- newEntry->setProp("@snapshot", snapshot);
- return queryRegistry->addPropTree("Query", newEntry);
- }
- void removeNamedQuery(IPropertyTree * queryRegistry, const char * id)
- {
- StringBuffer lcId(id);
- lcId.toLowerCase();
- clearAliases(queryRegistry, lcId);
- StringBuffer xpath;
- xpath.append("Query[@id=\"").append(lcId).append("\"]");
- queryRegistry->removeProp(xpath);
- }
- void removeDllFromNamedQueries(IPropertyTree * queryRegistry, const char * dll)
- {
- Owned<IPropertyTree> match = resolveQueryByDll(queryRegistry, dll);
- if (!match)
- return;
- clearAliases(queryRegistry, match->queryProp("@id"));
- queryRegistry->removeTree(match);
- }
- void removeWuidFromNamedQueries(IPropertyTree * queryRegistry, const char * wuid)
- {
- Owned<IPropertyTree> match = resolveQueryByWuid(queryRegistry, wuid);
- if (!match)
- return;
- clearAliases(queryRegistry, match->queryProp("@id"));
- queryRegistry->removeTree(match);
- }
- void removeAliasesFromNamedQuery(IPropertyTree * queryRegistry, const char * id)
- {
- clearAliases(queryRegistry, id);
- }
- void setQueryAlias(IPropertyTree * queryRegistry, const char * name, const char * value)
- {
- StringBuffer lcName(name);
- lcName.toLowerCase();
- StringBuffer xpath;
- xpath.append("Alias[@name=\"").append(lcName).append("\"]");
- IPropertyTree * match = queryRegistry->queryPropTree(xpath);
- if (!match)
- {
- IPropertyTree * newEntry = createPTree("Alias");
- newEntry->setProp("@name", lcName);
- match = queryRegistry->addPropTree("Alias", newEntry);
- }
- match->setProp("@id", value);
- }
- extern WORKUNIT_API IPropertyTree * getQueryById(IPropertyTree * queryRegistry, const char *queryid)
- {
- if (!queryRegistry || !queryid)
- return NULL;
- StringBuffer xpath;
- xpath.append("Query[@id=\"").append(queryid).append("\"]");
- return queryRegistry->getPropTree(xpath);
- }
- extern WORKUNIT_API IPropertyTree * getQueryById(const char *queryset, const char *queryid, bool readonly)
- {
- Owned<IPropertyTree> queryRegistry = getQueryRegistry(queryset, readonly);
- return getQueryById(queryRegistry, queryid);
- }
- extern WORKUNIT_API IPropertyTree * resolveQueryAlias(IPropertyTree * queryRegistry, const char * alias)
- {
- if (!queryRegistry || !alias)
- return NULL;
- StringBuffer xpath;
- unsigned cnt = 0;
- StringBuffer lc(alias);
- const char * search = lc.toLowerCase().str();
- loop
- {
- xpath.set("Alias[@name='").append(search).append("']/@id");
- const char * queryId = queryRegistry->queryProp(xpath);
- if (!queryId)
- break;
- //Check for too many alias indirections.
- if (cnt++ > 10)
- return NULL;
- search = lc.set(queryId).toLowerCase().str();
- }
- return getQueryById(queryRegistry, search);
- }
- extern WORKUNIT_API IPropertyTree * resolveQueryAlias(const char *queryset, const char *alias, bool readonly)
- {
- Owned<IPropertyTree> queryRegistry = getQueryRegistry(queryset, readonly);
- return resolveQueryAlias(queryRegistry, alias);
- }
- void setQuerySuspendedState(IPropertyTree * queryRegistry, const char *id, bool suspend, const char *userid)
- {
- StringBuffer lcId(id);
- lcId.toLowerCase();
- StringBuffer xpath;
- xpath.append("Query[@id=\"").append(lcId).append("\"]");
- IPropertyTree *tree = queryRegistry->queryPropTree(xpath);
- if (tree)
- {
- if (tree->getPropBool("@suspended", false) == suspend)
- return;
- if (suspend)
- {
- tree->addPropBool("@suspended", true);
- if (userid && *userid)
- tree->addProp("@suspendedBy", userid);
- }
- else
- {
- tree->removeProp("@suspended");
- tree->removeProp("@suspendedBy");
- }
- }
- else
- throw MakeStringException((suspend)? QUERRREG_SUSPEND : QUERRREG_UNSUSPEND, "Modifying query suspended state failed. Could not find query %s", id);
- }
- void setQueryCommentForNamedQuery(IPropertyTree * queryRegistry, const char *id, const char *queryComment)
- {
- if (queryComment)
- {
- StringBuffer lcId(id);
- lcId.toLowerCase();
- StringBuffer xpath;
- xpath.append("Query[@id=\"").append(lcId).append("\"]");
- IPropertyTree *tree = queryRegistry->queryPropTree(xpath);
- if (tree)
- tree->setProp("@queryComment", queryComment);
- else
- throw MakeStringException(QUERRREG_COMMENT, "Could not find query %s", id);
- }
- }
- extern WORKUNIT_API IPropertyTree * getQueryRegistryRoot()
- {
- Owned<IRemoteConnection> conn = querySDS().connect("/QuerySets", myProcessSession(), RTM_LOCK_READ, SDS_LOCK_TIMEOUT);
- if (conn)
- return conn->getRoot();
- else
- return NULL;
- }
- extern WORKUNIT_API void checkAddLibrariesToQueryEntry(IPropertyTree *queryTree, IConstWULibraryIterator *libraries)
- {
- if (!queryTree || !libraries)
- return;
- if (queryTree->hasProp("@libCount")) //already added
- return;
- unsigned libCount=0;
- ForEach(*libraries)
- {
- IConstWULibrary &library = libraries->query();
- SCMStringBuffer libname;
- if (!library.getName(libname).length())
- continue;
- queryTree->addProp("Library", libname.str());
- libCount++;
- }
- queryTree->setPropInt("@libCount", libCount);
- }
- extern WORKUNIT_API void checkAddLibrariesToQueryEntry(IPropertyTree *queryTree, IConstWorkUnit *cw)
- {
- Owned<IConstWULibraryIterator> libraries = &cw->getLibraries();
- checkAddLibrariesToQueryEntry(queryTree, libraries);
- }
- extern WORKUNIT_API IPropertyTree * getQueryRegistry(const char * wsEclId, bool readonly)
- {
- //Only lock the branch for the target we're interested in.
- StringBuffer xpath;
- xpath.append("/QuerySets/QuerySet[@id=\"").append(wsEclId).append("\"]");
- Owned<IRemoteConnection> conn = querySDS().connect(xpath.str(), myProcessSession(), readonly ? RTM_LOCK_READ : RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT);
- if (conn)
- return conn->getRoot();
- if (readonly)
- return NULL;
- //Lock the QuerySets in case another thread/client wants to check/add the same QuerySet.
- Owned<IRemoteConnection> globalLock = querySDS().connect("/QuerySets/", myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT);
- //Re-check if the QuerySet has been added between checking the 1st time and gaining the globalLock.
- conn.setown(querySDS().connect(xpath.str(), myProcessSession(), RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT));
- if (conn)
- return conn->getRoot();
- conn.setown(querySDS().connect("/QuerySets/QuerySet", myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_ADD, SDS_LOCK_TIMEOUT));
- if (!conn)
- throwUnexpected();
- IPropertyTree * root = conn->queryRoot();
- root->setProp("@id",wsEclId);
- conn->commit();
- return LINK(root);
- }
- IPropertyTree * addNamedPackageSet(IPropertyTree * packageRegistry, const char * name, IPropertyTree *packageInfo, bool overWrite)
- {
- StringBuffer xpath;
- StringBuffer lcName(name);
- lcName.toLowerCase();
- // see if "name" already exists
- xpath.append("Package[@id='").append(name).append("']");
- IPropertyTree *pkgTree = packageRegistry->queryPropTree(xpath.str());
- if (pkgTree)
- {
- if (overWrite)
- packageRegistry->removeTree(pkgTree);
- else
- throw MakeStringException(WUERR_PackageAlreadyExists, "Package name %s already exists, either delete it or specify overwrite",name);
- }
-
- IPropertyTree *tree = packageRegistry->addPropTree("Package", packageInfo);
- tree->setProp("@id", lcName);
- return tree;
- }
- void removeNamedPackage(IPropertyTree * packageRegistry, const char * id)
- {
- StringBuffer lcId(id);
- lcId.toLowerCase();
- StringBuffer xpath;
- xpath.append("Package[@id=\"").append(lcId).append("\"]");
- packageRegistry->removeProp(xpath);
- }
- extern WORKUNIT_API IPropertyTree * getPackageSetRegistry(const char * wsEclId, bool readonly)
- {
- //Only lock the branch for the target we're interested in.
- StringBuffer xpath;
- xpath.append("/PackageSets/PackageSet[@id=\"").append(wsEclId).append("\"]");
- Owned<IRemoteConnection> conn = querySDS().connect(xpath.str(), myProcessSession(), readonly ? RTM_LOCK_READ : RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT);
- if (conn)
- return conn->getRoot();
- if (readonly)
- return NULL;
- //Lock the PackageSets in case another thread/client wants to check/add the same PackageSet.
- Owned<IRemoteConnection> globalLock = querySDS().connect("/PackageSets/", myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT);
- //Re-check if the PackageSet has been added between checking the 1st time and gaining the globalLock.
- conn.setown(querySDS().connect(xpath.str(), myProcessSession(), RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT));
- if (conn)
- return conn->getRoot();
- conn.setown(querySDS().connect("/PackageSets/PackageSet", myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_ADD, SDS_LOCK_TIMEOUT));
- if (!conn)
- throwUnexpected();
- IPropertyTree* root = conn->queryRoot();
- root->setProp("@id",wsEclId);
- conn->commit();
- return LINK(root);
- }
- void addQueryToQuerySet(IWorkUnit *workunit, IPropertyTree *queryRegistry, const char *queryName, WUQueryActivationOptions activateOption, StringBuffer &newQueryId, const char *userid)
- {
- StringBuffer cleanQueryName;
- appendUtf8XmlName(cleanQueryName, strlen(queryName), queryName);
- SCMStringBuffer dllName;
- Owned<IConstWUQuery> q = workunit->getQuery();
- q->getQueryDllName(dllName);
- if (!dllName.length())
- throw MakeStringException(WUERR_InvalidDll, "Cannot deploy query - no associated dll.");
- StringBuffer currentTargetClusterType;
- queryRegistry->getProp("@targetclustertype", currentTargetClusterType);
- SCMStringBuffer targetClusterType;
- workunit->getDebugValue("targetclustertype", targetClusterType);
- SCMStringBuffer snapshot;
- workunit->getSnapshot(snapshot);
- if (currentTargetClusterType.length() < 1)
- {
- queryRegistry->setProp("@targetclustertype", targetClusterType.str());
- }
- else
- {
- if (strcmp(currentTargetClusterType.str(), "roxie") == 0 && strcmp(currentTargetClusterType.str(), targetClusterType.str())!=0)
- {
- throw MakeStringException(WUERR_MismatchClusterType, "TargetClusterTypes of workunit and queryset do not match.");
- }
- }
- IPropertyTree *newEntry = addNamedQuery(queryRegistry, cleanQueryName, workunit->queryWuid(), dllName.str(), isLibrary(workunit), userid, snapshot.str());
- Owned<IConstWULibraryIterator> libraries = &workunit->getLibraries();
- checkAddLibrariesToQueryEntry(newEntry, libraries);
- newQueryId.append(newEntry->queryProp("@id"));
- workunit->setIsQueryService(true); //will check querysets before delete
- workunit->commit();
- activateQuery(queryRegistry, activateOption, queryName, newQueryId, userid);
- }
- void activateQuery(IPropertyTree *queryRegistry, WUQueryActivationOptions activateOption, const char *queryName, const char *queryId, const char *userid)
- {
- StringBuffer cleanQueryName;
- appendUtf8XmlName(cleanQueryName, strlen(queryName), queryName);
- if (activateOption == ACTIVATE_SUSPEND_PREVIOUS|| activateOption == ACTIVATE_DELETE_PREVIOUS)
- {
- Owned<IPropertyTree> prevQuery = resolveQueryAlias(queryRegistry, cleanQueryName);
- setQueryAlias(queryRegistry, cleanQueryName, queryId);
- if (prevQuery && !streq(queryId, prevQuery->queryProp("@id")))
- {
- if (activateOption == ACTIVATE_SUSPEND_PREVIOUS)
- setQuerySuspendedState(queryRegistry, prevQuery->queryProp("@id"), true, userid);
- else
- removeNamedQuery(queryRegistry, prevQuery->queryProp("@id"));
- }
- }
- else if (activateOption == MAKE_ACTIVATE || activateOption == MAKE_ACTIVATE_LOAD_DATA_ONLY)
- setQueryAlias(queryRegistry, cleanQueryName, queryId);
- }
- void addQueryToQuerySet(IWorkUnit *workunit, const char *querySetName, const char *queryName, WUQueryActivationOptions activateOption, StringBuffer &newQueryId, const char *userid)
- {
- Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySetName, false);
- addQueryToQuerySet(workunit, queryRegistry, queryName, activateOption, newQueryId, userid);
- }
- bool removeQuerySetAlias(const char *querySetName, const char *alias)
- {
- Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySetName, true);
- StringBuffer xpath;
- xpath.appendf("Alias[@name='%s']", alias);
- IPropertyTree *t = queryRegistry->queryPropTree(xpath);
- return queryRegistry->removeTree(t);
- }
- void addQuerySetAlias(const char *querySetName, const char *alias, const char *id)
- {
- Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySetName, false);
- setQueryAlias(queryRegistry, alias, id);
- }
- void setSuspendQuerySetQuery(const char *querySetName, const char *id, bool suspend, const char *userid)
- {
- Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySetName, true);
- setQuerySuspendedState(queryRegistry, id, suspend, userid);
- }
- void deleteQuerySetQuery(const char *querySetName, const char *id)
- {
- Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySetName, true);
- removeNamedQuery(queryRegistry, id);
- }
- void removeQuerySetAliasesFromNamedQuery(const char *querySetName, const char * id)
- {
- Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySetName, true);
- clearAliases(queryRegistry, id);
- }
- void setQueryCommentForNamedQuery(const char *querySetName, const char *id, const char *queryComment)
- {
- Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySetName, true);
- setQueryCommentForNamedQuery(queryRegistry, id, queryComment);
- }
- const char *queryIdFromQuerySetWuid(IPropertyTree *queryRegistry, const char *wuid, const char *queryName, IStringVal &id)
- {
- if (!queryRegistry)
- return NULL;
- StringBuffer xpath;
- xpath.appendf("Query[@wuid='%s']", wuid);
- if (queryName && *queryName)
- xpath.appendf("[@name='%s']", queryName);
- IPropertyTree *q = queryRegistry->queryPropTree(xpath.str());
- if (q)
- {
- id.set(q->queryProp("@id"));
- }
- return id.str();
- }
- const char *queryIdFromQuerySetWuid(const char *querySetName, const char *wuid, const char *queryName, IStringVal &id)
- {
- Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySetName, true);
- return queryIdFromQuerySetWuid(queryRegistry, wuid, queryName, id);
- }
- extern WORKUNIT_API void gatherLibraryNames(StringArray &names, StringArray &unresolved, IWorkUnitFactory &workunitFactory, IConstWorkUnit &cw, IPropertyTree *queryset)
- {
- Owned<IConstWULibraryIterator> wulibraries = &cw.getLibraries();
- ForEach(*wulibraries)
- {
- SCMStringBuffer libname;
- IConstWULibrary &wulibrary = wulibraries->query();
- wulibrary.getName(libname);
- if (names.contains(libname.str()) || unresolved.contains(libname.str()))
- continue;
- Owned<IPropertyTree> query = resolveQueryAlias(queryset, libname.str());
- if (query && query->getPropBool("@isLibrary"))
- {
- const char *wuid = query->queryProp("@wuid");
- Owned<IConstWorkUnit> libcw = workunitFactory.openWorkUnit(wuid);
- if (libcw)
- {
- names.appendUniq(libname.str());
- gatherLibraryNames(names, unresolved, workunitFactory, *libcw, queryset);
- continue;
- }
- }
- unresolved.appendUniq(libname.str());
- }
- }
- bool looksLikeAWuid(const char * wuid, const char firstChar)
- {
- if (!wuid)
- return false;
- if (wuid[0] != firstChar)
- return false;
- if (!isdigit(wuid[1]) || !isdigit(wuid[2]) || !isdigit(wuid[3]) || !isdigit(wuid[4]))
- return false;
- if (!isdigit(wuid[5]) || !isdigit(wuid[6]) || !isdigit(wuid[7]) || !isdigit(wuid[8]))
- return false;
- return (wuid[9]=='-');
- }
- IPropertyTree * resolveDefinitionInArchive(IPropertyTree * archive, const char * path)
- {
- IPropertyTree * module = archive;
- const char * dot = strrchr(path, '.');
- StringBuffer xpath;
- if (dot)
- {
- xpath.clear().append("Module[@key='").appendLower(dot-path, path).append("']");
- module = archive->queryPropTree(xpath);
- path = dot+1;
- }
- else
- module = archive->queryPropTree("Module[@key='']");
- if (!module)
- return NULL;
- xpath.clear().append("Attribute[@key='").appendLower(strlen(path), path).append("']");
- return module->queryPropTree(xpath);
- }
- extern WORKUNIT_API void associateLocalFile(IWUQuery * query, WUFileType type, const char * name, const char * description, unsigned crc, unsigned minActivity, unsigned maxActivity)
- {
- StringBuffer hostname;
- queryHostIP().getIpText(hostname);
- StringBuffer fullPathname;
- makeAbsolutePath(name, fullPathname);
- query->addAssociatedFile(type, fullPathname, hostname, description, crc, minActivity, maxActivity);
- }
- extern WORKUNIT_API void descheduleWorkunit(char const * wuid)
- {
- Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
- Owned<IWorkUnit> workunit = factory->updateWorkUnit(wuid);
- if(workunit)
- workunit->deschedule();
- else
- doDescheduleWorkkunit(wuid);
- }
- extern WORKUNIT_API void updateWorkunitTimeStat(IWorkUnit * wu, StatisticScopeType scopeType, const char * scope, StatisticKind kind, const char * description, unsigned __int64 value)
- {
- wu->setStatistic(queryStatisticsComponentType(), queryStatisticsComponentName(), scopeType, scope, kind, description, value, 1, 0, StatsMergeReplace);
- }
- extern WORKUNIT_API void updateWorkunitTimings(IWorkUnit * wu, ITimeReporter *timer)
- {
- StringBuffer scope;
- for (unsigned i = 0; i < timer->numSections(); i++)
- {
- StatisticScopeType scopeType= timer->getScopeType(i);
- timer->getScope(i, scope.clear());
- StatisticKind kind = timer->getTimerType(i);
- wu->setStatistic(queryStatisticsComponentType(), queryStatisticsComponentName(), scopeType, scope, kind, NULL, timer->getTime(i), timer->getCount(i), timer->getMaxTime(i), StatsMergeReplace);
- }
- }
- extern WORKUNIT_API void getWorkunitTotalTime(IConstWorkUnit* workunit, const char* creator, unsigned __int64 & totalTimeNs, unsigned __int64 & totalThisTimeNs)
- {
- StatisticsFilter summaryTimeFilter(SCTsummary, creator, SSTglobal, GLOBAL_SCOPE, SMeasureTimeNs, StTimeElapsed);
- Owned<IConstWUStatistic> totalThorTime = getStatistic(workunit, summaryTimeFilter);
- Owned<IConstWUStatistic> totalThisThorTime = workunit->getStatistic(queryStatisticsComponentName(), GLOBAL_SCOPE, StTimeElapsed);
- if (totalThorTime)
- totalTimeNs = totalThorTime->getValue();
- else
- totalTimeNs = 0;
- if (totalThisThorTime)
- totalThisTimeNs = totalThisThorTime->getValue();
- else
- totalThisTimeNs = 0;
- }
- extern WORKUNIT_API void addTimeStamp(IWorkUnit * wu, StatisticScopeType scopeType, const char * scope, StatisticKind kind)
- {
- wu->setStatistic(queryStatisticsComponentType(), queryStatisticsComponentName(), scopeType, scope, kind, NULL, getTimeStampNowValue(), 1, 0, StatsMergeAppend);
- }
- IConstWUStatistic * getStatistic(IConstWorkUnit * wu, const IStatisticsFilter & filter)
- {
- Owned<IConstWUStatisticIterator> iter = &wu->getStatistics(&filter);
- if (iter->first())
- return &OLINK(iter->query());
- return NULL;
- }
- class GlobalStatisticGatherer : public CInterfaceOf<IStatisticGatherer>
- {
- public:
- GlobalStatisticGatherer(IWorkUnit * _wu) : wu(_wu) {}
- virtual void beginScope(const StatsScopeId & id)
- {
- prevLenStack.append(scope.length());
- if (scope.length())
- scope.append(":");
- id.getScopeText(scope);
- scopeTypeStack.append(id.queryScopeType());
- }
- virtual void beginSubGraphScope(unsigned id)
- {
- StatsScopeId scopeId(SSTsubgraph, id);
- beginScope(scopeId);
- }
- virtual void beginActivityScope(unsigned id)
- {
- StatsScopeId scopeId(SSTactivity, id);
- beginScope(scopeId);
- }
- virtual void beginEdgeScope(unsigned id, unsigned oid)
- {
- StatsScopeId scopeId(SSTedge, id, oid);
- beginScope(scopeId);
- }
- virtual void endScope()
- {
- scope.setLength(prevLenStack.popGet());
- scopeTypeStack.pop();
- }
- virtual void addStatistic(StatisticKind kind, unsigned __int64 value)
- {
- StatisticScopeType scopeType = scopeTypeStack.ordinality() ? (StatisticScopeType)scopeTypeStack.tos() : SSTglobal;
- wu->setStatistic(queryStatisticsComponentType(), queryStatisticsComponentName(), scopeType, scope, kind, NULL, value, 1, 0, StatsMergeAppend);
- }
- virtual void updateStatistic(StatisticKind kind, unsigned __int64 value, StatsMergeAction mergeAction)
- {
- StatisticScopeType scopeType = scopeTypeStack.ordinality() ? (StatisticScopeType)scopeTypeStack.tos() : SSTglobal;
- wu->setStatistic(queryStatisticsComponentType(), queryStatisticsComponentName(), scopeType, scope, kind, NULL, value, 1, 0, mergeAction);
- }
- virtual IStatisticCollection * getResult()
- {
- return NULL;
- }
- protected:
- Linked<IWorkUnit> wu;
- StringBuffer scope;
- UnsignedArray prevLenStack;
- UnsignedArray scopeTypeStack;
- };
- IStatisticGatherer * createGlobalStatisticGatherer(IWorkUnit * wu)
- {
- return new GlobalStatisticGatherer(wu);
- }
- extern WORKUNIT_API IPropertyTree * getWUGraphProgress(const char * wuid, bool readonly)
- {
- if (!wuid || !*wuid)
- return NULL;
- VStringBuffer path("/GraphProgress/%s", wuid);
- Owned<IRemoteConnection> conn = querySDS().connect(path.str(),myProcessSession(),readonly ? RTM_LOCK_READ : RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT);
- if (conn)
- return conn->getRoot();
- else
- return NULL;
- }
|