dadfs.cpp 431 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #define da_decl DECL_EXPORT
  14. #include "platform.h"
  15. #include "jlib.hpp"
  16. #include "jfile.hpp"
  17. #include "jlzw.hpp"
  18. #include "jmisc.hpp"
  19. #include "jtime.hpp"
  20. #include "jregexp.hpp"
  21. #include "jexcept.hpp"
  22. #include "jsort.hpp"
  23. #include "jptree.hpp"
  24. #include "jbuff.hpp"
  25. #include "dafdesc.hpp"
  26. #include "dasds.hpp"
  27. #include "dasess.hpp"
  28. #include "daclient.hpp"
  29. #include "daserver.hpp"
  30. #include "dautils.hpp"
  31. #include "danqs.hpp"
  32. #include "mputil.hpp"
  33. #include "rmtfile.hpp"
  34. #include "dadfs.hpp"
  35. #include "eclhelper.hpp"
  36. #include "seclib.hpp"
  37. #ifdef _DEBUG
  38. //#define EXTRA_LOGGING
  39. //#define TRACE_LOCKS
  40. #endif
  41. #define SDS_CONNECT_TIMEOUT (1000*60*60*2) // better than infinite
  42. #define SDS_SUB_LOCK_TIMEOUT (10000)
  43. #define SDS_TRANSACTION_RETRY (60000)
  44. #define SDS_UPDATEFS_TIMEOUT (10000)
  45. #define DEFAULT_NUM_DFS_THREADS 30
  46. #define TIMEOUT_ON_CLOSEDOWN 120000 // On closedown, give up on trying to join a thread in CDaliDFSServer after two minutes
  47. #define MAX_PHYSICAL_DELETE_THREADS 1000
  48. #if _INTERNAL_EDITION == 1
  49. #ifndef _MSC_VER
  50. #warning Disabling Sub-file compatibility checking
  51. #endif
  52. #else
  53. #define SUBFILE_COMPATIBILITY_CHECKING
  54. #endif
  55. //#define PACK_ECL
  56. #define SDS_GROUPSTORE_ROOT "Groups" // followed by name
  57. class CDistributedFile;
  58. enum MDFSRequestKind
  59. {
  60. MDFS_ITERATE_FILES,
  61. MDFS_UNUSED1,
  62. MDFS_GET_FILE_TREE,
  63. MDFS_GET_GROUP_TREE,
  64. MDFS_SET_FILE_ACCESSED,
  65. MDFS_ITERATE_RELATIONSHIPS,
  66. MDFS_SET_FILE_PROTECT,
  67. MDFS_ITERATE_FILTEREDFILES,
  68. MDFS_ITERATE_FILTEREDFILES2,
  69. MDFS_MAX
  70. };
  71. // Mutex for physical operations (remove/rename)
  72. static CriticalSection physicalChange;
  73. #define MDFS_GET_FILE_TREE_V2 ((unsigned)1)
  74. static int strcompare(const void * left, const void * right)
  75. {
  76. const char * l = (const char *)left;
  77. const char * r = (const char *)right;
  78. return stricmp(l,r);
  79. }
  80. inline unsigned ipGroupDistance(const IpAddress &ip,const IGroup *grp)
  81. {
  82. if (!grp)
  83. return (unsigned)-1;
  84. return grp->distance(ip);
  85. }
  86. inline unsigned groupDistance(IGroup *grp1,IGroup *grp2)
  87. {
  88. if (grp1==grp2)
  89. return 0;
  90. if (!grp1||!grp2)
  91. return (unsigned)-1;
  92. return grp1->distance(grp2);
  93. }
  94. static StringBuffer &normalizeFormat(StringBuffer &in)
  95. {
  96. in.toLowerCase();
  97. for (unsigned i = 0;i<in.length();)
  98. {
  99. switch (in.charAt(i)) {
  100. case '-':
  101. case '_':
  102. case ' ':
  103. in.remove(i,1);
  104. break;
  105. default:
  106. i++;
  107. break;
  108. }
  109. }
  110. return in;
  111. }
  112. static StringBuffer &getAttrQueryStr(StringBuffer &str,const char *sub,const char *key,const char *name)
  113. {
  114. assertex(key[0]=='@');
  115. str.appendf("%s[%s=\"%s\"]",sub,key,name);
  116. return str;
  117. }
  118. static IPropertyTree *getNamedPropTree(IPropertyTree *parent,const char *sub,const char *key,const char *name,bool preload)
  119. { // no create
  120. if (!parent)
  121. return NULL;
  122. StringBuffer query;
  123. getAttrQueryStr(query,sub,key,name);
  124. if (preload)
  125. return parent->getBranch(query.str());
  126. return parent->getPropTree(query.str());
  127. }
  128. static IPropertyTree *addNamedPropTree(IPropertyTree *parent,const char *sub,const char *key,const char *name, IPropertyTree* init=NULL)
  129. {
  130. IPropertyTree* ret = init?createPTreeFromIPT(init):createPTree(sub);
  131. assertex(key[0]=='@');
  132. ret->setProp(key,name);
  133. ret = parent->addPropTree(sub,ret);
  134. return LINK(ret);
  135. }
  136. const char *normalizeLFN(const char *s,StringBuffer &tmp)
  137. {
  138. CDfsLogicalFileName dlfn;
  139. dlfn.set(s);
  140. return dlfn.get(tmp).str();
  141. }
  142. static IPropertyTree *getEmptyAttr()
  143. {
  144. return createPTree("Attr");
  145. }
  146. RemoteFilename &constructPartFilename(IGroup *grp,unsigned partno,unsigned partmax,const char *name,const char *partmask,const char *partdir,unsigned copy,ClusterPartDiskMapSpec &mspec,RemoteFilename &rfn)
  147. {
  148. partno--;
  149. StringBuffer tmp;
  150. if (!name||!*name) {
  151. if (!partmask||!*partmask) {
  152. partmask = "!ERROR!._$P$_of_$N$"; // could use logical tail name if I had it
  153. ERRLOG("No partmask for constructPartFilename");
  154. }
  155. name = expandMask(tmp,partmask,partno,partmax).str();
  156. }
  157. StringBuffer fullname;
  158. if (findPathSepChar(name)==NULL)
  159. addPathSepChar(fullname.append(partdir));
  160. fullname.append(name);
  161. unsigned n;
  162. unsigned d;
  163. mspec.calcPartLocation(partno,partmax,copy,grp?grp->ordinality():partmax,n,d);
  164. setReplicateFilename(fullname,d);
  165. SocketEndpoint ep;
  166. if (grp)
  167. ep=grp->queryNode(n).endpoint();
  168. rfn.setPath(ep,fullname.toLowerCase().str());
  169. return rfn;
  170. }
  171. inline void LOGPTREE(const char *title,IPropertyTree *pt)
  172. {
  173. StringBuffer buf;
  174. if (pt) {
  175. toXML(pt,buf);
  176. PROGLOG("%s:\n%s\n",title,buf.str());
  177. }
  178. else
  179. PROGLOG("%s : NULL",title);
  180. }
  181. inline void LOGFDESC(const char *title,IFileDescriptor *fdesc)
  182. {
  183. if (fdesc) {
  184. Owned<IPropertyTree> pt = fdesc->getFileTree();
  185. LOGPTREE(title,pt);
  186. }
  187. else
  188. PROGLOG("%s : NULL",title);
  189. }
  190. class DECL_EXCEPTION CDFS_Exception: implements IDFS_Exception, public CInterface
  191. {
  192. int errcode;
  193. StringAttr errstr;
  194. public:
  195. CDFS_Exception(int _errcode, const char *_errstr)
  196. : errstr(_errstr)
  197. {
  198. errcode = _errcode;
  199. }
  200. int errorCode() const { return errcode; }
  201. StringBuffer & errorMessage(StringBuffer &str) const
  202. {
  203. if (errcode==DFSERR_ok)
  204. return str;
  205. str.append("DFS Exception: ").append(errcode);
  206. switch(errcode) {
  207. case DFSERR_LogicalNameAlreadyExists:
  208. return str.append(": logical name ").append(errstr).append(" already exists");
  209. case DFSERR_CannotFindPartFileSize:
  210. return str.append(": Cannot find physical file size for ").append(errstr);
  211. case DFSERR_CannotFindPartFileCrc:
  212. return str.append(": Cannot find physical file crc for ").append(errstr);
  213. case DFSERR_LookupAccessDenied:
  214. return str.append(" Lookup access denied for scope ").append(errstr);
  215. case DFSERR_CreateAccessDenied:
  216. return str.append(" Create access denied for scope ").append(errstr);
  217. case DFSERR_PhysicalPartAlreadyExists:
  218. return str.append(": physical part ").append(errstr).append(" already exists");
  219. case DFSERR_PhysicalPartDoesntExist:
  220. return str.append(": physical part ").append(errstr).append(" doesnt exist");
  221. case DFSERR_ForeignDaliTimeout:
  222. return str.append(": Timeout connecting to Dali Server on ").append(errstr);
  223. case DFSERR_ClusterNotFound:
  224. return str.append(": Cluster not found: ").append(errstr);
  225. case DFSERR_ClusterAlreadyExists:
  226. return str.append(": Cluster already exists: ").append(errstr);
  227. case DFSERR_LookupConnectionTimout:
  228. return str.append(": Lookup connection timeout: ").append(errstr);
  229. case DFSERR_FailedToDeleteFile:
  230. return str.append(": Failed to delete file: ").append(errstr);
  231. }
  232. return str.append("Unknown DFS Exception");
  233. }
  234. MessageAudience errorAudience() const { return MSGAUD_user; }
  235. IMPLEMENT_IINTERFACE;
  236. };
  237. class CConnectLock
  238. {
  239. public:
  240. Owned<IRemoteConnection> conn;
  241. CConnectLock(const char *caller, const char *name, bool write, bool preload, bool hold, unsigned timeout)
  242. {
  243. unsigned start = msTick();
  244. bool first = true;
  245. loop
  246. {
  247. try
  248. {
  249. unsigned mode = write ? RTM_LOCK_WRITE : RTM_LOCK_READ;
  250. if (preload) mode |= RTM_SUB;
  251. if (hold) mode |= RTM_LOCK_HOLD;
  252. conn.setown(querySDS().connect(name, queryCoven().inCoven() ? 0 : myProcessSession(), mode, (timeout==INFINITE)?1000*60*5:timeout));
  253. #ifdef TRACE_LOCKS
  254. PROGLOG("%s: LOCKGOT(%x) %s %s",caller,(unsigned)(memsize_t)conn.get(),name,write?"WRITE":"");
  255. LogRemoteConn(conn);
  256. PrintStackReport();
  257. #endif
  258. break;
  259. }
  260. catch (ISDSException *e)
  261. {
  262. if (SDSExcpt_LockTimeout == e->errorCode())
  263. {
  264. #ifdef TRACE_LOCKS
  265. PROGLOG("%s: LOCKFAIL %s %s",caller,name,write?"WRITE":"");
  266. LogRemoteConn(conn);
  267. #endif
  268. unsigned tt = msTick()-start;
  269. if (timeout!=INFINITE) {
  270. StringBuffer tmp;
  271. e->errorMessage(tmp);
  272. CDFS_Exception *dfse = new CDFS_Exception(DFSERR_LookupConnectionTimout,tmp.str());
  273. e->Release();
  274. throw dfse;
  275. }
  276. WARNLOG("CConnectLock on %s waiting for %ds",name,tt/1000);
  277. if (first) {
  278. PrintStackReport();
  279. first = false;
  280. }
  281. if (tt>SDS_CONNECT_TIMEOUT)
  282. throw;
  283. e->Release();
  284. }
  285. else
  286. throw;
  287. }
  288. catch (IException *e) {
  289. StringBuffer tmp("CConnectLock ");
  290. tmp.append(caller).append(' ').append(name);
  291. EXCLOG(e, tmp.str());
  292. throw;
  293. }
  294. }
  295. }
  296. IRemoteConnection *detach()
  297. {
  298. #ifdef TRACE_LOCKS
  299. if (conn.get()) {
  300. PROGLOG("LOCKDETACH(%x)",(unsigned)(memsize_t)conn.get());
  301. LogRemoteConn(conn);
  302. }
  303. #endif
  304. return conn.getClear();
  305. }
  306. #ifdef TRACE_LOCKS
  307. ~CConnectLock()
  308. {
  309. if (conn.get()) {
  310. PROGLOG("LOCKDELETE(%x)",(unsigned)(memsize_t)conn.get());
  311. LogRemoteConn(conn);
  312. }
  313. }
  314. #endif
  315. };
  316. void ensureFileScope(const CDfsLogicalFileName &dlfn,unsigned timeout)
  317. {
  318. CConnectLock connlock("ensureFileScope",querySdsFilesRoot(),true,false,false,timeout);
  319. StringBuffer query;
  320. IPropertyTree *r = connlock.conn->getRoot();
  321. StringBuffer scopes;
  322. const char *s=dlfn.getScopes(scopes,true).str();
  323. loop {
  324. IPropertyTree *nr;
  325. const char *e = strstr(s,"::");
  326. query.clear();
  327. if (e)
  328. query.append(e-s,s);
  329. else
  330. query.append(s);
  331. nr = getNamedPropTree(r,queryDfsXmlBranchName(DXB_Scope),"@name",query.trim().toLowerCase().str(),false);
  332. if (!nr)
  333. nr = addNamedPropTree(r,queryDfsXmlBranchName(DXB_Scope),"@name",query.str());
  334. r->Release();
  335. if (!e) {
  336. ::Release(nr);
  337. break;
  338. }
  339. r = nr;
  340. s = e+2;
  341. }
  342. }
  343. void removeFileEmptyScope(const CDfsLogicalFileName &dlfn,unsigned timeout)
  344. {
  345. CConnectLock connlock("removeFileEmptyScope",querySdsFilesRoot(),true,false,false,timeout); //*1
  346. IPropertyTree *root = connlock.conn.get()?connlock.conn->queryRoot():NULL;
  347. if (!root)
  348. return;
  349. StringBuffer query;
  350. dlfn.makeScopeQuery(query.clear(),false);
  351. StringBuffer head;
  352. loop {
  353. if (query.length()) {
  354. const char *tail = splitXPath(query.str(),head.clear());
  355. if (!tail||!*tail)
  356. break;
  357. IPropertyTree *pt;
  358. if (head.length()) {
  359. query.set(head);
  360. pt = root->queryPropTree(query.str());
  361. }
  362. else
  363. pt = root;
  364. IPropertyTree *t = pt?pt->queryPropTree(tail):NULL;
  365. if (t) {
  366. if (t->hasChildren())
  367. break;
  368. pt->removeTree(t);
  369. if (root==pt)
  370. break;
  371. }
  372. else
  373. break;
  374. }
  375. else
  376. break;
  377. }
  378. }
  379. class CFileLockBase
  380. {
  381. IRemoteConnection *conn;
  382. protected:
  383. Owned<IRemoteConnection> lock;
  384. bool init(const char *lockPath, unsigned mode, IRemoteConnection *_conn, unsigned timeout, const char *msg)
  385. {
  386. conn = NULL;
  387. lock.clear();
  388. CTimeMon tm(timeout);
  389. loop
  390. {
  391. try
  392. {
  393. lock.setown(querySDS().connect(lockPath, myProcessSession(), mode, timeout>60000 ? 60000 : timeout));
  394. if (lock.get())
  395. {
  396. conn = _conn;
  397. return true;
  398. }
  399. return false;
  400. }
  401. catch (ISDSException *e)
  402. {
  403. if (SDSExcpt_LockTimeout != e->errorCode() || tm.timedout())
  404. throw;
  405. WARNLOG("CFileAttrLockBase(%s) blocked for %ds", msg, tm.elapsed()/1000);
  406. e->Release();
  407. }
  408. }
  409. }
  410. public:
  411. CFileLockBase()
  412. {
  413. conn = NULL;
  414. }
  415. ~CFileLockBase()
  416. {
  417. // if conn provided, 'lock' was just a surrogate for the owner connection, commit now to conn if write lock
  418. if (conn && lock)
  419. conn->commit();
  420. }
  421. IRemoteConnection *detach()
  422. {
  423. return lock.getClear();
  424. }
  425. void clear()
  426. {
  427. lock.clear();
  428. conn = NULL;
  429. }
  430. IPropertyTree *queryRoot() const
  431. {
  432. return lock.get() ? lock->queryRoot() : NULL;
  433. }
  434. };
  435. class CFileLock : protected CFileLockBase
  436. {
  437. protected:
  438. DfsXmlBranchKind kind;
  439. public:
  440. CFileLock()
  441. {
  442. kind = DXB_Internal;
  443. }
  444. bool init(const CDfsLogicalFileName &logicalName, DfsXmlBranchKind bkind, unsigned mode, unsigned timeout, const char *msg)
  445. {
  446. StringBuffer lockPath;
  447. logicalName.makeFullnameQuery(lockPath, bkind, true);
  448. if (CFileLockBase::init(lockPath, mode, NULL, timeout, msg))
  449. {
  450. kind = bkind;
  451. return true;
  452. }
  453. kind = DXB_Internal;
  454. return false;
  455. }
  456. bool init(const CDfsLogicalFileName &logicalName, unsigned mode, unsigned timeout, const char *msg)
  457. {
  458. StringBuffer lockPath;
  459. logicalName.makeFullnameQuery(lockPath, DXB_File, true);
  460. if (CFileLockBase::init(lockPath, mode, NULL, timeout, msg))
  461. {
  462. kind = DXB_File;
  463. return true;
  464. }
  465. // try super
  466. logicalName.makeFullnameQuery(lockPath.clear(), DXB_SuperFile, true);
  467. if (CFileLockBase::init(lockPath, mode, NULL, timeout, msg))
  468. {
  469. kind = DXB_SuperFile;
  470. return true;
  471. }
  472. kind = DXB_Internal;
  473. return false;
  474. }
  475. IRemoteConnection *detach() { return CFileLockBase::detach(); }
  476. IPropertyTree *queryRoot() const { return CFileLockBase::queryRoot(); }
  477. IRemoteConnection *queryConnection() const
  478. {
  479. return lock;
  480. }
  481. void clear()
  482. {
  483. CFileLockBase::clear();
  484. kind = DXB_Internal;
  485. }
  486. DfsXmlBranchKind getKind() const { return kind; }
  487. };
  488. class CFileSubLock : protected CFileLockBase
  489. {
  490. public:
  491. bool init(const CDfsLogicalFileName &logicalName, DfsXmlBranchKind bkind, unsigned mode, const char *subLock, IRemoteConnection *conn, unsigned timeout, const char *msg)
  492. {
  493. StringBuffer lockPath;
  494. logicalName.makeFullnameQuery(lockPath, bkind, true);
  495. lockPath.appendf("/%s", subLock);
  496. return CFileLockBase::init(lockPath, mode, conn, timeout, msg);
  497. }
  498. bool init(const CDfsLogicalFileName &logicalName, unsigned mode, const char *subLock, IRemoteConnection *conn, unsigned timeout, const char *msg)
  499. {
  500. StringBuffer lockPath;
  501. logicalName.makeFullnameQuery(lockPath, DXB_File, true);
  502. lockPath.appendf("/%s", subLock);
  503. if (CFileLockBase::init(lockPath, mode, conn, timeout, msg))
  504. return true;
  505. // try super
  506. logicalName.makeFullnameQuery(lockPath.clear(), DXB_SuperFile, true);
  507. return CFileLockBase::init(lockPath, mode, conn, timeout, msg);
  508. }
  509. };
  510. class CFileAttrLock : protected CFileSubLock
  511. {
  512. public:
  513. bool init(const CDfsLogicalFileName &logicalName, DfsXmlBranchKind bkind, unsigned mode, IRemoteConnection *conn, unsigned timeout, const char *msg)
  514. {
  515. return CFileSubLock::init(logicalName, bkind, mode, "Attr", conn, timeout, msg);
  516. }
  517. bool init(const CDfsLogicalFileName &logicalName, unsigned mode, IRemoteConnection *conn, unsigned timeout, const char *msg)
  518. {
  519. return CFileSubLock::init(logicalName, mode, "Attr", conn, timeout, msg);
  520. }
  521. IPropertyTree *queryRoot() const { return CFileSubLock::queryRoot(); }
  522. };
  523. class CFileLockCompound : protected CFileLockBase
  524. {
  525. public:
  526. bool init(const CDfsLogicalFileName &logicalName, unsigned mode, IRemoteConnection *conn, const char *subLock, unsigned timeout, const char *msg)
  527. {
  528. StringBuffer lockPath;
  529. if (subLock)
  530. lockPath.appendf("/_Locks/%s/", subLock);
  531. logicalName.makeXPathLName(lockPath);
  532. return CFileLockBase::init(lockPath, mode, conn, timeout, msg);
  533. }
  534. };
  535. class CFileSuperOwnerLock : protected CFileLockCompound
  536. {
  537. public:
  538. bool init(const CDfsLogicalFileName &logicalName, IRemoteConnection *conn, unsigned timeout, const char *msg)
  539. {
  540. return CFileLockCompound::init(logicalName, RTM_CREATE_QUERY | RTM_LOCK_WRITE | RTM_DELETE_ON_DISCONNECT, conn, "SuperOwnerLock", timeout, msg);
  541. }
  542. IRemoteConnection *detach()
  543. {
  544. return CFileLockCompound::detach();
  545. }
  546. bool initWithFileLock(const CDfsLogicalFileName &logicalName, unsigned timeout, const char *msg, CFileLock &fcl, unsigned fclmode)
  547. {
  548. // SuperOwnerLock while holding fcl
  549. IRemoteConnection *fclConn = fcl.queryConnection();
  550. if (!fclConn)
  551. return false; // throw ?
  552. CTimeMon tm(timeout);
  553. unsigned remaining = timeout;
  554. loop
  555. {
  556. try
  557. {
  558. if (init(logicalName, NULL, 0, msg))
  559. return true;
  560. else
  561. return false; // throw ?
  562. }
  563. catch (ISDSException *e)
  564. {
  565. if (SDSExcpt_LockTimeout != e->errorCode() || tm.timedout(&remaining))
  566. throw;
  567. e->Release();
  568. }
  569. // release lock
  570. {
  571. fclConn->changeMode(RTM_NONE, remaining);
  572. }
  573. tm.timedout(&remaining);
  574. unsigned stime = 1000 * (2+getRandom()%15); // 2-15 sec
  575. if (stime > remaining)
  576. stime = remaining;
  577. // let another get excl lock
  578. Sleep(stime);
  579. tm.timedout(&remaining);
  580. // get lock again (waiting for other to release excl)
  581. {
  582. fclConn->changeMode(fclmode, remaining);
  583. fclConn->reload();
  584. }
  585. }
  586. }
  587. };
  588. class CScopeConnectLock
  589. {
  590. CConnectLock *lock;
  591. public:
  592. CScopeConnectLock()
  593. {
  594. lock = NULL;
  595. }
  596. CScopeConnectLock(const char *caller, const CDfsLogicalFileName &lname, bool write, bool preload, bool hold, unsigned timeout)
  597. {
  598. lock = NULL;
  599. init(caller, lname, write, preload, hold, timeout);
  600. }
  601. ~CScopeConnectLock()
  602. {
  603. delete lock;
  604. }
  605. bool init(const char *caller, const CDfsLogicalFileName &lname, bool write, bool preload, bool hold, unsigned timeout)
  606. {
  607. delete lock;
  608. StringBuffer query;
  609. lname.makeScopeQuery(query,true);
  610. lock = new CConnectLock(caller, query.str(), write, preload,hold, timeout);
  611. if (lock->conn.get()==NULL)
  612. {
  613. delete lock;
  614. lock = NULL;
  615. ensureFileScope(lname);
  616. lock = new CConnectLock(caller, query.str(), write, preload, hold, timeout);
  617. }
  618. return lock->conn.get()!=NULL;
  619. }
  620. IRemoteConnection *detach()
  621. {
  622. return lock?lock->detach():NULL;
  623. }
  624. IRemoteConnection *conn()
  625. {
  626. return lock?lock->conn:NULL;
  627. }
  628. IPropertyTree *queryRoot()
  629. {
  630. return (lock&&lock->conn.get())?lock->conn->queryRoot():NULL;
  631. }
  632. void remove()
  633. {
  634. if (lock&&lock->conn.get())
  635. lock->conn->close(true);
  636. }
  637. IPropertyTree *queryFileRoot(const CDfsLogicalFileName &dlfn,DfsXmlBranchKind &bkind)
  638. {
  639. bool external;
  640. bool foreign;
  641. external = dlfn.isExternal();
  642. foreign = dlfn.isForeign();
  643. if (external||foreign)
  644. return NULL;
  645. IPropertyTree *sroot = queryRoot();
  646. if (!sroot)
  647. return NULL;
  648. StringBuffer tail;
  649. dlfn.getTail(tail);
  650. StringBuffer query;
  651. getAttrQueryStr(query,queryDfsXmlBranchName(DXB_File),"@name",tail.str());
  652. IPropertyTree *froot = sroot->queryPropTree(query.str());
  653. bkind = DXB_File;
  654. if (!froot) {
  655. // check for super file
  656. getAttrQueryStr(query.clear(),queryDfsXmlBranchName(DXB_SuperFile),"@name",tail.str());
  657. froot = sroot->queryPropTree(query.str());
  658. if (froot)
  659. bkind = DXB_SuperFile;
  660. }
  661. return froot;
  662. }
  663. };
  664. class CClustersLockedSection
  665. {
  666. Owned<IRemoteConnection> conn;
  667. public:
  668. CClustersLockedSection(CDfsLogicalFileName &dlfn, bool exclusive)
  669. {
  670. StringBuffer xpath;
  671. dlfn.makeFullnameQuery(xpath,DXB_File,true).append("/ClusterLock");
  672. /* Avoid RTM_CREATE_QUERY connect() if possible by making 1st call without. This is to avoid write contention caused by RTM_CREATE*
  673. * NB: RTM_CREATE_QUERY should probably only gain exclusive access in Dali if node is missing.
  674. */
  675. conn.setown(querySDS().connect(xpath.str(), myProcessSession(), exclusive ? RTM_LOCK_WRITE : RTM_LOCK_READ, SDS_CONNECT_TIMEOUT));
  676. if (!conn.get()) // NB: ClusterLock is now created at File create time, so this can only be true for pre-existing File's
  677. {
  678. conn.setown(querySDS().connect(xpath.str(), myProcessSession(), RTM_CREATE_QUERY | RTM_LOCK_WRITE, SDS_CONNECT_TIMEOUT));
  679. assertex(conn.get());
  680. if (!exclusive)
  681. conn->changeMode(RTM_LOCK_READ, SDS_CONNECT_TIMEOUT);
  682. }
  683. }
  684. };
  685. static void checkDfsReplyException(MemoryBuffer &mb)
  686. {
  687. if (mb.length()<=sizeof(int))
  688. return;
  689. if ((*(int *)mb.bufferBase()) == -1) { // exception indicator
  690. int i;
  691. mb.read(i);
  692. throw deserializeException(mb);
  693. }
  694. }
  695. static void foreignDaliSendRecv(const INode *foreigndali,CMessageBuffer &mb, unsigned foreigndalitimeout)
  696. {
  697. SocketEndpoint ep = foreigndali->endpoint();
  698. if (ep.port==0)
  699. ep.port = DALI_SERVER_PORT;
  700. Owned<IGroup> grp = createIGroup(1,&ep);
  701. Owned<ICommunicator> comm = createCommunicator(grp,true);
  702. if (!comm->verifyConnection(0,foreigndalitimeout)) {
  703. StringBuffer tmp;
  704. IDFS_Exception *e = new CDFS_Exception(DFSERR_ForeignDaliTimeout, foreigndali->endpoint().getUrlStr(tmp).str());
  705. throw e;
  706. }
  707. comm->sendRecv(mb,0,MPTAG_DFS_REQUEST);
  708. }
  709. static bool isLocalDali(const INode *foreigndali)
  710. {
  711. if (!foreigndali)
  712. return true;
  713. Owned<INode> node;
  714. SocketEndpoint ep = foreigndali->endpoint();
  715. if (ep.port==0) {
  716. ep.port = DALI_SERVER_PORT;
  717. node.setown(createINode(ep));
  718. foreigndali = node.get();
  719. }
  720. return queryCoven().inCoven((INode *)foreigndali);
  721. }
  722. class FileClusterInfoArray: public IArrayOf<IClusterInfo>
  723. {
  724. ClusterPartDiskMapSpec defaultmapping;
  725. bool singleclusteroverride;
  726. public:
  727. FileClusterInfoArray()
  728. {
  729. singleclusteroverride = false;
  730. }
  731. void clear()
  732. {
  733. IArrayOf<IClusterInfo>::kill();
  734. }
  735. unsigned getNames(StringArray &clusternames)
  736. {
  737. StringBuffer name;
  738. ForEachItem(i) {
  739. clusternames.append(item(i).getClusterLabel(name.clear()).str());
  740. if (singleclusteroverride)
  741. break;
  742. }
  743. return clusternames.ordinality();
  744. }
  745. unsigned find(const char *_clusterName)
  746. {
  747. StringAttr clusterName = _clusterName;
  748. clusterName.toLowerCase();
  749. StringBuffer name;
  750. ForEachItem(i) {
  751. if (strcmp(item(i).getClusterLabel(name.clear()).str(),clusterName)==0)
  752. return i;
  753. if (singleclusteroverride)
  754. break;
  755. }
  756. return NotFound;
  757. }
  758. IGroup *queryGroup(unsigned clusternum)
  759. {
  760. if (clusternum>=ordinality())
  761. return NULL;
  762. if (singleclusteroverride&&clusternum)
  763. return NULL;
  764. return item(clusternum).queryGroup();
  765. }
  766. IGroup *getGroup(unsigned clusternum)
  767. {
  768. IGroup *ret = queryGroup(clusternum);
  769. return LINK(ret);
  770. }
  771. unsigned copyNum(unsigned part,unsigned copy,unsigned maxparts, unsigned *replicate)
  772. {
  773. ForEachItem(i) {
  774. IGroup *g = queryGroup(i);
  775. unsigned cw = g?g->ordinality():1;
  776. unsigned mc = item(i).queryPartDiskMapping().numCopies(part,cw,maxparts);
  777. if (copy<mc) {
  778. if (replicate)
  779. *replicate = copy;
  780. return i;
  781. }
  782. copy -= mc;
  783. if (singleclusteroverride)
  784. break;
  785. }
  786. return NotFound;
  787. }
  788. ClusterPartDiskMapSpec &queryPartDiskMapping(unsigned clusternum)
  789. {
  790. if (clusternum>=ordinality()||(singleclusteroverride&&clusternum))
  791. return defaultmapping;
  792. return item(clusternum).queryPartDiskMapping();
  793. }
  794. void updatePartDiskMapping(unsigned clusternum,const ClusterPartDiskMapSpec &spec)
  795. {
  796. if (clusternum<ordinality())
  797. item(clusternum).queryPartDiskMapping() = spec;
  798. }
  799. StringBuffer &getName(unsigned clusternum,StringBuffer &name)
  800. {
  801. if (clusternum<ordinality())
  802. item(clusternum).getClusterLabel(name);
  803. return name;
  804. }
  805. void setPreferred(const char *clusters,CDfsLogicalFileName &lfname)
  806. {
  807. unsigned nc = ordinality();
  808. if (nc<=1)
  809. return;
  810. StringBuffer cname;
  811. StringArray clustlist;
  812. if (lfname.getCluster(cname).length())
  813. clustlist.append(cname.str());
  814. unsigned i;
  815. if (clusters) {
  816. loop {
  817. const char *s = clusters;
  818. while (*s&&(*s!=','))
  819. s++;
  820. if (s!=clusters) {
  821. cname.clear().append(s-clusters,clusters);
  822. for (i=0;i<clustlist.ordinality();i++)
  823. if (strcmp(clustlist.item(i),cname.str())==0)
  824. break;
  825. if (i==clustlist.ordinality())
  826. clustlist.append(cname.str());
  827. }
  828. if (!*s)
  829. break;
  830. clusters = s+1;
  831. }
  832. }
  833. if (clustlist.ordinality()==0) {
  834. // sort by closest to this node
  835. const IpAddress &myip = queryMyNode()->endpoint();
  836. unsigned *d=new unsigned[nc];
  837. for (i=0;i<nc;i++)
  838. d[i] = ipGroupDistance(myip,item(i).queryGroup());
  839. // bubble sort it - only a few
  840. for (i=0;i+1<nc;i++)
  841. for (unsigned j=0;j+i+1<nc;j++)
  842. if (d[j+1]<d[j]) {
  843. unsigned bd = d[j+1];
  844. d[j+1] = d[j];
  845. d[j] = bd;
  846. swap(j,j+1);
  847. }
  848. delete [] d;
  849. return;
  850. }
  851. Owned<IGroup> firstgrp;
  852. unsigned done = 0;
  853. StringBuffer name;
  854. StringBuffer name2;
  855. ForEachItemIn(ci,clustlist) {
  856. const char *cls = clustlist.item(ci);
  857. Owned<IGroup> grp = queryNamedGroupStore().lookup(cls);
  858. if (!grp) {
  859. ERRLOG("IDistributedFile::setPreferred - cannot find cluster %s",cls);
  860. return;
  861. }
  862. if (!firstgrp.get())
  863. firstgrp.set(grp);
  864. for (i=done;i<nc;i++) {
  865. IClusterInfo &info=item(i);
  866. if (stricmp(info.getClusterLabel(name2.clear()).str(),name.str())==0)
  867. break;
  868. IGroup *grp2 = info.queryGroup();
  869. if (grp2&&(grp->compare(grp2)!=GRdisjoint))
  870. break;
  871. }
  872. if (i<nc) {
  873. if (i) {
  874. Linked<IClusterInfo> tmp = &item(i);
  875. remove(i);
  876. add(*tmp.getClear(),done);
  877. }
  878. done++;
  879. if (done+1>=nc)
  880. break;
  881. }
  882. }
  883. if (done+1<nc) { // sort remaining by nearest to first group
  884. unsigned *d=new unsigned[nc]; // only use done to nc
  885. for (i=done;i<nc;i++)
  886. d[i] = groupDistance(firstgrp,item(i).queryGroup());
  887. // bubble sort it - only a few
  888. for (i=done;i+1<nc;i++)
  889. for (unsigned j=done;j+i+1<nc;j++)
  890. if (d[j+1]<d[j]) {
  891. unsigned bd = d[j+1];
  892. d[j+1] = d[j];
  893. d[j] = bd;
  894. swap(j,j+1);
  895. }
  896. delete [] d;
  897. }
  898. }
  899. void setSingleClusterOnly(bool set=true)
  900. {
  901. singleclusteroverride = set;
  902. }
  903. unsigned numCopies(unsigned part,unsigned maxparts)
  904. {
  905. unsigned ret = 0;
  906. ForEachItem(i) {
  907. IGroup *g = queryGroup(i);
  908. unsigned cw = g?g->ordinality():1;
  909. ret += item(i).queryPartDiskMapping().numCopies(part,cw,maxparts);
  910. if (singleclusteroverride)
  911. break;
  912. }
  913. return ret;
  914. }
  915. };
  916. // Internal extension of transaction interface, used to manipulate and track transaction
  917. interface IDistributedFileTransactionExt : extends IDistributedFileTransaction
  918. {
  919. virtual IUserDescriptor *queryUser()=0;
  920. virtual void descend()=0; // descend into a recursive call (can't autoCommit if depth is not zero)
  921. virtual void ascend()=0; // ascend back from the deep, one step at a time
  922. virtual void autoCommit()=0; // if transaction not active, commit straight away
  923. virtual void addAction(CDFAction *action)=0;
  924. virtual void addFile(IDistributedFile *file)=0;
  925. virtual void ensureFile(IDistributedFile *file)=0;
  926. virtual void clearFile(IDistributedFile *file)=0;
  927. virtual void clearFiles()=0;
  928. virtual void noteAddSubFile(IDistributedSuperFile *super, const char *superName, IDistributedFile *sub) = 0;
  929. virtual void noteRemoveSubFile(IDistributedSuperFile *super, IDistributedFile *sub) = 0;
  930. virtual void noteSuperSwap(IDistributedSuperFile *super1, IDistributedSuperFile *super2) = 0;
  931. virtual void clearSubFiles(IDistributedSuperFile *super) = 0;
  932. virtual void noteRename(IDistributedFile *file, const char *newName) = 0;
  933. virtual void validateAddSubFile(IDistributedSuperFile *super, IDistributedFile *sub, const char *subName) = 0;
  934. virtual bool isSubFile(IDistributedSuperFile *super, const char *subFile, bool sub) = 0;
  935. virtual bool addDelayedDelete(CDfsLogicalFileName &lfn,unsigned timeoutms=INFINITE)=0; // used internally to delay deletes until commit
  936. virtual bool prepareActions()=0;
  937. virtual void retryActions()=0;
  938. virtual void runActions()=0;
  939. virtual void commitAndClearup()=0;
  940. virtual ICodeContext *queryCodeContext()=0;
  941. };
  942. class CDistributedFileDirectory: implements IDistributedFileDirectory, public CInterface
  943. {
  944. Owned<IUserDescriptor> defaultudesc;
  945. Owned<IDFSredirection> redirection;
  946. void resolveForeignFiles(IPropertyTree *tree,const INode *foreigndali);
  947. protected: friend class CDistributedFile;
  948. StringAttr defprefclusters;
  949. unsigned defaultTimeout;
  950. public:
  951. IMPLEMENT_IINTERFACE;
  952. CDistributedFileDirectory()
  953. {
  954. defaultTimeout = INFINITE;
  955. defaultudesc.setown(createUserDescriptor());
  956. redirection.setown(createDFSredirection());
  957. }
  958. unsigned queryDefaultTimeout() const { return defaultTimeout; }
  959. IDistributedFile *dolookup(CDfsLogicalFileName &logicalname, IUserDescriptor *user, bool writeattr, bool hold, bool lockSuperOwner, IDistributedFileTransaction *transaction, unsigned timeout);
  960. IDistributedFile *lookup(const char *_logicalname, IUserDescriptor *user, bool writeattr, bool hold, bool lockSuperOwner, IDistributedFileTransaction *transaction, unsigned timeout);
  961. IDistributedFile *lookup(CDfsLogicalFileName &logicalname, IUserDescriptor *user, bool writeattr, bool hold, bool lockSuperOwner, IDistributedFileTransaction *transaction, unsigned timeout);
  962. /* createNew always creates an unnamed unattached distributed file
  963. * The caller must associated it with a name and credentials when it is attached (attach())
  964. */
  965. IDistributedFile *createNew(IFileDescriptor * fdesc);
  966. IDistributedFile *createExternal(IFileDescriptor *desc, const char *name);
  967. IDistributedSuperFile *createSuperFile(const char *logicalname,IUserDescriptor *user,bool interleaved,bool ifdoesnotexist,IDistributedFileTransaction *transaction=NULL);
  968. IDistributedSuperFile *createNewSuperFile(IPropertyTree *tree, const char *optionalName=nullptr);
  969. void removeSuperFile(const char *_logicalname, bool delSubs, IUserDescriptor *user, IDistributedFileTransaction *transaction);
  970. IDistributedFileIterator *getIterator(const char *wildname, bool includesuper,IUserDescriptor *user);
  971. IDFAttributesIterator *getDFAttributesIterator(const char *wildname, IUserDescriptor *user, bool recursive, bool includesuper,INode *foreigndali,unsigned foreigndalitimeout);
  972. IPropertyTreeIterator *getDFAttributesTreeIterator(const char *filters, DFUQResultField* localFilters, const char *localFilterBuf,
  973. IUserDescriptor *user, bool& allMatchingFilesReceived, INode *foreigndali,unsigned foreigndalitimeout);
  974. IDFAttributesIterator *getForeignDFAttributesIterator(const char *wildname, IUserDescriptor *user, bool recursive=true, bool includesuper=false, const char *foreigndali="", unsigned foreigndalitimeout=FOREIGN_DALI_TIMEOUT)
  975. {
  976. Owned<INode> foreign;
  977. if (foreigndali&&*foreigndali) {
  978. SocketEndpoint ep(foreigndali);
  979. foreign.setown(createINode(ep));
  980. }
  981. return getDFAttributesIterator(wildname, user, recursive, includesuper,foreign,foreigndalitimeout);
  982. }
  983. IDFScopeIterator *getScopeIterator(IUserDescriptor *user, const char *subscope,bool recursive,bool includeempty);
  984. bool loadScopeContents(const char *scopelfn,StringArray *scopes, StringArray *supers,StringArray *files, bool includeemptyscopes);
  985. IPropertyTree *getFileTree(const char *lname,IUserDescriptor *user,const INode *foreigndali,unsigned foreigndalitimeout,bool expandnodes=false, bool appendForeign=true);
  986. void setFileAccessed(CDfsLogicalFileName &dlfn, IUserDescriptor *user,const CDateTime &dt,const INode *foreigndali=NULL,unsigned foreigndalitimeout=FOREIGN_DALI_TIMEOUT);
  987. IFileDescriptor *getFileDescriptor(const char *lname,IUserDescriptor *user,const INode *foreigndali=NULL,unsigned foreigndalitimeout=FOREIGN_DALI_TIMEOUT);
  988. IDistributedFile *getFile(const char *lname,IUserDescriptor *user,const INode *foreigndali=NULL,unsigned foreigndalitimeout=FOREIGN_DALI_TIMEOUT);
  989. bool exists(const char *_logicalname,IUserDescriptor *user,bool notsuper=false,bool superonly=false);
  990. bool existsPhysical(const char *_logicalname,IUserDescriptor *user);
  991. void addEntry(CDfsLogicalFileName &lfn,IPropertyTree *root,bool superfile, bool ignoreexists);
  992. bool removeEntry(const char *name, IUserDescriptor *user, IDistributedFileTransaction *transaction=NULL, unsigned timeoutms=INFINITE, bool throwException=false);
  993. void renamePhysical(const char *oldname,const char *newname,IUserDescriptor *user,IDistributedFileTransaction *transaction);
  994. void removeEmptyScope(const char *name);
  995. IDistributedSuperFile *lookupSuperFile(const char *logicalname,IUserDescriptor *user,IDistributedFileTransaction *transaction,unsigned timeout=INFINITE);
  996. SecAccessFlags getFilePermissions(const char *lname,IUserDescriptor *user,unsigned auditflags);
  997. SecAccessFlags getNodePermissions(const IpAddress &ip,IUserDescriptor *user,unsigned auditflags);
  998. SecAccessFlags getFDescPermissions(IFileDescriptor *,IUserDescriptor *user,unsigned auditflags=0);
  999. void setDefaultUser(IUserDescriptor *user);
  1000. IUserDescriptor* queryDefaultUser();
  1001. DistributedFileCompareResult fileCompare(const char *lfn1,const char *lfn2,DistributedFileCompareMode mode,StringBuffer &errstr,IUserDescriptor *user);
  1002. bool filePhysicalVerify(const char *lfn1,IUserDescriptor *user,bool includecrc,StringBuffer &errstr);
  1003. void setDefaultPreferredClusters(const char *clusters);
  1004. void fixDates(IDistributedFile *fil);
  1005. GetFileClusterNamesType getFileClusterNames(const char *logicalname,StringArray &out); // returns 0 for normal file, 1 for
  1006. bool isSuperFile( const char *logicalname, IUserDescriptor *user=NULL, INode *foreigndali=NULL, unsigned timeout=0);
  1007. void promoteSuperFiles(unsigned numsf,const char **sfnames,const char *addsubnames,bool delsub,bool createonlyonesuperfile,IUserDescriptor *user, unsigned timeout, StringArray &outunlinked);
  1008. ISimpleSuperFileEnquiry * getSimpleSuperFileEnquiry(const char *logicalname,const char *title,IUserDescriptor *udesc,unsigned timeout);
  1009. bool getFileSuperOwners(const char *logicalname, StringArray &owners);
  1010. IDFSredirection & queryRedirection() { return *redirection; }
  1011. static StringBuffer &getFileRelationshipXPath(StringBuffer &xpath, const char *primary, const char *secondary,const char *primflds,const char *secflds,
  1012. const char *kind, const char *cardinality, const bool *payload
  1013. );
  1014. void doRemoveFileRelationship( IRemoteConnection *conn, const char *primary,const char *secondary,const char *primflds,const char *secflds, const char *kind);
  1015. void removeFileRelationships(const char *primary,const char *secondary, const char *primflds, const char *secflds, const char *kind);
  1016. void addFileRelationship(const char *kind,const char *primary,const char *secondary,const char *primflds, const char *secflds,const char *cardinality,bool payload,IUserDescriptor *user,const char *description);
  1017. IFileRelationshipIterator *lookupFileRelationships(const char *primary,const char *secondary,const char *primflds,const char *secflds,
  1018. const char *kind,const char *cardinality,const bool *payload,
  1019. const char *foreigndali,unsigned foreigndalitimeout);
  1020. void removeAllFileRelationships(const char *filename);
  1021. IFileRelationshipIterator *lookupAllFileRelationships(const char *filenames);
  1022. void renameFileRelationships(const char *oldname,const char *newname,IFileRelationshipIterator *reliter, IUserDescriptor *user);
  1023. bool publishMetaFileXML(const CDfsLogicalFileName &logicalname,IUserDescriptor *user);
  1024. IFileDescriptor *createDescriptorFromMetaFile(const CDfsLogicalFileName &logicalname,IUserDescriptor *user);
  1025. bool isProtectedFile(const CDfsLogicalFileName &logicalname, unsigned timeout) ;
  1026. unsigned queryProtectedCount(const CDfsLogicalFileName &logicalname, const char *owner);
  1027. bool getProtectedInfo(const CDfsLogicalFileName &logicalname, StringArray &names, UnsignedArray &counts);
  1028. IDFProtectedIterator *lookupProtectedFiles(const char *owner=NULL,bool notsuper=false,bool superonly=false);
  1029. IDFAttributesIterator* getLogicalFilesSorted(IUserDescriptor* udesc, DFUQResultField *sortOrder, const void *filterBuf, DFUQResultField *specialFilters,
  1030. const void *specialFilterBuf, unsigned startOffset, unsigned maxNum, __int64 *cacheHint, unsigned *total, bool *allMatchingFilesReceived);
  1031. void setFileProtect(CDfsLogicalFileName &dlfn,IUserDescriptor *user, const char *owner, bool set, const INode *foreigndali=NULL,unsigned foreigndalitimeout=FOREIGN_DALI_TIMEOUT);
  1032. unsigned setDefaultTimeout(unsigned timems)
  1033. {
  1034. unsigned ret = defaultTimeout;
  1035. defaultTimeout = timems;
  1036. return ret;
  1037. }
  1038. };
  1039. // === Transactions
  1040. class CDFAction: public CInterface
  1041. {
  1042. unsigned locked;
  1043. protected:
  1044. IDistributedFileTransactionExt *transaction;
  1045. IArrayOf<IDistributedFile> lockedFiles;
  1046. DFTransactionState state;
  1047. void addFileLock(IDistributedFile *file)
  1048. {
  1049. // derived's prepare must call this before locking
  1050. lockedFiles.append(*LINK(file));
  1051. }
  1052. bool lock()
  1053. {
  1054. // Files most have been acquired already by derived's class prepare
  1055. ForEachItemIn(i,lockedFiles)
  1056. {
  1057. try
  1058. {
  1059. lockedFiles.item(i).lockProperties(0);
  1060. }
  1061. catch (ISDSException *e)
  1062. {
  1063. if (SDSExcpt_LockTimeout != e->errorCode())
  1064. throw;
  1065. e->Release();
  1066. PROGLOG("CDFAction lock timed out on %s",lockedFiles.item(i).queryLogicalName());
  1067. return false;
  1068. }
  1069. locked++;
  1070. }
  1071. return true;
  1072. }
  1073. void unlock()
  1074. {
  1075. for(unsigned i=0; i<locked; i++)
  1076. lockedFiles.item(i).unlockProperties(state);
  1077. locked = 0;
  1078. lockedFiles.kill();
  1079. }
  1080. public:
  1081. CDFAction() : locked(0), state(TAS_NONE)
  1082. {
  1083. transaction = NULL;
  1084. }
  1085. // Clear all locked files (when re-using transaction on auto-commit mode)
  1086. virtual ~CDFAction()
  1087. {
  1088. if (transaction)
  1089. unlock();
  1090. }
  1091. void setTransaction(IDistributedFileTransactionExt *_transaction)
  1092. {
  1093. assertex(_transaction);
  1094. assertex(!transaction);
  1095. transaction = _transaction;
  1096. }
  1097. virtual bool prepare()=0; // should call lock
  1098. virtual void run()=0; // must override this
  1099. // If some lock fails, call this
  1100. virtual void retry()
  1101. {
  1102. state = TAS_RETRY;
  1103. unlock();
  1104. }
  1105. // MORE: In the rare event of a commit failure, not all actions can be rolled back.
  1106. // Since all actions today occur during "run", and since commit phases does very little,
  1107. // this chance is minimal and will probably be caused by corrupted file descriptors.
  1108. // The problem is that the state of the sub removals and the order in which they occur might not
  1109. // be trivial on such a low level error, and there's no way to atomically do operations in SDS
  1110. // at present time. We need more thought about this.
  1111. virtual void commit()
  1112. {
  1113. state = TAS_SUCCESS;
  1114. unlock();
  1115. }
  1116. virtual void rollback()
  1117. {
  1118. state = TAS_FAILURE;
  1119. unlock();
  1120. }
  1121. };
  1122. static void setUserDescriptor(Linked<IUserDescriptor> &udesc,IUserDescriptor *user)
  1123. {
  1124. if (!user)
  1125. {
  1126. #ifdef NULL_DALIUSER_STACKTRACE
  1127. StringBuffer sb;
  1128. if (user)
  1129. user->getUserName(sb);
  1130. if (sb.length()==0)
  1131. {
  1132. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp setUserDescriptor() %d",__LINE__);
  1133. //following debug code to be removed
  1134. PrintStackReport();
  1135. }
  1136. #endif
  1137. user = queryDistributedFileDirectory().queryDefaultUser();
  1138. }
  1139. udesc.set(user);
  1140. }
  1141. static SecAccessFlags getScopePermissions(const char *scopename,IUserDescriptor *user,unsigned auditflags)
  1142. { // scope must be normalized already
  1143. static bool permissionsavail=true;
  1144. if (auditflags==(unsigned)-1)
  1145. return permissionsavail ? SecAccess_Access : SecAccess_None;
  1146. SecAccessFlags perms = SecAccess_Full;
  1147. if (permissionsavail&&scopename&&*scopename&&((*scopename!='.')||scopename[1])) {
  1148. if (!user)
  1149. {
  1150. #ifdef NULL_DALIUSER_STACKTRACE
  1151. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp getScopePermissions() line %d",__LINE__);
  1152. //following debug code to be removed
  1153. PrintStackReport();
  1154. #endif
  1155. user = queryDistributedFileDirectory().queryDefaultUser();
  1156. }
  1157. perms = querySessionManager().getPermissionsLDAP(queryDfsXmlBranchName(DXB_Scope),scopename,user,auditflags);
  1158. if (perms<0) {
  1159. if (perms == SecAccess_Unavailable) {
  1160. permissionsavail=false;
  1161. perms = SecAccess_Full;
  1162. }
  1163. else
  1164. perms = SecAccess_None;
  1165. }
  1166. }
  1167. return perms;
  1168. }
  1169. static void checkLogicalScope(const char *scopename,IUserDescriptor *user,bool readreq,bool createreq)
  1170. {
  1171. // scope must be normalized already
  1172. if (!readreq&&!createreq)
  1173. return;
  1174. unsigned auditflags = 0;
  1175. if (readreq)
  1176. auditflags |= (DALI_LDAP_AUDIT_REPORT|DALI_LDAP_READ_WANTED);
  1177. if (createreq)
  1178. auditflags |= (DALI_LDAP_AUDIT_REPORT|DALI_LDAP_WRITE_WANTED);
  1179. #ifdef NULL_DALIUSER_STACKTRACE
  1180. if (!user)
  1181. {
  1182. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp checkLogicalScope() line %d",__LINE__);
  1183. PrintStackReport();
  1184. }
  1185. #endif
  1186. SecAccessFlags perm = getScopePermissions(scopename,user,auditflags);
  1187. IDFS_Exception *e = NULL;
  1188. if (readreq&&!HASREADPERMISSION(perm))
  1189. e = new CDFS_Exception(DFSERR_LookupAccessDenied,scopename);
  1190. else if (createreq&&!HASWRITEPERMISSION(perm))
  1191. e = new CDFS_Exception(DFSERR_CreateAccessDenied,scopename);
  1192. if (e)
  1193. throw e;
  1194. }
  1195. static bool checkLogicalName(CDfsLogicalFileName &dlfn,IUserDescriptor *user,bool readreq,bool createreq,bool allowquery,const char *specialnotallowedmsg)
  1196. {
  1197. bool ret = true;
  1198. if (dlfn.isMulti()) { //is temporary superFile?
  1199. if (specialnotallowedmsg)
  1200. throw MakeStringException(-1,"cannot %s a multi file name (%s)",specialnotallowedmsg,dlfn.get());
  1201. if (!dlfn.isExpanded())
  1202. dlfn.expand(user);//expand wildcards
  1203. unsigned i = dlfn.multiOrdinality();
  1204. while (--i)//continue looping even when ret is false, in order to check for illegal elements (foreigns/externals), and to check each scope permission
  1205. ret = checkLogicalName((CDfsLogicalFileName &)dlfn.multiItem(i),user,readreq,createreq,allowquery,specialnotallowedmsg)&&ret;
  1206. }
  1207. else {
  1208. if (specialnotallowedmsg) {
  1209. if (dlfn.isExternal()) {
  1210. if (dlfn.isQuery()&&allowquery)
  1211. ret = false;
  1212. else
  1213. throw MakeStringException(-1,"cannot %s an external file name (%s)",specialnotallowedmsg,dlfn.get());
  1214. }
  1215. if (dlfn.isForeign()) {
  1216. throw MakeStringException(-1,"cannot %s a foreign file name (%s)",specialnotallowedmsg,dlfn.get());
  1217. }
  1218. }
  1219. StringBuffer scopes;
  1220. dlfn.getScopes(scopes);
  1221. checkLogicalScope(scopes.str(),user,readreq,createreq);
  1222. }
  1223. return ret;
  1224. }
  1225. /*
  1226. * This class removes all files marked for deletion during transactions.
  1227. *
  1228. * TODO: the doDelete method re-acquires the lock to remove the files, and
  1229. * that creates a window (between end of commit and deletion) where other
  1230. * processes can acquire locks and blow things up. To fix this, you'd have
  1231. * to be selective on what files you unlock during commit, so that you
  1232. * can still keep an unified cache AND release the deletions later on.
  1233. */
  1234. class CDelayedDelete: public CInterface
  1235. {
  1236. CDfsLogicalFileName lfn;
  1237. Linked<IUserDescriptor> user;
  1238. unsigned timeoutms;
  1239. public:
  1240. CDelayedDelete(CDfsLogicalFileName &_lfn,IUserDescriptor *_user,unsigned _timeoutms)
  1241. : user(_user), timeoutms(_timeoutms)
  1242. {
  1243. lfn.set(_lfn);
  1244. }
  1245. void doDelete() // Throw on error!
  1246. {
  1247. const char *logicalname = lfn.get();
  1248. if (!lfn.isExternal() && !checkLogicalName(lfn,user,true,true,true,"remove"))
  1249. ThrowStringException(-1, "Logical Name fails for removal on %s", lfn.get());
  1250. loop
  1251. {
  1252. // Transaction files have already been unlocked at this point, delete all remaining files
  1253. Owned<IDistributedFile> file = queryDistributedFileDirectory().lookup(lfn, user, true, false, true, NULL, SDS_SUB_LOCK_TIMEOUT);
  1254. if (!file.get())
  1255. return;
  1256. StringBuffer reason;
  1257. if (!file->canRemove(reason, false))
  1258. ThrowStringException(-1, "Can't remove %s: %s", lfn.get(), reason.str());
  1259. // This will do the right thing for either super-files and logical-files.
  1260. try
  1261. {
  1262. file->detach(0, NULL); // 0 == timeout immediately if cannot get exclusive lock
  1263. return;
  1264. }
  1265. catch (ISDSException *e)
  1266. {
  1267. switch (e->errorCode())
  1268. {
  1269. case SDSExcpt_LockTimeout:
  1270. case SDSExcpt_LockHeld:
  1271. e->Release();
  1272. break;
  1273. default:
  1274. throw;
  1275. }
  1276. }
  1277. file.clear();
  1278. PROGLOG("CDelayedDelete: pausing due to locked file = %s", logicalname);
  1279. Sleep(SDS_TRANSACTION_RETRY/2+(getRandom()%SDS_TRANSACTION_RETRY));
  1280. }
  1281. }
  1282. };
  1283. class CDistributedFileTransaction: implements IDistributedFileTransactionExt, public CInterface
  1284. {
  1285. class CTransactionFile : public CSimpleInterface
  1286. {
  1287. class HTMapping : public CInterface
  1288. {
  1289. IDistributedFile *file;
  1290. StringAttr name;
  1291. public:
  1292. HTMapping(const char *_name, IDistributedFile *_file) : name(_name), file(_file) { }
  1293. IDistributedFile &query() { return *file; }
  1294. const char *queryFindString() const { return name; }
  1295. const void *queryFindParam() const { return &file; }
  1296. };
  1297. class CSubFileIter : protected SuperHashIteratorOf<HTMapping>, implements IDistributedFileIterator
  1298. {
  1299. typedef SuperHashIteratorOf<HTMapping> PARENT;
  1300. public:
  1301. IMPLEMENT_IINTERFACE_USING(PARENT);
  1302. CSubFileIter(OwningStringSuperHashTableOf<HTMapping> &table) : PARENT(table)
  1303. {
  1304. }
  1305. // IDistributedFileIterator impl.
  1306. virtual IDistributedFile &query()
  1307. {
  1308. HTMapping &map = PARENT::query();
  1309. return map.query();
  1310. }
  1311. virtual bool first() { return PARENT::first(); }
  1312. virtual bool isValid() { return PARENT::isValid(); }
  1313. virtual bool next() { return PARENT::next(); }
  1314. virtual StringBuffer &getName(StringBuffer &name)
  1315. {
  1316. HTMapping &map = PARENT::query();
  1317. return name.append(map.queryFindString());
  1318. }
  1319. };
  1320. CDistributedFileTransaction &owner;
  1321. OwningStringSuperHashTableOf<HTMapping> subFilesByName;
  1322. StringAttr name;
  1323. Linked<IDistributedFile> file;
  1324. public:
  1325. CTransactionFile(CDistributedFileTransaction &_owner, const char *_name, IDistributedFile *_file) : owner(_owner), name(_name), file(_file)
  1326. {
  1327. }
  1328. const char *queryName() const { return name; }
  1329. IDistributedFile *queryFile() { return file; }
  1330. IDistributedFileIterator *getSubFiles()
  1331. {
  1332. IDistributedSuperFile *super = file->querySuperFile();
  1333. if (!super)
  1334. return NULL;
  1335. return new CSubFileIter(subFilesByName);
  1336. }
  1337. void clearSubs()
  1338. {
  1339. subFilesByName.kill();
  1340. }
  1341. unsigned numSubFiles() const { return subFilesByName.count(); }
  1342. void noteAddSubFile(IDistributedFile *sub)
  1343. {
  1344. if (NULL == subFilesByName.find(sub->queryLogicalName()))
  1345. {
  1346. Owned<HTMapping> map = new HTMapping(sub->queryLogicalName(), sub);
  1347. subFilesByName.replace(*map.getLink());
  1348. }
  1349. }
  1350. void noteRemoveSubFile(IDistributedFile *sub)
  1351. {
  1352. HTMapping *map = subFilesByName.find(sub->queryLogicalName());
  1353. if (map)
  1354. verifyex(subFilesByName.removeExact(map));
  1355. }
  1356. bool find(const char *subFile, bool sub)
  1357. {
  1358. StringBuffer tmp;
  1359. subFile = normalizeLFN(subFile, tmp);
  1360. HTMapping *match = subFilesByName.find(subFile);
  1361. if (match)
  1362. return true;
  1363. else if (sub)
  1364. {
  1365. SuperHashIteratorOf<HTMapping> iter(subFilesByName);
  1366. ForEach(iter)
  1367. {
  1368. HTMapping &map = iter.query();
  1369. IDistributedFile &file = map.query();
  1370. IDistributedSuperFile *super = file.querySuperFile();
  1371. if (super)
  1372. {
  1373. if (owner.isSubFile(super, subFile, sub))
  1374. return true;
  1375. }
  1376. }
  1377. }
  1378. return false;
  1379. }
  1380. const void *queryFindParam() const { return &file; }
  1381. const char *queryFindString() const { return name; }
  1382. };
  1383. CIArrayOf<CDFAction> actions;
  1384. OwningSimpleHashTableOf<CTransactionFile, IDistributedFile *> trackedFiles;
  1385. OwningStringSuperHashTableOf<CTransactionFile> trackedFilesByName;
  1386. bool isactive;
  1387. Linked<IUserDescriptor> udesc;
  1388. CIArrayOf<CDelayedDelete> delayeddelete;
  1389. // auto-commit only works at depth zero (for recursive calls)
  1390. // MORE: Maybe this needs a context object (descend on c-tor, ascend on d-tor)
  1391. // But we need all actions within transactions first to find out if there is
  1392. // any exception to the rule used by addSubFile / removeSubFile
  1393. unsigned depth;
  1394. unsigned prepared;
  1395. ICodeContext *codeCtx;
  1396. /* 'owner' is set if, transaction object is implicitly created, because none provided
  1397. * The owner cannot be release or unlocked. The transaction can still retry if other files are locked,
  1398. * so need to ensure 'owner' remains in tracked file cache.
  1399. */
  1400. IDistributedSuperFile *owner;
  1401. CTransactionFile *queryCreate(const char *name, IDistributedFile *file, bool recreate=false)
  1402. {
  1403. Owned<CTransactionFile> trackedFile;
  1404. if (!recreate)
  1405. trackedFile.set(trackedFiles.find(file));
  1406. if (!trackedFile)
  1407. {
  1408. StringBuffer tmp;
  1409. name = normalizeLFN(name, tmp);
  1410. trackedFile.setown(new CTransactionFile(*this, tmp.str(), file));
  1411. trackedFiles.replace(*trackedFile.getLink());
  1412. trackedFilesByName.replace(*trackedFile.getLink());
  1413. }
  1414. return trackedFile;
  1415. }
  1416. CTransactionFile *lookupTrackedFile(IDistributedFile *file)
  1417. {
  1418. return trackedFiles.find(file);
  1419. }
  1420. void commitActions()
  1421. {
  1422. while (actions.ordinality()) // if we get here everything should work!
  1423. {
  1424. Owned<CDFAction> action = &actions.popGet();
  1425. action->commit();
  1426. }
  1427. }
  1428. IDistributedFile *findFile(const char *name)
  1429. {
  1430. StringBuffer tmp;
  1431. name = normalizeLFN(name, tmp);
  1432. CTransactionFile *trackedFile = trackedFilesByName.find(tmp.str());
  1433. if (!trackedFile)
  1434. return NULL;
  1435. return trackedFile->queryFile();
  1436. }
  1437. void deleteFiles() // no rollback at this point
  1438. {
  1439. Owned<IMultiException> me = MakeMultiException("Transaction");
  1440. ForEachItemIn(i,delayeddelete) {
  1441. try {
  1442. delayeddelete.item(i).doDelete();
  1443. } catch (IException *e) {
  1444. me->append(*e);
  1445. }
  1446. }
  1447. delayeddelete.kill();
  1448. if (me->ordinality())
  1449. throw me.getClear();
  1450. }
  1451. public:
  1452. IMPLEMENT_IINTERFACE;
  1453. CDistributedFileTransaction(IUserDescriptor *user, IDistributedSuperFile *_owner=NULL, ICodeContext *_codeCtx=NULL)
  1454. : isactive(false), depth(0), prepared(0), owner(_owner), codeCtx(_codeCtx)
  1455. {
  1456. setUserDescriptor(udesc,user);
  1457. }
  1458. ~CDistributedFileTransaction()
  1459. {
  1460. // New files should be removed automatically if not committed
  1461. // MORE - refactor cCreateSuperFileAction to avoid this
  1462. if (isactive)
  1463. rollback();
  1464. assert(depth == 0);
  1465. }
  1466. // IDistributedFileTransaction impl.
  1467. virtual void start()
  1468. {
  1469. if (isactive)
  1470. throw MakeStringException(-1,"Transaction already started");
  1471. clearFiles();
  1472. actions.kill();
  1473. isactive = true;
  1474. prepared = 0;
  1475. assertex(actions.ordinality()==0);
  1476. }
  1477. virtual void commit()
  1478. {
  1479. if (!isactive)
  1480. return;
  1481. IException *rete=NULL;
  1482. // =============== PREPARE AND RETRY UNTIL READY
  1483. try
  1484. {
  1485. loop
  1486. {
  1487. if (prepareActions())
  1488. break;
  1489. else
  1490. retryActions();
  1491. PROGLOG("CDistributedFileTransaction: Transaction pausing");
  1492. Sleep(SDS_TRANSACTION_RETRY/2+(getRandom()%SDS_TRANSACTION_RETRY));
  1493. }
  1494. runActions();
  1495. commitAndClearup();
  1496. return;
  1497. }
  1498. catch (IException *e)
  1499. {
  1500. rete = e;
  1501. }
  1502. rollback();
  1503. throw rete;
  1504. }
  1505. virtual void rollback()
  1506. {
  1507. // =============== ROLLBACK AND CLEANUP
  1508. while (actions.ordinality())
  1509. {
  1510. try
  1511. {
  1512. // we don't want to unlock what hasn't been locked
  1513. // if an exception was thrown while locking, but we
  1514. // do want to pop them all
  1515. Owned<CDFAction> action = &actions.popGet();
  1516. if (actions.ordinality()<prepared)
  1517. action->rollback();
  1518. }
  1519. catch (IException *e)
  1520. {
  1521. e->Release();
  1522. }
  1523. }
  1524. actions.kill(); // should be empty
  1525. clearFiles(); // release locks
  1526. if (!isactive)
  1527. return;
  1528. isactive = false;
  1529. // this we only want to do if active
  1530. delayeddelete.kill();
  1531. }
  1532. virtual bool active()
  1533. {
  1534. return isactive;
  1535. }
  1536. virtual IDistributedFile *lookupFile(const char *name,unsigned timeout)
  1537. {
  1538. IDistributedFile *ret = findFile(name);
  1539. if (ret)
  1540. return LINK(ret);
  1541. else
  1542. {
  1543. ret = queryDistributedFileDirectory().lookup(name, udesc, false, false, false, this, timeout);
  1544. if (ret)
  1545. queryCreate(name, ret, true);
  1546. return ret;
  1547. }
  1548. }
  1549. virtual IDistributedSuperFile *lookupSuperFile(const char *name, unsigned timeout)
  1550. {
  1551. IDistributedFile *f = findFile(name);
  1552. if (f)
  1553. return LINK(f->querySuperFile());
  1554. else
  1555. {
  1556. IDistributedSuperFile *ret = queryDistributedFileDirectory().lookupSuperFile(name,udesc,this,timeout);
  1557. if (ret)
  1558. addFile(ret);
  1559. return ret;
  1560. }
  1561. }
  1562. // IDistributedFileTransactionExt impl.
  1563. virtual IUserDescriptor *queryUser()
  1564. {
  1565. return udesc;
  1566. }
  1567. virtual void descend() // Call this when you're recurring
  1568. {
  1569. depth++;
  1570. }
  1571. virtual void ascend() // Call this at the end of the block that started recursion
  1572. {
  1573. assertex(depth);
  1574. depth--;
  1575. }
  1576. virtual void autoCommit()
  1577. {
  1578. // Recursive calls to transaction will not commit until
  1579. // all calls have finished (gone back to zero depth)
  1580. if (!depth && !isactive) {
  1581. try {
  1582. isactive = true;
  1583. commit();
  1584. }
  1585. catch (IException *) {
  1586. rollback();
  1587. throw;
  1588. }
  1589. }
  1590. }
  1591. virtual void addAction(CDFAction *action)
  1592. {
  1593. actions.append(*action); // takes ownership
  1594. action->setTransaction(this);
  1595. }
  1596. virtual void addFile(IDistributedFile *file)
  1597. {
  1598. CTransactionFile *trackedFile = queryCreate(file->queryLogicalName(), file, false);
  1599. // Also add subfiles to cache
  1600. IDistributedSuperFile *sfile = file->querySuperFile();
  1601. if (sfile)
  1602. {
  1603. Owned<IDistributedFileIterator> iter = sfile->getSubFileIterator();
  1604. ForEach(*iter)
  1605. {
  1606. IDistributedFile *f = &iter->query();
  1607. trackedFile->noteAddSubFile(f);
  1608. addFile(f);
  1609. }
  1610. }
  1611. }
  1612. virtual void ensureFile(IDistributedFile *file)
  1613. {
  1614. if (!trackedFiles.find(file))
  1615. addFile(file);
  1616. }
  1617. virtual void clearFile(IDistributedFile *file)
  1618. {
  1619. CTransactionFile *trackedFile = lookupTrackedFile(file);
  1620. IDistributedSuperFile *sfile = file->querySuperFile();
  1621. if (trackedFile)
  1622. {
  1623. Owned<IDistributedFileIterator> iter = trackedFile->getSubFiles();
  1624. if (iter)
  1625. {
  1626. ForEach(*iter)
  1627. clearFile(&iter->query());
  1628. }
  1629. trackedFiles.removeExact(trackedFile);
  1630. trackedFilesByName.removeExact(trackedFile);
  1631. }
  1632. }
  1633. virtual void clearFiles()
  1634. {
  1635. trackedFiles.kill();
  1636. trackedFilesByName.kill();
  1637. if (owner)
  1638. addFile(owner); // ensure remains tracked
  1639. }
  1640. virtual void noteAddSubFile(IDistributedSuperFile *super, const char *superName, IDistributedFile *sub)
  1641. {
  1642. CTransactionFile *trackedSuper = queryCreate(superName, super);
  1643. trackedSuper->noteAddSubFile(sub);
  1644. }
  1645. virtual void noteRemoveSubFile(IDistributedSuperFile *super, IDistributedFile *sub)
  1646. {
  1647. CTransactionFile *trackedSuper = lookupTrackedFile(super);
  1648. if (trackedSuper)
  1649. trackedSuper->noteRemoveSubFile(sub);
  1650. }
  1651. virtual void noteSuperSwap(IDistributedSuperFile *super1, IDistributedSuperFile *super2)
  1652. {
  1653. CTransactionFile *trackedSuper1 = lookupTrackedFile(super1);
  1654. CTransactionFile *trackedSuper2 = lookupTrackedFile(super2);
  1655. assertex(trackedSuper1 && trackedSuper2);
  1656. ICopyArrayOf<IDistributedFile> super1Subs, super2Subs;
  1657. Owned<IDistributedFileIterator> iter = trackedSuper1->getSubFiles();
  1658. ForEach(*iter)
  1659. super1Subs.append(iter->query());
  1660. trackedSuper1->clearSubs();
  1661. iter.setown(trackedSuper2->getSubFiles());
  1662. ForEach(*iter)
  1663. super2Subs.append(iter->query());
  1664. trackedSuper2->clearSubs();
  1665. ForEachItemIn(s, super2Subs)
  1666. trackedSuper1->noteAddSubFile(&super2Subs.item(s));
  1667. ForEachItemIn(s2, super1Subs)
  1668. trackedSuper2->noteAddSubFile(&super1Subs.item(s2));
  1669. }
  1670. virtual void clearSubFiles(IDistributedSuperFile *super)
  1671. {
  1672. CTransactionFile *trackedSuper = lookupTrackedFile(super);
  1673. if (trackedSuper)
  1674. trackedSuper->clearSubs();
  1675. }
  1676. virtual void noteRename(IDistributedFile *file, const char *newName)
  1677. {
  1678. CTransactionFile *trackedFile = lookupTrackedFile(file);
  1679. if (trackedFile)
  1680. {
  1681. trackedFiles.removeExact(trackedFile);
  1682. trackedFilesByName.removeExact(trackedFile);
  1683. trackedFile = queryCreate(newName, file);
  1684. }
  1685. }
  1686. virtual void validateAddSubFile(IDistributedSuperFile *super, IDistributedFile *sub, const char *subName);
  1687. virtual bool isSubFile(IDistributedSuperFile *super, const char *subFile, bool sub)
  1688. {
  1689. CTransactionFile *trackedSuper = lookupTrackedFile(super);
  1690. if (!trackedSuper)
  1691. return false;
  1692. return trackedSuper->find(subFile, sub);
  1693. }
  1694. virtual bool addDelayedDelete(CDfsLogicalFileName &lfn,unsigned timeoutms)
  1695. {
  1696. delayeddelete.append(*new CDelayedDelete(lfn,udesc,timeoutms));
  1697. return true;
  1698. }
  1699. virtual bool prepareActions()
  1700. {
  1701. prepared = 0;
  1702. unsigned toPrepare = actions.ordinality();
  1703. ForEachItemIn(i0,actions)
  1704. {
  1705. if (actions.item(i0).prepare())
  1706. ++prepared;
  1707. else
  1708. break;
  1709. }
  1710. return prepared == toPrepare;
  1711. }
  1712. virtual void retryActions()
  1713. {
  1714. clearFiles(); // clear all previously tracked pending file changes, e.g. renames, super file additions/removals
  1715. while (prepared) // unlock for retry
  1716. actions.item(--prepared).retry();
  1717. }
  1718. virtual void runActions()
  1719. {
  1720. ForEachItemIn(i,actions)
  1721. actions.item(i).run();
  1722. }
  1723. virtual void commitAndClearup()
  1724. {
  1725. // =============== COMMIT and CLEANUP
  1726. commitActions();
  1727. clearFiles();
  1728. isactive = false;
  1729. actions.kill();
  1730. deleteFiles();
  1731. }
  1732. virtual ICodeContext *queryCodeContext()
  1733. {
  1734. return codeCtx;
  1735. }
  1736. };
  1737. static bool recursiveCheckEmptyScope(IPropertyTree &ct)
  1738. {
  1739. Owned<IPropertyTreeIterator> iter = ct.getElements("*");
  1740. ForEach(*iter) {
  1741. IPropertyTree &item = iter->query();
  1742. const char *n = item.queryName();
  1743. if (!n||(strcmp(n,queryDfsXmlBranchName(DXB_Scope))!=0))
  1744. return false;
  1745. if (!recursiveCheckEmptyScope(item))
  1746. return false;
  1747. }
  1748. return true;
  1749. }
  1750. class CDFScopeIterator: implements IDFScopeIterator, public CInterface
  1751. {
  1752. PointerArray scopes;
  1753. unsigned index;
  1754. IDistributedFileDirectory *dir;
  1755. bool includeempty;
  1756. void add(IPropertyTree &t, bool recursive, StringBuffer &name)
  1757. {
  1758. name.trim();
  1759. size32_t nl = name.length();
  1760. size32_t l=nl;
  1761. if (nl) {
  1762. name.append("::");
  1763. l+=2;
  1764. }
  1765. Owned<IPropertyTreeIterator> iter = t.getElements(queryDfsXmlBranchName(DXB_Scope));
  1766. ForEach(*iter) {
  1767. IPropertyTree &ct = iter->query();
  1768. if (includeempty||!recursiveCheckEmptyScope(ct)) {
  1769. name.append(ct.queryProp("@name"));
  1770. scopes.append(strdup(name.str()));
  1771. if (recursive)
  1772. add(ct,recursive,name);
  1773. name.setLength(l);
  1774. }
  1775. }
  1776. name.setLength(nl);
  1777. }
  1778. public:
  1779. IMPLEMENT_IINTERFACE;
  1780. CDFScopeIterator(IDistributedFileDirectory *_dir,const char *base,bool recursive, bool _includeempty,unsigned timeout) // attrib not yet implemented
  1781. {
  1782. includeempty = _includeempty;
  1783. dir = _dir;
  1784. StringBuffer baseq;
  1785. StringBuffer tmp;
  1786. if (base&&*base) {
  1787. CDfsLogicalFileName dlfn;
  1788. dlfn.set(base,".");
  1789. dlfn.makeScopeQuery(baseq,false);
  1790. }
  1791. {
  1792. CConnectLock connlock("CDFScopeIterator",querySdsFilesRoot(),false,false,false,timeout);
  1793. // could use CScopeConnectLock here probably
  1794. StringBuffer name;
  1795. IPropertyTree *root = connlock.conn->queryRoot();
  1796. if (baseq.length())
  1797. root = root->queryPropTree(baseq.str());
  1798. if (root)
  1799. add(*root,recursive,name);
  1800. }
  1801. if (scopes.ordinality()>1)
  1802. qsortvec(scopes.getArray(),scopes.ordinality(),strcompare);
  1803. index = 0;
  1804. }
  1805. ~CDFScopeIterator()
  1806. {
  1807. ForEachItemIn(i,scopes) {
  1808. free(scopes.item(i));
  1809. }
  1810. }
  1811. bool first()
  1812. {
  1813. index = 0;
  1814. return isValid();
  1815. }
  1816. bool next()
  1817. {
  1818. index++;
  1819. return isValid();
  1820. }
  1821. bool isValid()
  1822. {
  1823. return (index<scopes.ordinality());
  1824. }
  1825. const char *query()
  1826. {
  1827. return (const char *)scopes.item(index);
  1828. }
  1829. };
  1830. struct SerializeFileAttrOptions
  1831. {
  1832. bool includeSuperOwner;
  1833. //Add more as needed
  1834. SerializeFileAttrOptions()
  1835. {
  1836. includeSuperOwner = false;
  1837. }
  1838. };
  1839. class CDFAttributeIterator: implements IDFAttributesIterator, public CInterface
  1840. {
  1841. unsigned index;
  1842. IArrayOf<IPropertyTree> attrs;
  1843. public:
  1844. IMPLEMENT_IINTERFACE;
  1845. static MemoryBuffer &serializeFileAttributes(MemoryBuffer &mb, IPropertyTree &root, const char *name, bool issuper, SerializeFileAttrOptions& option)
  1846. {
  1847. StringBuffer buf;
  1848. mb.append(name);
  1849. if (issuper) {
  1850. mb.append("!SF");
  1851. mb.append(root.getPropInt("@numsubfiles",0));
  1852. mb.append("");
  1853. }
  1854. else {
  1855. mb.append(root.queryProp("@directory"));
  1856. mb.append(root.getPropInt("@numparts",0));
  1857. mb.append(root.queryProp("@partmask"));
  1858. }
  1859. mb.append(root.queryProp("@modified"));
  1860. Owned<IPropertyTree> attrs = root.getPropTree("Attr");;
  1861. Owned<IAttributeIterator> attriter;
  1862. if (attrs)
  1863. attriter.setown(attrs->getAttributes());
  1864. unsigned count=0;
  1865. size32_t countpos = mb.length();
  1866. mb.append(count);
  1867. if (attriter.get()&&attriter->first()) {
  1868. do {
  1869. mb.append(attriter->queryName());
  1870. mb.append(attriter->queryValue());
  1871. count++;
  1872. } while (attriter->next());
  1873. }
  1874. const char *ps = root.queryProp("@group");
  1875. if (ps&&*ps) {
  1876. count++;
  1877. mb.append("@group");
  1878. mb.append(ps);
  1879. }
  1880. // add protected
  1881. if (attrs) {
  1882. Owned<IPropertyTreeIterator> piter = attrs->getElements("Protect");
  1883. StringBuffer plist;
  1884. ForEach(*piter) {
  1885. const char *name = piter->get().queryProp("@name");
  1886. if (name&&*name) {
  1887. unsigned count = piter->get().getPropInt("@count");
  1888. if (count) {
  1889. if (plist.length())
  1890. plist.append(',');
  1891. plist.append(name);
  1892. if (count>1)
  1893. plist.append(':').append(count);
  1894. }
  1895. }
  1896. }
  1897. if (plist.length()) {
  1898. count++;
  1899. mb.append("@protect");
  1900. mb.append(plist.str());
  1901. }
  1902. }
  1903. if (option.includeSuperOwner) {
  1904. //add superowners
  1905. StringBuffer soList;
  1906. Owned<IPropertyTreeIterator> superOwners = root.getElements("SuperOwner");
  1907. ForEach(*superOwners) {
  1908. IPropertyTree &superOwner = superOwners->query();
  1909. const char *name = superOwner.queryProp("@name");
  1910. if (name&&*name) {
  1911. if (soList.length())
  1912. soList.append(",");
  1913. soList.append(name);
  1914. }
  1915. }
  1916. if (soList.length()) {
  1917. count++;
  1918. mb.append("@superowners");
  1919. mb.append(soList.str());
  1920. }
  1921. }
  1922. mb.writeDirect(countpos,sizeof(count),&count);
  1923. return mb;
  1924. }
  1925. CDFAttributeIterator(MemoryBuffer &mb) // attrib not yet implemented
  1926. {
  1927. unsigned numfiles;
  1928. mb.read(numfiles);
  1929. while (numfiles--) {
  1930. IPropertyTree *attr = getEmptyAttr();
  1931. StringAttr val;
  1932. unsigned n;
  1933. mb.read(val);
  1934. attr->setProp("@name",val.get());
  1935. mb.read(val);
  1936. if (stricmp(val,"!SF")==0) {
  1937. mb.read(n);
  1938. attr->setPropInt("@numsubfiles",n);
  1939. mb.read(val); // not used currently
  1940. }
  1941. else {
  1942. attr->setProp("@directory",val.get());
  1943. mb.read(n);
  1944. attr->setPropInt("@numparts",n);
  1945. mb.read(val);
  1946. attr->setProp("@partmask",val.get());
  1947. }
  1948. mb.read(val);
  1949. attr->setProp("@modified",val.get());
  1950. unsigned count;
  1951. mb.read(count);
  1952. StringAttr at;
  1953. while (count--) {
  1954. mb.read(at);
  1955. mb.read(val);
  1956. attr->setProp(at.get(),val.get());
  1957. }
  1958. attrs.append(*attr);
  1959. }
  1960. index = 0;
  1961. }
  1962. CDFAttributeIterator(IArrayOf<IPropertyTree>& trees)
  1963. {
  1964. ForEachItemIn(t, trees)
  1965. attrs.append(*LINK(&trees.item(t)));
  1966. index = 0;
  1967. }
  1968. ~CDFAttributeIterator()
  1969. {
  1970. attrs.kill();
  1971. }
  1972. bool first()
  1973. {
  1974. index = 0;
  1975. return (attrs.ordinality()!=0);
  1976. }
  1977. bool next()
  1978. {
  1979. index++;
  1980. return (index<attrs.ordinality());
  1981. }
  1982. bool isValid()
  1983. {
  1984. return (index<attrs.ordinality());
  1985. }
  1986. IPropertyTree & query()
  1987. {
  1988. return attrs.item(index);
  1989. }
  1990. };
  1991. class CDFProtectedIterator: implements IDFProtectedIterator, public CInterface
  1992. {
  1993. StringAttr owner;
  1994. StringAttr fn;
  1995. unsigned count;
  1996. bool issuper;
  1997. Owned<IRemoteConnection> conn;
  1998. Owned<IPropertyTreeIterator> fiter;
  1999. Owned<IPropertyTreeIterator> piter;
  2000. unsigned defaultTimeout;
  2001. bool notsuper;
  2002. bool superonly;
  2003. void fill()
  2004. {
  2005. IPropertyTree &t = fiter->query();
  2006. fn.set(t.queryProp("OrigName"));
  2007. IPropertyTree &pt = piter->query();
  2008. owner.set(pt.queryProp("@name"));
  2009. count = pt.getPropInt("@count");
  2010. }
  2011. void clear()
  2012. {
  2013. piter.clear();
  2014. fiter.clear();
  2015. conn.clear();
  2016. issuper = false;
  2017. }
  2018. public:
  2019. IMPLEMENT_IINTERFACE;
  2020. CDFProtectedIterator(const char *_owner,bool _notsuper,bool _superonly,unsigned _defaultTimeout)
  2021. : owner(_owner)
  2022. {
  2023. count = 0;
  2024. issuper = false;
  2025. notsuper=_notsuper;
  2026. superonly=_superonly;
  2027. defaultTimeout = _defaultTimeout;
  2028. }
  2029. ~CDFProtectedIterator()
  2030. {
  2031. clear();
  2032. }
  2033. bool first()
  2034. {
  2035. clear();
  2036. conn.setown(querySDS().connect("Files",myProcessSession(),0, defaultTimeout));
  2037. if (!conn)
  2038. return false;
  2039. IPropertyTree *t = conn->queryRoot();
  2040. if (!superonly) {
  2041. fiter.setown(t->getElements("//File[Attr/Protect]", iptiter_remote));
  2042. if (fiter->first()) {
  2043. piter.setown(fiter->query().getElements("Attr/Protect"));
  2044. if (piter->first()) {
  2045. fill();
  2046. return true;
  2047. }
  2048. }
  2049. }
  2050. if (!notsuper) {
  2051. issuper = true;
  2052. fiter.clear();
  2053. fiter.setown(t->getElements("//SuperFile[Attr/Protect]", iptiter_remote));
  2054. if (fiter->first()) {
  2055. piter.setown(fiter->query().getElements("Attr/Protect"));
  2056. if (piter->first()) {
  2057. fill();
  2058. return true;
  2059. }
  2060. }
  2061. }
  2062. clear();
  2063. return false;
  2064. }
  2065. bool next()
  2066. {
  2067. if (!fiter.get())
  2068. return false;
  2069. if (piter->next()) {
  2070. fill();
  2071. return true;
  2072. }
  2073. loop {
  2074. if (fiter->next()) {
  2075. piter.setown(fiter->query().getElements("Attr/Protect"));
  2076. if (piter->first()) {
  2077. fill();
  2078. return true;
  2079. }
  2080. }
  2081. else if (!notsuper&&!issuper) {
  2082. issuper = true;
  2083. fiter.clear();
  2084. fiter.setown(conn->queryRoot()->getElements("//SuperFile[Attr/Protect]", iptiter_remote));
  2085. if (fiter->first()) {
  2086. piter.setown(fiter->query().getElements("Attr/Protect"));
  2087. if (piter->first()) {
  2088. fill();
  2089. return true;
  2090. }
  2091. }
  2092. else
  2093. break;
  2094. }
  2095. else
  2096. break;
  2097. }
  2098. clear();
  2099. return false;
  2100. }
  2101. bool isValid()
  2102. {
  2103. return fiter.get()!=NULL;
  2104. }
  2105. const char *queryFilename()
  2106. {
  2107. return fn;
  2108. }
  2109. const char *queryOwner()
  2110. {
  2111. return owner;
  2112. }
  2113. unsigned getCount()
  2114. {
  2115. return count;
  2116. }
  2117. bool isSuper()
  2118. {
  2119. return issuper;
  2120. }
  2121. };
  2122. // --------------------------------------------------------
  2123. class CDistributedFilePart: public CInterface, implements IDistributedFilePart
  2124. {
  2125. unsigned partIndex;
  2126. CDistributedFile &parent;
  2127. Owned<IPropertyTree> attr;
  2128. CriticalSection sect;
  2129. StringAttr overridename; // may or not be relative to directory
  2130. bool dirty; // whether needs updating in tree
  2131. offset_t getSize(bool checkCompressed);
  2132. public:
  2133. virtual void Link(void) const;
  2134. virtual bool Release(void) const;
  2135. void set(IPropertyTree *pt,FileClusterInfoArray &clusters,unsigned maxcluster);
  2136. RemoteFilename &getFilename(RemoteFilename &ret,unsigned copy);
  2137. void renameFile(IFile *file);
  2138. IPropertyTree &queryAttributes();
  2139. bool lockProperties(unsigned timems);
  2140. void unlockProperties(DFTransactionState state);
  2141. bool isHost(unsigned copy);
  2142. offset_t getFileSize(bool allowphysical,bool forcephysical);
  2143. offset_t getDiskSize(bool allowphysical,bool forcephysical);
  2144. bool getModifiedTime(bool allowphysical,bool forcephysical,CDateTime &dt);
  2145. bool getCrc(unsigned &crc);
  2146. unsigned getPhysicalCrc();
  2147. IPartDescriptor *getPartDescriptor();
  2148. unsigned numCopies();
  2149. INode *queryNode(unsigned copy);
  2150. unsigned queryDrive(unsigned copy);
  2151. StringBuffer &getPartName(StringBuffer &name);
  2152. StringBuffer &getPartDirectory(StringBuffer &name,unsigned copy);
  2153. const char *queryOverrideName() { return overridename; }
  2154. void clearOverrideName()
  2155. {
  2156. if (overridename.get()&&overridename.length()) {
  2157. dirty = true;
  2158. overridename.clear();
  2159. }
  2160. }
  2161. unsigned bestCopyNum(const IpAddress &ip,unsigned rel=0);
  2162. unsigned copyClusterNum(unsigned copy,unsigned *replicate=NULL);
  2163. void childLink(void) { CInterface::Link(); }
  2164. bool childRelease(void) { return CInterface::Release(); }
  2165. CDistributedFilePart(CDistributedFile &_parent,unsigned _part,IPartDescriptor *pd);
  2166. unsigned getPartIndex()
  2167. {
  2168. return partIndex;
  2169. }
  2170. INode *getNode(unsigned copy)
  2171. {
  2172. INode *ret = queryNode(copy);
  2173. if (ret)
  2174. return LINK(ret);
  2175. return NULL;
  2176. }
  2177. void setAttr(IPropertyTree &pt)
  2178. {
  2179. attr.setown(createPTreeFromIPT(&pt)); // take a copy
  2180. dirty = false;
  2181. }
  2182. IPropertyTree *queryAttr()
  2183. {
  2184. return attr;
  2185. }
  2186. inline CDistributedFile &queryParent()
  2187. {
  2188. return parent;
  2189. }
  2190. inline bool isDirty()
  2191. {
  2192. return dirty;
  2193. }
  2194. inline bool clearDirty()
  2195. {
  2196. bool ret=dirty;
  2197. dirty = false;
  2198. return ret;
  2199. }
  2200. };
  2201. // --------------------------------------------------------
  2202. class CDistributedFilePartArray: public CIArrayOf<CDistributedFilePart>
  2203. {
  2204. public:
  2205. virtual ~CDistributedFilePartArray() // this shouldn't be needed - points to problem in CIArrayOf?
  2206. {
  2207. kill();
  2208. }
  2209. void kill(bool nodel = false)
  2210. {
  2211. if (nodel)
  2212. CIArrayOf<CDistributedFilePart>::kill(true);
  2213. else {
  2214. while (ordinality()) {
  2215. CDistributedFilePart &part = popGet();
  2216. part.Release();
  2217. }
  2218. }
  2219. }
  2220. };
  2221. // --------------------------------------------------------
  2222. /**
  2223. * Base Iterator class for all iterator types. Implements basic iteration
  2224. * logic and forces all iterators to behave similarly. This will simplify
  2225. * future compatibility with STL containers/algorithms.
  2226. *
  2227. * INTERFACE needs to be extended from IIteratorOf<>
  2228. * ARRAYTY need to be extended from IArrayOf<>
  2229. */
  2230. template <class INTERFACE, class ARRAYTY>
  2231. class CDistributedFileIteratorBase: implements INTERFACE, public CInterface
  2232. {
  2233. protected:
  2234. unsigned index;
  2235. ARRAYTY list;
  2236. virtual bool set() { return isValid(); }
  2237. public:
  2238. IMPLEMENT_IINTERFACE;
  2239. CDistributedFileIteratorBase()
  2240. : index(0)
  2241. {
  2242. }
  2243. virtual ~CDistributedFileIteratorBase()
  2244. {
  2245. list.kill();
  2246. }
  2247. bool first()
  2248. {
  2249. if (list.ordinality() == 0)
  2250. return false;
  2251. index = 0;
  2252. return set();
  2253. }
  2254. bool next()
  2255. {
  2256. index++;
  2257. set();
  2258. return isValid();
  2259. }
  2260. bool isValid()
  2261. {
  2262. return (index < list.ordinality());
  2263. }
  2264. };
  2265. /**
  2266. * FilePart Iterator, used by files to manipulate its parts.
  2267. */
  2268. class CDistributedFilePartIterator: public CDistributedFileIteratorBase<IDistributedFilePartIterator, CDistributedFilePartArray>
  2269. {
  2270. public:
  2271. CDistributedFilePartIterator(CDistributedFilePartArray &parts, IDFPartFilter *filter)
  2272. {
  2273. ForEachItemIn(i,parts) {
  2274. if (!filter||filter->includePart(i))
  2275. list.append(*LINK(&parts.item(i)));
  2276. }
  2277. }
  2278. CDistributedFilePartIterator()
  2279. {
  2280. }
  2281. IDistributedFilePart & query()
  2282. {
  2283. return list.item(index);
  2284. }
  2285. CDistributedFilePartArray &queryParts()
  2286. {
  2287. return list;
  2288. }
  2289. };
  2290. /**
  2291. * File Iterator, used by directory to list file search results.
  2292. */
  2293. class CDistributedFileIterator: public CDistributedFileIteratorBase<IDistributedFileIterator, PointerArray>
  2294. {
  2295. Owned<IDistributedFile> cur;
  2296. IDistributedFileDirectory *parent;
  2297. Linked<IUserDescriptor> udesc;
  2298. Linked<IDistributedFileTransaction> transaction;
  2299. bool set()
  2300. {
  2301. while (isValid()) {
  2302. cur.setown(parent->lookup(queryName(),udesc));
  2303. if (cur)
  2304. return true;
  2305. index++;
  2306. }
  2307. return false;
  2308. }
  2309. public:
  2310. CDistributedFileIterator(IDistributedFileDirectory *_dir,const char *wildname,bool includesuper,IUserDescriptor *user,IDistributedFileTransaction *_transaction=NULL)
  2311. : transaction(_transaction)
  2312. {
  2313. setUserDescriptor(udesc,user);
  2314. if (!wildname||!*wildname)
  2315. wildname = "*";
  2316. parent = _dir;
  2317. bool recursive = (stricmp(wildname,"*")==0);
  2318. Owned<IDFAttributesIterator> attriter = parent->getDFAttributesIterator(wildname,user,recursive,includesuper,NULL);
  2319. ForEach(*attriter) {
  2320. IPropertyTree &pt = attriter->query();
  2321. list.append(strdup(pt.queryProp("@name")));
  2322. }
  2323. index = 0;
  2324. if (list.ordinality()>1)
  2325. qsortvec(list.getArray(),list.ordinality(),strcompare);
  2326. }
  2327. const char *queryName()
  2328. {
  2329. return (const char *)list.item(index);
  2330. }
  2331. StringBuffer & getName(StringBuffer &name)
  2332. {
  2333. return name.append(queryName());
  2334. }
  2335. IDistributedFile & query()
  2336. {
  2337. return *cur;
  2338. }
  2339. };
  2340. /**
  2341. * SuperFile Iterator, used by CDistributedFile to list all its super-owners by name.
  2342. */
  2343. class CDistributedSuperFileIterator: public CDistributedFileIteratorBase<IDistributedSuperFileIterator, StringAttrArray>
  2344. {
  2345. CDistributedFileDirectory *parent;
  2346. Linked<IUserDescriptor> udesc;
  2347. Linked<IDistributedFileTransaction> transaction;
  2348. Owned<IDistributedSuperFile> cur;
  2349. Linked<IDistributedFile> owner;
  2350. public:
  2351. CDistributedSuperFileIterator(IDistributedFile *_owner, CDistributedFileDirectory *_parent,IPropertyTree *root,IUserDescriptor *user, IDistributedFileTransaction *_transaction)
  2352. : owner(_owner), transaction(_transaction)
  2353. {
  2354. setUserDescriptor(udesc,user);
  2355. parent = _parent;
  2356. if (root)
  2357. {
  2358. Owned<IPropertyTreeIterator> iter = root->getElements("SuperOwner");
  2359. StringBuffer pname;
  2360. ForEach(*iter)
  2361. {
  2362. iter->query().getProp("@name",pname.clear());
  2363. if (pname.length())
  2364. list.append(* new StringAttrItem(pname.str()));
  2365. }
  2366. }
  2367. }
  2368. IDistributedSuperFile & query()
  2369. {
  2370. // NOTE: This used to include a do/while (!cur.get()&&next()) loop
  2371. // this should never be needed but match previous semantics
  2372. // throwing an exception now, to catch the error early on
  2373. if (transaction.get())
  2374. cur.setown(transaction->lookupSuperFile(queryName()));
  2375. else
  2376. cur.setown(parent->lookupSuperFile(queryName(),udesc,NULL));
  2377. if (!cur.get())
  2378. throw MakeStringException(-1,"superFileIter: invalid super-file on query at %s", queryName());
  2379. return *cur;
  2380. }
  2381. virtual const char *queryName()
  2382. {
  2383. if (isValid())
  2384. return list.item(index).text.get();
  2385. return NULL;
  2386. }
  2387. };
  2388. //-----------------------------------------------------------------------------
  2389. inline void dfCheckRoot(const char *trc,Owned<IPropertyTree> &root,IRemoteConnection *conn)
  2390. {
  2391. if (root.get()!=conn->queryRoot()) {
  2392. WARNLOG("%s - root changed",trc);
  2393. #ifdef _DEBUG
  2394. PrintStackReport();
  2395. #endif
  2396. root.setown(conn->getRoot());
  2397. }
  2398. }
  2399. static bool setFileProtectTree(IPropertyTree &p,const char *owner, bool protect)
  2400. {
  2401. bool ret = false;
  2402. CDateTime dt;
  2403. dt.setNow();
  2404. if (owner&&*owner) {
  2405. Owned<IPropertyTree> t = getNamedPropTree(&p,"Protect","@name",owner,false);
  2406. if (t) {
  2407. unsigned c = t->getPropInt("@count");
  2408. if (protect)
  2409. c++;
  2410. else {
  2411. if (c>=1) {
  2412. p.removeTree(t);
  2413. c = 0;
  2414. }
  2415. else
  2416. c--;
  2417. }
  2418. if (c) {
  2419. t->setPropInt("@count",c);
  2420. StringBuffer str;
  2421. t->setProp("@modified",dt.getString(str).str());
  2422. }
  2423. }
  2424. else if (protect) {
  2425. t.setown(addNamedPropTree(&p,"Protect","@name",owner));
  2426. t->setPropInt("@count",1);
  2427. StringBuffer str;
  2428. t->setProp("@modified",dt.getString(str).str());
  2429. }
  2430. ret = true;
  2431. }
  2432. else if (!protect) {
  2433. unsigned n=0;
  2434. IPropertyTree *pt;
  2435. while ((pt=p.queryPropTree("Protect[1]"))!=NULL) {
  2436. p.removeTree(pt);
  2437. n++;
  2438. }
  2439. if (n)
  2440. ret = true;
  2441. }
  2442. return ret;
  2443. }
  2444. static bool checkProtectAttr(const char *logicalname,IPropertyTree *froot,StringBuffer &reason)
  2445. {
  2446. Owned<IPropertyTreeIterator> wpiter = froot->getElements("Attr/Protect");
  2447. bool prot = false;
  2448. ForEach(*wpiter) {
  2449. IPropertyTree &t = wpiter->query();
  2450. if (t.getPropInt("@count")) {
  2451. const char *wpname = t.queryProp("@name");
  2452. if (!wpname||!*wpname)
  2453. wpname = "<Unknown>";
  2454. if (prot)
  2455. reason.appendf(", %s",wpname);
  2456. else {
  2457. reason.appendf("file %s protected by %s",logicalname,wpname);
  2458. prot = true;
  2459. }
  2460. }
  2461. }
  2462. return prot;
  2463. }
  2464. /**
  2465. * A template class which implements the common methods of an IDistributedFile interface.
  2466. * The actual interface (extended from IDistributedFile) is provided as a template argument.
  2467. */
  2468. template <class INTERFACE>
  2469. class CDistributedFileBase : implements INTERFACE, public CInterface
  2470. {
  2471. protected:
  2472. Owned<IPropertyTree> root;
  2473. Owned<IRemoteConnection> conn; // kept connected during lifetime for attributes
  2474. CDfsLogicalFileName logicalName;
  2475. CriticalSection sect;
  2476. CDistributedFileDirectory *parent;
  2477. unsigned proplockcount;
  2478. unsigned transactionnest;
  2479. Linked<IUserDescriptor> udesc;
  2480. unsigned defaultTimeout;
  2481. bool dirty;
  2482. bool external = false;
  2483. Owned<IRemoteConnection> superOwnerLock;
  2484. public:
  2485. IPropertyTree *queryRoot() { return root; }
  2486. CDistributedFileBase<INTERFACE>()
  2487. {
  2488. parent = NULL;
  2489. proplockcount = 0;
  2490. transactionnest = 0;
  2491. defaultTimeout = INFINITE;
  2492. dirty = false;
  2493. }
  2494. ~CDistributedFileBase<INTERFACE>()
  2495. {
  2496. root.clear();
  2497. }
  2498. void setSuperOwnerLock(IRemoteConnection *_superOwnerLock)
  2499. {
  2500. superOwnerLock.setown(_superOwnerLock);
  2501. }
  2502. unsigned setPropLockCount(unsigned _propLockCount)
  2503. {
  2504. unsigned prevPropLockCount = proplockcount;
  2505. proplockcount = _propLockCount;
  2506. return prevPropLockCount;
  2507. }
  2508. bool isCompressed(bool *blocked)
  2509. {
  2510. return ::isCompressed(queryAttributes(),blocked);
  2511. }
  2512. StringBuffer &getLogicalName(StringBuffer &lname)
  2513. {
  2514. lname.append(logicalName.get());
  2515. return lname;
  2516. }
  2517. void setLogicalName(const char *lname)
  2518. {
  2519. logicalName.set(lname);
  2520. }
  2521. const char *queryLogicalName()
  2522. {
  2523. return logicalName.get();
  2524. }
  2525. IPropertyTree &queryAttributes()
  2526. {
  2527. IPropertyTree *t = root->queryPropTree("Attr");
  2528. if (!t)
  2529. t = root->setPropTree("Attr",createPTree("Attr")); // takes ownership
  2530. return *t;
  2531. }
  2532. IPropertyTree *queryHistory() const
  2533. {
  2534. IPropertyTree *attr = root->queryPropTree("Attr");
  2535. if (attr)
  2536. return attr->queryPropTree("History");
  2537. return nullptr;
  2538. }
  2539. void resetHistory()
  2540. {
  2541. DistributedFilePropertyLock lock(this);
  2542. queryAttributes().removeTree(queryHistory());
  2543. }
  2544. protected:
  2545. class CFileChangeWriteLock
  2546. {
  2547. IRemoteConnection *conn;
  2548. unsigned timeoutMs, prevMode;
  2549. public:
  2550. CFileChangeWriteLock(IRemoteConnection *_conn, unsigned _timeoutMs)
  2551. : conn(_conn), timeoutMs(_timeoutMs)
  2552. {
  2553. if (conn)
  2554. {
  2555. prevMode = conn->queryMode();
  2556. unsigned newMode = (prevMode & ~RTM_LOCKBASIC_MASK) | RTM_LOCK_WRITE;
  2557. conn->changeMode(RTM_LOCK_WRITE, timeoutMs);
  2558. }
  2559. else
  2560. prevMode = RTM_NONE;
  2561. }
  2562. ~CFileChangeWriteLock()
  2563. {
  2564. if (conn)
  2565. conn->changeMode(prevMode, timeoutMs);
  2566. }
  2567. void clear() { conn = NULL; }
  2568. };
  2569. IPropertyTree *closeConnection(bool removeFile)
  2570. {
  2571. Owned<IPropertyTree> detachedRoot = createPTreeFromIPT(root);
  2572. root.clear();
  2573. if (conn)
  2574. {
  2575. conn->close(removeFile);
  2576. conn.clear();
  2577. }
  2578. return detachedRoot.getClear();
  2579. }
  2580. IPropertyTree *resetFileAttr(IPropertyTree *prop=NULL)
  2581. {
  2582. if (prop)
  2583. return root->setPropTree("Attr", prop);
  2584. root->removeProp("Attr");
  2585. return NULL;
  2586. }
  2587. void updateFS(const CDfsLogicalFileName &lfn, unsigned timeoutMs)
  2588. {
  2589. // Update the file system
  2590. removeFileEmptyScope(lfn, timeoutMs);
  2591. // MORE: We shouldn't have to update all relationships if we had done a better job making sure
  2592. // that all correct relationships were properly cleaned up
  2593. queryDistributedFileDirectory().removeAllFileRelationships(lfn.get());
  2594. }
  2595. public:
  2596. bool isAnon()
  2597. {
  2598. return !logicalName.isSet();
  2599. }
  2600. /*
  2601. * Change connection to write-mode, allowing multiple writers only on the same instance.
  2602. * Returns true if the lock was lost at least once before succeeding, hinting that some
  2603. * resources might need reload (like sub-files list, etc).
  2604. *
  2605. * WARN: This is not thread-safe
  2606. *
  2607. * @deprecated : use DistributedFilePropertyLock instead, when possible
  2608. */
  2609. bool lockProperties(unsigned timeoutms)
  2610. {
  2611. bool reload = false;
  2612. if (timeoutms==INFINITE)
  2613. timeoutms = defaultTimeout;
  2614. if (proplockcount++==0)
  2615. {
  2616. if (conn)
  2617. {
  2618. conn->rollback(); // changes chouldn't be done outside lock properties
  2619. #ifdef TRACE_LOCKS
  2620. PROGLOG("lockProperties: pre safeChangeModeWrite(%x)",(unsigned)(memsize_t)conn.get());
  2621. #endif
  2622. try
  2623. {
  2624. if (0 == timeoutms)
  2625. conn->changeMode(RTM_LOCK_WRITE, 0, true); // 0 timeout, test and fail immediately if contention
  2626. else
  2627. safeChangeModeWrite(conn,queryLogicalName(),reload,timeoutms);
  2628. }
  2629. catch(IException *)
  2630. {
  2631. proplockcount--;
  2632. dfCheckRoot("lockProperties",root,conn);
  2633. if (reload)
  2634. dirty = true; // safeChangeModeWrite unlocked, and reload will be need if retried
  2635. throw;
  2636. }
  2637. if (dirty) // a previous attempt unlocked and did not reload
  2638. {
  2639. dirty = false;
  2640. if (!reload) // if reload=true, safeChangeModeWrite has just reloaded, so no need to again here
  2641. {
  2642. conn->reload();
  2643. reload = true;
  2644. }
  2645. }
  2646. #ifdef TRACE_LOCKS
  2647. PROGLOG("lockProperties: done safeChangeModeWrite(%x)",(unsigned)(memsize_t)conn.get());
  2648. LogRemoteConn(conn);
  2649. #endif
  2650. dfCheckRoot("lockProperties",root,conn);
  2651. }
  2652. }
  2653. return reload;
  2654. }
  2655. /*
  2656. * Change connection back to read mode on the last unlock. There should never be
  2657. * an uneven number of locks/unlocks, since that will leave the connection with
  2658. * the DFS locked until the instance's destruction.
  2659. *
  2660. * WARN: This is not thread-safe
  2661. *
  2662. * @deprecated : use DistributedFilePropertyLock instead, when possible
  2663. */
  2664. void unlockProperties(DFTransactionState state=TAS_NONE)
  2665. {
  2666. savePartsAttr();
  2667. if (--proplockcount==0) {
  2668. if (conn) {
  2669. // Transactional logic, if any
  2670. switch(state) {
  2671. case TAS_SUCCESS:
  2672. conn->commit();
  2673. break;
  2674. case TAS_FAILURE:
  2675. conn->rollback();
  2676. break;
  2677. case TAS_RETRY:
  2678. conn->changeMode(RTM_NONE,defaultTimeout,true);
  2679. return;
  2680. // TAS_NONE, do nothing
  2681. }
  2682. #ifdef TRACE_LOCKS
  2683. PROGLOG("unlockProperties: pre changeMode(%x)",(unsigned)(memsize_t)conn.get());
  2684. #endif
  2685. conn->changeMode(RTM_LOCK_READ,defaultTimeout,true);
  2686. #ifdef TRACE_LOCKS
  2687. PROGLOG("unlockProperties: post changeMode(%x)",(unsigned)(memsize_t)conn.get());
  2688. LogRemoteConn(conn);
  2689. #endif
  2690. dfCheckRoot("unlockProperties",root,conn);
  2691. }
  2692. }
  2693. }
  2694. bool getModificationTime(CDateTime &dt)
  2695. {
  2696. StringBuffer str;
  2697. if (!root->getProp("@modified",str))
  2698. return false;
  2699. dt.setString(str.str());
  2700. return true;
  2701. }
  2702. void setModificationTime(const CDateTime &dt)
  2703. {
  2704. DistributedFilePropertyLock lock(this);
  2705. if (dt.isNull())
  2706. root->removeProp("@modified");
  2707. else {
  2708. StringBuffer str;
  2709. root->setProp("@modified",dt.getString(str).str());
  2710. }
  2711. root->removeProp("@verified");
  2712. }
  2713. void setModified()
  2714. {
  2715. CDateTime dt;
  2716. dt.setNow();
  2717. setModificationTime(dt);
  2718. }
  2719. virtual StringBuffer &getECL(StringBuffer &buf)
  2720. {
  2721. MemoryBuffer mb;
  2722. if (queryAttributes().getPropBin("ECLbin",mb))
  2723. buf.deserialize(mb);
  2724. else
  2725. queryAttributes().getProp("ECL",buf);
  2726. return buf;
  2727. }
  2728. virtual void setECL(const char *ecl)
  2729. {
  2730. DistributedFilePropertyLock lock(this);
  2731. IPropertyTree &p = queryAttributes();
  2732. #ifdef PACK_ECL
  2733. p.removeProp("ECL");
  2734. if (!ecl||!*ecl)
  2735. p.removeProp("ECLbin");
  2736. else {
  2737. MemoryBuffer mb; // could be better
  2738. StringBuffer buf(ecl);
  2739. buf.serialize(mb);
  2740. root->setPropBin("ECLbin",mb.length(),mb.toByteArray());
  2741. }
  2742. #else
  2743. p.setProp("ECL",ecl);
  2744. #endif
  2745. }
  2746. void setProtect(const char *owner, bool protect, unsigned timems)
  2747. {
  2748. if (logicalName.isForeign()) {
  2749. parent->setFileProtect(logicalName,udesc,owner,protect);
  2750. }
  2751. else {
  2752. bool ret=false;
  2753. if (conn) {
  2754. DistributedFilePropertyLock lock(this);
  2755. IPropertyTree &p = queryAttributes();
  2756. CDateTime dt;
  2757. dt.setNow();
  2758. if (setFileProtectTree(p,owner,protect))
  2759. conn->commit();
  2760. dfCheckRoot("setProtect.1",root,conn);
  2761. }
  2762. else
  2763. ERRLOG("setProtect - cannot protect %s (no connection in file)",owner?owner:"");
  2764. }
  2765. }
  2766. virtual IDistributedSuperFileIterator *getOwningSuperFiles(IDistributedFileTransaction *_transaction)
  2767. {
  2768. CriticalBlock block(sect);
  2769. return new CDistributedSuperFileIterator(this,parent,root,udesc,_transaction);
  2770. }
  2771. virtual void checkFormatAttr(IDistributedFile *sub, const char* exprefix="")
  2772. {
  2773. // check file has same (or similar) format
  2774. IPropertyTree &superProp = queryAttributes();
  2775. IPropertyTree &subProp = sub->queryAttributes();
  2776. if (!exprefix)
  2777. exprefix = "CheckFormatAttr";
  2778. bool superBlocked = false;
  2779. bool superComp = ::isCompressed(superProp,&superBlocked);
  2780. bool subBlocked = false;
  2781. bool subComp = ::isCompressed(subProp,&subBlocked);
  2782. // FIXME: this may fail if an empty superfile added to a compressed superfile
  2783. if (superComp != subComp)
  2784. throw MakeStringException(-1,"%s: %s's compression setting (%s) is different than %s's (%s)",
  2785. exprefix, sub->queryLogicalName(), (subComp?"compressed":"uncompressed"),
  2786. queryLogicalName(), (superComp?"compressed":"uncompressed"));
  2787. if (superBlocked != subBlocked)
  2788. throw MakeStringException(-1,"%s: %s's blocked setting (%s) is different than %s's (%s)",
  2789. exprefix, sub->queryLogicalName(), (subBlocked?"blocked":"unblocked"),
  2790. queryLogicalName(), (superBlocked?"blocked":"unblocked"));
  2791. #ifdef SUBFILE_COMPATIBILITY_CHECKING
  2792. bool subSoft = subProp.hasProp("_record_layout");
  2793. bool superSoft = superProp.hasProp("_record_layout");
  2794. if (superSoft != subSoft)
  2795. throw MakeStringException(-1,"%s: %s's record layout (%s) is different than %s's (%s)",
  2796. exprefix, sub->queryLogicalName(), (subSoft?"dynamic":"fixed"),
  2797. queryLogicalName(), (superSoft?"dynamic":"fixed"));
  2798. // If they don't, they must have the same size
  2799. if (!superSoft) {
  2800. unsigned superSize = superProp.getPropInt("@recordSize",0);
  2801. unsigned subSize = subProp.getPropInt("@recordSize",0);
  2802. // Variable length files (CSV, etc) have zero record size
  2803. if (superSize && subSize && (superSize != subSize))
  2804. throw MakeStringException(-1,"%s: %s's record size (%d) is different than %s's (%d)",
  2805. exprefix, sub->queryLogicalName(), subSize, queryLogicalName(), superSize);
  2806. }
  2807. StringBuffer superFmt;
  2808. bool superHasFmt = superProp.getProp("@format",superFmt);
  2809. StringBuffer subFmt;
  2810. bool subHasFmt = subProp.getProp("@format",subFmt);
  2811. if (subHasFmt && superHasFmt)
  2812. if (strcmp(normalizeFormat(superFmt).str(),normalizeFormat(subFmt).str()) != 0)
  2813. throw MakeStringException(-1,"%s: %s's format (%s) is different than %s's (%s)",
  2814. exprefix, sub->queryLogicalName(), superFmt.str(),
  2815. queryLogicalName(), subFmt.str());
  2816. #endif
  2817. bool superLocal = superProp.getPropBool("@local",false);
  2818. bool subLocal = subProp.getPropBool("@local",false);
  2819. if (subLocal != superLocal)
  2820. throw MakeStringException(-1,"%s: %s's local setting (%s) is different than %s's (%s)",
  2821. exprefix, sub->queryLogicalName(), (subLocal?"local":"global"),
  2822. queryLogicalName(), (superLocal?"local":"global"));
  2823. int superRepO = superProp.getPropInt("@replicateOffset",1);
  2824. int subRepO = subProp.getPropInt("@replicateOffset",1);
  2825. if (subRepO != superRepO)
  2826. throw MakeStringException(-1,"%s: %s's replication offset (%d) is different than %s's (%d)",
  2827. exprefix, sub->queryLogicalName(), subRepO,
  2828. queryLogicalName(), superRepO);
  2829. }
  2830. void getSuperOwners(StringArray &owners)
  2831. {
  2832. if (root)
  2833. {
  2834. StringBuffer owner;
  2835. Owned<IPropertyTreeIterator> iter = root->getElements("SuperOwner");
  2836. ForEach (*iter)
  2837. {
  2838. iter->query().getProp("@name", owner.clear());
  2839. if (owner.length())
  2840. {
  2841. if (NotFound == owners.find(owner))
  2842. owners.append(owner);
  2843. }
  2844. }
  2845. }
  2846. }
  2847. void linkSuperOwner(const char *superfile,bool link)
  2848. {
  2849. if (!superfile||!*superfile)
  2850. return;
  2851. if (conn)
  2852. {
  2853. CFileSuperOwnerLock attrLock;
  2854. if (0 == proplockcount)
  2855. verifyex(attrLock.init(logicalName, conn, defaultTimeout, "CDistributedFile::linkSuperOwner"));
  2856. Owned<IPropertyTree> t = getNamedPropTree(root,"SuperOwner","@name",superfile,false);
  2857. if (t && !link)
  2858. root->removeTree(t);
  2859. else if (!t && link)
  2860. t.setown(addNamedPropTree(root,"SuperOwner","@name",superfile));
  2861. }
  2862. else
  2863. ERRLOG("linkSuperOwner - cannot link to %s (no connection in file)",superfile);
  2864. }
  2865. void setAccessed()
  2866. {
  2867. CDateTime dt;
  2868. dt.setNow();
  2869. setAccessedTime(dt);
  2870. }
  2871. virtual StringBuffer &getColumnMapping(StringBuffer &mapping)
  2872. {
  2873. queryAttributes().getProp("@columnMapping",mapping);
  2874. return mapping;
  2875. }
  2876. virtual void setColumnMapping(const char *mapping)
  2877. {
  2878. DistributedFilePropertyLock lock(this);
  2879. if (!mapping||!*mapping)
  2880. queryAttributes().removeProp("@columnMapping");
  2881. else
  2882. queryAttributes().setProp("@columnMapping",mapping);
  2883. }
  2884. unsigned setDefaultTimeout(unsigned timems)
  2885. {
  2886. unsigned ret = defaultTimeout;
  2887. defaultTimeout = timems;
  2888. return ret;
  2889. }
  2890. // MORE - simplify this, after removing CLightWeightSuperFileConn
  2891. bool canModify(StringBuffer &reason)
  2892. {
  2893. return !checkProtectAttr(logicalName.get(),root,reason);
  2894. }
  2895. bool checkOwned(StringBuffer &error)
  2896. {
  2897. Owned<IPropertyTreeIterator> iter = root->getElements("SuperOwner");
  2898. if (iter->first())
  2899. {
  2900. error.append("Cannot remove file ").append(logicalName.get()).append(" as owned by SuperFile(s): ");
  2901. loop
  2902. {
  2903. error.append(iter->query().queryProp("@name"));
  2904. if (!iter->next())
  2905. break;
  2906. error.append(", ");
  2907. }
  2908. return true;
  2909. }
  2910. return false;
  2911. }
  2912. bool canRemove(StringBuffer &reason,bool ignoresub=false)
  2913. {
  2914. CriticalBlock block(sect);
  2915. if (!canModify(reason))
  2916. return false;
  2917. const char *logicalname = logicalName.get();
  2918. if (!logicalname||!*logicalname) {
  2919. reason.appendf("empty filename");
  2920. return false;
  2921. }
  2922. if (logicalName.isQuery())
  2923. {
  2924. reason.appendf("%s is query",logicalname);
  2925. return false;
  2926. }
  2927. if (logicalName.isForeign())
  2928. {
  2929. reason.appendf("%s is foreign",logicalname);
  2930. return false;
  2931. }
  2932. if (logicalName.isMulti())
  2933. {
  2934. reason.appendf("%s is multi",logicalname);
  2935. return false;
  2936. }
  2937. if (!ignoresub)
  2938. {
  2939. if (checkOwned(reason))
  2940. return false;
  2941. }
  2942. return true;
  2943. }
  2944. virtual const char *queryDefaultDir() = 0;
  2945. virtual unsigned numParts() = 0;
  2946. virtual IDistributedFilePart &queryPart(unsigned idx) = 0;
  2947. virtual IDistributedFilePart* getPart(unsigned idx) = 0;
  2948. virtual void savePartsAttr(bool force=false) = 0;
  2949. virtual IDistributedFilePartIterator *getIterator(IDFPartFilter *filter=NULL) = 0;
  2950. virtual IDistributedSuperFile *querySuperFile() = 0;
  2951. virtual ClusterPartDiskMapSpec &queryPartDiskMapping(unsigned clusternum)=0;
  2952. virtual void updatePartDiskMapping(const char *clustername,const ClusterPartDiskMapSpec &spec)=0;
  2953. virtual void enqueueReplicate()=0;
  2954. virtual bool getAccessedTime(CDateTime &dt) = 0; // get date and time last accessed (returns false if not set)
  2955. virtual void setAccessedTime(const CDateTime &dt) = 0; // set date and time last accessed
  2956. virtual bool isExternal() const { return external; }
  2957. };
  2958. class CDistributedFile: public CDistributedFileBase<IDistributedFile>
  2959. {
  2960. protected:
  2961. CDistributedFilePartArray parts; // use queryParts to access
  2962. CriticalSection sect;
  2963. StringAttr directory;
  2964. StringAttr partmask;
  2965. FileClusterInfoArray clusters;
  2966. void savePartsAttr(bool force)
  2967. {
  2968. CriticalBlock block (sect);
  2969. IPropertyTree *pt;
  2970. if (parts.ordinality()==1) { // single part saved as part
  2971. if (parts.item(0).clearDirty()||force) {
  2972. CDistributedFilePart &part = parts.item(0);
  2973. while ((pt=root->queryPropTree("Part[1]"))!=NULL)
  2974. root->removeTree(pt);
  2975. pt = createPTreeFromIPT(part.queryAttr());
  2976. pt->setPropInt("@num",1);
  2977. const char *grp = root->queryProp("@group");
  2978. if (!grp||!*grp) {
  2979. StringBuffer eps;
  2980. pt->addProp("@node",part.queryNode(0)->endpoint().getUrlStr(eps).str()); // legacy
  2981. }
  2982. const char *override = part.queryOverrideName();
  2983. if (override&&*override)
  2984. pt->setProp("@name",override);
  2985. else {
  2986. pt->removeProp("@name");
  2987. const char *mask=queryPartMask();
  2988. if (mask&&*mask) {
  2989. StringBuffer tmp;
  2990. expandMask(tmp,mask,0,1);
  2991. pt->setProp("@name",tmp.str());
  2992. }
  2993. }
  2994. root->setPropTree("Part",pt);
  2995. }
  2996. }
  2997. else {
  2998. unsigned n = parts.ordinality();
  2999. unsigned i1;
  3000. for (i1=0;i1<n;i1++) {
  3001. if (parts.item(i1).clearDirty()||force) {
  3002. MemoryBuffer mb;
  3003. CriticalBlock block (sect);
  3004. ForEachItemIn(i2,parts)
  3005. serializePartAttr(mb,parts.item(i2).queryAttr());
  3006. root->setPropBin("Parts",mb.length(),mb.toByteArray());
  3007. while ((pt=root->queryPropTree("Part[1]"))!=NULL)
  3008. root->removeTree(pt);
  3009. break;
  3010. }
  3011. }
  3012. while (i1<n)
  3013. parts.item(i1++).clearDirty();
  3014. }
  3015. }
  3016. void detach(unsigned timeoutMs, bool removePhysicals, ICodeContext *ctx)
  3017. {
  3018. // Removes either a cluster in case of multi cluster file or the whole File entry from DFS
  3019. assert(proplockcount == 0 && "CDistributedFile detach: Some properties are still locked");
  3020. assertex(!isAnon()); // not attached!
  3021. if (removePhysicals)
  3022. {
  3023. // Avoid removing physically when there is no physical representation
  3024. if (logicalName.isMulti())
  3025. removePhysicals = false;
  3026. }
  3027. StringBuffer clusterName;
  3028. Owned<IFileDescriptor> fileDescCopy;
  3029. #ifdef EXTRA_LOGGING
  3030. PROGLOG("CDistributedFile::detach(%s)",logicalName.get());
  3031. LOGPTREE("CDistributedFile::detach root.1",root);
  3032. #endif
  3033. {
  3034. CriticalBlock block(sect); // JCSMORE - not convinced this is still necessary
  3035. CFileChangeWriteLock writeLock(conn, timeoutMs);
  3036. logicalName.getCluster(clusterName);
  3037. // copy file descriptor before altered, used by physical file removal routines
  3038. if (removePhysicals)
  3039. {
  3040. MemoryBuffer mb;
  3041. Owned<IFileDescriptor> fdesc = getFileDescriptor(clusterName);
  3042. fdesc->serialize(mb);
  3043. fileDescCopy.setown(deserializeFileDescriptor(mb));
  3044. }
  3045. bool removeFile=true;
  3046. if (clusterName.length())
  3047. {
  3048. // Remove just cluster specified, unless it's the last, in which case detach below will remove File entry.
  3049. if (clusters.ordinality()>1)
  3050. {
  3051. if (removeCluster(clusterName.str()))
  3052. removeFile=false;
  3053. else
  3054. ThrowStringException(-1, "Cluster %s not present in file %s", clusterName.str(), logicalName.get());
  3055. }
  3056. }
  3057. if (removeFile)
  3058. {
  3059. // check can remove, e.g. cannot if this is a subfile of a super
  3060. StringBuffer reason;
  3061. if (!canRemove(reason))
  3062. throw MakeStringException(-1,"detach: %s", reason.str());
  3063. }
  3064. // detach this IDistributeFile
  3065. /* JCSMORE - In 'removeFile=true' case, this should really delete before release exclusive lock.
  3066. */
  3067. writeLock.clear();
  3068. root.setown(closeConnection(removeFile));
  3069. // NB: The file is now unlocked
  3070. if (removeFile && !logicalName.isExternal())
  3071. updateFS(logicalName, parent->queryDefaultTimeout());
  3072. logicalName.clear();
  3073. }
  3074. // NB: beyond unlock
  3075. if (removePhysicals)
  3076. {
  3077. CriticalBlock block(physicalChange);
  3078. Owned<IMultiException> exceptions = MakeMultiException("CDistributedFile::detach");
  3079. removePhysicalPartFiles(fileDescCopy, exceptions);
  3080. if (exceptions->ordinality())
  3081. throw exceptions.getClear();
  3082. }
  3083. }
  3084. bool removePhysicalPartFiles(IFileDescriptor *fileDesc, IMultiException *mexcept, unsigned numParallelDeletes=0)
  3085. {
  3086. if (logicalName.isExternal())
  3087. {
  3088. if (logicalName.isQuery())
  3089. return false;
  3090. }
  3091. if (logicalName.isForeign())
  3092. throw MakeStringException(-1,"cannot remove a foreign file (%s)",logicalName.get());
  3093. class casyncfor: public CAsyncFor
  3094. {
  3095. IFileDescriptor *fileDesc;
  3096. CriticalSection errcrit;
  3097. IMultiException *mexcept;
  3098. public:
  3099. bool ok;
  3100. bool islazy;
  3101. casyncfor(IFileDescriptor *_fileDesc, IMultiException *_mexcept)
  3102. {
  3103. fileDesc = _fileDesc;
  3104. ok = true;
  3105. islazy = false;
  3106. mexcept = _mexcept;
  3107. }
  3108. void Do(unsigned i)
  3109. {
  3110. IPartDescriptor *part = fileDesc->queryPart(i);
  3111. unsigned nc = part->numCopies();
  3112. for (unsigned copy = 0; copy < nc; copy++)
  3113. {
  3114. RemoteFilename rfn;
  3115. part->getFilename(copy, rfn);
  3116. Owned<IFile> partfile = createIFile(rfn);
  3117. StringBuffer eps;
  3118. try
  3119. {
  3120. unsigned start = msTick();
  3121. if (!partfile->remove()&&(copy==0)&&!islazy) // only warn about missing primary files
  3122. LOG(MCwarning, unknownJob, "Failed to remove file part %s from %s", partfile->queryFilename(),rfn.queryEndpoint().getUrlStr(eps).str());
  3123. else
  3124. {
  3125. unsigned t = msTick()-start;
  3126. if (t>5*1000)
  3127. LOG(MCwarning, unknownJob, "Removing %s from %s took %ds", partfile->queryFilename(), rfn.queryEndpoint().getUrlStr(eps).str(), t/1000);
  3128. }
  3129. }
  3130. catch (IException *e)
  3131. {
  3132. CriticalBlock block(errcrit);
  3133. if (mexcept)
  3134. mexcept->append(*e);
  3135. else
  3136. {
  3137. StringBuffer s("Failed to remove file part ");
  3138. s.append(partfile->queryFilename()).append(" from ");
  3139. rfn.queryEndpoint().getUrlStr(s);
  3140. EXCLOG(e, s.str());
  3141. e->Release();
  3142. }
  3143. ok = false;
  3144. }
  3145. }
  3146. }
  3147. } afor(fileDesc, mexcept);
  3148. afor.islazy = fileDesc->queryProperties().getPropBool("@lazy");
  3149. if (0 == numParallelDeletes)
  3150. numParallelDeletes = fileDesc->numParts();
  3151. if (numParallelDeletes > MAX_PHYSICAL_DELETE_THREADS)
  3152. {
  3153. WARNLOG("Limiting parallel physical delete threads to %d", MAX_PHYSICAL_DELETE_THREADS);
  3154. numParallelDeletes = MAX_PHYSICAL_DELETE_THREADS;
  3155. }
  3156. afor.For(fileDesc->numParts(),numParallelDeletes,false,true);
  3157. return afor.ok;
  3158. }
  3159. protected: friend class CDistributedFilePart;
  3160. CDistributedFilePartArray &queryParts()
  3161. {
  3162. return parts;
  3163. }
  3164. public:
  3165. IMPLEMENT_IINTERFACE;
  3166. CDistributedFile(CDistributedFileDirectory *_parent, IRemoteConnection *_conn,const CDfsLogicalFileName &lname,IUserDescriptor *user) // takes ownership of conn
  3167. {
  3168. setUserDescriptor(udesc,user);
  3169. logicalName.set(lname);
  3170. parent = _parent;
  3171. conn.setown(_conn);
  3172. CClustersLockedSection sect(logicalName, false);
  3173. root.setown(conn->getRoot());
  3174. root->queryBranch("."); // load branch
  3175. #ifdef EXTRA_LOGGING
  3176. LOGPTREE("CDistributedFile.a root",root);
  3177. #endif
  3178. Owned<IFileDescriptor> fdesc = deserializeFileDescriptorTree(root,&queryNamedGroupStore(),0);
  3179. #ifdef EXTRA_LOGGING
  3180. LOGFDESC("CDistributedFile.a fdesc",fdesc);
  3181. #endif
  3182. setFileAttrs(fdesc,false);
  3183. setClusters(fdesc);
  3184. setPreferredClusters(_parent->defprefclusters);
  3185. setParts(fdesc,false);
  3186. //shrinkFileTree(root); // enable when safe!
  3187. }
  3188. CDistributedFile(CDistributedFileDirectory *_parent, IFileDescriptor *fdesc, IUserDescriptor *user, bool _external)
  3189. {
  3190. #ifdef EXTRA_LOGGING
  3191. LOGFDESC("CDistributedFile.b fdesc",fdesc);
  3192. #endif
  3193. parent = _parent;
  3194. root.setown(createPTree(queryDfsXmlBranchName(DXB_File)));
  3195. root->setPropTree("ClusterLock", createPTree());
  3196. // fdesc->serializeTree(*root,IFDSF_EXCLUDE_NODES);
  3197. setFileAttrs(fdesc,true);
  3198. setClusters(fdesc);
  3199. setPreferredClusters(_parent->defprefclusters);
  3200. saveClusters();
  3201. setParts(fdesc,true);
  3202. udesc.set(user);
  3203. external = _external;
  3204. #ifdef EXTRA_LOGGING
  3205. LOGPTREE("CDistributedFile.b root.1",root);
  3206. #endif
  3207. offset_t totalsize=0;
  3208. unsigned checkSum = ~0;
  3209. bool useableCheckSum = true;
  3210. MemoryBuffer pmb;
  3211. unsigned n = fdesc->numParts();
  3212. for (unsigned i=0;i<n;i++) {
  3213. IPropertyTree *partattr = &fdesc->queryPart(i)->queryProperties();
  3214. if (!partattr)
  3215. {
  3216. totalsize = (unsigned)-1;
  3217. useableCheckSum = false;
  3218. }
  3219. else
  3220. {
  3221. offset_t psz;
  3222. if (totalsize!=(offset_t)-1) {
  3223. psz = (offset_t)partattr->getPropInt64("@size", -1);
  3224. if (psz==(offset_t)-1)
  3225. totalsize = psz;
  3226. else
  3227. totalsize += psz;
  3228. }
  3229. if (useableCheckSum) {
  3230. unsigned crc;
  3231. if (fdesc->queryPart(i)->getCrc(crc))
  3232. checkSum ^= crc;
  3233. else
  3234. useableCheckSum = false;
  3235. }
  3236. }
  3237. }
  3238. shrinkFileTree(root);
  3239. if (totalsize!=(offset_t)-1)
  3240. queryAttributes().setPropInt64("@size", totalsize);
  3241. if (useableCheckSum)
  3242. queryAttributes().setPropInt64("@checkSum", checkSum);
  3243. setModified();
  3244. #ifdef EXTRA_LOGGING
  3245. LOGPTREE("CDistributedFile.b root.2",root);
  3246. #endif
  3247. }
  3248. void killParts()
  3249. {
  3250. ForEachItemIn(i,parts)
  3251. parts.item(i).childRelease();
  3252. parts.kill(true);
  3253. }
  3254. ~CDistributedFile()
  3255. {
  3256. assert(proplockcount == 0 && "CDistributedFile destructor: Some properties are still locked");
  3257. if (conn)
  3258. conn->rollback(); // changes should always be done in locked properties
  3259. killParts();
  3260. clusters.kill();
  3261. }
  3262. IFileDescriptor *getFileDescriptor(const char *_clusterName)
  3263. {
  3264. CriticalBlock block (sect);
  3265. Owned<IFileDescriptor> fdesc = deserializeFileDescriptorTree(root,&queryNamedGroupStore(),0);
  3266. fdesc->setTraceName(logicalName.get());
  3267. StringArray cnames;
  3268. if (_clusterName&&*_clusterName)
  3269. {
  3270. StringAttr clusterName = _clusterName;
  3271. clusterName.toLowerCase();
  3272. cnames.append(clusterName);
  3273. }
  3274. else
  3275. getClusterNames(cnames);
  3276. fdesc->setClusterOrder(cnames,_clusterName&&*_clusterName);
  3277. return fdesc.getClear();
  3278. }
  3279. void setFileAttrs(IFileDescriptor *fdesc,bool save)
  3280. {
  3281. directory.set(fdesc->queryDefaultDir());
  3282. partmask.set(fdesc->queryPartMask());
  3283. const char *lfn = logicalName.get();
  3284. if (lfn&&*lfn) {
  3285. if (partmask.isEmpty()) {
  3286. StringBuffer mask;
  3287. getPartMask(mask,lfn,0);
  3288. partmask.set(mask);
  3289. }
  3290. }
  3291. if (!save)
  3292. return;
  3293. if (directory.isEmpty())
  3294. root->removeProp("@directory");
  3295. else
  3296. root->setProp("@directory",directory);
  3297. if (partmask.isEmpty())
  3298. root->removeProp("@partmask");
  3299. else
  3300. root->setProp("@partmask",partmask);
  3301. IPropertyTree *t = &fdesc->queryProperties();
  3302. if (isEmptyPTree(t))
  3303. resetFileAttr();
  3304. else
  3305. resetFileAttr(createPTreeFromIPT(t));
  3306. }
  3307. void setClusters(IFileDescriptor *fdesc)
  3308. {
  3309. clusters.clear();
  3310. unsigned nc = fdesc->numClusters();
  3311. if (nc) {
  3312. for (unsigned i=0;i<nc;i++) {
  3313. StringBuffer cname;
  3314. StringBuffer clabel;
  3315. IClusterInfo &cluster = *createClusterInfo(
  3316. fdesc->getClusterGroupName(i,cname,NULL).str(),
  3317. fdesc->queryClusterGroup(i),
  3318. fdesc->queryPartDiskMapping(i),
  3319. &queryNamedGroupStore()
  3320. );
  3321. #ifdef EXTRA_LOGGING
  3322. PROGLOG("setClusters(%d,%s)",i,cname.str());
  3323. #endif
  3324. if (!cluster.queryGroup(&queryNamedGroupStore())) {
  3325. ERRLOG("IDistributedFileDescriptor cannot set cluster for %s",logicalName.get());
  3326. }
  3327. clusters.append(cluster);
  3328. }
  3329. }
  3330. else
  3331. ERRLOG("No cluster specified for %s",logicalName.get());
  3332. }
  3333. unsigned numClusters()
  3334. {
  3335. return clusters.ordinality();
  3336. }
  3337. unsigned findCluster(const char *clustername)
  3338. {
  3339. return clusters.find(clustername);
  3340. }
  3341. unsigned getClusterNames(StringArray &clusternames)
  3342. {
  3343. return clusters.getNames(clusternames);
  3344. }
  3345. void reloadClusters()
  3346. {
  3347. // called from CClustersLockedSection
  3348. if (!CDistributedFileBase<IDistributedFile>::conn)
  3349. return;
  3350. assertex(CDistributedFileBase<IDistributedFile>::proplockcount==0); // cannot reload clusters if properties locked
  3351. CDistributedFileBase<IDistributedFile>::conn->reload(); // should only be cluster changes but a bit dangerous
  3352. IPropertyTree *t = CDistributedFileBase<IDistributedFile>::conn->queryRoot(); // NB not CDistributedFileBase<IDistributedFile>::queryRoot();
  3353. if (!t)
  3354. return;
  3355. clusters.clear();
  3356. getClusterInfo(*t,&queryNamedGroupStore(),0,clusters);
  3357. }
  3358. void saveClusters()
  3359. {
  3360. // called from CClustersLockedSection
  3361. IPropertyTree *t;
  3362. if (CDistributedFileBase<IDistributedFile>::conn)
  3363. t = CDistributedFileBase<IDistributedFile>::conn->queryRoot();
  3364. else
  3365. t = CDistributedFileBase<IDistributedFile>::queryRoot(); //cache
  3366. if (!t)
  3367. return;
  3368. IPropertyTree *pt;
  3369. IPropertyTree *tc = CDistributedFileBase<IDistributedFile>::queryRoot(); //cache
  3370. IPropertyTree *t0 = t;
  3371. StringBuffer grplist;
  3372. // the following is complicated by fact there is a cache of the file branch
  3373. loop {
  3374. while ((pt=t->queryPropTree("Cluster[1]"))!=NULL)
  3375. t->removeTree(pt);
  3376. ForEachItemIn(i,clusters) {
  3377. IPropertyTree *pt = createPTree("Cluster");
  3378. clusters.item(i).serializeTree(pt,IFDSF_EXCLUDE_GROUPS);
  3379. if (!isEmptyPTree(pt)) {
  3380. t->addPropTree("Cluster",pt);
  3381. if (t==t0) {
  3382. StringBuffer clabel;
  3383. clusters.item(i).getClusterLabel(clabel);
  3384. if (clabel.length()) {
  3385. if (grplist.length())
  3386. grplist.append(',');
  3387. grplist.append(clabel);
  3388. }
  3389. }
  3390. }
  3391. else
  3392. WARNLOG("CFileClusterOwner::saveClusters - empty cluster");
  3393. }
  3394. if (grplist.length())
  3395. t->setProp("@group",grplist.str());
  3396. else
  3397. t->removeProp("@group");
  3398. t->setPropInt("@numclusters",clusters.ordinality());
  3399. t->setProp("@directory", directory);
  3400. if (t==tc)
  3401. break;
  3402. t = tc; // now fix cache
  3403. }
  3404. if (CDistributedFileBase<IDistributedFile>::conn)
  3405. CDistributedFileBase<IDistributedFile>::conn->commit(); // should only be cluster changes but a bit dangerous
  3406. }
  3407. void addCluster(const char *clustername,const ClusterPartDiskMapSpec &mspec)
  3408. {
  3409. if (!clustername&&!*clustername)
  3410. return;
  3411. CClustersLockedSection cls(CDistributedFileBase<IDistributedFile>::logicalName, true);
  3412. reloadClusters();
  3413. if (findCluster(clustername)!=NotFound) {
  3414. IDFS_Exception *e = new CDFS_Exception(DFSERR_ClusterAlreadyExists,clustername);
  3415. throw e;
  3416. }
  3417. Owned<IClusterInfo> cluster = createClusterInfo(clustername,NULL,mspec,&queryNamedGroupStore());
  3418. if (cluster->queryGroup(&queryNamedGroupStore())) {
  3419. clusters.append(*cluster.getClear());
  3420. }
  3421. else {
  3422. IDFS_Exception *e = new CDFS_Exception(DFSERR_ClusterNotFound,clustername);
  3423. throw e;
  3424. }
  3425. saveClusters();
  3426. }
  3427. bool removeCluster(const char *clustername)
  3428. {
  3429. CClustersLockedSection cls(CDistributedFileBase<IDistributedFile>::logicalName, true);
  3430. reloadClusters();
  3431. unsigned i = findCluster(clustername);
  3432. if (i!=NotFound) {
  3433. if (clusters.ordinality()==1)
  3434. throw MakeStringException(-1,"CFileClusterOwner::removeCluster cannot remove sole cluster %s",clustername);
  3435. // If the cluster is the 'default' one we need to update the directory too
  3436. StringBuffer oldBaseDir;
  3437. char pathSepChar = getPathSepChar(directory.get());
  3438. DFD_OS os = SepCharBaseOs(pathSepChar);
  3439. clusters.item(i).getBaseDir(oldBaseDir, os);
  3440. unsigned oldLen = oldBaseDir.length();
  3441. clusters.remove(i);
  3442. if (oldLen && strncmp(directory, oldBaseDir, oldLen)==0 && (directory[oldLen]==pathSepChar || directory[oldLen]=='\0'))
  3443. {
  3444. StringBuffer newBaseDir;
  3445. clusters.item(0).getBaseDir(newBaseDir, os);
  3446. newBaseDir.append(directory.get() + oldBaseDir.length());
  3447. directory.set(newBaseDir);
  3448. }
  3449. saveClusters();
  3450. return true;
  3451. }
  3452. return false;
  3453. }
  3454. void setPreferredClusters(const char *clusterlist)
  3455. {
  3456. clusters.setPreferred(clusterlist,CDistributedFileBase<IDistributedFile>::logicalName);
  3457. }
  3458. INode *queryNode(unsigned idx,unsigned copy)
  3459. {
  3460. unsigned rep;
  3461. unsigned cluster = copyClusterNum(idx,copy,&rep);
  3462. if (cluster==NotFound)
  3463. return queryNullNode();
  3464. unsigned nn;
  3465. unsigned dn;
  3466. IGroup *grp = clusters.queryGroup(cluster);
  3467. if (!grp)
  3468. return queryNullNode();
  3469. if (!clusters.item(cluster).queryPartDiskMapping().calcPartLocation (idx, numParts(),rep, grp->ordinality(), nn, dn))
  3470. return queryNullNode();
  3471. return &grp->queryNode(nn);
  3472. }
  3473. unsigned queryDrive(unsigned idx,unsigned copy,const char *dir)
  3474. {
  3475. // this is odd routine
  3476. unsigned dn = dir?getPathDrive(dir):0;
  3477. if (dn)
  3478. return dn;
  3479. unsigned rep;
  3480. unsigned cluster = copyClusterNum(idx,copy,&rep);
  3481. if (cluster==NotFound)
  3482. return 0;
  3483. unsigned nn;
  3484. IGroup *grp = clusters.queryGroup(cluster);
  3485. if (!grp)
  3486. return 0;
  3487. if (!clusters.item(cluster).queryPartDiskMapping().calcPartLocation (idx, numParts(),rep, grp->ordinality(), nn, dn))
  3488. return 0;
  3489. return dn;
  3490. }
  3491. StringBuffer &getClusterName(unsigned clusternum,StringBuffer &name)
  3492. {
  3493. return clusters.getName(clusternum,name);
  3494. }
  3495. unsigned copyClusterNum(unsigned part, unsigned copy,unsigned *replicate)
  3496. {
  3497. return clusters.copyNum(part,copy, numParts(),replicate);
  3498. }
  3499. ClusterPartDiskMapSpec &queryPartDiskMapping(unsigned clusternum)
  3500. {
  3501. assertex(clusternum<clusters.ordinality());
  3502. return clusters.queryPartDiskMapping(clusternum);
  3503. }
  3504. void updatePartDiskMapping(const char *clustername,const ClusterPartDiskMapSpec &spec)
  3505. {
  3506. CClustersLockedSection cls(CDistributedFileBase<IDistributedFile>::logicalName, true);
  3507. reloadClusters();
  3508. unsigned i = findCluster(clustername);
  3509. if (i!=NotFound) {
  3510. clusters.updatePartDiskMapping(i,spec);
  3511. saveClusters();
  3512. }
  3513. }
  3514. IGroup *queryClusterGroup(unsigned clusternum)
  3515. {
  3516. return clusters.queryGroup(clusternum);
  3517. }
  3518. StringBuffer &getClusterGroupName(unsigned clusternum, StringBuffer &name)
  3519. {
  3520. return clusters.item(clusternum).getGroupName(name, &queryNamedGroupStore());
  3521. }
  3522. virtual unsigned numCopies(unsigned partno)
  3523. {
  3524. return clusters.numCopies(partno,numParts());
  3525. }
  3526. void setSingleClusterOnly()
  3527. {
  3528. clusters.setSingleClusterOnly();
  3529. }
  3530. unsigned numClusterCopies(unsigned cnum,unsigned partnum)
  3531. {
  3532. IClusterInfo &cluster = clusters.item(cnum);
  3533. IGroup *grp = cluster.queryGroup();
  3534. return cluster.queryPartDiskMapping().numCopies(partnum,grp?grp->ordinality():1,numParts());
  3535. }
  3536. void adjustClusterDir(unsigned partno,unsigned copy, StringBuffer &path)
  3537. {
  3538. // this corrects the directory for a copy
  3539. // assumes default dir matches one of clusters
  3540. unsigned rep=0;
  3541. unsigned cluster = NotFound;
  3542. const char *ds = path.str();
  3543. unsigned nc = clusters.ordinality();
  3544. if (nc>1) {
  3545. StringAttr matched;
  3546. StringAttr toadd;
  3547. unsigned i=0;
  3548. bool c = 0;
  3549. int cp = (int)copy;
  3550. while (i<nc) {
  3551. StringBuffer dcmp;
  3552. clusters.item(i).getBaseDir(dcmp,SepCharBaseOs(getPathSepChar(ds))); // no trailing sep
  3553. const char *t = dcmp.str();
  3554. const char *d = ds;
  3555. while (*d&&(*t==*d)) {
  3556. d++;
  3557. t++;
  3558. }
  3559. if (!*t&&(!*d||isPathSepChar(*d))&&(dcmp.length()>matched.length()))
  3560. matched.set(dcmp);
  3561. unsigned mc = numClusterCopies(i,partno);
  3562. if ((cp>=0)&&(cp<(int)mc)) {
  3563. toadd.set(dcmp);
  3564. rep = (unsigned)cp;
  3565. cluster = i;
  3566. }
  3567. cp -= mc;
  3568. i++;
  3569. }
  3570. if (!matched.isEmpty()&&!toadd.isEmpty()&&(strcmp(matched,toadd)!=0)) {
  3571. StringBuffer tmp(toadd);
  3572. tmp.append(ds+matched.length());
  3573. path.swapWith(tmp);
  3574. }
  3575. }
  3576. else {
  3577. rep = copy;
  3578. cluster = 0;
  3579. }
  3580. // now set replicate
  3581. if (cluster!=NotFound) {
  3582. unsigned n;
  3583. unsigned d;
  3584. ClusterPartDiskMapSpec& mspec = clusters.item(cluster).queryPartDiskMapping();
  3585. mspec.calcPartLocation(partno,numParts(),rep,clusters.queryGroup(cluster)?clusters.queryGroup(cluster)->ordinality():numParts(),n,d);
  3586. if ((d==1) && (mspec.flags&CPDMSF_overloadedConfig) && mspec.defaultReplicateDir.length())
  3587. path.set(mspec.defaultReplicateDir.get());
  3588. else
  3589. setReplicateFilename(path,d);
  3590. }
  3591. }
  3592. void setParts(IFileDescriptor *fdesc,bool save)
  3593. {
  3594. unsigned np = fdesc->numParts();
  3595. for (unsigned i = 0;i<np;i++) {
  3596. CDistributedFilePart &part = *new CDistributedFilePart(*this,i,fdesc->queryPart(i));
  3597. parts.append(part);
  3598. }
  3599. if (save) {
  3600. root->setPropInt("@numparts",parts.ordinality());
  3601. savePartsAttr(true);
  3602. }
  3603. }
  3604. unsigned numParts()
  3605. {
  3606. return parts.ordinality();
  3607. }
  3608. IDistributedFilePart &queryPart(unsigned idx)
  3609. {
  3610. if (idx<parts.ordinality())
  3611. return queryParts().item(idx);
  3612. return *(IDistributedFilePart *)NULL;
  3613. }
  3614. IDistributedFilePart* getPart(unsigned idx)
  3615. {
  3616. if (idx>=parts.ordinality())
  3617. return NULL;
  3618. IDistributedFilePart *ret = &queryParts().item(idx);
  3619. return LINK(ret);
  3620. }
  3621. IDistributedFilePartIterator *getIterator(IDFPartFilter *filter=NULL)
  3622. {
  3623. return new CDistributedFilePartIterator(queryParts(),filter);
  3624. }
  3625. void rename(const char *_logicalname,IUserDescriptor *user)
  3626. {
  3627. StringBuffer prevname;
  3628. Owned<IFileRelationshipIterator> reliter;
  3629. // set prevname
  3630. if (!isAnon()) {
  3631. getLogicalName(prevname);
  3632. try {
  3633. IFileRelationshipIterator *iter = parent->lookupAllFileRelationships(prevname.str());
  3634. reliter.setown(iter);
  3635. }
  3636. catch (IException *e) {
  3637. EXCLOG(e,"CDistributedFile::rename");
  3638. e->Release();
  3639. }
  3640. detachLogical();
  3641. }
  3642. attach(_logicalname,user);
  3643. if (prevname.length()) {
  3644. DistributedFilePropertyLock lock(this);
  3645. IPropertyTree &pt = queryAttributes();
  3646. StringBuffer list;
  3647. if (pt.getProp("@renamedFrom",list)&&list.length())
  3648. list.append(',');
  3649. pt.setProp("@renamedFrom",list.append(prevname).str());
  3650. }
  3651. if (reliter.get()) {
  3652. // add back any relationships with new name
  3653. parent->renameFileRelationships(prevname.str(),_logicalname,reliter,user);
  3654. }
  3655. }
  3656. const char *queryDefaultDir()
  3657. {
  3658. CriticalBlock block (sect);
  3659. return directory.get();
  3660. }
  3661. const char *queryPartMask()
  3662. {
  3663. CriticalBlock block (sect);
  3664. if (partmask.isEmpty()) {
  3665. assertex(root);
  3666. partmask.set(root->queryProp("@partmask"));
  3667. }
  3668. return partmask.get();
  3669. }
  3670. bool isAnon()
  3671. {
  3672. return (!logicalName.isSet());
  3673. }
  3674. void attach(const char *_logicalname,IUserDescriptor *user)
  3675. {
  3676. CriticalBlock block (sect);
  3677. assertex(isAnon()); // already attached!
  3678. logicalName.set(_logicalname);
  3679. if (!checkLogicalName(logicalName,user,true,true,true,"attach"))
  3680. return; // query
  3681. #ifdef EXTRA_LOGGING
  3682. PROGLOG("CDistributedFile::attach(%s)",_logicalname);
  3683. LOGPTREE("CDistributedFile::attach root.1",root);
  3684. #endif
  3685. parent->addEntry(logicalName,root.getClear(),false,false);
  3686. killParts();
  3687. clusters.kill();
  3688. CFileLock fcl;
  3689. verifyex(fcl.init(logicalName, DXB_File, RTM_LOCK_READ, defaultTimeout, "CDistributedFile::attach"));
  3690. conn.setown(fcl.detach());
  3691. root.setown(conn->getRoot());
  3692. root->queryBranch("."); // load branch
  3693. Owned<IFileDescriptor> fdesc = deserializeFileDescriptorTree(root,&queryNamedGroupStore(),0);
  3694. setFileAttrs(fdesc,false);
  3695. setClusters(fdesc);
  3696. setParts(fdesc,false);
  3697. setUserDescriptor(udesc, user);
  3698. #ifdef EXTRA_LOGGING
  3699. LOGFDESC("CDistributedFile::attach fdesc",fdesc);
  3700. LOGPTREE("CDistributedFile::attach root.2",root);
  3701. #endif
  3702. }
  3703. /*
  3704. * Internal method (not in IDistributedFile interface) that is used
  3705. * when renaming files (so don't delete the physical representation).
  3706. *
  3707. * This is also used during CPPUINT tests, so we need to make them public
  3708. * only when tests are enabled (ie. non-production mode).
  3709. *
  3710. * See removeLogical()
  3711. */
  3712. public:
  3713. void detachLogical(unsigned timeoutms=INFINITE)
  3714. {
  3715. detach(timeoutms, false, NULL);
  3716. }
  3717. public:
  3718. virtual void detach(unsigned timeoutMs=INFINITE, ICodeContext *ctx=NULL)
  3719. {
  3720. detach(timeoutMs, true, ctx);
  3721. }
  3722. bool existsPhysicalPartFiles(unsigned short port)
  3723. {
  3724. unsigned width = numParts();
  3725. CriticalSection errcrit;
  3726. class casyncfor: public CAsyncFor
  3727. {
  3728. IDistributedFile *file;
  3729. unsigned short port;
  3730. CriticalSection &errcrit;
  3731. unsigned width;
  3732. public:
  3733. bool ok;
  3734. casyncfor(IDistributedFile *_file,unsigned _width,unsigned short _port,CriticalSection &_errcrit)
  3735. : errcrit(_errcrit)
  3736. {
  3737. file = _file;
  3738. port = _port;
  3739. ok = true;
  3740. width = _width;
  3741. ok = true;
  3742. }
  3743. void Do(unsigned i)
  3744. {
  3745. {
  3746. CriticalBlock block(errcrit);
  3747. if (!ok)
  3748. return;
  3749. }
  3750. Owned<IDistributedFilePart> part = file->getPart(i);
  3751. unsigned nc = part->numCopies();
  3752. for (unsigned copy = 0; copy < nc; copy++)
  3753. {
  3754. RemoteFilename rfn;
  3755. part->getFilename(rfn,copy);
  3756. if (port)
  3757. rfn.setPort(port); // if daliservix
  3758. Owned<IFile> partfile = createIFile(rfn);
  3759. try
  3760. {
  3761. if (partfile->exists())
  3762. return;
  3763. }
  3764. catch (IException *e)
  3765. {
  3766. CriticalBlock block(errcrit);
  3767. StringBuffer s("Failed to find file part ");
  3768. s.append(partfile->queryFilename()).append(" on ");
  3769. rfn.queryEndpoint().getUrlStr(s);
  3770. EXCLOG(e, s.str());
  3771. e->Release();
  3772. }
  3773. }
  3774. CriticalBlock block(errcrit);
  3775. ok = false;
  3776. }
  3777. } afor(this,width,port,errcrit);
  3778. afor.For(width,10,false,true);
  3779. return afor.ok;
  3780. }
  3781. // This method takes an existing physical directory path for a logical file
  3782. // and a constructed path to the same logical file created in this context
  3783. // and deduces the original base path e.g. /var/lib/HPCCSystems/hpcc-data/thor
  3784. // This is necessary, because there is no not enough context to directly fetch the
  3785. // original base path to construct new paths for the rename
  3786. bool getBase(const char *oldPath, const char *thisPath, StringBuffer &baseDir)
  3787. {
  3788. const char *oldEnd = oldPath+strlen(oldPath)-1;
  3789. const char *thisEnd = thisPath+strlen(thisPath)-1;
  3790. if (isPathSepChar(*oldEnd))
  3791. oldEnd--;
  3792. if (isPathSepChar(*thisEnd))
  3793. thisEnd--;
  3794. const char *oldP = oldEnd, *thisP = thisEnd;
  3795. loop {
  3796. if (oldP==oldPath || thisP==thisPath)
  3797. break;
  3798. if (*oldP != *thisP) {
  3799. // unless last was separator, continue until find one
  3800. if (isPathSepChar(*(oldP+1)))
  3801. oldP++;
  3802. else {
  3803. while (oldP != oldPath && (!isPathSepChar(*oldP)))
  3804. oldP--;
  3805. }
  3806. baseDir.append(oldP-oldPath, oldPath);
  3807. return true;
  3808. }
  3809. --oldP;
  3810. --thisP;
  3811. }
  3812. return false;
  3813. }
  3814. bool renamePhysicalPartFiles(const char *newname,
  3815. const char *cluster,
  3816. IMultiException *mexcept,
  3817. const char *newbasedir)
  3818. {
  3819. // cluster TBD
  3820. unsigned width = numParts();
  3821. StringBuffer newdir;
  3822. StringBuffer newmask;
  3823. const char *diroverride = NULL;
  3824. char psc = getPathSepChar(directory.get());
  3825. DFD_OS os = SepCharBaseOs(psc);
  3826. StringBuffer basedir;
  3827. if (newbasedir)
  3828. diroverride = newbasedir;
  3829. const char *myBase = queryBaseDirectory(grp_unknown, 0, os);
  3830. StringBuffer baseDir, newPath;
  3831. makePhysicalPartName(logicalName.get(), 0, 0, newPath, false, os, diroverride);
  3832. if (!getBase(directory, newPath, baseDir))
  3833. baseDir.append(myBase); // getBase returns false, if directory==newPath, so have common base
  3834. getPartMask(newmask,newname,width);
  3835. if (newmask.length()==0)
  3836. return false;
  3837. makePhysicalPartName(newname, 0, 0, newPath.clear(), false, os, diroverride);
  3838. if (newPath.length()==0)
  3839. return false;
  3840. if (isPathSepChar(newPath.charAt(newPath.length()-1)))
  3841. newPath.setLength(newPath.length()-1);
  3842. newPath.remove(0, strlen(myBase));
  3843. newdir.append(baseDir).append(newPath);
  3844. StringBuffer fullname;
  3845. CIArrayOf<CIStringArray> newNames;
  3846. unsigned i;
  3847. for (i=0;i<width;i++) {
  3848. newNames.append(*new CIStringArray);
  3849. CDistributedFilePart &part = parts.item(i);
  3850. for (unsigned copy=0; copy<part.numCopies(); copy++) {
  3851. makePhysicalPartName(newname, i+1, width, newPath.clear(), false, os, myBase);
  3852. newPath.remove(0, strlen(myBase));
  3853. StringBuffer copyDir(baseDir);
  3854. adjustClusterDir(i, copy, copyDir);
  3855. fullname.clear().append(copyDir).append(newPath);
  3856. PROGLOG("fullname = %s", fullname.str());
  3857. newNames.item(i).append(fullname);
  3858. }
  3859. }
  3860. // NB: the code below, specifically deals with 1 primary + 1 replicate
  3861. // it will need refactoring if it's to deal with multiple clusters/copies
  3862. // first check file doestn't exist for any new part
  3863. CriticalSection crit;
  3864. class casyncforbase: public CAsyncFor
  3865. {
  3866. protected:
  3867. CriticalSection &crit;
  3868. CIArrayOf<CIStringArray> &newNames;
  3869. IDistributedFile *file;
  3870. unsigned width;
  3871. IMultiException *mexcept;
  3872. bool *ignoreprim;
  3873. bool *ignorerep;
  3874. public:
  3875. bool ok;
  3876. bool * doneprim;
  3877. bool * donerep;
  3878. IException *except;
  3879. casyncforbase(IDistributedFile *_file,CIArrayOf<CIStringArray> &_newNames,unsigned _width,IMultiException *_mexcept,CriticalSection &_crit,bool *_ignoreprim,bool *_ignorerep)
  3880. : newNames(_newNames),crit(_crit)
  3881. {
  3882. width = _width;
  3883. file = _file;
  3884. ok = true;
  3885. mexcept = _mexcept;
  3886. doneprim = (bool *)calloc(sizeof(bool),width);
  3887. donerep = (bool *)calloc(sizeof(bool),width);
  3888. except = NULL;
  3889. ignoreprim = _ignoreprim;
  3890. ignorerep = _ignorerep;
  3891. }
  3892. ~casyncforbase()
  3893. {
  3894. free(doneprim);
  3895. free(donerep);
  3896. }
  3897. virtual bool doPart(IDistributedFilePart *,bool,RemoteFilename &,RemoteFilename &, bool &)
  3898. #ifdef _WIN32
  3899. {
  3900. assertex(!"doPart"); // stupid microsoft error
  3901. return false;
  3902. }
  3903. #else
  3904. = 0;
  3905. #endif
  3906. void Do(unsigned idx)
  3907. {
  3908. {
  3909. CriticalBlock block(crit);
  3910. if (!ok)
  3911. return;
  3912. }
  3913. Owned<IDistributedFilePart> part = file->getPart(idx);
  3914. unsigned copies = part->numCopies();
  3915. for (int copy = copies-1; copy>=0; copy--)
  3916. {
  3917. if ((copy==0)&&ignoreprim&&ignoreprim[idx])
  3918. continue;
  3919. if ((copy!=0)&&ignorerep&&ignorerep[idx])
  3920. continue;
  3921. bool pok=false;
  3922. IException *ex = NULL;
  3923. RemoteFilename oldrfn;
  3924. part->getFilename(oldrfn,(unsigned)copy);
  3925. const char *newfn = newNames.item(idx).item(copy);
  3926. if (!newfn||!*newfn)
  3927. continue;
  3928. RemoteFilename newrfn;
  3929. newrfn.setPath(part->queryNode(copy)->endpoint(),newfn);
  3930. try {
  3931. pok = doPart(part,copy!=0,oldrfn,newrfn,(copy==0)?doneprim[idx]:donerep[idx]);
  3932. }
  3933. catch (IException *e) {
  3934. EXCLOG(e, NULL);
  3935. ex = e;
  3936. }
  3937. CriticalBlock block(crit);
  3938. if (!pok||ex) {
  3939. ok = false;
  3940. if (ex) {
  3941. StringBuffer s("renamePhysicalPartFiles ");
  3942. s.append(file->queryLogicalName()).append(" part ").append(newfn);
  3943. EXCLOG(ex, s.str());
  3944. if (mexcept)
  3945. mexcept->append(*ex);
  3946. else {
  3947. if (except)
  3948. ex->Release();
  3949. else
  3950. except = ex;
  3951. }
  3952. }
  3953. }
  3954. }
  3955. }
  3956. };
  3957. class casyncfor1: public casyncforbase
  3958. {
  3959. public:
  3960. casyncfor1(IDistributedFile *_file,CIArrayOf<CIStringArray> &_newNames,unsigned _width,IMultiException *_mexcept,CriticalSection &_crit,bool *_ignoreprim,bool *_ignorerep)
  3961. : casyncforbase(_file,_newNames,_width,_mexcept,_crit,_ignoreprim,_ignorerep)
  3962. {
  3963. }
  3964. bool doPart(IDistributedFilePart *part,bool isrep,RemoteFilename &oldrfn,RemoteFilename &newrfn, bool &done)
  3965. {
  3966. done = false;
  3967. Owned<IFile> src = createIFile(oldrfn);
  3968. if (src->exists())
  3969. done = true;
  3970. else {
  3971. StringBuffer s;
  3972. oldrfn.getRemotePath(s);
  3973. WARNLOG("renamePhysicalPartFiles: %s doesn't exist",s.str());
  3974. return true;
  3975. }
  3976. Owned<IFile> dest = createIFile(newrfn);
  3977. StringBuffer newname;
  3978. newrfn.getRemotePath(newname);
  3979. if (dest->exists()) {
  3980. IDFS_Exception *e = new CDFS_Exception(DFSERR_PhysicalPartAlreadyExists,newname.str());
  3981. throw e;
  3982. }
  3983. // check destination directory exists
  3984. StringBuffer newdir;
  3985. splitDirTail(newname.str(),newdir);
  3986. Owned<IFile> destdir = createIFile(newdir.str());
  3987. destdir->createDirectory();
  3988. return true;
  3989. }
  3990. } afor1 (this,newNames,width,mexcept,crit,NULL,NULL);
  3991. afor1.For(width,10,false,true);
  3992. if (afor1.except)
  3993. throw afor1.except; // no recovery needed
  3994. if (!afor1.ok)
  3995. return false; // no recovery needed
  3996. MemoryAttr ignorebuf;
  3997. bool *ignoreprim = (bool *)ignorebuf.allocate(width*sizeof(bool)*2);
  3998. bool *ignorerep = ignoreprim+width;
  3999. for (i=0;i<width;i++) {
  4000. if (afor1.donerep[i]) {
  4001. ignorerep[i] = false;
  4002. ignoreprim[i] = !afor1.doneprim[i];
  4003. }
  4004. else if (afor1.doneprim[i]) {
  4005. ignorerep[i] = true;
  4006. ignoreprim[i] = false;
  4007. }
  4008. else {
  4009. StringBuffer s(queryLogicalName());
  4010. s.append(" Part ").append(i+1);
  4011. IDFS_Exception *e = new CDFS_Exception(DFSERR_PhysicalPartDoesntExist,s.str());
  4012. throw e;
  4013. }
  4014. }
  4015. // now do the rename
  4016. class casyncfor2: public casyncforbase
  4017. {
  4018. public:
  4019. casyncfor2(IDistributedFile *_file,CIArrayOf<CIStringArray> &_newNames,unsigned _width,IMultiException *_mexcept,CriticalSection &_crit,bool *_ignoreprim,bool *_ignorerep)
  4020. : casyncforbase(_file,_newNames,_width,_mexcept,_crit,_ignoreprim,_ignorerep)
  4021. {
  4022. }
  4023. bool doPart(IDistributedFilePart *part,bool isrep,RemoteFilename &oldrfn,RemoteFilename &newrfn, bool &done)
  4024. {
  4025. done = false;
  4026. StringBuffer oldfn;
  4027. oldrfn.getRemotePath(oldfn);
  4028. StringBuffer newfn;
  4029. newrfn.getRemotePath(newfn);
  4030. Owned<IFile> f = createIFile(oldrfn);
  4031. if (!isrep||f->exists()) { // ignore non-existant replicates
  4032. f->move(newfn.str());
  4033. PROGLOG("Succeeded rename %s to %s",oldfn.str(),newfn.str());
  4034. }
  4035. done = true;
  4036. return true;;
  4037. }
  4038. } afor2 (this,newNames,width,mexcept,crit,ignoreprim,ignorerep);
  4039. afor2.For(width,10,false,true);
  4040. if (afor2.ok) {
  4041. // now rename directory and partmask
  4042. DistributedFilePropertyLock lock(this);
  4043. root->setProp("@directory",newdir.str());
  4044. root->setProp("@partmask",newmask.str());
  4045. partmask.set(newmask.str());
  4046. directory.set(newdir.str());
  4047. StringBuffer mask;
  4048. for (unsigned i=0;i<width;i++) {
  4049. mask.appendf("Part[%d]/@name",i+1);
  4050. parts.item(i).clearOverrideName();
  4051. }
  4052. savePartsAttr(false);
  4053. }
  4054. else {
  4055. // attempt recovery
  4056. // do this synchronously to maximize chance of success (I don't expect many to have been done)
  4057. for (i=0;i<width;i++) {
  4058. Owned<IDistributedFilePart> part = getPart(i);
  4059. unsigned copies = part->numCopies();
  4060. for (int copy = copies-1; copy>=0; copy--) {
  4061. bool done = (copy==0)?afor2.doneprim[i]:afor2.donerep[i];
  4062. if (done) {
  4063. RemoteFilename oldrfn;
  4064. part->getFilename(oldrfn,(unsigned)copy);
  4065. const char *newfn = newNames.item(i).item(copy);
  4066. if (!newfn||!*newfn)
  4067. continue;
  4068. RemoteFilename newrfn;
  4069. newrfn.setPath(part->queryNode(copy)->endpoint(),newfn);
  4070. for (unsigned t=1;t<3;t++) { // 3 goes
  4071. try {
  4072. StringBuffer oldfn;
  4073. oldrfn.getRemotePath(oldfn);
  4074. StringBuffer newfn;
  4075. newrfn.getRemotePath(newfn);
  4076. Owned<IFile> f = createIFile(newrfn);
  4077. f->move(oldfn.str());
  4078. PROGLOG("Succeeded rename %s back to %s",newfn.str(),oldfn.str());
  4079. break;
  4080. }
  4081. catch (IException *e) {
  4082. if (!afor2.except)
  4083. afor2.except = e;
  4084. else
  4085. e->Release();
  4086. }
  4087. }
  4088. }
  4089. }
  4090. }
  4091. }
  4092. if (afor2.except)
  4093. throw afor2.except;
  4094. return afor2.ok;
  4095. }
  4096. IPropertyTree *queryRoot() { return root; }
  4097. __int64 getFileSize(bool allowphysical,bool forcephysical)
  4098. {
  4099. __int64 ret = (__int64)(forcephysical?-1:queryAttributes().getPropInt64("@size",-1));
  4100. if (ret==-1)
  4101. {
  4102. ret = 0;
  4103. unsigned n = numParts();
  4104. for (unsigned i=0;i<n;i++)
  4105. {
  4106. Owned<IDistributedFilePart> part = getPart(i);
  4107. __int64 ps = part->getFileSize(allowphysical,forcephysical);
  4108. if (ps == -1)
  4109. {
  4110. ret = ps;
  4111. break;
  4112. }
  4113. ret += ps;
  4114. }
  4115. }
  4116. return ret;
  4117. }
  4118. __int64 getDiskSize(bool allowphysical,bool forcephysical)
  4119. {
  4120. if (!isCompressed(NULL))
  4121. return getFileSize(allowphysical, forcephysical);
  4122. __int64 ret = (__int64)(forcephysical?-1:queryAttributes().getPropInt64("@compressedSize",-1));
  4123. if (ret==-1)
  4124. {
  4125. ret = 0;
  4126. unsigned n = numParts();
  4127. for (unsigned i=0;i<n;i++)
  4128. {
  4129. Owned<IDistributedFilePart> part = getPart(i);
  4130. __int64 ps = part->getDiskSize(allowphysical,forcephysical);
  4131. if (ps == -1)
  4132. {
  4133. ret = ps;
  4134. break;
  4135. }
  4136. ret += ps;
  4137. }
  4138. }
  4139. return ret;
  4140. }
  4141. bool getFileCheckSum(unsigned &checkSum)
  4142. {
  4143. if (queryAttributes().hasProp("@checkSum"))
  4144. checkSum = (unsigned)queryAttributes().getPropInt64("@checkSum");
  4145. else
  4146. {
  4147. checkSum = ~0;
  4148. unsigned n = numParts();
  4149. for (unsigned i=0;i<n;i++) {
  4150. Owned<IDistributedFilePart> part = getPart(i);
  4151. unsigned crc;
  4152. if (!part->getCrc(crc))
  4153. return false;
  4154. checkSum ^= crc;
  4155. }
  4156. }
  4157. return true;
  4158. }
  4159. virtual bool getFormatCrc(unsigned &crc)
  4160. {
  4161. if (queryAttributes().hasProp("@formatCrc")) {
  4162. // NB pre record_layout CRCs are not valid
  4163. crc = (unsigned)queryAttributes().getPropInt("@formatCrc");
  4164. return true;
  4165. }
  4166. return false;
  4167. }
  4168. virtual bool getRecordLayout(MemoryBuffer &layout)
  4169. {
  4170. return queryAttributes().getPropBin("_record_layout",layout);
  4171. }
  4172. virtual bool getRecordSize(size32_t &rsz)
  4173. {
  4174. if (queryAttributes().hasProp("@recordSize")) {
  4175. rsz = (size32_t)queryAttributes().getPropInt("@recordSize");
  4176. return true;
  4177. }
  4178. return false;
  4179. }
  4180. virtual unsigned getPositionPart(offset_t pos, offset_t &base)
  4181. {
  4182. unsigned n = numParts();
  4183. base = 0;
  4184. for (unsigned i=0;i<n;i++) {
  4185. Owned<IDistributedFilePart> part = getPart(i);
  4186. offset_t ps = part->getFileSize(true,false);
  4187. if (ps==(offset_t)-1)
  4188. break;
  4189. if (ps>pos)
  4190. return i;
  4191. pos -= ps;
  4192. base += ps;
  4193. }
  4194. return NotFound;
  4195. }
  4196. IDistributedSuperFile *querySuperFile()
  4197. {
  4198. return NULL; // i.e. this isn't super file
  4199. }
  4200. virtual bool checkClusterCompatible(IFileDescriptor &fdesc, StringBuffer &err)
  4201. {
  4202. unsigned n = numParts();
  4203. if (fdesc.numParts()!=n) {
  4204. err.appendf("Different cluster width (%d/%d)",n,fdesc.numParts());
  4205. return false;
  4206. }
  4207. if (fdesc.numClusters()!=1) {
  4208. err.append("Cannot merge more than one cluster");
  4209. return false;
  4210. }
  4211. StringBuffer cname;
  4212. fdesc.getClusterLabel(0,cname);
  4213. if (cname.length()&&(findCluster(cname.str())!=NotFound)) {
  4214. err.append("File already contains cluster");
  4215. err.append(cname.str());
  4216. return false;
  4217. }
  4218. StringBuffer pname;
  4219. StringBuffer fdtail;
  4220. for (unsigned pn=0;pn<n;pn++) {
  4221. IDistributedFilePart &part = queryPart(pn);
  4222. part.getPartName(pname.clear());
  4223. fdesc.queryPart(pn)->getTail(fdtail.clear());
  4224. if (strcmp(pname.str(),fdtail.str())!=0) {
  4225. err.appendf("Part name mismatch (%s,%s)",pname.str(),fdtail.str());
  4226. return false;
  4227. }
  4228. RemoteFilename fdrfn;
  4229. fdesc.getFilename(pn,0,fdrfn);
  4230. unsigned nc = numCopies(pn);
  4231. for (unsigned c = 0;c<nc;c++) {
  4232. RemoteFilename rfn;
  4233. part.getFilename(rfn,c);
  4234. if (rfn.equals(fdrfn)) {
  4235. err.appendf("Parts overlap %s and %s",pname.str(),fdtail.str());
  4236. return false;
  4237. }
  4238. }
  4239. }
  4240. return true;
  4241. }
  4242. void enqueueReplicate()
  4243. {
  4244. MemoryBuffer mb;
  4245. mb.append((byte)DRQ_REPLICATE).append(queryLogicalName());
  4246. udesc->serialize(mb);
  4247. CDateTime filedt;
  4248. getModificationTime(filedt);
  4249. filedt.serialize(mb);
  4250. Owned<INamedQueueConnection> qconn = createNamedQueueConnection(0);
  4251. Owned<IQueueChannel> qchannel = qconn->open(DFS_REPLICATE_QUEUE);
  4252. qchannel->put(mb);
  4253. }
  4254. bool getAccessedTime(CDateTime &dt)
  4255. {
  4256. StringBuffer str;
  4257. if (!root->getProp("@accessed",str))
  4258. return false;
  4259. dt.setString(str.str());
  4260. return true;
  4261. }
  4262. virtual void setAccessedTime(const CDateTime &dt)
  4263. {
  4264. if (logicalName.isForeign())
  4265. parent->setFileAccessed(logicalName,udesc,dt);
  4266. else
  4267. {
  4268. CFileAttrLock attrLock;
  4269. if (0 == proplockcount && conn)
  4270. verifyex(attrLock.init(logicalName, DXB_File, RTM_LOCK_WRITE, conn, defaultTimeout, "CDistributedFile::setAccessedTime"));
  4271. if (dt.isNull())
  4272. queryAttributes().removeProp("@accessed");
  4273. else
  4274. {
  4275. StringBuffer str;
  4276. queryAttributes().setProp("@accessed",dt.getString(str).str());
  4277. }
  4278. }
  4279. }
  4280. void setAccessed()
  4281. {
  4282. CDateTime dt;
  4283. dt.setNow();
  4284. setAccessedTime(dt);
  4285. }
  4286. virtual void validate()
  4287. {
  4288. if (!existsPhysicalPartFiles(0))
  4289. {
  4290. const char * logicalName = queryLogicalName();
  4291. throw MakeStringException(-1, "Some physical parts do not exists, for logical file : %s",(isEmptyString(logicalName) ? "[unattached]" : logicalName));
  4292. }
  4293. }
  4294. };
  4295. static unsigned findSubFileOrd(const char *name)
  4296. {
  4297. if (*name=='#') {
  4298. const char *n = name+1;
  4299. if (*n) {
  4300. do { n++; } while (*n&&isdigit(*n));
  4301. if (!*n)
  4302. return atoi(name+1)-1;
  4303. }
  4304. }
  4305. return NotFound;
  4306. }
  4307. class CDistributedSuperFile: public CDistributedFileBase<IDistributedSuperFile>
  4308. {
  4309. void checkNotForeign()
  4310. {
  4311. if (!conn)
  4312. throw MakeStringException(-1,"Operation not allowed on foreign file");
  4313. }
  4314. CDistributedFilePartArray partscache;
  4315. FileClusterInfoArray clusterscache;
  4316. /**
  4317. * Adds a sub-file to a super-file within a transaction.
  4318. */
  4319. class cAddSubFileAction: public CDFAction
  4320. {
  4321. StringAttr parentlname;
  4322. Owned<IDistributedSuperFile> parent;
  4323. Owned<IDistributedFile> sub;
  4324. StringAttr subfile;
  4325. bool before;
  4326. StringAttr other;
  4327. public:
  4328. cAddSubFileAction(const char *_parentlname,const char *_subfile,bool _before,const char *_other)
  4329. : parentlname(_parentlname), subfile(_subfile), before(_before), other(_other)
  4330. {
  4331. }
  4332. virtual bool prepare()
  4333. {
  4334. parent.setown(transaction->lookupSuperFile(parentlname));
  4335. if (!parent)
  4336. throw MakeStringException(-1,"addSubFile: SuperFile %s cannot be found",parentlname.get());
  4337. if (!subfile.isEmpty())
  4338. {
  4339. try
  4340. {
  4341. sub.setown(transaction->lookupFile(subfile,SDS_SUB_LOCK_TIMEOUT));
  4342. if (!sub)
  4343. throw MakeStringException(-1,"cAddSubFileAction: sub file %s not found", subfile.str());
  4344. // Must validate before locking for update below, to check sub is not already in parent (and therefore locked already)
  4345. transaction->validateAddSubFile(parent, sub, subfile);
  4346. }
  4347. catch (IDFS_Exception *e)
  4348. {
  4349. if (e->errorCode()!=DFSERR_LookupConnectionTimout)
  4350. throw;
  4351. e->Release();
  4352. return false;
  4353. }
  4354. if (!sub.get())
  4355. throw MakeStringException(-1,"addSubFile: File %s cannot be found to add",subfile.get());
  4356. }
  4357. // Try to lock all files
  4358. addFileLock(parent);
  4359. if (lock())
  4360. {
  4361. transaction->noteAddSubFile(parent, parentlname, sub);
  4362. return true;
  4363. }
  4364. unlock();
  4365. parent.clear();
  4366. sub.clear();
  4367. return false;
  4368. }
  4369. virtual void run()
  4370. {
  4371. if (!sub)
  4372. throw MakeStringException(-1,"addSubFile(2): File %s cannot be found to add",subfile.get());
  4373. CDistributedSuperFile *sf = QUERYINTERFACE(parent.get(),CDistributedSuperFile);
  4374. if (sf)
  4375. sf->doAddSubFile(LINK(sub),before,other,transaction);
  4376. }
  4377. virtual void commit()
  4378. {
  4379. CDistributedSuperFile *sf = QUERYINTERFACE(parent.get(),CDistributedSuperFile);
  4380. if (sf)
  4381. sf->updateParentFileAttrs(transaction);
  4382. CDFAction::commit();
  4383. }
  4384. virtual void retry()
  4385. {
  4386. parent.clear();
  4387. sub.clear();
  4388. CDFAction::retry();
  4389. }
  4390. };
  4391. /**
  4392. * Removes a sub-file of a super-file within a transaction.
  4393. */
  4394. class cRemoveSubFileAction: public CDFAction
  4395. {
  4396. StringAttr parentlname;
  4397. Owned<IDistributedSuperFile> parent;
  4398. Owned<IDistributedFile> sub;
  4399. StringAttr subfile;
  4400. bool remsub;
  4401. public:
  4402. cRemoveSubFileAction(const char *_parentlname,const char *_subfile,bool _remsub=false)
  4403. : parentlname(_parentlname), subfile(_subfile), remsub(_remsub)
  4404. {
  4405. }
  4406. virtual bool prepare()
  4407. {
  4408. parent.setown(transaction->lookupSuperFile(parentlname));
  4409. if (!parent)
  4410. throw MakeStringException(-1,"removeSubFile: SuperFile %s cannot be found",parentlname.get());
  4411. if (!subfile.isEmpty())
  4412. {
  4413. try
  4414. {
  4415. sub.setown(transaction->lookupFile(subfile,SDS_SUB_LOCK_TIMEOUT));
  4416. }
  4417. catch (IDFS_Exception *e)
  4418. {
  4419. if (e->errorCode()!=DFSERR_LookupConnectionTimout)
  4420. throw;
  4421. e->Release();
  4422. return false;
  4423. }
  4424. if (!transaction->isSubFile(parent, subfile, true))
  4425. {
  4426. WARNLOG("removeSubFile: File %s is not a subfile of %s", subfile.get(), parent->queryLogicalName());
  4427. parent.clear();
  4428. sub.clear();
  4429. return true; // NB: sub was not a member of super, issue warning and continue without locking
  4430. }
  4431. }
  4432. // Try to lock all files
  4433. addFileLock(parent);
  4434. if (sub && remsub) // NB: I only need to lock (for exclusivity, if going to delete
  4435. addFileLock(sub);
  4436. if (lock())
  4437. {
  4438. if (sub)
  4439. transaction->noteRemoveSubFile(parent, sub);
  4440. else
  4441. transaction->clearSubFiles(parent);
  4442. return true;
  4443. }
  4444. unlock();
  4445. parent.clear();
  4446. sub.clear();
  4447. return false;
  4448. }
  4449. virtual void run()
  4450. {
  4451. CDistributedSuperFile *sf = QUERYINTERFACE(parent.get(),CDistributedSuperFile);
  4452. if (sf) {
  4453. // Delay the deletion of the subs until commit
  4454. if (remsub) {
  4455. if (subfile) {
  4456. CDfsLogicalFileName lname;
  4457. lname.set(subfile.get());
  4458. transaction->addDelayedDelete(lname, SDS_SUB_LOCK_TIMEOUT);
  4459. } else { // Remove all subfiles
  4460. Owned<IDistributedFileIterator> iter = parent->getSubFileIterator(false);
  4461. ForEach (*iter) {
  4462. CDfsLogicalFileName lname;
  4463. IDistributedFile *f = &iter->query();
  4464. lname.set(f->queryLogicalName());
  4465. transaction->addDelayedDelete(lname, SDS_SUB_LOCK_TIMEOUT);
  4466. }
  4467. }
  4468. }
  4469. // Now we clean the subs
  4470. if (subfile.get())
  4471. sf->doRemoveSubFile(subfile.get(), transaction);
  4472. else
  4473. sf->doRemoveSubFiles(transaction);
  4474. }
  4475. }
  4476. virtual void retry()
  4477. {
  4478. parent.clear();
  4479. sub.clear();
  4480. CDFAction::retry();
  4481. }
  4482. };
  4483. /**
  4484. * Removes all subfiles exclusively owned by named superfile within a transaction.
  4485. */
  4486. class cRemoveOwnedSubFilesAction: public CDFAction
  4487. {
  4488. StringAttr parentlname;
  4489. Owned<IDistributedSuperFile> parent;
  4490. bool remsub;
  4491. public:
  4492. cRemoveOwnedSubFilesAction(IDistributedFileTransaction *_transaction, const char *_parentlname,bool _remsub=false)
  4493. : parentlname(_parentlname), remsub(_remsub)
  4494. {
  4495. }
  4496. virtual bool prepare()
  4497. {
  4498. parent.setown(transaction->lookupSuperFile(parentlname));
  4499. if (!parent)
  4500. throw MakeStringException(-1,"removeOwnedSubFiles: SuperFile %s cannot be found", parentlname.get());
  4501. // Try to lock all files
  4502. addFileLock(parent);
  4503. if (lock())
  4504. return true;
  4505. unlock();
  4506. parent.clear();
  4507. return false;
  4508. }
  4509. virtual void run()
  4510. {
  4511. CDistributedSuperFile *sf = QUERYINTERFACE(parent.get(),CDistributedSuperFile);
  4512. if (sf)
  4513. {
  4514. StringArray toRemove;
  4515. Owned<IDistributedFileIterator> iter = parent->getSubFileIterator(false);
  4516. ForEach (*iter)
  4517. {
  4518. IDistributedFile *file = &iter->query();
  4519. IDistributedSuperFile *super = file->querySuperFile();
  4520. StringArray owners;
  4521. if (super)
  4522. {
  4523. CDistributedSuperFile *_super = QUERYINTERFACE(super, CDistributedSuperFile);
  4524. if (_super)
  4525. _super->getSuperOwners(owners);
  4526. }
  4527. else
  4528. {
  4529. CDistributedFile *_file = QUERYINTERFACE(file, CDistributedFile);
  4530. if (_file)
  4531. _file->getSuperOwners(owners);
  4532. }
  4533. if (NotFound == owners.find(parentlname))
  4534. ThrowStringException(-1, "removeOwnedSubFiles: SuperFile %s, subfile %s - subfile not owned by superfile", parentlname.get(), file->queryLogicalName());
  4535. if (1 == owners.ordinality()) // just me
  4536. {
  4537. const char *logicalName = file->queryLogicalName();
  4538. toRemove.append(logicalName);
  4539. // Delay the deletion of the subs until commit
  4540. if (remsub)
  4541. {
  4542. CDfsLogicalFileName lname;
  4543. lname.set(logicalName);
  4544. transaction->addDelayedDelete(lname, SDS_SUB_LOCK_TIMEOUT);
  4545. }
  4546. }
  4547. }
  4548. // Now we clean the subs
  4549. if (sf->numSubFiles(false) == toRemove.ordinality())
  4550. sf->doRemoveSubFiles(transaction); // remove all
  4551. else
  4552. {
  4553. ForEachItemIn(r, toRemove)
  4554. sf->doRemoveSubFile(toRemove.item(r), transaction);
  4555. }
  4556. }
  4557. }
  4558. virtual void retry()
  4559. {
  4560. parent.clear();
  4561. CDFAction::retry();
  4562. }
  4563. };
  4564. /**
  4565. * Swaps sub-files between two super-files within a transaction.
  4566. */
  4567. class cSwapFileAction: public CDFAction
  4568. {
  4569. Linked<IDistributedSuperFile> super1, super2;
  4570. StringAttr super1Name, super2Name;
  4571. public:
  4572. cSwapFileAction(const char *_super1Name, const char *_super2Name)
  4573. : super1Name(_super1Name), super2Name(_super2Name)
  4574. {
  4575. }
  4576. virtual bool prepare()
  4577. {
  4578. super1.setown(transaction->lookupSuperFile(super1Name));
  4579. if (!super1)
  4580. throw MakeStringException(-1,"swapSuperFile: SuperFile %s cannot be found", super1Name.get());
  4581. super2.setown(transaction->lookupSuperFile(super2Name));
  4582. if (!super2)
  4583. {
  4584. super1.clear();
  4585. throw MakeStringException(-1,"swapSuperFile: SuperFile %s cannot be found", super2Name.get());
  4586. }
  4587. // Try to lock all files
  4588. addFileLock(super1);
  4589. for (unsigned i=0; i<super1->numSubFiles(); i++)
  4590. addFileLock(&super1->querySubFile(i));
  4591. addFileLock(super2);
  4592. for (unsigned i=0; i<super2->numSubFiles(); i++)
  4593. addFileLock(&super2->querySubFile(i));
  4594. if (lock())
  4595. {
  4596. transaction->noteSuperSwap(super1, super2);
  4597. return true;
  4598. }
  4599. unlock();
  4600. super1.clear();
  4601. super2.clear();
  4602. return false;
  4603. }
  4604. virtual void run()
  4605. {
  4606. CDistributedSuperFile *sf = QUERYINTERFACE(super1.get(),CDistributedSuperFile);
  4607. if (sf)
  4608. sf->doSwapSuperFile(super2,transaction);
  4609. }
  4610. virtual void retry()
  4611. {
  4612. super1.clear();
  4613. super2.clear();
  4614. CDFAction::retry();
  4615. }
  4616. };
  4617. /**
  4618. * SubFile Iterator, used only to list sub-files of a super-file.
  4619. */
  4620. class cSubFileIterator: public CDistributedFileIteratorBase< IDistributedFileIterator, IArrayOf<IDistributedFile> >
  4621. {
  4622. public:
  4623. cSubFileIterator(IArrayOf<IDistributedFile> &_subfiles, bool supersub)
  4624. {
  4625. ForEachItemIn(i,_subfiles) {
  4626. IDistributedSuperFile* super = supersub?_subfiles.item(i).querySuperFile():NULL;
  4627. if (super) {
  4628. Owned<IDistributedFileIterator> iter = super->getSubFileIterator(true);
  4629. ForEach(*iter)
  4630. list.append(iter->get());
  4631. }
  4632. else
  4633. list.append(*LINK(&_subfiles.item(i)));
  4634. }
  4635. }
  4636. StringBuffer & getName(StringBuffer &name)
  4637. {
  4638. return list.item(index).getLogicalName(name);
  4639. }
  4640. IDistributedFile & query()
  4641. {
  4642. return list.item(index);
  4643. }
  4644. };
  4645. void checkModify(const char *title)
  4646. {
  4647. StringBuffer reason;
  4648. if (!canModify(reason)) {
  4649. #ifdef EXTRA_LOGGING
  4650. PROGLOG("CDistributedSuperFile::%s(canModify) %s",title,reason.str());
  4651. #endif
  4652. if (reason.length())
  4653. throw MakeStringException(-1,"CDistributedSuperFile::%s %s",title,reason.str());
  4654. }
  4655. }
  4656. protected:
  4657. int interleaved; // 0 not interleaved, 1 interleaved old, 2 interleaved new
  4658. IArrayOf<IDistributedFile> subfiles;
  4659. void clearSuperOwners(unsigned timeoutMs, ICodeContext *ctx)
  4660. {
  4661. /* JCSMORE - Why on earth is this doing this way?
  4662. * We are in a super file, we already have [read] locks to sub files (in 'subfiles' array)
  4663. * This should iterate through those and call unlinkSubFile I think.
  4664. */
  4665. Owned<IPropertyTreeIterator> iter = root->getElements("SubFile");
  4666. StringBuffer oquery;
  4667. oquery.append("SuperOwner[@name=\"").append(logicalName.get()).append("\"]");
  4668. ForEach(*iter)
  4669. {
  4670. const char *name = iter->query().queryProp("@name");
  4671. if (name&&*name)
  4672. {
  4673. CDfsLogicalFileName subfn;
  4674. subfn.set(name);
  4675. CFileLock fconnlockSub;
  4676. // JCSMORE - this is really not right, but consistent with previous version
  4677. // MORE: Use CDistributedSuperFile::linkSuperOwner(false) - ie. unlink
  4678. if (fconnlockSub.init(subfn, RTM_LOCK_READ, timeoutMs, "CDistributedFile::doRemoveEntry"))
  4679. {
  4680. IPropertyTree *subfroot = fconnlockSub.queryRoot();
  4681. if (subfroot)
  4682. {
  4683. if (!subfroot->removeProp(oquery.str()))
  4684. {
  4685. VStringBuffer s("SubFile %s is not owned by SuperFile %s", name, logicalName.get());
  4686. if (ctx)
  4687. ctx->addWuException(s.str(), 0, SeverityWarning, "DFS[clearSuperOwner]");
  4688. else
  4689. {
  4690. Owned<IException> e = makeStringException(-1, s.str());
  4691. EXCLOG(e, "DFS[clearSuperOwner]");
  4692. }
  4693. }
  4694. }
  4695. }
  4696. }
  4697. }
  4698. }
  4699. static StringBuffer &getSubPath(StringBuffer &path,unsigned idx)
  4700. {
  4701. return path.append("SubFile[@num=\"").append(idx+1).append("\"]");
  4702. }
  4703. void loadSubFiles(IDistributedFileTransaction *transaction, unsigned timeout, bool link=false)
  4704. {
  4705. partscache.kill();
  4706. StringBuffer path;
  4707. StringBuffer subname;
  4708. subfiles.kill();
  4709. unsigned n = root->getPropInt("@numsubfiles");
  4710. if (n == 0)
  4711. return;
  4712. try
  4713. {
  4714. // Find all reported indexes and bail on bad range (before we lock any file)
  4715. Owned<IPropertyTreeIterator> subit = root->getElements("SubFile");
  4716. // Adding a sub 'before' another get the list out of order (but still valid)
  4717. OwnedMalloc<IPropertyTree *> orderedSubFiles(n, true);
  4718. ForEach (*subit)
  4719. {
  4720. IPropertyTree &sub = subit->query();
  4721. unsigned sn = sub.getPropInt("@num",0);
  4722. if (sn == 0)
  4723. ThrowStringException(-1, "CDistributedSuperFile: SuperFile %s: bad subfile part number %d of %d", logicalName.get(), sn, n);
  4724. if (sn > n)
  4725. ThrowStringException(-1, "CDistributedSuperFile: SuperFile %s: out-of-range subfile part number %d of %d", logicalName.get(), sn, n);
  4726. if (orderedSubFiles[sn-1])
  4727. ThrowStringException(-1, "CDistributedSuperFile: SuperFile %s: duplicated subfile part number %d of %d", logicalName.get(), sn, n);
  4728. orderedSubFiles[sn-1] = &sub;
  4729. }
  4730. for (unsigned i=0; i<n; i++)
  4731. {
  4732. if (!orderedSubFiles[i])
  4733. ThrowStringException(-1, "CDistributedSuperFile: SuperFile %s: missing subfile part number %d of %d", logicalName.get(), i+1, n);
  4734. }
  4735. // Now try to resolve them all (file/superfile)
  4736. for (unsigned f=0; f<n; f++)
  4737. {
  4738. IPropertyTree &sub = *(orderedSubFiles[f]);
  4739. sub.getProp("@name",subname.clear());
  4740. Owned<IDistributedFile> subfile;
  4741. subfile.setown(transaction?transaction->lookupFile(subname.str(),timeout):parent->lookup(subname.str(), udesc, false, false, false, transaction, timeout));
  4742. if (!subfile.get())
  4743. subfile.setown(transaction?transaction->lookupSuperFile(subname.str(),timeout):parent->lookupSuperFile(subname.str(),udesc,transaction,timeout));
  4744. // Some files are ok not to exist
  4745. if (!subfile.get())
  4746. {
  4747. CDfsLogicalFileName cdfsl;
  4748. cdfsl.set(subname);
  4749. if (cdfsl.isForeign())
  4750. {
  4751. WARNLOG("CDistributedSuperFile: SuperFile %s's sub-file file '%s' is foreign, but missing", logicalName.get(), subname.str());
  4752. // Create a dummy empty superfile as a placeholder for the missing foreign file
  4753. Owned<IPropertyTree> dummySuperRoot = createPTree();
  4754. dummySuperRoot->setPropInt("@interleaved", 0);
  4755. subfile.setown(queryDistributedFileDirectory().createNewSuperFile(dummySuperRoot, subname));
  4756. if (transaction)
  4757. {
  4758. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  4759. _transaction->ensureFile(subfile);
  4760. }
  4761. }
  4762. else
  4763. ThrowStringException(-1, "CDistributedSuperFile: SuperFile %s: corrupt subfile file '%s' cannot be found", logicalName.get(), subname.str());
  4764. }
  4765. subfiles.append(*subfile.getClear());
  4766. if (link)
  4767. linkSubFile(f);
  4768. }
  4769. // This is *only* due to foreign files
  4770. if (subfiles.ordinality() != n)
  4771. {
  4772. WARNLOG("CDistributedSuperFile: SuperFile %s's number of sub-files updated to %d", logicalName.get(), subfiles.ordinality());
  4773. root->setPropInt("@numsubfiles", subfiles.ordinality());
  4774. }
  4775. }
  4776. catch (IException *)
  4777. {
  4778. partscache.kill();
  4779. subfiles.kill(); // one out, all out
  4780. throw;
  4781. }
  4782. }
  4783. void addItem(unsigned pos,IDistributedFile *_file)
  4784. {
  4785. Owned<IDistributedFile> file = _file;
  4786. partscache.kill();
  4787. // first renumber all above
  4788. StringBuffer path;
  4789. IPropertyTree *sub;
  4790. for (unsigned i=subfiles.ordinality();i>pos;i--) {
  4791. sub = root->queryPropTree(getSubPath(path.clear(),i-1).str());
  4792. if (!sub)
  4793. throw MakeStringException(-1,"C(2): Corrupt subfile file part %d cannot be found",i);
  4794. sub->setPropInt("@num",i+1);
  4795. }
  4796. sub = createPTree();
  4797. sub->setPropInt("@num",pos+1);
  4798. sub->setProp("@name",file->queryLogicalName());
  4799. if (pos==0) {
  4800. resetFileAttr(createPTreeFromIPT(&file->queryAttributes()));
  4801. }
  4802. root->addPropTree("SubFile",sub);
  4803. subfiles.add(*file.getClear(),pos);
  4804. root->setPropInt("@numsubfiles",subfiles.ordinality());
  4805. }
  4806. void removeItem(unsigned pos)
  4807. {
  4808. partscache.kill();
  4809. StringBuffer path;
  4810. IPropertyTree* sub = root->queryPropTree(getSubPath(path,pos).str());
  4811. if (!sub)
  4812. throw MakeStringException(-1,"CDistributedSuperFile(3): Corrupt subfile file part %d cannot be found",pos+1);
  4813. root->removeTree(sub);
  4814. // now renumber all above
  4815. for (unsigned i=pos+1; i<subfiles.ordinality(); i++) {
  4816. sub = root->queryPropTree(getSubPath(path.clear(),i).str());
  4817. if (!sub)
  4818. throw MakeStringException(-1,"CDistributedSuperFile(2): Corrupt subfile file part %d cannot be found",i+1);
  4819. sub->setPropInt("@num",i);
  4820. }
  4821. subfiles.remove(pos);
  4822. if (pos==0) {
  4823. if (subfiles.ordinality())
  4824. resetFileAttr(createPTreeFromIPT(&subfiles.item(0).queryAttributes()));
  4825. else
  4826. resetFileAttr(getEmptyAttr());
  4827. }
  4828. root->setPropInt("@numsubfiles",subfiles.ordinality());
  4829. }
  4830. void loadParts(CDistributedFilePartArray &partsret, IDFPartFilter *filter)
  4831. {
  4832. unsigned p = 0;
  4833. if (interleaved) { // a bit convoluted but should work
  4834. IArrayOf<IDistributedFile> allsubfiles;
  4835. ForEachItemIn(i,subfiles) {
  4836. // if old format keep original interleaving
  4837. IDistributedSuperFile* super = (interleaved==1)?NULL:subfiles.item(i).querySuperFile();
  4838. if (super) {
  4839. Owned<IDistributedFileIterator> iter = super->getSubFileIterator(true);
  4840. ForEach(*iter)
  4841. allsubfiles.append(iter->get());
  4842. }
  4843. else
  4844. allsubfiles.append(*LINK(&subfiles.item(i)));
  4845. }
  4846. unsigned *pn = new unsigned[allsubfiles.ordinality()];
  4847. ForEachItemIn(j,allsubfiles)
  4848. pn[j] = allsubfiles.item(j).numParts();
  4849. unsigned f=0;
  4850. bool found=false;
  4851. loop {
  4852. if (f==allsubfiles.ordinality()) {
  4853. if (!found)
  4854. break; // no more
  4855. found = false;
  4856. f = 0;
  4857. }
  4858. if (pn[f]) {
  4859. found = true;
  4860. if (!filter||filter->includePart(p)) {
  4861. IDistributedFile &subfile = allsubfiles.item(f);
  4862. IDistributedFilePart *part = subfile.getPart(subfile.numParts()-pn[f]);
  4863. partsret.append(*QUERYINTERFACE(part,CDistributedFilePart)); // bit kludgy
  4864. }
  4865. p++;
  4866. pn[f]--;
  4867. }
  4868. f++;
  4869. }
  4870. delete [] pn;
  4871. }
  4872. else { // sequential
  4873. ForEachItemIn(i,subfiles) { // not wonderfully quick
  4874. IDistributedFile &subfile = subfiles.item(i);
  4875. unsigned n = subfile.numParts();
  4876. unsigned j = 0;
  4877. while (n--) {
  4878. if (!filter||filter->includePart(p)) {
  4879. IDistributedFilePart *part = subfile.getPart(j++);
  4880. partsret.append(*QUERYINTERFACE(part,CDistributedFilePart)); // bit kludgy
  4881. }
  4882. p++;
  4883. }
  4884. }
  4885. }
  4886. }
  4887. void linkSubFile(unsigned pos, bool link=true)
  4888. {
  4889. IDistributedFile *subfile = &subfiles.item(pos);
  4890. IDistributedSuperFile *ssub = subfile->querySuperFile();
  4891. if (ssub) {
  4892. CDistributedSuperFile *cdsuper = QUERYINTERFACE(ssub,CDistributedSuperFile);
  4893. cdsuper->linkSuperOwner(queryLogicalName(),link);
  4894. }
  4895. else {
  4896. CDistributedFile *cdfile = QUERYINTERFACE(subfile,CDistributedFile);
  4897. cdfile->linkSuperOwner(queryLogicalName(),link);
  4898. }
  4899. }
  4900. void unlinkSubFile(unsigned pos)
  4901. {
  4902. linkSubFile(pos, false);
  4903. }
  4904. void checkSubFormatAttr(IDistributedFile *sub, const char* exprefix="")
  4905. {
  4906. // empty super files now pass
  4907. ForEachItemIn(i,subfiles) {
  4908. IDistributedSuperFile* super = subfiles.item(i).querySuperFile();
  4909. if (super) {
  4910. CDistributedSuperFile *cdsuper = QUERYINTERFACE(super,CDistributedSuperFile);
  4911. if (cdsuper)
  4912. cdsuper->checkSubFormatAttr(sub,exprefix);
  4913. return;
  4914. }
  4915. CDistributedFile *cdfile = QUERYINTERFACE(&subfiles.item(0),CDistributedFile);
  4916. if (cdfile)
  4917. cdfile->checkFormatAttr(sub,exprefix); // any file will do
  4918. }
  4919. }
  4920. public:
  4921. void checkFormatAttr(IDistributedFile *sub, const char* exprefix="")
  4922. {
  4923. IDistributedSuperFile *superSub = sub->querySuperFile();
  4924. if (superSub && (0 == superSub->numSubFiles(true)))
  4925. return;
  4926. // only check sub files not siblings, which is excessive (format checking is really only debug aid)
  4927. checkSubFormatAttr(sub,exprefix);
  4928. }
  4929. unsigned findSubFile(const char *name)
  4930. {
  4931. StringBuffer lfn;
  4932. normalizeLFN(name,lfn);
  4933. ForEachItemIn(i,subfiles)
  4934. if (stricmp(subfiles.item(i).queryLogicalName(),lfn.str())==0)
  4935. return i;
  4936. return NotFound;
  4937. }
  4938. IMPLEMENT_IINTERFACE;
  4939. void commonInit(CDistributedFileDirectory *_parent, IPropertyTree *_root)
  4940. {
  4941. parent = _parent;
  4942. root.set(_root);
  4943. const char *val = root->queryProp("@interleaved");
  4944. if (val&&isdigit(*val))
  4945. interleaved = atoi(val);
  4946. else
  4947. interleaved = strToBool(val)?1:0;
  4948. }
  4949. void init(CDistributedFileDirectory *_parent, IPropertyTree *_root, const CDfsLogicalFileName &_name, IUserDescriptor* user, IDistributedFileTransaction *transaction, unsigned timeout=INFINITE)
  4950. {
  4951. assertex(_name.isSet());
  4952. setUserDescriptor(udesc,user);
  4953. logicalName.set(_name);
  4954. commonInit(_parent, _root);
  4955. loadSubFiles(transaction,timeout);
  4956. }
  4957. CDistributedSuperFile(CDistributedFileDirectory *_parent, IPropertyTree *_root,const CDfsLogicalFileName &_name,IUserDescriptor* user)
  4958. {
  4959. init(_parent,_root,_name,user,NULL);
  4960. }
  4961. CDistributedSuperFile(CDistributedFileDirectory *_parent, IRemoteConnection *_conn,const CDfsLogicalFileName &_name,IUserDescriptor* user, IDistributedFileTransaction *transaction,unsigned timeout)
  4962. {
  4963. conn.setown(_conn);
  4964. init(_parent,conn->queryRoot(),_name,user,transaction,timeout);
  4965. }
  4966. CDistributedSuperFile(CDistributedFileDirectory *_parent, CDfsLogicalFileName &_name, IUserDescriptor* user, IDistributedFileTransaction *transaction)
  4967. {
  4968. // temp super file
  4969. assertex(_name.isMulti());
  4970. if (!_name.isExpanded())
  4971. _name.expand(user);//expand wildcards
  4972. Owned<IPropertyTree> tree = _name.createSuperTree();
  4973. init(_parent,tree,_name,user,transaction);
  4974. }
  4975. CDistributedSuperFile(CDistributedFileDirectory *_parent, IPropertyTree *_root, const char *optionalName)
  4976. {
  4977. commonInit(_parent, _root);
  4978. if (optionalName)
  4979. logicalName.set(optionalName);
  4980. }
  4981. ~CDistributedSuperFile()
  4982. {
  4983. partscache.kill();
  4984. subfiles.kill();
  4985. }
  4986. StringBuffer &getClusterName(unsigned clusternum,StringBuffer &name)
  4987. {
  4988. // returns the cluster name if all the same
  4989. CriticalBlock block (sect);
  4990. if (subfiles.ordinality()==1)
  4991. return subfiles.item(0).getClusterName(clusternum,name);
  4992. size32_t rl = name.length();
  4993. StringBuffer test;
  4994. ForEachItemIn(i,subfiles) {
  4995. if (i) {
  4996. subfiles.item(i).getClusterName(clusternum,test.clear());
  4997. if (strcmp(name.str(),test.str())!=0) {
  4998. name.setLength(rl);
  4999. break;
  5000. }
  5001. }
  5002. else
  5003. subfiles.item(i).getClusterName(clusternum,name);
  5004. }
  5005. return name;
  5006. }
  5007. IFileDescriptor *getFileDescriptor(const char *clustername)
  5008. {
  5009. CriticalBlock block (sect);
  5010. if (subfiles.ordinality()==1)
  5011. return subfiles.item(0).getFileDescriptor(clustername);
  5012. // superfiles assume consistant replication & compression
  5013. UnsignedArray subcounts;
  5014. bool mixedwidth = false;
  5015. unsigned width = 0;
  5016. bool first = true;
  5017. Owned<IPropertyTree> at = getEmptyAttr();
  5018. Owned<IDistributedFileIterator> fiter = getSubFileIterator(true);
  5019. ForEach(*fiter)
  5020. {
  5021. IDistributedFile &file = fiter->query();
  5022. if (first)
  5023. {
  5024. first = false;
  5025. Owned<IAttributeIterator> ait = file.queryAttributes().getAttributes();
  5026. ForEach(*ait)
  5027. {
  5028. const char *name = ait->queryName();
  5029. if ((stricmp(name,"@size")!=0)&&(stricmp(name,"@recordCount")!=0))
  5030. {
  5031. const char *v = ait->queryValue();
  5032. if (!v)
  5033. continue;
  5034. bool ok = true;
  5035. // add attributes that are common
  5036. for (unsigned i=1;i<subfiles.ordinality();i++)
  5037. {
  5038. IDistributedFile &file = subfiles.item(i);
  5039. IDistributedSuperFile *sFile = file.querySuperFile();
  5040. if (!sFile || sFile->numSubFiles(true)) // skip empty super files
  5041. {
  5042. const char *p = file.queryAttributes().queryProp(name);
  5043. if (!p||(strcmp(p,v)!=0))
  5044. {
  5045. ok = false;
  5046. break;
  5047. }
  5048. }
  5049. }
  5050. if (ok)
  5051. at->setProp(name,v);
  5052. }
  5053. }
  5054. }
  5055. unsigned np = file.numParts();
  5056. if (0 == width)
  5057. width = np;
  5058. else if (np!=width)
  5059. mixedwidth = true;
  5060. subcounts.append(np);
  5061. }
  5062. // need common attributes
  5063. Owned<ISuperFileDescriptor> fdesc=createSuperFileDescriptor(at.getClear());
  5064. if (interleaved&&(interleaved!=2))
  5065. WARNLOG("getFileDescriptor: Unsupported interleave value (1)");
  5066. fdesc->setSubMapping(subcounts,interleaved!=0);
  5067. fdesc->setTraceName(logicalName.get());
  5068. Owned<IDistributedFilePartIterator> iter = getIterator(NULL);
  5069. unsigned n = 0;
  5070. SocketEndpointArray reps;
  5071. ForEach(*iter) {
  5072. IDistributedFilePart &part = iter->query();
  5073. CDistributedFilePart *cpart = (clustername&&*clustername)?QUERYINTERFACE(&part,CDistributedFilePart):NULL;
  5074. unsigned copy = 0;
  5075. if (cpart) {
  5076. IDistributedFile &f = cpart->queryParent();
  5077. unsigned cn = f.findCluster(clustername);
  5078. if (cn!=NotFound) {
  5079. for (unsigned i = 0;i<cpart->numCopies();i++)
  5080. if (cpart->copyClusterNum(i,NULL)==cn) {
  5081. copy = i;
  5082. break;
  5083. }
  5084. }
  5085. }
  5086. if (mixedwidth) {
  5087. SocketEndpoint rep;
  5088. if (copy+1<part.numCopies())
  5089. rep = part.queryNode(copy+1)->endpoint();
  5090. reps.append(rep);
  5091. }
  5092. RemoteFilename rfn;
  5093. fdesc->setPart(n,part.getFilename(rfn,copy),&part.queryAttributes());
  5094. n++;
  5095. }
  5096. ClusterPartDiskMapSpec mspec;
  5097. if (subfiles.ordinality()) {
  5098. mspec = subfiles.item(0).queryPartDiskMapping(0);
  5099. }
  5100. mspec.interleave = numSubFiles(true);
  5101. fdesc->endCluster(mspec);
  5102. if (mixedwidth) { // bleah - have to add replicate node numbers
  5103. Owned<IGroup> group = fdesc->getGroup();
  5104. unsigned gw = group->ordinality();
  5105. for (unsigned pn=0;pn<reps.ordinality();pn++) {
  5106. const SocketEndpoint &ep=reps.item(pn);
  5107. if (!ep.isNull()) {
  5108. unsigned gn = pn;
  5109. if (gn<gw) {
  5110. do {
  5111. gn++;
  5112. if (gn==gw)
  5113. gn = 0;
  5114. if (ep.equals(group->queryNode((rank_t)gn).endpoint())) {
  5115. IPartDescriptor *part = fdesc->queryPart(pn);
  5116. if (part)
  5117. part->queryProperties().setPropInt("@rn",(unsigned)gn);
  5118. break;
  5119. }
  5120. } while (gn!=pn);
  5121. }
  5122. }
  5123. }
  5124. }
  5125. return fdesc.getClear();
  5126. }
  5127. unsigned numParts()
  5128. {
  5129. CriticalBlock block(sect);
  5130. unsigned ret=0;
  5131. ForEachItemIn(i,subfiles)
  5132. ret += subfiles.item(i).numParts();
  5133. return ret;
  5134. }
  5135. IDistributedFilePart &queryPart(unsigned idx)
  5136. {
  5137. CriticalBlock block(sect);
  5138. if (subfiles.ordinality()==1)
  5139. return subfiles.item(0).queryPart(idx);
  5140. if (partscache.ordinality()==0)
  5141. loadParts(partscache,NULL);
  5142. if (idx>=partscache.ordinality())
  5143. return *(IDistributedFilePart *)NULL;
  5144. return partscache.item(idx);
  5145. }
  5146. IDistributedFilePart* getPart(unsigned idx)
  5147. {
  5148. IDistributedFilePart* ret = &queryPart(idx);
  5149. return LINK(ret);
  5150. }
  5151. IDistributedFilePartIterator *getIterator(IDFPartFilter *filter=NULL)
  5152. {
  5153. CriticalBlock block(sect);
  5154. if (subfiles.ordinality()==1)
  5155. return subfiles.item(0).getIterator(filter);
  5156. CDistributedFilePartIterator *ret = new CDistributedFilePartIterator();
  5157. loadParts(ret->queryParts(),filter);
  5158. return ret;
  5159. }
  5160. void rename(const char *_logicalname,IUserDescriptor *user)
  5161. {
  5162. StringBuffer prevname;
  5163. Owned<IFileRelationshipIterator> reliter;
  5164. // set prevname
  5165. if (!isAnon()) {
  5166. getLogicalName(prevname);
  5167. try {
  5168. IFileRelationshipIterator *iter = parent->lookupAllFileRelationships(prevname.str());
  5169. reliter.setown(iter);
  5170. }
  5171. catch (IException *e) {
  5172. EXCLOG(e,"CDistributedFileDirectory::rename");
  5173. e->Release();
  5174. }
  5175. detach();
  5176. }
  5177. attach(_logicalname,user);
  5178. if (reliter.get()) {
  5179. // add back any relationships with new name
  5180. parent->renameFileRelationships(prevname.str(),_logicalname,reliter,user);
  5181. }
  5182. }
  5183. const char *queryDefaultDir()
  5184. {
  5185. // returns the directory if all the same
  5186. const char *ret = NULL;
  5187. CriticalBlock block (sect);
  5188. ForEachItemIn(i,subfiles) {
  5189. if (subfiles.item(i).numParts())
  5190. {
  5191. const char *s = subfiles.item(i).queryDefaultDir();
  5192. if (!s)
  5193. return NULL;
  5194. if (!ret)
  5195. ret = s;
  5196. else if (strcmp(ret,s)!=0)
  5197. return NULL;
  5198. }
  5199. }
  5200. return ret;
  5201. }
  5202. const char *queryPartMask()
  5203. {
  5204. // returns the part mask if all the same
  5205. const char *ret = NULL;
  5206. CriticalBlock block (sect);
  5207. ForEachItemIn(i,subfiles) {
  5208. const char *s = subfiles.item(i).queryPartMask();
  5209. if (!s)
  5210. return NULL;
  5211. if (!ret)
  5212. ret = s;
  5213. else if (stricmp(ret,s)!=0)
  5214. return NULL;
  5215. }
  5216. return ret;
  5217. }
  5218. void attach(const char *_logicalname,IUserDescriptor *user)
  5219. {
  5220. assertex(!conn.get()); // already attached
  5221. CriticalBlock block (sect);
  5222. StringBuffer tail;
  5223. StringBuffer lfn;
  5224. logicalName.set(_logicalname);
  5225. checkLogicalName(logicalName,user,true,true,false,"attach");
  5226. parent->addEntry(logicalName,root.getClear(),true,false);
  5227. conn.clear();
  5228. CFileLock fcl;
  5229. verifyex(fcl.init(logicalName, DXB_SuperFile, RTM_LOCK_READ, defaultTimeout, "CDistributedSuperFile::attach"));
  5230. conn.setown(fcl.detach());
  5231. assertex(conn.get()); // must have been attached
  5232. root.setown(conn->getRoot());
  5233. loadSubFiles(NULL, 0, true);
  5234. }
  5235. void detach(unsigned timeoutMs=INFINITE, ICodeContext *ctx=NULL)
  5236. {
  5237. assertex(conn.get()); // must be attached
  5238. CriticalBlock block(sect);
  5239. checkModify("CDistributedSuperFile::detach");
  5240. StringBuffer reason;
  5241. if (checkOwned(reason))
  5242. throw MakeStringException(-1, "detach: %s", reason.str());
  5243. subfiles.kill();
  5244. // Remove from SDS
  5245. /* JCSMORE - this looks very kludgy...
  5246. * We have readlock, this code is doing
  5247. * 1) change to write lock (not using lockProperties or DistributedFilePropertyLock to do so) [using CFileChangeWriteLock]
  5248. * CFileChangeWriteLock doesn't preserve lock mode quite right.. (see 'newMode')
  5249. * 2) manually deleting SuperOwner from subfiles (in clearSuperOwners)
  5250. * 3) Using the connection to delete the SuperFile from Dali (clones to 'root' in process)
  5251. * 4) ~CFileChangeWriteLock() [writeLock.clear()], restores read lock from write to read
  5252. * 5) updateFS (housekeeping of empty scopes, relationships) - ok
  5253. */
  5254. CFileChangeWriteLock writeLock(conn, timeoutMs);
  5255. clearSuperOwners(timeoutMs, ctx);
  5256. writeLock.clear();
  5257. root.setown(closeConnection(true));
  5258. updateFS(logicalName, parent->queryDefaultTimeout());
  5259. logicalName.clear();
  5260. }
  5261. bool existsPhysicalPartFiles(unsigned short port)
  5262. {
  5263. CriticalBlock block (sect);
  5264. ForEachItemIn(i,subfiles) {
  5265. IDistributedFile &f=subfiles.item(i);
  5266. if (!f.existsPhysicalPartFiles(port))
  5267. return false;
  5268. }
  5269. return true;
  5270. }
  5271. bool renamePhysicalPartFiles(const char *newlfn,const char *cluster,IMultiException *mexcept,const char *newbasedir)
  5272. {
  5273. throw MakeStringException(-1,"renamePhysicalPartFiles not supported for SuperFiles");
  5274. return false;
  5275. }
  5276. void serialize(MemoryBuffer &mb)
  5277. {
  5278. UNIMPLEMENTED; // not yet needed
  5279. }
  5280. virtual unsigned numCopies(unsigned partno)
  5281. {
  5282. unsigned ret = (unsigned)-1;
  5283. CriticalBlock block (sect);
  5284. ForEachItemIn(i,subfiles) {
  5285. IDistributedFile &f=subfiles.item(i);
  5286. unsigned fnc = f.numCopies(partno);
  5287. if (fnc<ret)
  5288. ret = fnc;
  5289. }
  5290. return (ret==(unsigned)-1)?1:ret;
  5291. }
  5292. __int64 getFileSize(bool allowphysical,bool forcephysical)
  5293. {
  5294. __int64 ret = (__int64)(forcephysical?-1:queryAttributes().getPropInt64("@size",-1));
  5295. if (ret==-1)
  5296. {
  5297. ret = 0;
  5298. ForEachItemIn(i,subfiles)
  5299. {
  5300. __int64 ps = subfiles.item(i).getFileSize(allowphysical,forcephysical);
  5301. if (ps == -1)
  5302. return -1; // i.e. if cannot determine size of any part, total is unknown
  5303. ret += ps;
  5304. }
  5305. }
  5306. return ret;
  5307. }
  5308. __int64 getDiskSize(bool allowphysical,bool forcephysical)
  5309. {
  5310. if (!isCompressed(NULL))
  5311. return getFileSize(allowphysical, forcephysical);
  5312. __int64 ret = (__int64)(forcephysical?-1:queryAttributes().getPropInt64("@compressedSize",-1));
  5313. if (ret==-1)
  5314. {
  5315. ret = 0;
  5316. ForEachItemIn(i,subfiles)
  5317. {
  5318. __int64 ps = subfiles.item(i).getDiskSize(allowphysical,forcephysical);
  5319. if (ps == -1)
  5320. return -1; // i.e. if cannot determine size of any part, total is unknown
  5321. ret += ps;
  5322. }
  5323. }
  5324. return ret;
  5325. }
  5326. __int64 getRecordCount()
  5327. {
  5328. __int64 ret = queryAttributes().getPropInt64("@recordCount",-1);
  5329. if (ret==-1) {
  5330. ret = 0;
  5331. ForEachItemIn(i,subfiles) {
  5332. __int64 rc = subfiles.item(i).queryAttributes().getPropInt64("@recordCount",-1);
  5333. if (rc == -1) {
  5334. ret = rc;
  5335. break;
  5336. }
  5337. ret += rc;
  5338. }
  5339. }
  5340. return ret;
  5341. }
  5342. bool getFileCheckSum(unsigned &checkSum)
  5343. {
  5344. if (queryAttributes().hasProp("@checkSum"))
  5345. checkSum = (unsigned)queryAttributes().getPropInt64("@checkSum");
  5346. else
  5347. {
  5348. checkSum = ~0;
  5349. ForEachItemIn(i,subfiles) {
  5350. unsigned cs;
  5351. if (!subfiles.item(i).getFileCheckSum(cs))
  5352. return false;
  5353. checkSum ^= cs;
  5354. }
  5355. }
  5356. return true;
  5357. }
  5358. IDistributedSuperFile *querySuperFile()
  5359. {
  5360. return this;
  5361. }
  5362. virtual IDistributedFile &querySubFile(unsigned idx,bool sub)
  5363. {
  5364. CriticalBlock block (sect);
  5365. if (sub) {
  5366. ForEachItemIn(i,subfiles) {
  5367. IDistributedFile &f=subfiles.item(i);
  5368. IDistributedSuperFile *super = f.querySuperFile();
  5369. if (super) {
  5370. unsigned ns = super->numSubFiles(true);
  5371. if (ns>idx)
  5372. return super->querySubFile(idx,true);
  5373. idx -= ns;
  5374. }
  5375. else if (idx--==0)
  5376. return f;
  5377. }
  5378. // fall through to error
  5379. }
  5380. return subfiles.item(idx);
  5381. }
  5382. virtual IDistributedFile *querySubFileNamed(const char *name, bool sub)
  5383. {
  5384. CriticalBlock block (sect);
  5385. unsigned idx=findSubFileOrd(name);
  5386. if ((idx!=NotFound)&&(idx<subfiles.ordinality()))
  5387. return &subfiles.item(idx);
  5388. idx=findSubFile(name);
  5389. if (idx!=NotFound)
  5390. return &subfiles.item(idx);
  5391. if (sub) {
  5392. ForEachItemIn(i,subfiles) {
  5393. IDistributedFile &f=subfiles.item(i);
  5394. IDistributedSuperFile *super = f.querySuperFile();
  5395. if (super) {
  5396. IDistributedFile *ret = super->querySubFileNamed(name);
  5397. if (ret)
  5398. return ret;
  5399. }
  5400. }
  5401. }
  5402. return NULL;
  5403. }
  5404. virtual IDistributedFile *getSubFile(unsigned idx,bool sub)
  5405. {
  5406. CriticalBlock block (sect);
  5407. return LINK(&querySubFile(idx,sub));
  5408. }
  5409. virtual unsigned numSubFiles(bool sub)
  5410. {
  5411. CriticalBlock block (sect);
  5412. unsigned ret = 0;
  5413. if (sub) {
  5414. ForEachItemIn(i,subfiles) {
  5415. IDistributedFile &f=subfiles.item(i);
  5416. IDistributedSuperFile *super = f.querySuperFile();
  5417. if (super)
  5418. ret += super->numSubFiles();
  5419. else
  5420. ret++;
  5421. }
  5422. }
  5423. else
  5424. ret = subfiles.ordinality();
  5425. return ret;
  5426. }
  5427. virtual bool getFormatCrc(unsigned &crc)
  5428. {
  5429. if (queryAttributes().hasProp("@formatCrc")) {
  5430. crc = (unsigned)queryAttributes().getPropInt("@formatCrc");
  5431. return true;
  5432. }
  5433. bool found = false;
  5434. ForEachItemIn(i,subfiles) {
  5435. unsigned c;
  5436. if (subfiles.item(i).getFormatCrc(c)) {
  5437. if (found&&(c!=crc))
  5438. return false;
  5439. found = true;
  5440. crc = c;
  5441. }
  5442. }
  5443. return found;
  5444. }
  5445. virtual bool getRecordLayout(MemoryBuffer &layout)
  5446. {
  5447. layout.clear();
  5448. if (queryAttributes().getPropBin("_record_layout",layout))
  5449. return true;
  5450. bool found = false;
  5451. ForEachItemIn(i,subfiles) {
  5452. MemoryBuffer b;
  5453. if (subfiles.item(i).getRecordLayout(found?b:layout)) {
  5454. if (found) {
  5455. if ((b.length()!=layout.length())||(memcmp(b.bufferBase(),layout.bufferBase(),b.length())!=0))
  5456. return false;
  5457. }
  5458. else
  5459. found = true;
  5460. }
  5461. }
  5462. return found;
  5463. }
  5464. virtual bool getRecordSize(size32_t &rsz)
  5465. {
  5466. if (queryAttributes().hasProp("@recordSize")) {
  5467. rsz = (size32_t)queryAttributes().getPropInt("@recordSize");
  5468. return true;
  5469. }
  5470. bool found = false;
  5471. ForEachItemIn(i,subfiles) {
  5472. size32_t sz;
  5473. if (subfiles.item(i).getRecordSize(sz)) {
  5474. if (found&&(sz!=rsz))
  5475. return false;
  5476. found = true;
  5477. rsz = sz;
  5478. }
  5479. }
  5480. return found;
  5481. }
  5482. virtual bool isInterleaved()
  5483. {
  5484. return interleaved!=0;
  5485. }
  5486. virtual IDistributedFile *querySubPart(unsigned partidx,unsigned &subfileidx)
  5487. {
  5488. CriticalBlock block (sect);
  5489. subfileidx = 0;
  5490. Owned<IDistributedFilePart> part = getPart(partidx);
  5491. if (!part)
  5492. return NULL;
  5493. CDistributedFilePart *cpart = QUERYINTERFACE(part.get(),CDistributedFilePart);
  5494. if (!cpart)
  5495. return NULL;
  5496. IDistributedFile &ret = cpart->queryParent();
  5497. unsigned n = ret.numParts();
  5498. for (unsigned i=0;i<n;i++) {
  5499. Owned<IDistributedFilePart> spart = ret.getPart(i);
  5500. if (spart.get()==part.get()) {
  5501. subfileidx = i;
  5502. return &ret;
  5503. }
  5504. }
  5505. return NULL;
  5506. }
  5507. virtual unsigned getPositionPart(offset_t pos, offset_t &base)
  5508. { // not very quick!
  5509. CriticalBlock block (sect);
  5510. unsigned n = numParts();
  5511. base = 0;
  5512. for (unsigned i=0;i<n;i++) {
  5513. Owned<IDistributedFilePart> part = getPart(i);
  5514. offset_t ps = part->getFileSize(true,false);
  5515. if (ps==(offset_t)-1)
  5516. break;
  5517. if (ps>pos)
  5518. return i;
  5519. pos -= ps;
  5520. base += ps;
  5521. }
  5522. return NotFound;
  5523. }
  5524. IDistributedFileIterator *getSubFileIterator(bool supersub=false)
  5525. {
  5526. CriticalBlock block (sect);
  5527. return new cSubFileIterator(subfiles,supersub);
  5528. }
  5529. void updateFileAttrs()
  5530. {
  5531. if (subfiles.ordinality()==0) {
  5532. StringBuffer desc;
  5533. root->getProp("Attr/@description",desc);
  5534. root->removeProp("Attr"); // remove all other attributes if superfile empty
  5535. IPropertyTree *t=resetFileAttr(getEmptyAttr());
  5536. if (desc.length())
  5537. t->setProp("@description",desc.str());
  5538. return;
  5539. }
  5540. root->removeProp("Attr/@size");
  5541. root->removeProp("Attr/@compressedSize");
  5542. root->removeProp("Attr/@checkSum");
  5543. root->removeProp("Attr/@recordCount"); // recordCount not currently supported by superfiles
  5544. root->removeProp("Attr/@formatCrc"); // formatCrc set if all consistant
  5545. root->removeProp("Attr/@recordSize"); // record size set if all consistant
  5546. root->removeProp("Attr/_record_layout");
  5547. __int64 fs = getFileSize(false,false);
  5548. if (fs!=-1)
  5549. root->setPropInt64("Attr/@size",fs);
  5550. if (isCompressed(NULL))
  5551. {
  5552. fs = getDiskSize(false,false);
  5553. if (fs!=-1)
  5554. root->setPropInt64("Attr/@compressedSize",fs);
  5555. }
  5556. unsigned checkSum;
  5557. if (getFileCheckSum(checkSum))
  5558. root->setPropInt64("Attr/@checkSum", checkSum);
  5559. __int64 rc = getRecordCount();
  5560. if (rc!=-1)
  5561. root->setPropInt64("Attr/@recordCount",rc);
  5562. unsigned fcrc;
  5563. if (getFormatCrc(fcrc))
  5564. root->setPropInt("Attr/@formatCrc", fcrc);
  5565. size32_t rsz;
  5566. if (getRecordSize(rsz))
  5567. root->setPropInt("Attr/@recordSize", rsz);
  5568. MemoryBuffer mb;
  5569. if (getRecordLayout(mb))
  5570. root->setPropBin("Attr/_record_layout", mb.length(), mb.bufferBase());
  5571. }
  5572. void updateParentFileAttrs(IDistributedFileTransaction *transaction)
  5573. {
  5574. Owned<IPropertyTreeIterator> iter = root->getElements("SuperOwner");
  5575. StringBuffer pname;
  5576. ForEach(*iter) {
  5577. iter->query().getProp("@name",pname.clear());
  5578. Owned<IDistributedSuperFile> psfile = transaction?transaction->lookupSuperFile(pname.str()):
  5579. queryDistributedFileDirectory().lookupSuperFile(pname.str(),udesc,NULL);
  5580. CDistributedSuperFile *file = QUERYINTERFACE(psfile.get(),CDistributedSuperFile);
  5581. if (file) {
  5582. {
  5583. DistributedFilePropertyLock lock(file);
  5584. file->setModified();
  5585. file->updateFileAttrs();
  5586. }
  5587. file->updateParentFileAttrs(transaction);
  5588. }
  5589. }
  5590. }
  5591. void validateAddSubFile(IDistributedFile *sub)
  5592. {
  5593. if (strcmp(sub->queryLogicalName(),queryLogicalName())==0)
  5594. throw MakeStringException(-1,"addSubFile: Cannot add file %s to itself", queryLogicalName());
  5595. if (subfiles.ordinality())
  5596. checkFormatAttr(sub,"addSubFile");
  5597. if (NotFound!=findSubFile(sub->queryLogicalName()))
  5598. throw MakeStringException(-1,"addSubFile: File %s is already a subfile of %s", sub->queryLogicalName(),queryLogicalName());
  5599. }
  5600. void validate()
  5601. {
  5602. unsigned numSubfiles = root->getPropInt("@numsubfiles",0);
  5603. if (numSubfiles)
  5604. {
  5605. Owned<IPropertyTreeIterator> treeIter = root->getElements("SubFile");
  5606. unsigned subFileCount = 0;
  5607. ForEach(*treeIter)
  5608. {
  5609. IPropertyTree & st = treeIter->query();
  5610. StringBuffer subfilename;
  5611. st.getProp("@name", subfilename);
  5612. if (!parent->exists(subfilename.str(), NULL))
  5613. throw MakeStringException(-1, "Logical subfile '%s' doesn't exists!", subfilename.str());
  5614. if (!parent->isSuperFile(subfilename.str()))
  5615. if (!parent->existsPhysical(subfilename.str(), NULL))
  5616. {
  5617. const char * logicalName = queryLogicalName();
  5618. throw MakeStringException(-1, "Some physical parts do not exists, for logical file : %s",(isEmptyString(logicalName) ? "[unattached]" : logicalName));
  5619. }
  5620. subFileCount++;
  5621. }
  5622. if (numSubfiles != subFileCount)
  5623. throw MakeStringException(-1, "The value of @numsubfiles (%d) is not equal to the number of SubFile items (%d)!",numSubfiles, subFileCount);
  5624. }
  5625. }
  5626. private:
  5627. void doAddSubFile(IDistributedFile *_sub,bool before,const char *other,IDistributedFileTransactionExt *transaction) // takes ownership of sub
  5628. {
  5629. Owned<IDistributedFile> sub = _sub;
  5630. validateAddSubFile(sub); // shouldn't really be necessary, was validated in transaction before here
  5631. unsigned pos;
  5632. if (other&&*other) {
  5633. pos = findSubFileOrd(other);
  5634. if (pos==NotFound)
  5635. pos = findSubFile(other);
  5636. if (pos==NotFound)
  5637. pos = before?0:subfiles.ordinality();
  5638. else if (!before&&(pos<subfiles.ordinality()))
  5639. pos++;
  5640. }
  5641. else
  5642. pos = before?0:subfiles.ordinality();
  5643. if (pos > subfiles.ordinality())
  5644. throw MakeStringException(-1,"addSubFile: Insert position %d out of range for file %s in superfile %s", pos+1, sub->queryLogicalName(), queryLogicalName());
  5645. addItem(pos,sub.getClear()); // remove if failure TBD?
  5646. setModified();
  5647. updateFileAttrs();
  5648. linkSubFile(pos);
  5649. }
  5650. bool doRemoveSubFiles(IDistributedFileTransactionExt *transaction)
  5651. {
  5652. // have to be quite careful here
  5653. unsigned pos = subfiles.ordinality();
  5654. if (pos)
  5655. {
  5656. DistributedFilePropertyLock lock(this);
  5657. if (lock.needsReload())
  5658. loadSubFiles(transaction,1000*60*10);
  5659. pos = subfiles.ordinality();
  5660. if (pos)
  5661. {
  5662. do
  5663. {
  5664. pos--;
  5665. unlinkSubFile(pos);
  5666. removeItem(pos);
  5667. } while (pos);
  5668. setModified();
  5669. updateFileAttrs();
  5670. lock.unlock();
  5671. updateParentFileAttrs(transaction);
  5672. }
  5673. }
  5674. return true;
  5675. }
  5676. bool doRemoveSubFile(const char *subfile,
  5677. IDistributedFileTransactionExt *transaction)
  5678. {
  5679. // have to be quite careful here
  5680. unsigned pos=findSubFileOrd(subfile);
  5681. if ((pos==NotFound)||(pos>=subfiles.ordinality()))
  5682. pos = findSubFile(subfile);
  5683. if (pos==NotFound)
  5684. return false;
  5685. {
  5686. DistributedFilePropertyLock lock(this);
  5687. // don't reload subfiles here
  5688. pos=findSubFileOrd(subfile);
  5689. if ((pos==NotFound)||(pos>=subfiles.ordinality()))
  5690. pos = findSubFile(subfile);
  5691. if (pos==NotFound)
  5692. return false;
  5693. unlinkSubFile(pos);
  5694. removeItem(pos);
  5695. setModified();
  5696. updateFileAttrs();
  5697. }
  5698. updateParentFileAttrs(transaction);
  5699. return true;
  5700. }
  5701. bool doSwapSuperFile(IDistributedSuperFile *_file,
  5702. IDistributedFileTransactionExt *transaction)
  5703. {
  5704. assertex(transaction);
  5705. CDistributedSuperFile *file = QUERYINTERFACE(_file,CDistributedSuperFile);
  5706. if (!file)
  5707. return false;
  5708. // Cache names (so we can delete without problems)
  5709. StringArray subnames1;
  5710. StringArray subnames2;
  5711. for (unsigned i=0; i<this->numSubFiles(false); i++)
  5712. subnames1.append(querySubFile(i, false).queryLogicalName());
  5713. for (unsigned i=0; i<file->numSubFiles(false); i++)
  5714. subnames2.append(file->querySubFile(i, false).queryLogicalName());
  5715. // Delete all files
  5716. ForEachItemIn(d1,subnames1) {
  5717. Owned<IDistributedFile> sub = transaction->lookupFile(subnames1.item(d1));
  5718. if (!doRemoveSubFile(sub->queryLogicalName(), transaction))
  5719. return false;
  5720. }
  5721. ForEachItemIn(d2,subnames2) {
  5722. Owned<IDistributedFile> sub = transaction->lookupFile(subnames2.item(d2));
  5723. if (!file->doRemoveSubFile(sub->queryLogicalName(), transaction))
  5724. return false;
  5725. }
  5726. // Add files swapped
  5727. ForEachItemIn(a1,subnames1) {
  5728. Owned<IDistributedFile> sub = transaction->lookupFile(subnames1.item(a1));
  5729. file->doAddSubFile(LINK(sub), false, NULL, transaction);
  5730. }
  5731. ForEachItemIn(a2,subnames2) {
  5732. Owned<IDistributedFile> sub = transaction->lookupFile(subnames2.item(a2));
  5733. doAddSubFile(LINK(sub), false, NULL, transaction);
  5734. }
  5735. return true;
  5736. }
  5737. public:
  5738. void addSubFile(const char * subfile,
  5739. bool before=false, // if true before other
  5740. const char *other=NULL, // in NULL add at end (before=false) or start(before=true)
  5741. bool addcontents=false,
  5742. IDistributedFileTransaction *transaction=NULL
  5743. )
  5744. {
  5745. CriticalBlock block (sect);
  5746. if (!subfile||!*subfile)
  5747. return;
  5748. checkModify("addSubFile");
  5749. partscache.kill();
  5750. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  5751. Linked<IDistributedFileTransactionExt> localtrans;
  5752. if (transaction)
  5753. {
  5754. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  5755. localtrans.set(_transaction);
  5756. }
  5757. else
  5758. localtrans.setown(new CDistributedFileTransaction(udesc, this));
  5759. localtrans->ensureFile(this);
  5760. if (addcontents)
  5761. {
  5762. localtrans->descend();
  5763. StringArray subs;
  5764. Owned<IDistributedSuperFile> sfile = localtrans->lookupSuperFile(subfile);
  5765. if (sfile)
  5766. {
  5767. Owned<IDistributedFileIterator> iter = sfile->getSubFileIterator();
  5768. ForEach(*iter)
  5769. subs.append(iter->query().queryLogicalName());
  5770. }
  5771. sfile.clear();
  5772. ForEachItemIn(i,subs)
  5773. addSubFile(subs.item(i),before,other,false,localtrans);
  5774. localtrans->ascend();
  5775. }
  5776. else
  5777. {
  5778. cAddSubFileAction *action = new cAddSubFileAction(queryLogicalName(),subfile,before,other);
  5779. localtrans->addAction(action); // takes ownership
  5780. }
  5781. localtrans->autoCommit();
  5782. }
  5783. virtual bool removeSubFile(const char *subfile, // if NULL removes all
  5784. bool remsub, // if true removes subfiles from DFS
  5785. bool remcontents, // if true, recurse super-files
  5786. IDistributedFileTransaction *transaction)
  5787. {
  5788. CriticalBlock block (sect);
  5789. if (subfile&&!*subfile)
  5790. return false;
  5791. checkModify("removeSubFile");
  5792. partscache.kill();
  5793. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  5794. Linked<IDistributedFileTransactionExt> localtrans;
  5795. if (transaction)
  5796. {
  5797. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  5798. localtrans.set(_transaction);
  5799. }
  5800. else
  5801. localtrans.setown(new CDistributedFileTransaction(udesc, this));
  5802. // Make sure this file is in cache (reuse below)
  5803. localtrans->ensureFile(this);
  5804. // If recurring, traverse super-file subs (if super)
  5805. if (remcontents)
  5806. {
  5807. localtrans->descend();
  5808. CDfsLogicalFileName logicalname;
  5809. logicalname.set(subfile);
  5810. IDistributedFile *sub = querySubFileNamed(logicalname.get(),false);
  5811. if (!sub)
  5812. return false;
  5813. IDistributedSuperFile *sfile = sub->querySuperFile();
  5814. if (sfile)
  5815. {
  5816. Owned<IDistributedFileIterator> iter = sfile->getSubFileIterator(true);
  5817. bool ret = true;
  5818. StringArray toremove;
  5819. ForEach(*iter)
  5820. toremove.append(iter->query().queryLogicalName());
  5821. iter.clear();
  5822. ForEachItemIn(i,toremove)
  5823. {
  5824. if (!sfile->removeSubFile(toremove.item(i),remsub,false,localtrans))
  5825. ret = false;
  5826. }
  5827. if (!ret||!remsub)
  5828. return ret;
  5829. }
  5830. localtrans->ascend();
  5831. }
  5832. cRemoveSubFileAction *action = new cRemoveSubFileAction(queryLogicalName(),subfile,remsub);
  5833. localtrans->addAction(action); // takes ownership
  5834. localtrans->autoCommit();
  5835. // MORE - auto-commit will throw an exception, change this to void
  5836. return true;
  5837. }
  5838. virtual bool removeOwnedSubFiles(bool remsub, // if true removes subfiles from DFS
  5839. IDistributedFileTransaction *transaction)
  5840. {
  5841. CriticalBlock block (sect);
  5842. checkModify("removeOwnedSubFiles");
  5843. partscache.kill();
  5844. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  5845. Linked<IDistributedFileTransactionExt> localtrans;
  5846. if (transaction)
  5847. {
  5848. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  5849. localtrans.set(_transaction);
  5850. }
  5851. else
  5852. localtrans.setown(new CDistributedFileTransaction(udesc, this));
  5853. // Make sure this file is in cache (reuse below)
  5854. localtrans->addFile(this);
  5855. cRemoveOwnedSubFilesAction *action = new cRemoveOwnedSubFilesAction(localtrans, queryLogicalName(), remsub);
  5856. localtrans->addAction(action); // takes ownership
  5857. localtrans->autoCommit();
  5858. // MORE - auto-commit will throw an exception, change this to void
  5859. return true;
  5860. }
  5861. virtual bool swapSuperFile( IDistributedSuperFile *_file,
  5862. IDistributedFileTransaction *transaction)
  5863. {
  5864. CriticalBlock block (sect);
  5865. if (!_file)
  5866. return false;
  5867. checkModify("swapSuperFile");
  5868. partscache.kill();
  5869. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  5870. Linked<IDistributedFileTransactionExt> localtrans;
  5871. if (transaction)
  5872. {
  5873. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  5874. localtrans.set(_transaction);
  5875. }
  5876. else
  5877. localtrans.setown(new CDistributedFileTransaction(udesc, this));
  5878. // Make sure this file is in cache
  5879. localtrans->ensureFile(this);
  5880. cSwapFileAction *action = new cSwapFileAction(queryLogicalName(),_file->queryLogicalName());
  5881. localtrans->addAction(action); // takes ownership
  5882. localtrans->autoCommit();
  5883. return true;
  5884. }
  5885. void savePartsAttr(bool force)
  5886. {
  5887. }
  5888. void fillClustersCache()
  5889. {
  5890. if (clusterscache.ordinality()==0) {
  5891. StringBuffer name;
  5892. ForEachItemIn(i,subfiles) {
  5893. StringArray clusters;
  5894. IDistributedFile &f=subfiles.item(i);
  5895. unsigned nc = f.numClusters();
  5896. for(unsigned j=0;j<nc;j++) {
  5897. f.getClusterName(j,name.clear());
  5898. if (clusterscache.find(name.str())==NotFound) {
  5899. IClusterInfo &cluster = *createClusterInfo(name.str(),f.queryClusterGroup(j),f.queryPartDiskMapping(j),&queryNamedGroupStore());
  5900. clusterscache.append(cluster);
  5901. }
  5902. }
  5903. }
  5904. }
  5905. }
  5906. unsigned getClusterNames(StringArray &clusters)
  5907. {
  5908. CriticalBlock block (sect);
  5909. fillClustersCache();
  5910. return clusterscache.getNames(clusters);
  5911. }
  5912. unsigned numClusters()
  5913. {
  5914. CriticalBlock block (sect);
  5915. fillClustersCache();
  5916. return clusterscache.ordinality();
  5917. }
  5918. unsigned findCluster(const char *clustername)
  5919. {
  5920. CriticalBlock block (sect);
  5921. fillClustersCache();
  5922. return clusterscache.find(clustername);
  5923. }
  5924. ClusterPartDiskMapSpec &queryPartDiskMapping(unsigned clusternum)
  5925. {
  5926. CriticalBlock block (sect);
  5927. fillClustersCache();
  5928. return clusterscache.queryPartDiskMapping(clusternum);
  5929. }
  5930. void updatePartDiskMapping(const char *clustername,const ClusterPartDiskMapSpec &spec)
  5931. {
  5932. if (!clustername||!*clustername)
  5933. return;
  5934. CriticalBlock block (sect);
  5935. fillClustersCache();
  5936. ForEachItemIn(i,subfiles) {
  5937. IDistributedFile &f=subfiles.item(i);
  5938. f.updatePartDiskMapping(clustername,spec);
  5939. }
  5940. }
  5941. IGroup *queryClusterGroup(unsigned clusternum)
  5942. {
  5943. CriticalBlock block (sect);
  5944. fillClustersCache();
  5945. return clusterscache.queryGroup(clusternum);
  5946. }
  5947. StringBuffer &getClusterGroupName(unsigned clusternum, StringBuffer &name)
  5948. {
  5949. CriticalBlock block (sect);
  5950. fillClustersCache();
  5951. return clusterscache.item(clusternum).getGroupName(name, &queryNamedGroupStore());
  5952. }
  5953. void addCluster(const char *clustername,const ClusterPartDiskMapSpec &mspec)
  5954. {
  5955. if (!clustername||!*clustername)
  5956. return;
  5957. CriticalBlock block (sect);
  5958. clusterscache.clear();
  5959. subfiles.item(0).addCluster(clustername,mspec);
  5960. }
  5961. virtual bool removeCluster(const char *clustername)
  5962. {
  5963. bool clusterRemoved=false;
  5964. CriticalBlock block (sect);
  5965. clusterscache.clear();
  5966. ForEachItemIn(i,subfiles) {
  5967. IDistributedFile &f=subfiles.item(i);
  5968. clusterRemoved |= f.removeCluster(clustername);
  5969. }
  5970. return clusterRemoved;
  5971. }
  5972. void setPreferredClusters(const char *clusters)
  5973. {
  5974. CriticalBlock block (sect);
  5975. clusterscache.clear();
  5976. ForEachItemIn(i,subfiles) {
  5977. IDistributedFile &f=subfiles.item(i);
  5978. f.setPreferredClusters(clusters);
  5979. }
  5980. }
  5981. virtual bool checkClusterCompatible(IFileDescriptor &fdesc, StringBuffer &err)
  5982. {
  5983. CriticalBlock block (sect);
  5984. if (subfiles.ordinality()!=1) {
  5985. err.append("only singleton superfiles allowed");
  5986. return false;
  5987. }
  5988. ForEachItemIn(i,subfiles) {
  5989. IDistributedFile &f=subfiles.item(i);
  5990. if (!f.checkClusterCompatible(fdesc,err))
  5991. return false;
  5992. }
  5993. return true;
  5994. }
  5995. void setSingleClusterOnly()
  5996. {
  5997. CriticalBlock block (sect);
  5998. ForEachItemIn(i,subfiles) {
  5999. IDistributedFile &f=subfiles.item(i);
  6000. f.setSingleClusterOnly();
  6001. }
  6002. }
  6003. void enqueueReplicate()
  6004. {
  6005. CriticalBlock block (sect);
  6006. ForEachItemIn(i,subfiles) {
  6007. IDistributedFile &f=subfiles.item(i);
  6008. f.enqueueReplicate();
  6009. }
  6010. }
  6011. bool getAccessedTime(CDateTime &dt)
  6012. {
  6013. bool set=false;
  6014. CriticalBlock block (sect);
  6015. ForEachItemIn(i,subfiles) {
  6016. IDistributedFile &f=subfiles.item(i);
  6017. if (!set)
  6018. set = f.getAccessedTime(dt);
  6019. else {
  6020. CDateTime cmp;
  6021. if (f.getAccessedTime(cmp)) {
  6022. if (cmp.compare(dt)>0)
  6023. dt.set(cmp);
  6024. }
  6025. }
  6026. }
  6027. return set;
  6028. }
  6029. void setAccessedTime(const CDateTime &dt)
  6030. {
  6031. {
  6032. CriticalBlock block (sect);
  6033. ForEachItemIn(i,subfiles) {
  6034. IDistributedFile &f=subfiles.item(i);
  6035. f.setAccessedTime(dt);
  6036. }
  6037. }
  6038. }
  6039. };
  6040. // --------------------------------------------------------
  6041. void CDistributedFileTransaction::validateAddSubFile(IDistributedSuperFile *super, IDistributedFile *sub, const char *subName)
  6042. {
  6043. CTransactionFile *trackedSuper = lookupTrackedFile(super);
  6044. if (!trackedSuper)
  6045. return;
  6046. const char *superName = trackedSuper->queryName();
  6047. if (strcmp(subName, superName)==0)
  6048. throw MakeStringException(-1,"addSubFile: Cannot add file %s to itself", superName);
  6049. if (trackedSuper->numSubFiles())
  6050. {
  6051. CDistributedSuperFile *sf = dynamic_cast<CDistributedSuperFile *>(super);
  6052. sf->checkFormatAttr(sub, "addSubFile");
  6053. if (trackedSuper->find(subName, false))
  6054. throw MakeStringException(-1,"addSubFile: File %s is already a subfile of %s", subName, superName);
  6055. }
  6056. }
  6057. // --------------------------------------------------------
  6058. CDistributedFilePart::CDistributedFilePart(CDistributedFile &_parent,unsigned _part,IPartDescriptor *pd)
  6059. : parent(_parent)
  6060. {
  6061. partIndex = _part;
  6062. dirty = false;
  6063. if (pd) {
  6064. if (pd->isMulti())
  6065. ERRLOG("Multi filenames not supported in Dali DFS Part %d of %s",_part+1,_parent.queryLogicalName());
  6066. overridename.set(pd->queryOverrideName());
  6067. setAttr(*pd->getProperties());
  6068. }
  6069. else
  6070. ERRLOG("CDistributedFilePart::CDistributedFilePart no IPartDescriptor for part");
  6071. }
  6072. void CDistributedFilePart::Link(void) const
  6073. {
  6074. parent.Link();
  6075. CInterface::Link();
  6076. }
  6077. bool CDistributedFilePart::Release(void) const
  6078. {
  6079. parent.Release();
  6080. return CInterface::Release();
  6081. }
  6082. offset_t CDistributedFilePart::getSize(bool checkCompressed)
  6083. {
  6084. offset_t ret = (offset_t)-1;
  6085. StringBuffer firstname;
  6086. bool compressed = ::isCompressed(parent.queryAttributes());
  6087. unsigned nc=parent.numCopies(partIndex);
  6088. for (unsigned copy=0;copy<nc;copy++)
  6089. {
  6090. RemoteFilename rfn;
  6091. try
  6092. {
  6093. Owned<IFile> partfile = createIFile(getFilename(rfn,copy));
  6094. if (checkCompressed && compressed)
  6095. {
  6096. Owned<ICompressedFileIO> compressedIO = createCompressedFileReader(partfile);
  6097. if (compressedIO)
  6098. ret = compressedIO->size();
  6099. }
  6100. else
  6101. ret = partfile->size();
  6102. if (ret!=(offset_t)-1)
  6103. return ret;
  6104. }
  6105. catch (IException *e)
  6106. {
  6107. StringBuffer s("CDistributedFilePart::getSize ");
  6108. rfn.getRemotePath(s);
  6109. EXCLOG(e, s.str());
  6110. e->Release();
  6111. }
  6112. if (copy==0)
  6113. rfn.getRemotePath(firstname);
  6114. }
  6115. throw new CDFS_Exception(DFSERR_CannotFindPartFileSize,firstname.str());;
  6116. }
  6117. StringBuffer & CDistributedFilePart::getPartName(StringBuffer &partname)
  6118. {
  6119. if (!overridename.isEmpty()) {
  6120. if (isSpecialPath(overridename)) {
  6121. // bit of a kludge
  6122. if (isPathSepChar(*overridename)&&partname.length()&&isPathSepChar(partname.charAt(partname.length()-1)))
  6123. partname.setLength(partname.length()-1);
  6124. return partname.append(overridename);
  6125. }
  6126. return partname.append(pathTail(overridename));
  6127. }
  6128. const char *mask=parent.queryPartMask();
  6129. if (!mask||!*mask) {
  6130. const char *err ="CDistributedFilePart::getPartName cannot determine part name (no mask)";
  6131. ERRLOG("%s", err);
  6132. throw MakeStringExceptionDirect(-1, err);
  6133. }
  6134. expandMask(partname,mask,partIndex,parent.numParts());
  6135. return partname;
  6136. }
  6137. unsigned CDistributedFilePart::bestCopyNum(const IpAddress &ip,unsigned rel)
  6138. {
  6139. unsigned n = numCopies();
  6140. unsigned *dist = new unsigned[n];
  6141. unsigned *idx = new unsigned[n];
  6142. for (unsigned c=0;c<n;c++) {
  6143. dist[c] = ip.ipdistance(queryNode(c)->endpoint());
  6144. idx[c] = c;
  6145. }
  6146. if (rel>=n)
  6147. rel = n-1;
  6148. // do bubble sort as not that many!
  6149. for (unsigned i=0; i<n-1; i++)
  6150. for (unsigned j=0; j<n-1-i; j++)
  6151. if (dist[idx[j+1]] < dist[idx[j]]) {
  6152. unsigned t = idx[j];
  6153. idx[j] = idx[j+1];
  6154. idx[j+1] = t;
  6155. }
  6156. unsigned ret = idx[rel];
  6157. delete [] idx;
  6158. delete [] dist;
  6159. return ret;
  6160. }
  6161. unsigned CDistributedFilePart::copyClusterNum(unsigned copy,unsigned *replicate)
  6162. {
  6163. return parent.copyClusterNum(partIndex,copy,replicate);
  6164. }
  6165. StringBuffer &CDistributedFilePart::getPartDirectory(StringBuffer &ret,unsigned copy)
  6166. {
  6167. const char *defdir = parent.queryDefaultDir();
  6168. StringBuffer dir;
  6169. const char *pn;
  6170. if (overridename.isEmpty())
  6171. pn = parent.queryPartMask();
  6172. else {
  6173. pn = overridename.get();
  6174. if (isSpecialPath(pn)) // its a query
  6175. return ret; // ret.append('/'); // not sure if really need '/' here
  6176. }
  6177. if (pn&&*pn) {
  6178. StringBuffer odir;
  6179. splitDirTail(pn,odir);
  6180. if (odir.length()) {
  6181. if (isAbsolutePath(pn))
  6182. dir.append(odir);
  6183. else if (defdir&&*defdir)
  6184. addPathSepChar(dir.append(defdir)).append(odir);
  6185. }
  6186. else
  6187. dir.append(defdir);
  6188. }
  6189. if (dir.length()==0)
  6190. ERRLOG("IDistributedFilePart::getPartDirectory unable to determine part directory");
  6191. else {
  6192. parent.adjustClusterDir(partIndex,copy,dir);
  6193. ret.append(dir);
  6194. }
  6195. return ret;
  6196. }
  6197. unsigned CDistributedFilePart::numCopies()
  6198. {
  6199. return parent.numCopies(partIndex);
  6200. }
  6201. INode *CDistributedFilePart::queryNode(unsigned copy)
  6202. {
  6203. return parent.queryNode(partIndex,copy);
  6204. }
  6205. unsigned CDistributedFilePart::queryDrive(unsigned copy)
  6206. {
  6207. return parent.queryDrive(partIndex,copy,parent.directory);
  6208. }
  6209. bool CDistributedFilePart::isHost(unsigned copy)
  6210. {
  6211. return (queryNode(copy)->isHost());
  6212. }
  6213. IPropertyTree &CDistributedFilePart::queryAttributes()
  6214. {
  6215. CriticalBlock block (sect); // avoid nested blocks
  6216. if (attr)
  6217. return *attr;
  6218. WARNLOG("CDistributedFilePart::queryAttributes missing part attributes");
  6219. attr.setown(getEmptyAttr());
  6220. return *attr;
  6221. }
  6222. RemoteFilename &CDistributedFilePart::getFilename(RemoteFilename &ret,unsigned copy)
  6223. {
  6224. // this is probably not as efficient as could be
  6225. StringBuffer fullpath;
  6226. getPartDirectory(fullpath,copy);
  6227. addPathSepChar(fullpath);
  6228. getPartName(fullpath);
  6229. SocketEndpoint ep;
  6230. INode *node=queryNode(copy);
  6231. if (node)
  6232. ep = node->endpoint();
  6233. ret.setPath(ep,fullpath.str());
  6234. return ret;
  6235. }
  6236. bool CDistributedFilePart::getCrc(unsigned &crc)
  6237. {
  6238. return getCrcFromPartProps(parent.queryAttributes(),queryAttributes(), crc);
  6239. }
  6240. unsigned CDistributedFilePart::getPhysicalCrc()
  6241. {
  6242. StringBuffer firstname;
  6243. unsigned nc=parent.numCopies(partIndex);
  6244. for (unsigned copy=0;copy<nc;copy++) {
  6245. RemoteFilename rfn;
  6246. try {
  6247. Owned<IFile> partfile = createIFile(getFilename(rfn,copy));
  6248. if (partfile&&partfile->exists())
  6249. return partfile->getCRC();
  6250. }
  6251. catch (IException *e)
  6252. {
  6253. StringBuffer s("CDistributedFilePart::getPhysicalCrc ");
  6254. rfn.getRemotePath(s);
  6255. EXCLOG(e, s.str());
  6256. e->Release();
  6257. }
  6258. if (copy==0)
  6259. rfn.getRemotePath(firstname);
  6260. }
  6261. IDFS_Exception *e = new CDFS_Exception(DFSERR_CannotFindPartFileCrc,firstname.str());
  6262. throw e;
  6263. }
  6264. // TODO: Create DistributedFilePropertyLock for parts
  6265. bool CDistributedFilePart::lockProperties(unsigned timeoutms)
  6266. {
  6267. dirty = true;
  6268. return parent.lockProperties(timeoutms);
  6269. }
  6270. // TODO: Create DistributedFilePropertyLock for parts
  6271. void CDistributedFilePart::unlockProperties(DFTransactionState state=TAS_NONE)
  6272. {
  6273. parent.unlockProperties(state);
  6274. }
  6275. offset_t CDistributedFilePart::getFileSize(bool allowphysical,bool forcephysical)
  6276. {
  6277. offset_t ret = (offset_t)((forcephysical&&allowphysical)?-1:queryAttributes().getPropInt64("@size", -1));
  6278. if (allowphysical&&(ret==(offset_t)-1))
  6279. ret = getSize(true);
  6280. return ret;
  6281. }
  6282. offset_t CDistributedFilePart::getDiskSize(bool allowphysical,bool forcephysical)
  6283. {
  6284. if (!::isCompressed(parent.queryAttributes()))
  6285. return getFileSize(allowphysical, forcephysical);
  6286. if (forcephysical && allowphysical)
  6287. return getSize(false); // i.e. only if force, because all compressed should have @compressedSize attribute
  6288. // NB: compressSize is disk size
  6289. return queryAttributes().getPropInt64("@compressedSize", -1);
  6290. }
  6291. bool CDistributedFilePart::getModifiedTime(bool allowphysical,bool forcephysical, CDateTime &dt)
  6292. {
  6293. StringBuffer s;
  6294. if (!forcephysical&&queryAttributes().getProp("@modified", s)) {
  6295. dt.setString(s.str());
  6296. if (!dt.isNull())
  6297. return true;
  6298. }
  6299. if (allowphysical) {
  6300. unsigned nc=parent.numCopies(partIndex);
  6301. for (unsigned copy=0;copy<nc;copy++) {
  6302. RemoteFilename rfn;
  6303. try {
  6304. Owned<IFile> partfile = createIFile(getFilename(rfn,copy));
  6305. if (partfile->getTime(NULL,&dt,NULL))
  6306. return true;
  6307. }
  6308. catch (IException *e)
  6309. {
  6310. StringBuffer s("CDistributedFilePart::getFileTime ");
  6311. rfn.getRemotePath(s);
  6312. EXCLOG(e, s.str());
  6313. e->Release();
  6314. }
  6315. }
  6316. }
  6317. return false;
  6318. }
  6319. unsigned getSuperFileSubs(IDistributedSuperFile *super, IArrayOf<IDistributedFile> &subFiles, bool superSub)
  6320. {
  6321. unsigned numSubs = super->numSubFiles(superSub);
  6322. for (unsigned s=0; s<numSubs; s++)
  6323. {
  6324. IDistributedFile &subFile = super->querySubFile(s, superSub);
  6325. subFiles.append(*LINK(&subFile));
  6326. }
  6327. return numSubs;
  6328. }
  6329. // --------------------------------------------------------
  6330. class CNamedGroupIterator: implements INamedGroupIterator, public CInterface
  6331. {
  6332. Owned<IPropertyTreeIterator> pe;
  6333. Linked<IRemoteConnection> conn;
  6334. Linked<IGroup> matchgroup;
  6335. bool exactmatch;
  6336. bool match();
  6337. public:
  6338. IMPLEMENT_IINTERFACE;
  6339. CNamedGroupIterator(IRemoteConnection *_conn,IGroup *_matchgroup=NULL,bool _exactmatch=false)
  6340. : conn(_conn), matchgroup(_matchgroup)
  6341. {
  6342. exactmatch = _exactmatch;
  6343. if (matchgroup.get()) {
  6344. StringBuffer query;
  6345. query.append("Group[Node/@ip=\"");
  6346. matchgroup->queryNode(0).endpoint().getUrlStr(query);
  6347. query.append("\"]");
  6348. pe.setown(conn->getElements(query.str()));
  6349. }
  6350. else
  6351. pe.setown(conn->queryRoot()->getElements("Group"));
  6352. }
  6353. bool first()
  6354. {
  6355. if (!pe->first())
  6356. return false;
  6357. if (match())
  6358. return true;
  6359. return next();
  6360. }
  6361. bool next()
  6362. {
  6363. while (pe->next())
  6364. if (match())
  6365. return true;
  6366. return false;
  6367. }
  6368. bool isValid()
  6369. {
  6370. return pe->isValid();
  6371. }
  6372. StringBuffer &get(StringBuffer &name)
  6373. {
  6374. pe->query().getProp("@name",name);
  6375. return name;
  6376. }
  6377. StringBuffer &getdir(StringBuffer &dir)
  6378. {
  6379. pe->query().getProp("@dir",dir);
  6380. return dir;
  6381. }
  6382. bool isCluster()
  6383. {
  6384. return pe->query().getPropBool("@cluster");
  6385. }
  6386. };
  6387. // --------------------------------------------------------
  6388. #define GROUP_CACHE_INTERVAL (1000*60)
  6389. #define GROUP_EXCEPTION_CACHE_INTERVAL (1000*60*10)
  6390. static GroupType translateGroupType(const char *groupType)
  6391. {
  6392. if (!groupType)
  6393. return grp_unknown;
  6394. if (strieq(groupType, "Thor"))
  6395. return grp_thor;
  6396. else if (strieq(groupType, "Roxie"))
  6397. return grp_roxie;
  6398. else if (strieq(groupType, "hthor"))
  6399. return grp_hthor;
  6400. else
  6401. return grp_unknown;
  6402. }
  6403. class CNamedGroupCacheEntry: public CInterface
  6404. {
  6405. public:
  6406. Linked<IGroup> group;
  6407. StringAttr name;
  6408. StringAttr groupDir;
  6409. GroupType groupType;
  6410. Linked<IException> exception;
  6411. CNamedGroupCacheEntry(IGroup *_group, const char *_name, const char *_dir, GroupType _groupType)
  6412. : group(_group), name(_name), groupDir(_dir), groupType(_groupType)
  6413. {
  6414. cachedtime = msTick();
  6415. }
  6416. CNamedGroupCacheEntry(IException *_exception, const char *_name)
  6417. : exception(_exception), name(_name), groupType(grp_unknown)
  6418. {
  6419. cachedtime = msTick();
  6420. }
  6421. bool expired(unsigned timeNow)
  6422. {
  6423. if (exception)
  6424. return timeNow-cachedtime > GROUP_EXCEPTION_CACHE_INTERVAL;
  6425. else
  6426. return timeNow-cachedtime > GROUP_CACHE_INTERVAL;
  6427. }
  6428. protected:
  6429. unsigned cachedtime;
  6430. };
  6431. class CNamedGroupStore: implements INamedGroupStore, public CInterface
  6432. {
  6433. CriticalSection cachesect;
  6434. CIArrayOf<CNamedGroupCacheEntry> cache;
  6435. unsigned defaultTimeout;
  6436. unsigned defaultRemoteTimeout;
  6437. public:
  6438. IMPLEMENT_IINTERFACE;
  6439. CNamedGroupStore()
  6440. {
  6441. defaultTimeout = INFINITE;
  6442. defaultRemoteTimeout = FOREIGN_DALI_TIMEOUT;
  6443. }
  6444. IGroup *dolookup(const char *logicalgroupname,IRemoteConnection *conn, StringBuffer *dirret, GroupType &groupType)
  6445. {
  6446. SocketEndpointArray epa;
  6447. StringBuffer gname(logicalgroupname);
  6448. gname.trim();
  6449. if (!gname.length())
  6450. return NULL;
  6451. gname.toLowerCase();
  6452. logicalgroupname = gname.str();
  6453. bool isiprange = (*logicalgroupname!=0);
  6454. for (const char *s1=logicalgroupname;*s1;s1++)
  6455. if (isalpha(*s1)) {
  6456. isiprange = false;
  6457. break;
  6458. }
  6459. if (isiprange) {
  6460. // allow IP or IP list instead of group name
  6461. // I don't think this is a security problem as groups not checked
  6462. // NB ports not allowed here
  6463. char *buf = strdup(logicalgroupname);
  6464. char *s = buf;
  6465. while (*s) {
  6466. char *next = strchr(s,',');
  6467. if (next)
  6468. *next = 0;
  6469. SocketEndpoint ep;
  6470. unsigned n = ep.ipsetrange(s);
  6471. for (unsigned i=0;i<n;i++) {
  6472. if (ep.isNull()) { // failed
  6473. epa.kill();
  6474. break;
  6475. }
  6476. epa.append(ep);
  6477. ep.ipincrement(1);
  6478. }
  6479. if (!next)
  6480. break;
  6481. s = next+1;
  6482. }
  6483. free(buf);
  6484. if (epa.ordinality())
  6485. {
  6486. groupType = grp_unknown;
  6487. return createIGroup(epa);
  6488. }
  6489. }
  6490. StringBuffer range;
  6491. StringBuffer parent;
  6492. if (decodeChildGroupName(gname.str(),parent,range)) {
  6493. gname.clear().append(parent);
  6494. logicalgroupname = gname.str();
  6495. }
  6496. StringAttr groupdir;
  6497. GroupType type = grp_unknown;
  6498. bool cached = false;
  6499. unsigned timeNow = msTick();
  6500. {
  6501. CriticalBlock block(cachesect);
  6502. ForEachItemInRev(idx, cache)
  6503. {
  6504. CNamedGroupCacheEntry &entry = cache.item(idx);
  6505. if (entry.expired(timeNow))
  6506. {
  6507. cache.remove(idx);
  6508. }
  6509. else if (strcmp(gname.str(),entry.name.get())==0)
  6510. {
  6511. cached = true;
  6512. if (entry.exception)
  6513. throw LINK(entry.exception);
  6514. if (range.length()==0)
  6515. {
  6516. if (dirret)
  6517. dirret->append(entry.groupDir);
  6518. groupType = entry.groupType;
  6519. return entry.group.getLink();
  6520. }
  6521. // there is a range so copy to epa
  6522. entry.group->getSocketEndpoints(epa);
  6523. groupdir.set(entry.groupDir);
  6524. type = entry.groupType;
  6525. break;
  6526. }
  6527. }
  6528. }
  6529. try
  6530. {
  6531. if ((gname.length()>9)&&(memcmp(logicalgroupname,"foreign::",9)==0))
  6532. {
  6533. StringBuffer eps;
  6534. const char *s = logicalgroupname+9;
  6535. while (*s&&((*s!=':')||(s[1]!=':')))
  6536. eps.append(*(s++));
  6537. if (*s)
  6538. {
  6539. s+=2;
  6540. if (*s)
  6541. {
  6542. Owned<INode> dali = createINode(eps.str());
  6543. if (!dali || !getRemoteGroup(dali, s, defaultRemoteTimeout, groupdir, type, epa))
  6544. {
  6545. if (!cached)
  6546. {
  6547. CriticalBlock block(cachesect);
  6548. cache.append(*new CNamedGroupCacheEntry(NULL, gname, NULL, grp_unknown));
  6549. }
  6550. return NULL;
  6551. }
  6552. }
  6553. }
  6554. }
  6555. else if (epa.ordinality()==0) {
  6556. struct sLock
  6557. {
  6558. sLock() { lock = NULL; };
  6559. ~sLock() { delete lock; };
  6560. CConnectLock *lock;
  6561. } slock;
  6562. if (!conn)
  6563. {
  6564. slock.lock = new CConnectLock("CNamedGroup::lookup", SDS_GROUPSTORE_ROOT, false, false, false, defaultTimeout);
  6565. conn = slock.lock->conn;
  6566. if (!conn)
  6567. {
  6568. if (!cached)
  6569. {
  6570. CriticalBlock block(cachesect);
  6571. cache.append(*new CNamedGroupCacheEntry(NULL, gname, NULL, grp_unknown));
  6572. }
  6573. return NULL;
  6574. }
  6575. }
  6576. Owned<IPropertyTree> pt = getNamedPropTree(conn->queryRoot(),"Group","@name",gname.str(),true);
  6577. if (!pt)
  6578. return NULL;
  6579. type = translateGroupType(pt->queryProp("@kind"));
  6580. groupdir.set(pt->queryProp("@dir"));
  6581. if (groupdir.isEmpty())
  6582. groupdir.set(queryBaseDirectory(type));
  6583. Owned<IPropertyTreeIterator> pe2 = pt->getElements("Node");
  6584. ForEach(*pe2)
  6585. {
  6586. SocketEndpoint ep(pe2->query().queryProp("@ip"));
  6587. epa.append(ep);
  6588. }
  6589. }
  6590. }
  6591. catch (IException *E)
  6592. {
  6593. // cache the exception
  6594. CriticalBlock block(cachesect);
  6595. cache.append(*new CNamedGroupCacheEntry(E, gname));
  6596. throw;
  6597. }
  6598. Owned<IGroup> ret = createIGroup(epa);
  6599. if (!cached)
  6600. {
  6601. CriticalBlock block(cachesect);
  6602. cache.append(*new CNamedGroupCacheEntry(ret, gname, groupdir, type));
  6603. }
  6604. if (range.length())
  6605. {
  6606. SocketEndpointArray epar;
  6607. const char *s = range.str();
  6608. while (*s)
  6609. {
  6610. unsigned start = 0;
  6611. while (isdigit(*s))
  6612. {
  6613. start = start*10+*s-'0';
  6614. s++;
  6615. }
  6616. if (!start)
  6617. break;
  6618. unsigned end;
  6619. if (*s=='-')
  6620. {
  6621. s++;
  6622. end = 0;
  6623. while (isdigit(*s))
  6624. {
  6625. end = end*10+*s-'0';
  6626. s++;
  6627. }
  6628. if (!end)
  6629. end = epa.ordinality();
  6630. }
  6631. else
  6632. end = start;
  6633. if ((start>epa.ordinality())||(end>epa.ordinality()))
  6634. {
  6635. s = range.str();
  6636. break;
  6637. }
  6638. if (*s==',')
  6639. s++;
  6640. unsigned i=start-1;
  6641. do { // allow 400-1 etc
  6642. i++;
  6643. if (i>epa.ordinality())
  6644. i = 1;
  6645. epar.append(epa.item(i-1));
  6646. } while (i!=end);
  6647. }
  6648. if (*s)
  6649. throw MakeStringException(-1,"Invalid group range %s",range.str());
  6650. ret.setown(createIGroup(epar));
  6651. }
  6652. if (dirret)
  6653. dirret->append(groupdir);
  6654. groupType = type;
  6655. return ret.getClear();
  6656. }
  6657. IGroup *lookup(const char *logicalgroupname)
  6658. {
  6659. GroupType dummy;
  6660. return dolookup(logicalgroupname, NULL, NULL, dummy);
  6661. }
  6662. IGroup *lookup(const char *logicalgroupname, StringBuffer &dir, GroupType &groupType)
  6663. {
  6664. return dolookup(logicalgroupname, NULL, &dir, groupType);
  6665. }
  6666. INamedGroupIterator *getIterator()
  6667. {
  6668. CConnectLock connlock("CNamedGroup::getIterator", SDS_GROUPSTORE_ROOT, false, true, false, defaultTimeout);
  6669. return new CNamedGroupIterator(connlock.conn); // links connection
  6670. }
  6671. INamedGroupIterator *getIterator(IGroup *match,bool exact)
  6672. {
  6673. CConnectLock connlock("CNamedGroup::getIterator", SDS_GROUPSTORE_ROOT, false, false, false, defaultTimeout);
  6674. return new CNamedGroupIterator(connlock.conn,match,exact); // links connection
  6675. }
  6676. void doadd(CConnectLock &connlock,const char *name,IGroup *group,bool cluster,const char *dir)
  6677. {
  6678. if (!group)
  6679. return;
  6680. IPropertyTree *val = createPTree("Group");
  6681. val->setProp("@name",name);
  6682. if (cluster)
  6683. val->setPropBool("@cluster", true);
  6684. if (dir)
  6685. val->setProp("@dir",dir);
  6686. INodeIterator &gi = *group->getIterator();
  6687. StringBuffer str;
  6688. ForEach(gi) {
  6689. IPropertyTree *n = createPTree("Node");
  6690. n = val->addPropTree("Node",n);
  6691. gi.query().endpoint().getIpText(str.clear());
  6692. n->setProp("@ip",str.str());
  6693. }
  6694. gi.Release();
  6695. connlock.conn->queryRoot()->addPropTree("Group",val);
  6696. }
  6697. void addUnique(IGroup *group,StringBuffer &lname, const char *dir)
  6698. {
  6699. if (group->ordinality()==1)
  6700. {
  6701. group->getText(lname);
  6702. return;
  6703. }
  6704. CConnectLock connlock("CNamedGroup::addUnique", SDS_GROUPSTORE_ROOT, true, false, false, defaultTimeout);
  6705. StringBuffer name;
  6706. StringBuffer prop;
  6707. unsigned scale = 16;
  6708. loop {
  6709. name.clear();
  6710. if (lname.length()) { // try suggested name
  6711. name.append(lname);
  6712. name.toLowerCase();
  6713. lname.clear();
  6714. }
  6715. else
  6716. name.append("__anon").append(getRandom()%scale);
  6717. prop.clear().appendf("Group[@name=\"%s\"]",name.str());
  6718. if (!connlock.conn->queryRoot()->hasProp(prop.str()))
  6719. break;
  6720. scale*=2;
  6721. }
  6722. doadd(connlock,name.str(),group,false,dir);
  6723. lname.append(name);
  6724. }
  6725. void add(const char *logicalgroupname, IGroup *group, bool cluster, const char *dir, GroupType groupType)
  6726. {
  6727. StringBuffer name(logicalgroupname);
  6728. name.toLowerCase();
  6729. name.trim();
  6730. StringBuffer prop;
  6731. prop.appendf("Group[@name=\"%s\"]",name.str());
  6732. CConnectLock connlock("CNamedGroup::add", SDS_GROUPSTORE_ROOT, true, false, false, defaultTimeout);
  6733. connlock.conn->queryRoot()->removeProp(prop.str());
  6734. doadd(connlock,name.str(),group,cluster,dir);
  6735. {
  6736. CriticalBlock block(cachesect);
  6737. cache.kill();
  6738. if (group)
  6739. cache.append(*new CNamedGroupCacheEntry(group, name.str(), dir, groupType));
  6740. }
  6741. }
  6742. void remove(const char *logicalgroupname)
  6743. {
  6744. add(logicalgroupname, NULL, false, NULL, grp_unknown);
  6745. }
  6746. bool find(IGroup *grp, StringBuffer &gname, bool add)
  6747. {
  6748. // gname on entry is suggested name for add if set
  6749. unsigned n = grp->ordinality();
  6750. if (!grp||!n)
  6751. return false;
  6752. Owned<INamedGroupIterator> iter=getIterator(grp,(n==1)); // one node clusters must be exact match
  6753. StringAttr bestname;
  6754. StringBuffer name;
  6755. ForEach(*iter) {
  6756. bool iscluster = iter->isCluster();
  6757. if (iscluster||(bestname.isEmpty())) {
  6758. iter->get(name.clear());
  6759. if (name.length()) {
  6760. bestname.set(name);
  6761. if (iscluster)
  6762. break;
  6763. }
  6764. }
  6765. }
  6766. iter.clear();
  6767. if (bestname.isEmpty()) {
  6768. if (add||(n==1)) // single-nodes always have implicit group of IP
  6769. addUnique(grp,gname,NULL);
  6770. return false;
  6771. }
  6772. gname.clear().append(bestname);
  6773. return true;
  6774. }
  6775. void swapNode(const IpAddress &from, const IpAddress &to)
  6776. {
  6777. if (from.ipequals(to))
  6778. return;
  6779. CConnectLock connlock("CNamedGroup::swapNode", SDS_GROUPSTORE_ROOT, true, false, false, defaultTimeout);
  6780. StringBuffer froms;
  6781. from.getIpText(froms);
  6782. StringBuffer tos;
  6783. to.getIpText(tos);
  6784. Owned<IPropertyTreeIterator> pe = connlock.conn->queryRoot()->getElements("Group");
  6785. ForEach(*pe) {
  6786. IPropertyTree &group = pe->query();
  6787. const char *kind = group.queryProp("@kind");
  6788. if (kind && streq("Spare", kind))
  6789. continue;
  6790. StringBuffer name;
  6791. group.getProp("@name",name);
  6792. StringBuffer xpath("Node[@ip = \"");
  6793. xpath.append(froms).append("\"]");
  6794. for (unsigned guard=0; guard<1000; guard++) {
  6795. Owned<IPropertyTreeIterator> ne = group.getElements(xpath.str());
  6796. if (!ne->first())
  6797. break;
  6798. ne->query().setProp("@ip",tos.str());
  6799. PROGLOG("swapNode swapping %s for %s in group %s",froms.str(),tos.str(),name.str());
  6800. }
  6801. }
  6802. CriticalBlock block(cachesect);
  6803. cache.kill();
  6804. }
  6805. unsigned setDefaultTimeout(unsigned timems)
  6806. {
  6807. unsigned ret = defaultTimeout;
  6808. defaultTimeout = timems;
  6809. return ret;
  6810. }
  6811. unsigned setRemoteTimeout(unsigned timems)
  6812. {
  6813. unsigned ret = defaultRemoteTimeout;
  6814. defaultRemoteTimeout = timems;
  6815. return ret;
  6816. }
  6817. void resetCache()
  6818. {
  6819. CriticalBlock block(cachesect);
  6820. cache.kill();
  6821. }
  6822. private:
  6823. bool getRemoteGroup(const INode *foreigndali, const char *gname, unsigned foreigndalitimeout,
  6824. StringAttr &groupdir, GroupType &type, SocketEndpointArray &epa)
  6825. {
  6826. StringBuffer lcname(gname);
  6827. gname = lcname.trim().toLowerCase().str();
  6828. CMessageBuffer mb;
  6829. mb.append((int)MDFS_GET_GROUP_TREE).append(gname);
  6830. size32_t mbsz = mb.length();
  6831. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  6832. checkDfsReplyException(mb);
  6833. if (mb.length()==0)
  6834. return false;
  6835. byte ok;
  6836. mb.read(ok);
  6837. if (ok!=1) {
  6838. // kludge for prev bug
  6839. if ((ok==(byte)MDFS_GET_GROUP_TREE)&&mb.length()>mbsz) {
  6840. mb.skip(mbsz-1);
  6841. mb.read(ok);
  6842. if (ok!=1)
  6843. return false;
  6844. }
  6845. else
  6846. return false;
  6847. }
  6848. Owned<IPropertyTree> pt = createPTree(mb);
  6849. Owned<IPropertyTreeIterator> pe = pt->getElements("Node");
  6850. groupdir.set(pt->queryProp("@dir"));
  6851. type = translateGroupType(pt->queryProp("@kind"));
  6852. ForEach(*pe) {
  6853. SocketEndpoint ep(pe->query().queryProp("@ip"));
  6854. epa.append(ep);
  6855. }
  6856. return epa.ordinality() > 0;
  6857. }
  6858. };
  6859. static CNamedGroupStore *groupStore = NULL;
  6860. static CriticalSection groupsect;
  6861. bool CNamedGroupIterator::match()
  6862. {
  6863. if (conn.get()) {
  6864. if (matchgroup.get()) {
  6865. if (!groupStore)
  6866. return false;
  6867. const char *name = pe->query().queryProp("@name");
  6868. if (!name||!*name)
  6869. return false;
  6870. GroupType dummy;
  6871. Owned<IGroup> lgrp = groupStore->dolookup(name, conn, NULL, dummy);
  6872. if (lgrp) {
  6873. if (exactmatch)
  6874. return lgrp->equals(matchgroup);
  6875. GroupRelation gr = matchgroup->compare(lgrp);
  6876. return (gr==GRidentical)||(gr==GRbasesubset)||(gr==GRwrappedsuperset);
  6877. }
  6878. }
  6879. else
  6880. return true;
  6881. }
  6882. return false;
  6883. }
  6884. INamedGroupStore &queryNamedGroupStore()
  6885. {
  6886. if (!groupStore) {
  6887. CriticalBlock block(groupsect);
  6888. if (!groupStore)
  6889. groupStore = new CNamedGroupStore();
  6890. }
  6891. return *groupStore;
  6892. }
  6893. // --------------------------------------------------------
  6894. IDistributedFile *CDistributedFileDirectory::lookup(const char *_logicalname, IUserDescriptor *user, bool writeattr, bool hold, bool lockSuperOwner, IDistributedFileTransaction *transaction, unsigned timeout)
  6895. {
  6896. CDfsLogicalFileName logicalname;
  6897. logicalname.set(_logicalname);
  6898. return lookup(logicalname, user, writeattr, hold, lockSuperOwner, transaction, timeout);
  6899. }
  6900. IDistributedFile *CDistributedFileDirectory::dolookup(CDfsLogicalFileName &_logicalname, IUserDescriptor *user, bool writeattr, bool hold, bool lockSuperOwner, IDistributedFileTransaction *transaction, unsigned timeout)
  6901. {
  6902. CDfsLogicalFileName *logicalname = &_logicalname;
  6903. if (logicalname->isMulti())
  6904. // don't bother checking because the sub file creation will
  6905. return new CDistributedSuperFile(this,*logicalname,user,transaction); // temp superfile
  6906. if (strchr(logicalname->get(), '*')) // '*' only wildcard supported. NB: This is a temporary fix (See: HPCC-12523)
  6907. throw MakeStringException(-1, "Invalid filename lookup: %s", logicalname->get());
  6908. Owned<IDfsLogicalFileNameIterator> redmatch;
  6909. loop
  6910. {
  6911. checkLogicalName(*logicalname,user,true,writeattr,true,NULL);
  6912. if (logicalname->isExternal()) {
  6913. Owned<IFileDescriptor> fDesc = getExternalFileDescriptor(logicalname->get());
  6914. if (!fDesc)
  6915. return NULL;
  6916. return queryDistributedFileDirectory().createExternal(fDesc, logicalname->get());
  6917. }
  6918. if (logicalname->isForeign()) {
  6919. IDistributedFile * ret = getFile(logicalname->get(),user,NULL);
  6920. if (ret)
  6921. return ret;
  6922. }
  6923. else {
  6924. unsigned start = 0;
  6925. loop {
  6926. CFileLock fcl;
  6927. unsigned mode = RTM_LOCK_READ | RTM_SUB;
  6928. if (hold) mode |= RTM_LOCK_HOLD;
  6929. CTimeMon tm(timeout);
  6930. if (!fcl.init(*logicalname, mode, timeout, "CDistributedFileDirectory::lookup"))
  6931. break;
  6932. CFileSuperOwnerLock superOwnerLock;
  6933. if (lockSuperOwner)
  6934. {
  6935. unsigned remaining;
  6936. tm.timedout(&remaining);
  6937. verifyex(superOwnerLock.initWithFileLock(*logicalname, remaining, "CDistributedFileDirectory::dolookup(SuperOwnerLock)", fcl, mode));
  6938. }
  6939. if (fcl.getKind() == DXB_File)
  6940. {
  6941. StringBuffer cname;
  6942. if (logicalname->getCluster(cname).length())
  6943. {
  6944. IPropertyTree *froot=fcl.queryRoot();
  6945. if (froot)
  6946. {
  6947. StringBuffer query;
  6948. query.appendf("Cluster[@name=\"%s\"]",cname.str());
  6949. if (!froot->hasProp(query.str()))
  6950. break;
  6951. }
  6952. }
  6953. CDistributedFile *ret = new CDistributedFile(this,fcl.detach(),*logicalname,user); // found
  6954. ret->setSuperOwnerLock(superOwnerLock.detach());
  6955. return ret;
  6956. }
  6957. // now super file
  6958. if (fcl.getKind() != DXB_SuperFile)
  6959. break;
  6960. if (start==0)
  6961. start = msTick();
  6962. unsigned elapsed;
  6963. try
  6964. {
  6965. CDistributedSuperFile *ret = new CDistributedSuperFile(this,fcl.detach(),*logicalname,user,transaction,SDS_SUB_LOCK_TIMEOUT);
  6966. ret->setSuperOwnerLock(superOwnerLock.detach());
  6967. return ret;
  6968. }
  6969. catch (IDFS_Exception *e)
  6970. {
  6971. elapsed = msTick()-start;
  6972. if ((e->errorCode()!=DFSERR_LookupConnectionTimout)||(elapsed>((timeout==INFINITE)?SDS_CONNECT_TIMEOUT:timeout)))
  6973. throw;
  6974. EXCLOG(e,"Superfile lookup");
  6975. e->Release();
  6976. }
  6977. PROGLOG("CDistributedSuperFile connect timeout (%dms) pausing",elapsed);
  6978. Sleep(SDS_TRANSACTION_RETRY/2+(getRandom()%SDS_TRANSACTION_RETRY));
  6979. }
  6980. }
  6981. if (redmatch.get()) {
  6982. if (!redmatch->next())
  6983. break;
  6984. }
  6985. else {
  6986. redmatch.setown(queryRedirection().getMatch(logicalname->get()));
  6987. if (!redmatch.get())
  6988. break;
  6989. if (!redmatch->first())
  6990. break;
  6991. }
  6992. logicalname = &redmatch->query();
  6993. }
  6994. return NULL;
  6995. }
  6996. IDistributedFile *CDistributedFileDirectory::lookup(CDfsLogicalFileName &logicalname, IUserDescriptor *user, bool writeattr, bool hold, bool lockSuperOwner, IDistributedFileTransaction *transaction, unsigned timeout)
  6997. {
  6998. return dolookup(logicalname, user, writeattr, hold, lockSuperOwner, transaction, timeout);
  6999. }
  7000. IDistributedSuperFile *CDistributedFileDirectory::lookupSuperFile(const char *_logicalname,IUserDescriptor *user,IDistributedFileTransaction *transaction, unsigned timeout)
  7001. {
  7002. CDfsLogicalFileName logicalname;
  7003. logicalname.set(_logicalname);
  7004. IDistributedFile *file = dolookup(logicalname, user, false, false, false, transaction, timeout);
  7005. if (file) {
  7006. IDistributedSuperFile *sf = file->querySuperFile();
  7007. if (sf)
  7008. return sf;
  7009. file->Release();
  7010. }
  7011. return NULL;
  7012. }
  7013. bool CDistributedFileDirectory::isSuperFile( const char *logicalname,
  7014. IUserDescriptor *user,
  7015. INode *foreigndali,
  7016. unsigned timeout)
  7017. {
  7018. Owned<IPropertyTree> tree = getFileTree(logicalname, user, foreigndali,timeout, false);
  7019. return tree.get()&&(strcmp(tree->queryName(),queryDfsXmlBranchName(DXB_SuperFile))==0);
  7020. }
  7021. bool CDistributedFileDirectory::exists(const char *_logicalname,IUserDescriptor *user,bool notsuper,bool superonly)
  7022. {
  7023. // (currently) no check on scope permissions for exists
  7024. bool external;
  7025. bool foreign;
  7026. CDfsLogicalFileName dlfn;
  7027. dlfn.set(_logicalname);
  7028. const char *logicalname = dlfn.get();
  7029. external = dlfn.isExternal();
  7030. foreign = dlfn.isForeign();
  7031. if (foreign) {
  7032. Owned<IDistributedFile> file = lookup(_logicalname, user, false, false, false, NULL, defaultTimeout);
  7033. if (file.get()==NULL)
  7034. return false;
  7035. if (file->querySuperFile()) {
  7036. if (notsuper)
  7037. return false;
  7038. }
  7039. else
  7040. if (superonly)
  7041. return false;
  7042. }
  7043. else if (external) {
  7044. if (!existsPhysical(_logicalname,user))
  7045. return false;
  7046. }
  7047. else {
  7048. StringBuffer str;
  7049. if (!superonly) {
  7050. dlfn.makeFullnameQuery(str,DXB_File,true);
  7051. CConnectLock connlockfile("CDistributedFileDirectory::exists",str.str(),false,false,false,defaultTimeout);
  7052. if (connlockfile.conn.get())
  7053. return true;
  7054. }
  7055. if (notsuper)
  7056. return false;
  7057. dlfn.makeFullnameQuery(str.clear(),DXB_SuperFile,true);
  7058. CConnectLock connlocksuper("CDistributedFileDirectory::exists",str.str(),false,false,false,defaultTimeout);
  7059. if (!connlocksuper.conn.get())
  7060. return false;
  7061. }
  7062. return true;
  7063. }
  7064. bool CDistributedFileDirectory::existsPhysical(const char *_logicalname, IUserDescriptor *user)
  7065. {
  7066. Owned<IDistributedFile> file = lookup(_logicalname, user, false, false, false, NULL, defaultTimeout);
  7067. if (!file)
  7068. return false;
  7069. return file->existsPhysicalPartFiles(0);
  7070. }
  7071. IDistributedFile *CDistributedFileDirectory::createNew(IFileDescriptor *fdesc)
  7072. {
  7073. return new CDistributedFile(this, fdesc, NULL, false);
  7074. }
  7075. IDistributedFile *CDistributedFileDirectory::createExternal(IFileDescriptor *fdesc, const char *name)
  7076. {
  7077. CDistributedFile *dFile = new CDistributedFile(this, fdesc, NULL, true);
  7078. dFile->setLogicalName(name);
  7079. return dFile;
  7080. }
  7081. ////////////////////////////////////
  7082. class DistributedFilePropertyLockFree
  7083. {
  7084. unsigned lockedCount;
  7085. CDistributedFile *file;
  7086. CDistributedSuperFile *sfile;
  7087. public:
  7088. DistributedFilePropertyLockFree(IDistributedFile *_file)
  7089. {
  7090. file = dynamic_cast<CDistributedFile *>(_file);
  7091. sfile = NULL;
  7092. if (file)
  7093. lockedCount = file->setPropLockCount(0);
  7094. else
  7095. {
  7096. sfile = dynamic_cast<CDistributedSuperFile *>(_file);
  7097. lockedCount = sfile->setPropLockCount(0);
  7098. }
  7099. }
  7100. ~DistributedFilePropertyLockFree()
  7101. {
  7102. if (file)
  7103. verifyex(0 == file->setPropLockCount(lockedCount));
  7104. else if (sfile)
  7105. verifyex(0 == sfile->setPropLockCount(lockedCount));
  7106. }
  7107. };
  7108. /**
  7109. * Creates a super-file within a transaction.
  7110. */
  7111. class CCreateSuperFileAction: public CDFAction
  7112. {
  7113. CDfsLogicalFileName logicalname;
  7114. CDistributedFileDirectory *parent;
  7115. Linked<IDistributedSuperFile> super;
  7116. IUserDescriptor *user;
  7117. bool interleaved, created;
  7118. void clearSuper()
  7119. {
  7120. if (created)
  7121. {
  7122. created = false;
  7123. super->detach();
  7124. }
  7125. super.clear();
  7126. }
  7127. public:
  7128. CCreateSuperFileAction(CDistributedFileDirectory *_parent,
  7129. IUserDescriptor *_user,
  7130. const char *_flname,
  7131. bool _interleaved)
  7132. : parent(_parent), user(_user), created(false), interleaved(_interleaved)
  7133. {
  7134. logicalname.set(_flname);
  7135. }
  7136. IDistributedSuperFile *getSuper()
  7137. {
  7138. if (!super)
  7139. {
  7140. Owned<IDistributedSuperFile> _super = transaction->lookupSuperFile(logicalname.get(), SDS_SUB_LOCK_TIMEOUT);
  7141. if (_super)
  7142. super.setown(_super.getClear());
  7143. else
  7144. {
  7145. /* No super, create one if necessary.
  7146. * This really shouldn't have to work this way, looking up super early, or creating super stub now,
  7147. * because other super file transactions are based on
  7148. * TBD: There should be a way to obtain lock independently of actually attaching.
  7149. */
  7150. Owned<IPropertyTree> root = createPTree();
  7151. root->setPropInt("@interleaved",interleaved?2:0); // this is ill placed
  7152. super.setown(new CDistributedSuperFile(parent, root, logicalname, user));
  7153. created = true;
  7154. transaction->addFile(super);
  7155. }
  7156. }
  7157. return super.getLink();
  7158. }
  7159. bool prepare()
  7160. {
  7161. Owned<IDistributedFile> _super = getSuper();
  7162. // Attach the file to DFS, if wasn't there already
  7163. if (created)
  7164. super->attach(logicalname.get(), user);
  7165. addFileLock(super);
  7166. if (lock())
  7167. return true;
  7168. unlock();
  7169. return false;
  7170. }
  7171. void run()
  7172. {
  7173. // Do nothing, file is already created
  7174. }
  7175. void retry()
  7176. {
  7177. // on retry, we need to remove the file so next lock doesn't fail
  7178. clearSuper();
  7179. CDFAction::retry();
  7180. }
  7181. void rollback()
  7182. {
  7183. state = TAS_FAILURE;
  7184. clearSuper();
  7185. CDFAction::rollback();
  7186. }
  7187. };
  7188. /**
  7189. * Removes a super-file within a transaction.
  7190. */
  7191. class CRemoveSuperFileAction: public CDFAction
  7192. {
  7193. CDfsLogicalFileName logicalname;
  7194. Linked<IDistributedSuperFile> super;
  7195. IUserDescriptor *user;
  7196. bool delSub;
  7197. Owned<IDistributedFileTransactionExt> nestedTransaction;
  7198. class CNestedTransaction : public CDistributedFileTransaction
  7199. {
  7200. IDistributedFileTransactionExt *transaction;
  7201. CIArrayOf<CDFAction> actions;
  7202. public:
  7203. CNestedTransaction(IDistributedFileTransactionExt *_transaction, IUserDescriptor *user)
  7204. : CDistributedFileTransaction(user), transaction(_transaction)
  7205. {
  7206. if (transaction->active())
  7207. start();
  7208. }
  7209. // wrap rest of calls into parent transaction calls
  7210. virtual IDistributedFile *lookupFile(const char *lfn,unsigned timeout=INFINITE)
  7211. {
  7212. return transaction->lookupFile(lfn, timeout);
  7213. }
  7214. virtual IDistributedSuperFile *lookupSuperFile(const char *slfn,unsigned timeout=INFINITE)
  7215. {
  7216. return transaction->lookupSuperFile(slfn, timeout);
  7217. }
  7218. virtual IUserDescriptor *queryUser() { return transaction->queryUser(); }
  7219. virtual void descend() { transaction->descend(); }
  7220. virtual void ascend() { transaction->ascend(); }
  7221. virtual void addFile(IDistributedFile *file) { transaction->addFile(file); }
  7222. virtual void ensureFile(IDistributedFile *file) { transaction->ensureFile(file); }
  7223. virtual void clearFile(IDistributedFile *file) { transaction->clearFile(file); }
  7224. virtual void noteAddSubFile(IDistributedSuperFile *super, const char *superName, IDistributedFile *sub)
  7225. {
  7226. transaction->noteAddSubFile(super, superName, sub);
  7227. }
  7228. virtual void noteRemoveSubFile(IDistributedSuperFile *super, IDistributedFile *sub)
  7229. {
  7230. transaction->noteRemoveSubFile(super, sub);
  7231. }
  7232. virtual void noteSuperSwap(IDistributedSuperFile *super1, IDistributedSuperFile *super2)
  7233. {
  7234. transaction->noteSuperSwap(super1, super2);
  7235. }
  7236. virtual void clearSubFiles(IDistributedSuperFile *super)
  7237. {
  7238. transaction->clearSubFiles(super);
  7239. }
  7240. virtual void noteRename(IDistributedFile *file, const char *newName)
  7241. {
  7242. transaction->noteRename(file, newName);
  7243. }
  7244. virtual void validateAddSubFile(IDistributedSuperFile *super, IDistributedFile *sub, const char *subName)
  7245. {
  7246. transaction->validateAddSubFile(super, sub, subName);
  7247. }
  7248. virtual bool isSubFile(IDistributedSuperFile *super, const char *subFile, bool sub)
  7249. {
  7250. return transaction->isSubFile(super, subFile, sub);
  7251. }
  7252. virtual bool addDelayedDelete(CDfsLogicalFileName &lfn,unsigned timeoutms=INFINITE)
  7253. {
  7254. return transaction->addDelayedDelete(lfn, timeoutms);
  7255. }
  7256. };
  7257. public:
  7258. CRemoveSuperFileAction(IUserDescriptor *_user,
  7259. const char *_flname,
  7260. bool _delSub)
  7261. : user(_user), delSub(_delSub)
  7262. {
  7263. logicalname.set(_flname);
  7264. }
  7265. virtual bool prepare()
  7266. {
  7267. // We *have* to make sure the file exists here
  7268. super.setown(transaction->lookupSuperFile(logicalname.get(), SDS_SUB_LOCK_TIMEOUT));
  7269. if (!super)
  7270. ThrowStringException(-1, "Super File %s doesn't exist in the file system", logicalname.get());
  7271. addFileLock(super);
  7272. // Adds actions to transactions before this one and gets executed only on commit
  7273. if (delSub)
  7274. {
  7275. // As 'delSub' means additional actions, handle them in their own transaction context
  7276. // Wrap lookups and record of removed/added subs to parent transaction, for common cache purposes
  7277. nestedTransaction.setown(new CNestedTransaction(transaction, user));
  7278. super->removeSubFile(NULL, true, false, nestedTransaction);
  7279. }
  7280. if (lock())
  7281. {
  7282. if (nestedTransaction)
  7283. {
  7284. if (nestedTransaction->prepareActions())
  7285. return true;
  7286. }
  7287. else
  7288. return true;
  7289. }
  7290. unlock();
  7291. super.clear();
  7292. return false;
  7293. }
  7294. virtual void retry()
  7295. {
  7296. super.clear();
  7297. if (nestedTransaction)
  7298. nestedTransaction->retryActions();
  7299. CDFAction::retry();
  7300. }
  7301. virtual void run()
  7302. {
  7303. if (nestedTransaction)
  7304. nestedTransaction->runActions();
  7305. super->detach(INFINITE, transaction->queryCodeContext());
  7306. }
  7307. virtual void commit()
  7308. {
  7309. if (nestedTransaction)
  7310. nestedTransaction->commitAndClearup();
  7311. CDFAction::commit();
  7312. }
  7313. };
  7314. /**
  7315. * Renames a file within a transaction.
  7316. */
  7317. class CRenameFileAction: public CDFAction
  7318. {
  7319. CDfsLogicalFileName fromName, toName;
  7320. CDistributedFileDirectory *parent;
  7321. Linked<IDistributedFile> file;
  7322. IUserDescriptor *user;
  7323. bool renamed;
  7324. enum RenameAction { ra_regular, ra_splitfrom, ra_mergeinto } ra;
  7325. public:
  7326. CRenameFileAction(CDistributedFileDirectory *_parent,
  7327. IUserDescriptor *_user,
  7328. const char *_flname,
  7329. const char *_newname)
  7330. : user(_user), parent(_parent)
  7331. {
  7332. fromName.set(_flname);
  7333. // Basic consistency checking
  7334. toName.set(_newname);
  7335. if (fromName.isExternal() || toName.isExternal())
  7336. throw MakeStringException(-1,"rename: cannot rename external files"); // JCSMORE perhaps you should be able to?
  7337. if (fromName.isForeign() || toName.isForeign())
  7338. throw MakeStringException(-1,"rename: cannot rename foreign files");
  7339. // Make sure files are not the same
  7340. if (0 == strcmp(fromName.get(), toName.get()))
  7341. ThrowStringException(-1, "rename: cannot rename file %s to itself", toName.get());
  7342. ra = ra_regular;
  7343. renamed = false;
  7344. }
  7345. virtual bool prepare()
  7346. {
  7347. // We *have* to make sure the source file exists and can be renamed
  7348. file.setown(transaction->lookupFile(fromName.get(), SDS_SUB_LOCK_TIMEOUT));
  7349. if (!file)
  7350. ThrowStringException(-1, "rename: file %s doesn't exist in the file system", fromName.get());
  7351. if (file->querySuperFile())
  7352. ThrowStringException(-1,"rename: cannot rename file %s as is SuperFile", fromName.get()); // Why not
  7353. StringBuffer reason;
  7354. if (!file->canRemove(reason))
  7355. ThrowStringException(-1,"rename: %s",reason.str());
  7356. addFileLock(file);
  7357. renamed = false;
  7358. if (lock())
  7359. {
  7360. StringBuffer oldcluster, newcluster;
  7361. fromName.getCluster(oldcluster);
  7362. toName.getCluster(newcluster);
  7363. Owned<IDistributedFile> newFile = transaction->lookupFile(toName.get(), SDS_SUB_LOCK_TIMEOUT);
  7364. if (newFile)
  7365. {
  7366. if (newcluster.length())
  7367. {
  7368. if (oldcluster.length())
  7369. ThrowStringException(-1,"rename: cannot specify both source and destination clusters on rename");
  7370. if (newFile->findCluster(newcluster.str())!=NotFound)
  7371. ThrowStringException(-1,"rename: cluster %s already part of file %s",newcluster.str(),toName.get());
  7372. if (file->numClusters()!=1)
  7373. ThrowStringException(-1,"rename: source file %s has more than one cluster",fromName.get());
  7374. // check compatible here ** TBD
  7375. ra = ra_mergeinto;
  7376. }
  7377. else
  7378. ThrowStringException(-1, "rename: file %s already exist in the file system", toName.get());
  7379. }
  7380. else if (oldcluster.length())
  7381. {
  7382. if (newcluster.length())
  7383. ThrowStringException(-1,"rename: cannot specify both source and destination clusters on rename");
  7384. if (file->numClusters()==1)
  7385. ThrowStringException(-1,"rename: cannot rename sole cluster %s",oldcluster.str());
  7386. if (file->findCluster(oldcluster.str())==NotFound)
  7387. ThrowStringException(-1,"rename: cannot find cluster %s",oldcluster.str());
  7388. ra = ra_splitfrom;
  7389. }
  7390. else
  7391. {
  7392. // TODO: something should check that file being renamed is not a subfile of a super where both created in transaction
  7393. transaction->noteRename(file, toName.get());
  7394. ra = ra_regular;
  7395. }
  7396. return true;
  7397. }
  7398. unlock();
  7399. file.clear();
  7400. return false;
  7401. }
  7402. virtual void run()
  7403. {
  7404. doRename(fromName, toName, ra);
  7405. renamed = true;
  7406. }
  7407. virtual void retry()
  7408. {
  7409. file.clear();
  7410. CDFAction::retry();
  7411. }
  7412. virtual void rollback()
  7413. {
  7414. // Only roll back if already renamed
  7415. if (renamed)
  7416. {
  7417. switch (ra)
  7418. {
  7419. case ra_regular:
  7420. doRename(toName, fromName, ra_regular);
  7421. break;
  7422. case ra_splitfrom:
  7423. doRename(toName, fromName, ra_mergeinto);
  7424. break;
  7425. case ra_mergeinto:
  7426. doRename(toName, fromName, ra_splitfrom);
  7427. break;
  7428. default:
  7429. throwUnexpected();
  7430. }
  7431. renamed = false;
  7432. }
  7433. CDFAction::rollback();
  7434. }
  7435. private:
  7436. void doRename(CDfsLogicalFileName &from, CDfsLogicalFileName &to, RenameAction ra)
  7437. {
  7438. CriticalBlock block(physicalChange);
  7439. StringBuffer oldcluster, newcluster;
  7440. fromName.getCluster(oldcluster);
  7441. toName.getCluster(newcluster);
  7442. Owned<IDistributedFile> oldfile;
  7443. if (ra_splitfrom == ra)
  7444. {
  7445. oldfile.setown(file.getClear());
  7446. Owned<IFileDescriptor> newdesc = oldfile->getFileDescriptor(oldcluster.str());
  7447. file.setown(parent->createNew(newdesc));
  7448. }
  7449. // Physical Rename
  7450. Owned<IMultiException> exceptions = MakeMultiException();
  7451. if (!file->renamePhysicalPartFiles(to.get(),newcluster,exceptions))
  7452. {
  7453. unlock();
  7454. StringBuffer errors;
  7455. exceptions->errorMessage(errors);
  7456. ThrowStringException(-1, "rename: could not rename logical file %s to %s: %s", fromName.get(), to.get(), errors.str());
  7457. }
  7458. // Logical rename and cleanup
  7459. switch (ra)
  7460. {
  7461. case ra_splitfrom:
  7462. {
  7463. unlock();
  7464. oldfile->removeCluster(oldcluster.str());
  7465. file->attach(to.get(), user);
  7466. lock();
  7467. break;
  7468. }
  7469. case ra_mergeinto:
  7470. {
  7471. Owned<IDistributedFile> newFile = transaction->lookupFile(to.get(), SDS_SUB_LOCK_TIMEOUT);
  7472. ClusterPartDiskMapSpec mspec = file->queryPartDiskMapping(0);
  7473. // Unlock the old file
  7474. unlock();
  7475. CDistributedFile *_file = dynamic_cast<CDistributedFile *>(file.get());
  7476. _file->detachLogical(INFINITE); // don't delete physicals, now used by newFile
  7477. transaction->clearFile(file); // no long used in transaction
  7478. newFile->addCluster(newcluster.str(),mspec);
  7479. parent->fixDates(newFile);
  7480. // need to clear and re-lookup as changed outside of transaction
  7481. // TBD: Allow 'addCluster' 'fixDates' etc. to be delayed/work inside transaction
  7482. transaction->clearFile(newFile);
  7483. newFile.clear();
  7484. file.setown(transaction->lookupFile(to.get(), SDS_SUB_LOCK_TIMEOUT));
  7485. addFileLock(file);
  7486. lock();
  7487. break;
  7488. }
  7489. case ra_regular:
  7490. {
  7491. /* It is not enough to unlock this actions locks on the file being renamed,
  7492. * because other actions, before and after may hold locks to the same file.
  7493. * For now, IDistributeFile::rename, needs to work on a lock free instance.
  7494. * TBD: Allow IDistributedFile::rename to work properly within transaction.
  7495. */
  7496. DistributedFilePropertyLockFree unlock(file);
  7497. file->rename(to.get(), user);
  7498. break;
  7499. }
  7500. default:
  7501. throwUnexpected();
  7502. }
  7503. // MORE: If the logical rename fails, we should roll back the physical renaming
  7504. // What if the physical renaming-back fails?!
  7505. // For now, leaving as it was, since physical renaming is more prone to errors than logical
  7506. // And checks were made earlier to make sure it was safe to rename
  7507. }
  7508. };
  7509. // MORE: This should be implemented in DFSAccess later on
  7510. IDistributedSuperFile *CDistributedFileDirectory::createSuperFile(const char *_logicalname,IUserDescriptor *user, bool _interleaved,bool ifdoesnotexist,IDistributedFileTransaction *transaction)
  7511. {
  7512. CDfsLogicalFileName logicalname;
  7513. logicalname.set(_logicalname);
  7514. checkLogicalName(logicalname,user,true,true,false,"have a superfile with");
  7515. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  7516. Linked<IDistributedFileTransactionExt> localtrans;
  7517. if (transaction)
  7518. {
  7519. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  7520. localtrans.set(_transaction);
  7521. }
  7522. else
  7523. localtrans.setown(new CDistributedFileTransaction(user));
  7524. IDistributedSuperFile *sfile = localtrans->lookupSuperFile(logicalname.get());
  7525. if (sfile)
  7526. {
  7527. if (ifdoesnotexist)
  7528. return sfile;
  7529. else
  7530. throw MakeStringException(-1,"createSuperFile: SuperFile %s already exists",logicalname.get());
  7531. }
  7532. Owned<CCreateSuperFileAction> action = new CCreateSuperFileAction(this,user,_logicalname,_interleaved);
  7533. localtrans->addAction(action.getLink()); // takes ownership
  7534. localtrans->autoCommit();
  7535. return action->getSuper();
  7536. }
  7537. // MORE: This should be implemented in DFSAccess later on
  7538. IDistributedSuperFile *CDistributedFileDirectory::createNewSuperFile(IPropertyTree *tree, const char *optionalName)
  7539. {
  7540. return new CDistributedSuperFile(this, tree, optionalName);
  7541. }
  7542. // MORE: This should be implemented in DFSAccess later on
  7543. void CDistributedFileDirectory::removeSuperFile(const char *_logicalname, bool delSubs, IUserDescriptor *user, IDistributedFileTransaction *transaction)
  7544. {
  7545. CDfsLogicalFileName logicalname;
  7546. logicalname.set(_logicalname);
  7547. checkLogicalName(logicalname,user,true,true,false,"have a superfile with");
  7548. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  7549. Linked<IDistributedFileTransactionExt> localtrans;
  7550. if (transaction)
  7551. {
  7552. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  7553. localtrans.set(_transaction);
  7554. }
  7555. else
  7556. localtrans.setown(new CDistributedFileTransaction(user));
  7557. CRemoveSuperFileAction *action = new CRemoveSuperFileAction(user, _logicalname, delSubs);
  7558. localtrans->addAction(action); // takes ownership
  7559. localtrans->autoCommit();
  7560. }
  7561. bool CDistributedFileDirectory::removeEntry(const char *name, IUserDescriptor *user, IDistributedFileTransaction *transaction, unsigned timeoutms, bool throwException)
  7562. {
  7563. CDfsLogicalFileName logicalname;
  7564. logicalname.set(name);
  7565. if (!logicalname.isExternal())
  7566. checkLogicalName(logicalname,user,true,true,false,"delete");
  7567. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  7568. Linked<IDistributedFileTransactionExt> localtrans;
  7569. if (transaction)
  7570. {
  7571. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  7572. localtrans.set(_transaction);
  7573. }
  7574. else
  7575. localtrans.setown(new CDistributedFileTransaction(user));
  7576. // Action will be executed at the end of the transaction (commit)
  7577. localtrans->addDelayedDelete(logicalname, timeoutms);
  7578. try
  7579. {
  7580. localtrans->autoCommit();
  7581. }
  7582. catch (IException *e)
  7583. {
  7584. // TODO: Transform removeEntry into void
  7585. StringBuffer msg(logicalname.get());
  7586. msg.append(" - cause: ");
  7587. e->errorMessage(msg);
  7588. ERRLOG("%s", msg.str());
  7589. if (throwException)
  7590. throw new CDFS_Exception(DFSERR_FailedToDeleteFile, msg.str());
  7591. e->Release();
  7592. return false;
  7593. }
  7594. return true;
  7595. }
  7596. void CDistributedFileDirectory::removeEmptyScope(const char *scope)
  7597. {
  7598. if (scope&&*scope) {
  7599. StringBuffer fn(scope);
  7600. fn.append("::x");
  7601. CDfsLogicalFileName dlfn;
  7602. dlfn.set(fn.str());
  7603. removeFileEmptyScope(dlfn,defaultTimeout);
  7604. }
  7605. }
  7606. void CDistributedFileDirectory::renamePhysical(const char *oldname,const char *newname,IUserDescriptor *user,IDistributedFileTransaction *transaction)
  7607. {
  7608. if (!user)
  7609. {
  7610. #ifdef NULL_DALIUSER_STACKTRACE
  7611. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp CDistributedFileDirectory::renamePhysical %d",__LINE__);
  7612. //following debug code to be removed
  7613. PrintStackReport();
  7614. #endif
  7615. user = defaultudesc.get();
  7616. }
  7617. CDfsLogicalFileName oldlogicalname;
  7618. oldlogicalname.set(oldname);
  7619. checkLogicalName(oldlogicalname,user,true,true,false,"rename");
  7620. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  7621. Linked<IDistributedFileTransactionExt> localtrans;
  7622. if (transaction)
  7623. {
  7624. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  7625. localtrans.set(_transaction);
  7626. }
  7627. else
  7628. localtrans.setown(new CDistributedFileTransaction(user));
  7629. CRenameFileAction *action = new CRenameFileAction(this, user, oldname, newname);
  7630. localtrans->addAction(action); // takes ownership
  7631. localtrans->autoCommit();
  7632. }
  7633. void CDistributedFileDirectory::fixDates(IDistributedFile *file)
  7634. {
  7635. // should do in parallel
  7636. unsigned width = file->numParts();
  7637. CriticalSection crit;
  7638. class casyncfor: public CAsyncFor
  7639. {
  7640. IDistributedFile *file;
  7641. CriticalSection &crit;
  7642. unsigned width;
  7643. public:
  7644. bool ok;
  7645. casyncfor(IDistributedFile *_file,unsigned _width,CriticalSection &_errcrit)
  7646. : crit(_errcrit)
  7647. {
  7648. file = _file;
  7649. ok = true;
  7650. width = _width;
  7651. ok = true;
  7652. }
  7653. void Do(unsigned i)
  7654. {
  7655. CriticalBlock block(crit);
  7656. Owned<IDistributedFilePart> part = file->getPart(i);
  7657. CDateTime dt;
  7658. if (!part->getModifiedTime(false,false,dt))
  7659. return;
  7660. unsigned nc = part->numCopies();
  7661. for (unsigned copy = 0; copy < nc; copy++) {
  7662. RemoteFilename rfn;
  7663. part->getFilename(rfn,copy);
  7664. Owned<IFile> partfile = createIFile(rfn);
  7665. try {
  7666. CriticalUnblock unblock(crit);
  7667. CDateTime dt2;
  7668. if (partfile->getTime(NULL,&dt2,NULL)) {
  7669. if (!dt.equals(dt2)) {
  7670. partfile->setTime(NULL,&dt,NULL);
  7671. }
  7672. }
  7673. }
  7674. catch (IException *e) {
  7675. CriticalBlock block(crit);
  7676. StringBuffer s("Failed to find file part ");
  7677. s.append(partfile->queryFilename()).append(" on ");
  7678. rfn.queryEndpoint().getUrlStr(s);
  7679. EXCLOG(e, s.str());
  7680. e->Release();
  7681. }
  7682. }
  7683. }
  7684. } afor(file,width,crit);
  7685. afor.For(width,10,false,true);
  7686. }
  7687. void CDistributedFileDirectory::addEntry(CDfsLogicalFileName &dlfn,IPropertyTree *root,bool superfile, bool ignoreexists)
  7688. {
  7689. // add bit awkward
  7690. bool external;
  7691. bool foreign;
  7692. external = dlfn.isExternal();
  7693. foreign = dlfn.isForeign();
  7694. if (external) {
  7695. root->Release();
  7696. return; // ignore attempts to add external
  7697. }
  7698. CScopeConnectLock sconnlock("CDistributedFileDirectory::addEntry", dlfn, true, false, false, defaultTimeout);
  7699. if (!sconnlock.conn()) {// warn?
  7700. root->Release();
  7701. return;
  7702. }
  7703. IPropertyTree* sroot = sconnlock.conn()->queryRoot();
  7704. StringBuffer tail;
  7705. dlfn.getTail(tail);
  7706. IPropertyTree *prev = getNamedPropTree(sroot,superfile?queryDfsXmlBranchName(DXB_SuperFile):queryDfsXmlBranchName(DXB_File),"@name",tail.str(),false);
  7707. if (!prev) // check super/file doesn't exist
  7708. prev = getNamedPropTree(sroot,superfile?queryDfsXmlBranchName(DXB_File):queryDfsXmlBranchName(DXB_SuperFile),"@name",tail.str(),false);
  7709. if (prev!=nullptr)
  7710. {
  7711. prev->Release();
  7712. root->Release();
  7713. if (ignoreexists)
  7714. return;
  7715. throw new CDFS_Exception(DFSERR_LogicalNameAlreadyExists,dlfn.get());
  7716. }
  7717. root->setProp("@name",tail.str());
  7718. root->setProp("OrigName",dlfn.get());
  7719. if (superfile)
  7720. sroot->addPropTree(queryDfsXmlBranchName(DXB_SuperFile), root); // now owns root
  7721. else
  7722. {
  7723. IPropertyTree *file = sroot->addPropTree(queryDfsXmlBranchName(DXB_File), root); // now owns root
  7724. file->setPropTree("ClusterLock", createPTree());
  7725. }
  7726. }
  7727. IDistributedFileIterator *CDistributedFileDirectory::getIterator(const char *wildname, bool includesuper, IUserDescriptor *user)
  7728. {
  7729. return new CDistributedFileIterator(this,wildname,includesuper,user);
  7730. }
  7731. GetFileClusterNamesType CDistributedFileDirectory::getFileClusterNames(const char *_logicalname,StringArray &out)
  7732. {
  7733. CDfsLogicalFileName logicalname;
  7734. logicalname.set(_logicalname);
  7735. if (logicalname.isForeign())
  7736. return GFCN_Foreign;
  7737. if (logicalname.isExternal())
  7738. return GFCN_External;
  7739. CScopeConnectLock sconnlock("CDistributedFileDirectory::getFileClusterList", logicalname, false, false, false, defaultTimeout);
  7740. DfsXmlBranchKind bkind;
  7741. IPropertyTree *froot = sconnlock.queryFileRoot(logicalname,bkind);
  7742. if (froot) {
  7743. if (bkind==DXB_File) {
  7744. getFileGroups(froot,out);
  7745. return GFCN_Normal;
  7746. }
  7747. if (bkind==DXB_SuperFile)
  7748. return GFCN_Super;
  7749. }
  7750. return GFCN_NotFound;
  7751. }
  7752. // --------------------------------------------------------
  7753. static CDistributedFileDirectory *DFdir = NULL;
  7754. static CriticalSection dfdirCrit;
  7755. /**
  7756. * Public method to control DistributedFileDirectory access
  7757. * as a singleton. This is the only way to get directories,
  7758. * files, super-files and logic-files.
  7759. */
  7760. IDistributedFileDirectory &queryDistributedFileDirectory()
  7761. {
  7762. if (!DFdir) {
  7763. CriticalBlock block(dfdirCrit);
  7764. if (!DFdir)
  7765. DFdir = new CDistributedFileDirectory();
  7766. }
  7767. return *DFdir;
  7768. }
  7769. /**
  7770. * Shutdown distributed file system (root directory).
  7771. */
  7772. void closedownDFS() // called by dacoven
  7773. {
  7774. CriticalBlock block(dfdirCrit);
  7775. try {
  7776. delete DFdir;
  7777. }
  7778. catch (IMP_Exception *e) {
  7779. if (e->errorCode()!=MPERR_link_closed)
  7780. throw;
  7781. PrintExceptionLog(e,"closedownDFS");
  7782. e->Release();
  7783. }
  7784. catch (IDaliClient_Exception *e) {
  7785. if (e->errorCode()!=DCERR_server_closed)
  7786. throw;
  7787. e->Release();
  7788. }
  7789. DFdir = NULL;
  7790. CriticalBlock block2(groupsect);
  7791. ::Release(groupStore);
  7792. groupStore = NULL;
  7793. }
  7794. class CDFPartFilter : implements IDFPartFilter, public CInterface
  7795. {
  7796. protected:
  7797. bool *partincluded;
  7798. unsigned max;
  7799. public:
  7800. IMPLEMENT_IINTERFACE;
  7801. CDFPartFilter(const char *filter)
  7802. {
  7803. max = 0;
  7804. partincluded = NULL;
  7805. unsigned pn=0;
  7806. const char *s=filter;
  7807. if (!s)
  7808. return;
  7809. while (*s) {
  7810. if (isdigit(*s)) {
  7811. pn = pn*10+(*s-'0');
  7812. if (pn>max)
  7813. max = pn;
  7814. }
  7815. else
  7816. pn = 0;
  7817. s++;
  7818. }
  7819. if (max==0)
  7820. return;
  7821. partincluded = new bool[max];
  7822. unsigned i;
  7823. for (i=0;i<max;i++)
  7824. partincluded[i] = false;
  7825. pn=0;
  7826. s=filter;
  7827. unsigned start=0;
  7828. loop {
  7829. if ((*s==0)||(*s==',')||isspace(*s)) {
  7830. if (start) {
  7831. for (i=start-1;i<pn;i++)
  7832. partincluded[i] = true;
  7833. start = 0;
  7834. }
  7835. else
  7836. partincluded[pn-1] = true;
  7837. if (*s==0)
  7838. break;
  7839. pn = 0;
  7840. }
  7841. else if (isdigit(*s)) {
  7842. pn = pn*10+(*s-'0');
  7843. if (pn>max)
  7844. max = pn;
  7845. if (s[1]=='-') {
  7846. s++;
  7847. start = pn;
  7848. pn = 0;
  7849. }
  7850. }
  7851. s++;
  7852. }
  7853. }
  7854. ~CDFPartFilter()
  7855. {
  7856. delete [] partincluded;
  7857. }
  7858. bool includePart(unsigned part)
  7859. {
  7860. if (max==0)
  7861. return true;
  7862. if (part>=max)
  7863. return false;
  7864. return partincluded[part];
  7865. };
  7866. };
  7867. IDFPartFilter *createPartFilter(const char *filter)
  7868. {
  7869. return new CDFPartFilter(filter);
  7870. }
  7871. //=====================================================================================
  7872. // Server Side Support
  7873. class CFileMatch : public CInterface
  7874. {
  7875. StringAttr name;
  7876. Linked<IPropertyTree> tree;
  7877. bool isSuper;
  7878. public:
  7879. CFileMatch(const char *_name, IPropertyTree *_tree, bool _isSuper) : name(_name), tree(_tree), isSuper(_isSuper)
  7880. {
  7881. }
  7882. IPropertyTree &queryFileTree() const { return *tree; }
  7883. const char *queryName() const { return name; }
  7884. bool queryIsSuper() const { return isSuper; }
  7885. };
  7886. typedef CIArrayOf<CFileMatch> CFileMatchArray;
  7887. class CScope : public CInterface
  7888. {
  7889. StringAttr name;
  7890. CIArrayOf<CFileMatch> files; // matches
  7891. CIArrayOf<CScope> subScopes;
  7892. public:
  7893. CScope(const char *_name) : name(_name)
  7894. {
  7895. }
  7896. const char *getName() const { return name; }
  7897. void addMatch(const char *name, IPropertyTree &fileTree, bool isSuper)
  7898. {
  7899. files.append(*new CFileMatch(name, &fileTree, isSuper));
  7900. }
  7901. CScope *addScope(const char *scope)
  7902. {
  7903. CScope *subScope = new CScope(scope);
  7904. subScopes.append(*subScope);
  7905. return subScope;
  7906. }
  7907. void popLastScope()
  7908. {
  7909. subScopes.pop();
  7910. }
  7911. CIArrayOf<CScope> &querySubScopes() { return subScopes; }
  7912. CFileMatchArray &queryFiles() { return files; }
  7913. };
  7914. typedef CIArrayOf<CScope> CScopeArray;
  7915. const char* DFUQFilterFieldNames[] = { "", "@description", "@directory", "@group", "@modified", "@name", "@numclusters", "@numparts",
  7916. "@partmask", "@OrigName", "Attr", "Attr/@job", "Attr/@owner", "Attr/@recordCount", "Attr/@recordSize", "Attr/@size",
  7917. "Attr/@compressedsize", "Attr/@workunit", "Cluster", "Cluster/@defaultBaseDir", "Cluster/@defaultReplDir", "Cluster/@mapFlags",
  7918. "Cluster/@name", "Part", "Part/@name", "Part/@num", "Part/@size", "SuperOwner", "SuperOwner/@name",
  7919. "SubFile", "SubFile/@name", "SubFile/@num", "Attr/@kind" };
  7920. extern da_decl const char* getDFUQFilterFieldName(DFUQFilterField feild)
  7921. {
  7922. return DFUQFilterFieldNames[feild];
  7923. }
  7924. class CDFUSFFilter : public CInterface
  7925. {
  7926. DFUQFilterType filterType;
  7927. StringAttr attrPath;
  7928. bool hasFilter;
  7929. bool hasFilterHigh;
  7930. StringAttr filterValue;
  7931. StringAttr filterValueHigh;
  7932. int filterValueInt;
  7933. int filterValueHighInt;
  7934. __int64 filterValueInt64;
  7935. __int64 filterValueHighInt64;
  7936. bool filterValueBoolean;
  7937. StringAttr sep;
  7938. StringArray filterArray;
  7939. public:
  7940. CDFUSFFilter(DFUQFilterType _filterType, const char *_attrPath, const char *_filterValue, const char *_filterValueHigh)
  7941. : filterType(_filterType), attrPath(_attrPath), filterValue(_filterValue), filterValueHigh(_filterValueHigh) {};
  7942. CDFUSFFilter(DFUQFilterType _filterType, const char *_attrPath, bool _hasFilter, const int _filterValue, bool _hasFilterHigh, const int _filterValueHigh)
  7943. : filterType(_filterType), attrPath(_attrPath), hasFilter(_hasFilter), filterValueInt(_filterValue), hasFilterHigh(_hasFilterHigh), filterValueHighInt(_filterValueHigh) {};
  7944. CDFUSFFilter(DFUQFilterType _filterType, const char *_attrPath, bool _hasFilter, const __int64 _filterValue, bool _hasFilterHigh, const __int64 _filterValueHigh)
  7945. : filterType(_filterType), attrPath(_attrPath), hasFilter(_hasFilter), filterValueInt64(_filterValue), hasFilterHigh(_hasFilterHigh), filterValueHighInt64(_filterValueHigh) {};
  7946. CDFUSFFilter(DFUQFilterType _filterType, const char *_attrPath, bool _filterValue)
  7947. : filterType(_filterType), attrPath(_attrPath), filterValueBoolean(_filterValue) {};
  7948. CDFUSFFilter(DFUQFilterType _filterType, const char *_attrPath, const char *_filterValue, const char *_sep, StringArray& _filterArray)
  7949. : filterType(_filterType), attrPath(_attrPath), filterValue(_filterValue), sep(_sep)
  7950. {
  7951. ForEachItemIn(i,_filterArray)
  7952. {
  7953. const char* filter = _filterArray.item(i);
  7954. if (filter && *filter)
  7955. filterArray.append(filter);
  7956. }
  7957. };
  7958. DFUQFilterType getFilterType() { return filterType;}
  7959. const char * getAttrPath() { return attrPath.get();}
  7960. const char * getFilterValue() { return filterValue.get();}
  7961. const char * getFilterValueHigh() { return filterValueHigh.get();}
  7962. const int getFilterValueInt() { return filterValueInt;}
  7963. const int getFilterValueHighInt() { return filterValueHighInt;}
  7964. const __int64 getFilterValueInt64() { return filterValueInt64;}
  7965. const __int64 getFilterValueHighInt64() { return filterValueHighInt64;}
  7966. const bool getFilterValueBoolean() { return filterValueBoolean;}
  7967. const char * getSep() { return sep.get();}
  7968. void getFilterArray(StringArray &filters)
  7969. {
  7970. ForEachItemIn(c, filterArray)
  7971. filters.append(filterArray.item(c));
  7972. }
  7973. bool checkFilter(IPropertyTree &file)
  7974. {
  7975. bool match = true;
  7976. switch(filterType)
  7977. {
  7978. case DFUQFTwildcardMatch:
  7979. match = doWildMatch(file);
  7980. break;
  7981. case DFUQFTbooleanMatch:
  7982. match = doBooleanMatch(file);
  7983. break;
  7984. case DFUQFThasProp:
  7985. match = checkHasPropFilter(file);
  7986. break;
  7987. case DFUQFTcontainString:
  7988. match = checkContainStringFilter(file);
  7989. break;
  7990. case DFUQFTstringRange:
  7991. match = checkStringRangeFilter(file);
  7992. break;
  7993. case DFUQFTintegerRange:
  7994. match = checkIntegerRangeFilter(file);
  7995. break;
  7996. case DFUQFTinteger64Range:
  7997. match = checkInteger64RangeFilter(file);
  7998. break;
  7999. }
  8000. return match;
  8001. }
  8002. bool doWildMatch(IPropertyTree &file)
  8003. {
  8004. const char* filter = filterValue.get();
  8005. if (!attrPath.get() || !filter || !*filter || streq(filter, "*"))
  8006. return true;
  8007. const char* prop = file.queryProp(attrPath.get());
  8008. if (prop && WildMatch(prop, filter, true))
  8009. return true;
  8010. return false;
  8011. }
  8012. bool doBooleanMatch(IPropertyTree &file)
  8013. {
  8014. if (!attrPath.get())
  8015. return true;
  8016. return filterValueBoolean == file.getPropBool(attrPath.get(), true);
  8017. }
  8018. bool checkHasPropFilter(IPropertyTree &file)
  8019. {
  8020. if (!attrPath.get())
  8021. return true;
  8022. return filterValueBoolean == file.hasProp(attrPath.get());
  8023. }
  8024. bool checkContainStringFilter(IPropertyTree &file)
  8025. {
  8026. if (!attrPath.get())
  8027. return true;
  8028. const char* prop = file.queryProp(attrPath.get());
  8029. if (!prop || !*prop)
  8030. return false;
  8031. bool found = false;
  8032. if (!sep.get())
  8033. {
  8034. if (filterArray.find(prop) != NotFound) //Match with one of values in the filter
  8035. found = true;
  8036. return found;
  8037. }
  8038. StringArray propArray;
  8039. propArray.appendListUniq(prop, sep.get());
  8040. ForEachItemIn(i,propArray)
  8041. {
  8042. const char* value = propArray.item(i);
  8043. if (!value || !*value)
  8044. continue;
  8045. if (filterArray.find(value) != NotFound) //Match with one of values in the filter
  8046. {
  8047. found = true;
  8048. break;
  8049. }
  8050. }
  8051. return found;
  8052. }
  8053. bool checkStringRangeFilter(IPropertyTree &file)
  8054. {
  8055. if (!attrPath.get())
  8056. return true;
  8057. const char* prop = file.queryProp(attrPath.get());
  8058. if (!prop || !*prop)
  8059. return false;
  8060. if (filterValue && (strcmp(filterValue, prop) > 0))
  8061. return false;
  8062. if (filterValueHigh && (strcmp(filterValueHigh, prop) < 0))
  8063. return false;
  8064. return true;
  8065. }
  8066. bool checkIntegerRangeFilter(IPropertyTree &file)
  8067. {
  8068. if (!attrPath.get())
  8069. return true;
  8070. int prop = file.getPropInt(attrPath.get());
  8071. if (hasFilter && (prop < filterValueInt))
  8072. return false;
  8073. if (hasFilterHigh && (prop > filterValueHighInt))
  8074. return false;
  8075. return true;
  8076. }
  8077. bool checkInteger64RangeFilter(IPropertyTree &file)
  8078. {
  8079. if (!attrPath.get())
  8080. return true;
  8081. __int64 prop = file.getPropInt64(attrPath.get());
  8082. if (hasFilter && (prop < filterValueInt64))
  8083. return false;
  8084. if (hasFilterHigh && (prop > filterValueHighInt64))
  8085. return false;
  8086. return true;
  8087. }
  8088. };
  8089. typedef CIArrayOf<CDFUSFFilter> CDFUSFFilterArray;
  8090. class CIterateFileFilterContainer : public CInterface
  8091. {
  8092. StringAttr filterBuf; //Hold original filter string just in case
  8093. StringAttr wildNameFilter;
  8094. unsigned maxFilesFilter;
  8095. DFUQFileTypeFilter fileTypeFilter;
  8096. CIArrayOf<CDFUSFFilter> filters;
  8097. //The 'filters' contains the file scan filters other than wildNameFilter and fileTypeFilter. Those filters are used for
  8098. //filtering the files using File Attributes tree and CDFUSFFilter::checkFilter(). The wildNameFilter and fileTypeFilter need
  8099. //special code to filter the files.
  8100. SerializeFileAttrOptions options;
  8101. bool isValidInteger(const char *s)
  8102. {
  8103. if (!s || !*s)
  8104. return false;
  8105. while (*s)
  8106. {
  8107. if ((*s != '-') && !isdigit(*s))
  8108. return false;
  8109. s++;
  8110. }
  8111. return true;
  8112. }
  8113. void addOption(const char* optionStr)
  8114. {
  8115. if (!optionStr || !*optionStr || !isdigit(*optionStr))
  8116. return;
  8117. DFUQSerializeFileAttrOption option = (DFUQSerializeFileAttrOption) atoi(optionStr);
  8118. switch(option)
  8119. {
  8120. case DFUQSFAOincludeSuperOwner:
  8121. options.includeSuperOwner = true;
  8122. break;
  8123. //Add more when needed
  8124. }
  8125. }
  8126. void addFilter(DFUQFilterType filterType, const char* attr, const char* value, const char* valueHigh)
  8127. {
  8128. if (!attr || !*attr)
  8129. return;
  8130. if ((DFUQFTwildcardMatch == filterType) || (DFUQFTstringRange == filterType))
  8131. {
  8132. filters.append(*new CDFUSFFilter(filterType, attr, value, valueHigh));
  8133. return;
  8134. }
  8135. if ((DFUQFTbooleanMatch == filterType) || (DFUQFThasProp == filterType))
  8136. {
  8137. bool filter = true;
  8138. if (value && (streq(value, "0") || strieq(value, "false")))
  8139. filter = false;
  8140. filters.append(*new CDFUSFFilter(filterType, attr, filter));
  8141. return;
  8142. }
  8143. if ((DFUQFTintegerRange == filterType) || (DFUQFTinteger64Range == filterType))
  8144. {
  8145. bool hasFilter = false;
  8146. bool hasFilterHigh = false;
  8147. if (value && isValidInteger(value))
  8148. hasFilter = true;
  8149. if (valueHigh && isValidInteger(valueHigh))
  8150. hasFilterHigh = true;
  8151. if (!hasFilter && !hasFilterHigh)
  8152. return;
  8153. if (DFUQFTintegerRange == filterType)
  8154. filters.append(*new CDFUSFFilter(filterType, attr, hasFilter, atoi(value), hasFilterHigh, atoi(valueHigh)));
  8155. else
  8156. filters.append(*new CDFUSFFilter(filterType, attr, hasFilter, (__int64) atol(value), hasFilterHigh, (__int64) atol(valueHigh)));
  8157. return;
  8158. }
  8159. }
  8160. void addFilterArray(DFUQFilterType filterType, const char* attr, const char* value, const char* sep)
  8161. {
  8162. if (!attr || !*attr || !value || !*value)
  8163. return;
  8164. StringArray filterArray;
  8165. filterArray.appendListUniq(value, sep);
  8166. filters.append(*new CDFUSFFilter(filterType, attr, value, sep, filterArray));
  8167. }
  8168. void addSpecialFilter(const char* attr, const char* value)
  8169. {
  8170. if (!attr || !*attr || !value || !*value)
  8171. return;
  8172. if (!isdigit(*attr))
  8173. {
  8174. PROGLOG("Unsupported Special Filter: %s", attr);
  8175. return;
  8176. }
  8177. DFUQSpecialFilter filterName = (DFUQSpecialFilter) atoi(attr);
  8178. switch(filterName)
  8179. {
  8180. case DFUQSFFileNameWithPrefix:
  8181. wildNameFilter.set(value);
  8182. break;
  8183. case DFUQSFFileType:
  8184. if (isdigit(*value))
  8185. fileTypeFilter = (DFUQFileTypeFilter) atoi(value);
  8186. else
  8187. PROGLOG("Unsupported Special Filter: %s, value %s", attr, value);
  8188. break;
  8189. case DFUQSFMaxFiles:
  8190. if (isdigit(*value))
  8191. maxFilesFilter = atoi(value);
  8192. else
  8193. PROGLOG("Unsupported Special Filter: %s, value %s", attr, value);
  8194. break;
  8195. default:
  8196. PROGLOG("Unsupported Special Filter: %d", filterName);
  8197. break;
  8198. }
  8199. }
  8200. bool doWildMatch(const char* filter, const char* value)
  8201. {
  8202. if (!filter || !*filter || streq(filter, "*") || (value && WildMatch(value, filter, true)))
  8203. return true;
  8204. return false;
  8205. }
  8206. public:
  8207. CIterateFileFilterContainer()
  8208. {
  8209. maxFilesFilter = ITERATE_FILTEREDFILES_LIMIT;
  8210. fileTypeFilter = DFUQFFTall;
  8211. wildNameFilter.set("*");
  8212. filterBuf.clear();
  8213. };
  8214. void readFilters(const char *filterStr)
  8215. {
  8216. if (!filterStr || !*filterStr)
  8217. return;
  8218. filterBuf.set(filterStr);
  8219. StringArray filterStringArray;
  8220. char sep[] = { DFUQFilterSeparator, '\0' };
  8221. filterStringArray.appendList(filterStr, sep);
  8222. unsigned filterFieldsToRead = filterStringArray.length();
  8223. ForEachItemIn(i,filterStringArray)
  8224. {
  8225. const char* filterTypeStr = filterStringArray.item(i);
  8226. if (!filterTypeStr || !*filterTypeStr)
  8227. continue;
  8228. if (!isdigit(*filterTypeStr))
  8229. continue;
  8230. unsigned filterSize = 4;
  8231. DFUQFilterType filterType = (DFUQFilterType) atoi(filterTypeStr);
  8232. switch(filterType)
  8233. {
  8234. case DFUQFTcontainString:
  8235. if (filterFieldsToRead >= filterSize) //DFUQFilterType | filter name | separator | filter value separated by the separator
  8236. addFilterArray(DFUQFTcontainString, filterStringArray.item(i+1), (const char*)filterStringArray.item(i+2), (const char*)filterStringArray.item(i+3));
  8237. break;
  8238. case DFUQFThasProp:
  8239. case DFUQFTbooleanMatch:
  8240. case DFUQFTwildcardMatch:
  8241. filterSize = 3;
  8242. if (filterFieldsToRead >= filterSize) //DFUQFilterType | filter name | filter value
  8243. addFilter(filterType, filterStringArray.item(i+1), (const char*)filterStringArray.item(i+2), NULL);
  8244. break;
  8245. case DFUQFTstringRange:
  8246. case DFUQFTintegerRange:
  8247. case DFUQFTinteger64Range:
  8248. if (filterFieldsToRead >= filterSize) //DFUQFilterType | filter name | from filter | to filter
  8249. addFilter(filterType, filterStringArray.item(i+1), (const char*)filterStringArray.item(i+2), (const char*)filterStringArray.item(i+3));
  8250. break;
  8251. case DFUQFTincludeFileAttr:
  8252. filterSize = 2;
  8253. if (filterFieldsToRead >= filterSize) //DFUQFilterType | filter
  8254. addOption(filterStringArray.item(i+1));
  8255. break;
  8256. case DFUQFTspecial:
  8257. filterSize = 3;
  8258. if (filterFieldsToRead >= filterSize) //DFUQFilterType | filter name | filter value
  8259. addSpecialFilter(filterStringArray.item(i+1), (const char*)filterStringArray.item(i+2));
  8260. break;
  8261. }
  8262. filterFieldsToRead -= filterSize;
  8263. i += (filterSize - 1);
  8264. }
  8265. }
  8266. bool matchFileScanFilter(const char* name, IPropertyTree &file)
  8267. {
  8268. if (!doWildMatch(wildNameFilter.get(), name))
  8269. return false;
  8270. if (!filters.length())
  8271. return true;
  8272. ForEachItemIn(i,filters)
  8273. {
  8274. CDFUSFFilter &filter = filters.item(i);
  8275. const char* attrPath = filter.getAttrPath();
  8276. try
  8277. {
  8278. if (!filter.checkFilter(file))
  8279. return false;
  8280. }
  8281. catch (IException *e)
  8282. {
  8283. VStringBuffer msg("Failed to check filter %s for %s: ", attrPath, name);
  8284. int code = e->errorCode();
  8285. e->errorMessage(msg);
  8286. e->Release();
  8287. throw MakeStringException(code, "%s", msg.str());
  8288. }
  8289. }
  8290. return true;
  8291. }
  8292. DFUQFileTypeFilter getFileTypeFilter() { return fileTypeFilter; }
  8293. unsigned getMaxFilesFilter() { return maxFilesFilter; }
  8294. void setFileTypeFilter(DFUQFileTypeFilter _fileType)
  8295. {
  8296. fileTypeFilter = _fileType;
  8297. }
  8298. const char* getNameFilter() { return wildNameFilter.get(); }
  8299. void setNameFilter(const char* _wildName)
  8300. {
  8301. if (!_wildName || !*_wildName)
  8302. return;
  8303. wildNameFilter.set(_wildName);
  8304. }
  8305. SerializeFileAttrOptions& getSerializeFileAttrOptions() { return options; }
  8306. };
  8307. class CFileScanner
  8308. {
  8309. bool recursive;
  8310. bool includesuper;
  8311. StringAttr wildname;
  8312. Owned<CScope> topLevelScope;
  8313. CScope *currentScope;
  8314. Owned<CIterateFileFilterContainer> iterateFileFilterContainer;
  8315. bool scopeMatch(const char *name)
  8316. { // name has trailing '::'
  8317. if (!name || !*name)
  8318. return true;
  8319. const char *s1 = NULL;
  8320. if (!iterateFileFilterContainer)
  8321. s1 = wildname.get();
  8322. else
  8323. s1 = iterateFileFilterContainer->getNameFilter();
  8324. if (!s1 || !*s1)
  8325. return true;
  8326. const char *s2 = name;
  8327. while (*s2) {
  8328. if (*s1=='*') {
  8329. if (recursive)
  8330. return true;
  8331. if (*s2==':')
  8332. return false;
  8333. // '*' can only come at end of scope in non-recursive
  8334. while (*s1&&(*s1!=':'))
  8335. s1++;
  8336. while (*s2&&(*s2!=':'))
  8337. s2++;
  8338. }
  8339. else if ((*s1==*s2)||(*s1=='?')) {
  8340. s1++;
  8341. s2++;
  8342. }
  8343. else
  8344. return false;
  8345. }
  8346. return true;
  8347. }
  8348. bool processScopes(IPropertyTree &root,StringBuffer &name)
  8349. {
  8350. bool ret = false;
  8351. CScope *parentScope = currentScope;
  8352. if (parentScope)
  8353. currentScope = parentScope->addScope(name);
  8354. else
  8355. { // once only
  8356. topLevelScope.setown(new CScope(""));
  8357. currentScope = topLevelScope;
  8358. }
  8359. size32_t ns = name.length();
  8360. if (ns)
  8361. name.append("::");
  8362. size32_t ns2 = name.length();
  8363. if (scopeMatch(name.str())) {
  8364. Owned<IPropertyTreeIterator> iter = root.getElements(queryDfsXmlBranchName(DXB_Scope));
  8365. if (iter->first()) {
  8366. do {
  8367. IPropertyTree &scope = iter->query();
  8368. if (scope.hasChildren()) {
  8369. name.append(scope.queryProp("@name"));
  8370. ret |= processScopes(scope, name);
  8371. name.setLength(ns2);
  8372. }
  8373. } while (iter->next());
  8374. }
  8375. if (!iterateFileFilterContainer)
  8376. ret |= processFiles(root,name);
  8377. else
  8378. ret |= processFilesWithFilters(root,name);
  8379. }
  8380. if (!ret && parentScope)
  8381. parentScope->popLastScope(); // discard scopes where no matches
  8382. currentScope = parentScope;
  8383. name.setLength(ns);
  8384. return ret;
  8385. }
  8386. bool processFiles(IPropertyTree &root,StringBuffer &name)
  8387. {
  8388. bool ret = false;
  8389. const char *s1 = wildname.get();
  8390. size32_t ns = name.length();
  8391. Owned<IPropertyTreeIterator> iter = root.getElements(queryDfsXmlBranchName(DXB_File));
  8392. if (iter->first()) {
  8393. IPropertyTree &scope = iter->query();
  8394. do {
  8395. IPropertyTree &file = iter->query();
  8396. name.append(file.queryProp("@name"));
  8397. if (!s1||WildMatch(name.str(),s1,true)) {
  8398. currentScope->addMatch(name,file,false);
  8399. ret = true;
  8400. }
  8401. name.setLength(ns);
  8402. } while (iter->next());
  8403. }
  8404. if (includesuper) {
  8405. iter.setown(root.getElements(queryDfsXmlBranchName(DXB_SuperFile)));
  8406. if (iter->first()) {
  8407. do {
  8408. IPropertyTree &file = iter->query();
  8409. name.append(file.queryProp("@name"));
  8410. if (!s1||WildMatch(name.str(),s1,true)) {
  8411. currentScope->addMatch(name,file,true);
  8412. ret = true;
  8413. }
  8414. name.setLength(ns);
  8415. } while (iter->next());
  8416. }
  8417. }
  8418. return ret;
  8419. }
  8420. bool processFilesWithFilters(IPropertyTree &root, StringBuffer &name)
  8421. {
  8422. bool ret = false;
  8423. size32_t ns = name.length();
  8424. DFUQFileTypeFilter fileTypeFilter = iterateFileFilterContainer->getFileTypeFilter();
  8425. if (fileTypeFilter != DFUQFFTsuperfileonly)
  8426. addMatchedFiles(root.getElements(queryDfsXmlBranchName(DXB_File)), false, name, ns, ret);
  8427. if ((fileTypeFilter == DFUQFFTall) || (fileTypeFilter == DFUQFFTsuperfileonly))
  8428. addMatchedFiles(root.getElements(queryDfsXmlBranchName(DXB_SuperFile)), true, name, ns, ret);
  8429. return ret;
  8430. }
  8431. void addMatchedFiles(IPropertyTreeIterator* files, bool isSuper, StringBuffer &name, size32_t ns, bool& ret)
  8432. {
  8433. Owned<IPropertyTreeIterator> iter = files;
  8434. ForEach(*iter)
  8435. {
  8436. IPropertyTree &file = iter->query();
  8437. name.append(file.queryProp("@name"));
  8438. if (iterateFileFilterContainer->matchFileScanFilter(name.str(), file))
  8439. {
  8440. currentScope->addMatch(name,file,isSuper);
  8441. ret = true;
  8442. }
  8443. name.setLength(ns);
  8444. }
  8445. }
  8446. public:
  8447. void scan(IPropertyTree *sroot, const char *_wildname,bool _recursive,bool _includesuper)
  8448. {
  8449. if (_wildname)
  8450. wildname.set(_wildname);
  8451. else
  8452. wildname.clear();
  8453. recursive = _recursive;
  8454. includesuper = _includesuper;
  8455. StringBuffer name;
  8456. topLevelScope.clear();
  8457. currentScope = NULL;
  8458. processScopes(*sroot->queryPropTree(querySdsFilesRoot()),name);
  8459. }
  8460. void scan(IPropertyTree *sroot, CIterateFileFilterContainer* _iterateFileFilterContainer, bool _recursive)
  8461. {
  8462. iterateFileFilterContainer.setown(_iterateFileFilterContainer);
  8463. recursive = _recursive;
  8464. StringBuffer name;
  8465. topLevelScope.clear();
  8466. currentScope = NULL;
  8467. processScopes(*sroot->queryPropTree(querySdsFilesRoot()),name);
  8468. }
  8469. void _getResults(bool auth, IUserDescriptor *user, CScope &scope, CFileMatchArray &matchingFiles, StringArray &authScopes,
  8470. unsigned &count, bool checkFileCount)
  8471. {
  8472. if (auth)
  8473. {
  8474. SecAccessFlags perm = getScopePermissions(scope.getName(),user,0); // don't audit
  8475. if (!HASREADPERMISSION(perm))
  8476. return;
  8477. authScopes.append(scope.getName());
  8478. }
  8479. CFileMatchArray &files = scope.queryFiles();
  8480. ForEachItemIn(f, files)
  8481. {
  8482. if (checkFileCount && (count == iterateFileFilterContainer->getMaxFilesFilter()))
  8483. throw MakeStringException(DFSERR_PassIterateFilesLimit, "CFileScanner::_getResults() found >%d files.",
  8484. iterateFileFilterContainer->getMaxFilesFilter());
  8485. CFileMatch *match = &files.item(f);
  8486. matchingFiles.append(*LINK(match));
  8487. ++count;
  8488. }
  8489. CScopeArray &subScopes = scope.querySubScopes();
  8490. ForEachItemIn(s, subScopes)
  8491. {
  8492. CScope &subScope = subScopes.item(s);
  8493. _getResults(auth, user, subScope, matchingFiles, authScopes, count, checkFileCount);
  8494. }
  8495. }
  8496. unsigned getResults(bool auth, IUserDescriptor *user, CFileMatchArray &matchingFiles, StringArray &authScopes, unsigned &count, bool checkFileCount)
  8497. {
  8498. _getResults(auth, user, *topLevelScope, matchingFiles, authScopes, count, checkFileCount);
  8499. return count;
  8500. }
  8501. };
  8502. struct CMachineEntry: public CInterface
  8503. {
  8504. CMachineEntry(const char *_mname,SocketEndpoint _ep)
  8505. : mname(_mname),ep(_ep)
  8506. {
  8507. }
  8508. StringAttr mname;
  8509. SocketEndpoint ep;
  8510. };
  8511. typedef CMachineEntry *CMachineEntryPtr;
  8512. typedef MapStringTo<CMachineEntryPtr> CMachineEntryMap;
  8513. StringBuffer &getClusterGroupName(IPropertyTree &cluster, StringBuffer &groupName)
  8514. {
  8515. const char *name = cluster.queryProp("@name");
  8516. const char *nodeGroupName = cluster.queryProp("@nodeGroup");
  8517. if (nodeGroupName && *nodeGroupName)
  8518. name = nodeGroupName;
  8519. groupName.append(name);
  8520. return groupName.trim().toLowerCase();
  8521. }
  8522. StringBuffer &getClusterSpareGroupName(IPropertyTree &cluster, StringBuffer &groupName)
  8523. {
  8524. return getClusterGroupName(cluster, groupName).append("_spares");
  8525. }
  8526. // JCSMORE - dfs group handling may be clearer if in own module
  8527. class CInitGroups
  8528. {
  8529. CMachineEntryMap machinemap;
  8530. CIArrayOf<CMachineEntry> machinelist;
  8531. CConnectLock groupsconnlock;
  8532. StringArray clusternames;
  8533. unsigned defaultTimeout;
  8534. bool machinesLoaded;
  8535. GroupType getGroupType(const char *type)
  8536. {
  8537. if (0 == strcmp("ThorCluster", type))
  8538. return grp_thor;
  8539. else if (0 == strcmp("RoxieCluster", type))
  8540. return grp_roxie;
  8541. else
  8542. throwUnexpected();
  8543. }
  8544. bool clusterGroupCompare(IPropertyTree *newClusterGroup, IPropertyTree *oldClusterGroup)
  8545. {
  8546. if (!newClusterGroup && !oldClusterGroup)
  8547. return true; // i.e. both missing, so match
  8548. else if (!newClusterGroup || !oldClusterGroup)
  8549. return false; // i.e. one of them (not both) missing, so mismatch
  8550. // else // neither missing
  8551. // see if identical
  8552. const char *oldKind = oldClusterGroup->queryProp("@kind");
  8553. const char *oldDir = oldClusterGroup->queryProp("@dir");
  8554. const char *newKind = newClusterGroup->queryProp("@kind");
  8555. const char *newDir = newClusterGroup->queryProp("@dir");
  8556. if (oldKind) {
  8557. if (newKind) {
  8558. if (!streq(newKind, newKind))
  8559. return false;
  8560. }
  8561. else
  8562. return false;
  8563. }
  8564. else if (newKind)
  8565. return false;
  8566. if (oldDir) {
  8567. if (newDir) {
  8568. if (!streq(newDir,oldDir))
  8569. return false;
  8570. }
  8571. else
  8572. return false;
  8573. }
  8574. else if (NULL!=newDir)
  8575. return false;
  8576. unsigned oldGroupCount = oldClusterGroup->getCount("Node");
  8577. unsigned newGroupCount = newClusterGroup->getCount("Node");
  8578. if (oldGroupCount != newGroupCount)
  8579. return false;
  8580. if (0 == newGroupCount)
  8581. return true;
  8582. Owned<IPropertyTreeIterator> newIter = newClusterGroup->getElements("Node");
  8583. Owned<IPropertyTreeIterator> oldIter = oldClusterGroup->getElements("Node");
  8584. if (newIter->first() && oldIter->first()) {
  8585. loop {
  8586. const char *oldIp = oldIter->query().queryProp("@ip");
  8587. const char *newIp = newIter->query().queryProp("@ip");
  8588. if (!streq(oldIp, newIp))
  8589. return false;
  8590. if (!oldIter->next() || !newIter->next())
  8591. break;
  8592. }
  8593. }
  8594. return true;
  8595. }
  8596. void addClusterGroup(const char *name, IPropertyTree *newClusterGroup, bool realCluster)
  8597. {
  8598. VStringBuffer prop("Group[@name=\"%s\"]", name);
  8599. IPropertyTree *root = groupsconnlock.conn->queryRoot();
  8600. IPropertyTree *old = root->queryPropTree(prop.str());
  8601. if (old) {
  8602. // JCSMORE
  8603. // clone
  8604. // iterate through files and point to clone
  8605. // i) if change is minor, worth swapping to new group anyway?
  8606. // ii) if old group has machines that are no longer in new environment, mark file bad?
  8607. root->removeTree(old);
  8608. }
  8609. if (!newClusterGroup)
  8610. return;
  8611. if (realCluster)
  8612. clusternames.append(name);
  8613. IPropertyTree *grp = root->addPropTree("Group", newClusterGroup);
  8614. grp->setProp("@name", name);
  8615. }
  8616. IGroup *getGroupFromCluster(GroupType groupType, IPropertyTree &cluster, bool expand)
  8617. {
  8618. SocketEndpointArray eps;
  8619. const char *processName=NULL;
  8620. switch (groupType)
  8621. {
  8622. case grp_thor:
  8623. processName = "ThorSlaveProcess";
  8624. break;
  8625. case grp_thorspares:
  8626. processName = "ThorSpareProcess";
  8627. break;
  8628. case grp_roxie:
  8629. processName = "RoxieServerProcess";
  8630. break;
  8631. default:
  8632. throwUnexpected();
  8633. }
  8634. SocketEndpoint nullep;
  8635. Owned<IPropertyTreeIterator> nodes = cluster.getElements(processName);
  8636. ForEach(*nodes)
  8637. {
  8638. IPropertyTree &node = nodes->query();
  8639. SocketEndpoint ep;
  8640. const char *computer = node.queryProp("@computer");
  8641. const char *netAddress = node.queryProp("@netAddress");
  8642. if (computer && *computer)
  8643. {
  8644. CMachineEntryPtr *m = machinemap.getValue(computer);
  8645. if (!m)
  8646. {
  8647. ERRLOG("Cannot construct %s, computer name %s not found\n", cluster.queryProp("@name"), computer);
  8648. return NULL;
  8649. }
  8650. ep.set((*m)->ep);
  8651. }
  8652. else if (netAddress && *netAddress)
  8653. {
  8654. ep.set(netAddress, 0);
  8655. }
  8656. else
  8657. {
  8658. ERRLOG("Cannot construct %s, missing computer spec on node\n", cluster.queryProp("@name"));
  8659. return NULL;
  8660. }
  8661. switch (groupType)
  8662. {
  8663. case grp_roxie:
  8664. // Redundant copies are located via the flags.
  8665. // Old environments may contain duplicated sever information for multiple ports
  8666. eps.appendUniq(ep);
  8667. break;
  8668. case grp_thor:
  8669. case grp_thorspares:
  8670. eps.append(ep);
  8671. break;
  8672. default:
  8673. throwUnexpected();
  8674. }
  8675. }
  8676. if (!eps.ordinality())
  8677. return NULL;
  8678. Owned<IGroup> grp;
  8679. if (grp_thor != groupType)
  8680. expand = false;
  8681. if (expand)
  8682. {
  8683. unsigned slavesPerNode = cluster.getPropInt("@slavesPerNode", 1);
  8684. unsigned channelsPerSlave = cluster.getPropInt("@channelsPerSlave", 1);
  8685. SocketEndpointArray msEps;
  8686. for (unsigned s=0; s<(slavesPerNode*channelsPerSlave); s++)
  8687. {
  8688. ForEachItemIn(e, eps)
  8689. msEps.append(eps.item(e));
  8690. }
  8691. grp.setown(createIGroup(msEps));
  8692. }
  8693. else
  8694. grp.setown(createIGroup(eps));
  8695. return grp.getClear();
  8696. }
  8697. bool loadMachineMap()
  8698. {
  8699. if (machinesLoaded)
  8700. return true;
  8701. //GH->JCS This can't be changed to use getEnvironmentFactory() unless that moved inside dalibase;
  8702. Owned<IRemoteConnection> conn = querySDS().connect("/Environment/Hardware", myProcessSession(), RTM_LOCK_READ, SDS_CONNECT_TIMEOUT);
  8703. if (!conn) {
  8704. WARNLOG("Cannot connect to /Environment/Hardware");
  8705. return false;
  8706. }
  8707. IPropertyTree* root = conn->queryRoot();
  8708. Owned<IPropertyTreeIterator> machines= root->getElements("Computer");
  8709. ForEach(*machines) {
  8710. IPropertyTree &machine = machines->query();
  8711. SocketEndpoint ep(machine.queryProp("@netAddress"));
  8712. const char *name = machine.queryProp("@name");
  8713. CMachineEntry *entry = new CMachineEntry(name,ep);
  8714. machinemap.setValue(name, entry);
  8715. machinelist.append(*entry);
  8716. }
  8717. machinesLoaded = true;
  8718. return true;
  8719. }
  8720. IPropertyTree *createClusterGroup(GroupType groupType, IGroup *group, const char *dir, bool realCluster)
  8721. {
  8722. Owned<IPropertyTree> cluster = createPTree("Group");
  8723. if (realCluster)
  8724. cluster->setPropBool("@cluster", true);
  8725. const char *kind=NULL;
  8726. switch (groupType) {
  8727. case grp_thor:
  8728. kind = "Thor";
  8729. break;
  8730. case grp_roxie:
  8731. kind = "Roxie";
  8732. break;
  8733. case grp_hthor:
  8734. kind = "hthor";
  8735. break;
  8736. }
  8737. if (kind)
  8738. cluster->setProp("@kind",kind);
  8739. if (dir)
  8740. cluster->setProp("@dir",dir);
  8741. Owned<INodeIterator> iter = group->getIterator();
  8742. StringBuffer str;
  8743. ForEach(*iter) {
  8744. iter->query().endpoint().getIpText(str.clear());
  8745. IPropertyTree *n = createPTree("Node");
  8746. n->setProp("@ip",str.str());
  8747. cluster->addPropTree("Node", n);
  8748. }
  8749. return cluster.getClear();
  8750. }
  8751. IPropertyTree *createClusterGroupFromEnvCluster(GroupType groupType, IPropertyTree &cluster, const char *dir, bool realCluster)
  8752. {
  8753. Owned<IGroup> group = getGroupFromCluster(groupType, cluster, true);
  8754. if (!group)
  8755. return NULL;
  8756. return createClusterGroup(groupType, group, dir, realCluster);
  8757. }
  8758. bool constructGroup(IPropertyTree &cluster, const char *altName, IPropertyTree *oldEnvCluster, GroupType groupType, bool force, StringBuffer &messages)
  8759. {
  8760. /* a 'realCluster' is a cluster who's name matches it's nodeGroup
  8761. * if the nodeGroup differs it implies it's sharing the nodeGroup with other thor instance(s).
  8762. */
  8763. bool realCluster = true;
  8764. bool oldRealCluster = true;
  8765. StringBuffer gname, oldGname;
  8766. const char *defDir = NULL;
  8767. switch (groupType)
  8768. {
  8769. case grp_thor:
  8770. getClusterGroupName(cluster, gname);
  8771. if (!streq(cluster.queryProp("@name"), gname.str()))
  8772. realCluster = false;
  8773. if (oldEnvCluster)
  8774. {
  8775. getClusterGroupName(*oldEnvCluster, oldGname);
  8776. if (!streq(oldEnvCluster->queryProp("@name"), oldGname.str()))
  8777. oldRealCluster = false;
  8778. }
  8779. break;
  8780. case grp_thorspares:
  8781. getClusterSpareGroupName(cluster, gname);
  8782. oldRealCluster = realCluster = false;
  8783. break;
  8784. case grp_roxie:
  8785. gname.append(cluster.queryProp("@name"));
  8786. break;
  8787. default:
  8788. throwUnexpected();
  8789. }
  8790. if (altName)
  8791. gname.clear().append(altName).toLowerCase();
  8792. VStringBuffer xpath("Group[@name=\"%s\"]", gname.str());
  8793. IPropertyTree *existingClusterGroup = groupsconnlock.conn->queryRoot()->queryPropTree(xpath.str()); // 'live' cluster group
  8794. bool matchOldEnv = false;
  8795. Owned<IPropertyTree> newClusterGroup = createClusterGroupFromEnvCluster(groupType, cluster, defDir, realCluster);
  8796. bool matchExisting = clusterGroupCompare(newClusterGroup, existingClusterGroup);
  8797. if (oldEnvCluster)
  8798. {
  8799. // new matches old, only if neither has changed it's name to mismatch it's nodeGroup name
  8800. if (realCluster == oldRealCluster)
  8801. {
  8802. Owned<IPropertyTree> oldClusterGroup = createClusterGroupFromEnvCluster(groupType, *oldEnvCluster, defDir, oldRealCluster);
  8803. matchOldEnv = clusterGroupCompare(newClusterGroup, oldClusterGroup);
  8804. }
  8805. else
  8806. matchOldEnv = false;
  8807. }
  8808. if (!matchExisting)
  8809. {
  8810. if (force)
  8811. {
  8812. VStringBuffer msg("Forcing new group layout for %s [ matched active = false, matched old environment = %s ]", gname.str(), matchOldEnv?"true":"false");
  8813. WARNLOG("%s", msg.str());
  8814. messages.append(msg).newline();
  8815. matchOldEnv = false;
  8816. }
  8817. else
  8818. {
  8819. VStringBuffer msg("Active cluster '%s' group layout does not match environment [matched old environment=%s]", gname.str(), matchOldEnv?"true":"false");
  8820. LOG(MCoperatorWarning, unknownJob, "%s", msg.str()); \
  8821. messages.append(msg).newline();
  8822. if (existingClusterGroup)
  8823. {
  8824. // NB: not used at moment, but may help spot clusters that have swapped nodes
  8825. existingClusterGroup->setPropBool("@mismatched", true);
  8826. }
  8827. }
  8828. }
  8829. if (!existingClusterGroup || (!matchExisting && !matchOldEnv))
  8830. {
  8831. VStringBuffer msg("New cluster layout for cluster %s", gname.str());
  8832. WARNLOG("%s", msg.str());
  8833. messages.append(msg).newline();
  8834. addClusterGroup(gname.str(), newClusterGroup.getClear(), realCluster);
  8835. return true;
  8836. }
  8837. return false;
  8838. }
  8839. void constructHThorGroups(IPropertyTree &cluster)
  8840. {
  8841. const char *groupname = cluster.queryProp("@name");
  8842. if (!groupname || !*groupname)
  8843. return;
  8844. unsigned ins = 0;
  8845. Owned<IPropertyTreeIterator> insts = cluster.getElements("Instance");
  8846. ForEach(*insts) {
  8847. const char *na = insts->query().queryProp("@netAddress");
  8848. if (na&&*na) {
  8849. SocketEndpoint ep(na);
  8850. if (!ep.isNull()) {
  8851. ins++;
  8852. VStringBuffer gname("hthor__%s", groupname);
  8853. if (ins>1)
  8854. gname.append('_').append(ins);
  8855. Owned<IGroup> group = createIGroup(1, &ep);
  8856. Owned<IPropertyTree> clusterGroup = createClusterGroup(grp_hthor, group, NULL, true);
  8857. addClusterGroup(gname.str(), clusterGroup.getClear(), true);
  8858. }
  8859. }
  8860. }
  8861. }
  8862. enum CgCmd { cg_null, cg_reset, cg_add, cg_remove };
  8863. public:
  8864. CInitGroups(unsigned _defaultTimeout)
  8865. : groupsconnlock("constructGroup",SDS_GROUPSTORE_ROOT,true,false,false,_defaultTimeout)
  8866. {
  8867. defaultTimeout = _defaultTimeout;
  8868. machinesLoaded = false;
  8869. }
  8870. bool doClusterGroup(CgCmd cmd, const char *_clusterName, const char *type, bool spares, SocketEndpointArray *eps, StringBuffer &messages)
  8871. {
  8872. Owned<IRemoteConnection> conn = querySDS().connect("/Environment/Software", myProcessSession(), RTM_LOCK_READ, SDS_CONNECT_TIMEOUT);
  8873. if (!conn)
  8874. return false;
  8875. if (!_clusterName || !*_clusterName)
  8876. return false;
  8877. StringAttr clusterName = _clusterName;
  8878. clusterName.toLowerCase();
  8879. if (!type || !*type)
  8880. return false;
  8881. bool ret = true;
  8882. IPropertyTree* root = conn->queryRoot();
  8883. Owned<IPropertyTreeIterator> clusters;
  8884. StringBuffer errMsg;
  8885. const char *clusterType = type;
  8886. if (loadMachineMap()) {
  8887. VStringBuffer xpath("%s[@name=\"%s\"]", type, clusterName.get());
  8888. clusters.setown(root->getElements(xpath.str()));
  8889. if (!clusters || !clusters->first()) {
  8890. VStringBuffer errMsg("Could not find type %s, %s cluster", type, clusterName.get());
  8891. WARNLOG("%s", errMsg.str());
  8892. messages.append(errMsg).newline();
  8893. ret = false;
  8894. }
  8895. else {
  8896. if (!streq("ThorCluster", type))
  8897. return false; // currently only Thor supported here.
  8898. IPropertyTree &cluster = clusters->query();
  8899. switch (cmd) {
  8900. case cg_reset:
  8901. {
  8902. if (spares) {
  8903. if (!constructGroup(cluster,NULL,NULL,grp_thorspares,true,messages))
  8904. ret = false;
  8905. }
  8906. else {
  8907. if (!constructGroup(cluster,NULL,NULL,grp_thor,true,messages))
  8908. ret = false;
  8909. }
  8910. break;
  8911. }
  8912. case cg_add:
  8913. {
  8914. assertex(eps);
  8915. StringBuffer groupName;
  8916. getClusterSpareGroupName(cluster, groupName);
  8917. IPropertyTree *root = groupsconnlock.conn->queryRoot();
  8918. VStringBuffer xpath("Group[@name=\"%s\"]",groupName.str());
  8919. IPropertyTree *existing = root->queryPropTree(xpath.str());
  8920. if (existing) {
  8921. Owned<IPropertyTreeIterator> iter = existing->getElements("Node");
  8922. ForEach(*iter) {
  8923. SocketEndpoint ep(iter->query().queryProp("@ip"));
  8924. if (eps->zap(ep)) {
  8925. StringBuffer epStr;
  8926. VStringBuffer errMsg("addSpares: not adding: %s, already in spares", ep.getUrlStr(epStr).str());
  8927. WARNLOG("%s", errMsg.str());
  8928. messages.append(errMsg).newline();
  8929. while (eps->zap(ep)); // delete any other duplicates
  8930. }
  8931. }
  8932. }
  8933. else {
  8934. existing = createPTree();
  8935. existing->setProp("@name", groupName.str());
  8936. existing = root->addPropTree("Group", existing);
  8937. }
  8938. // add remaining
  8939. ForEachItemIn(e, *eps) {
  8940. const SocketEndpoint &ep = eps->item(e);
  8941. StringBuffer ipStr;
  8942. ep.getIpText(ipStr);
  8943. IPropertyTree *node = createPTree();
  8944. node->setProp("@ip", ipStr.str());
  8945. existing->addPropTree("Node", node);
  8946. }
  8947. break;
  8948. }
  8949. case cg_remove:
  8950. {
  8951. assertex(eps);
  8952. StringBuffer groupName;
  8953. getClusterSpareGroupName(cluster, groupName);
  8954. IPropertyTree *root = groupsconnlock.conn->queryRoot();
  8955. VStringBuffer xpath("Group[@name=\"%s\"]", groupName.str());
  8956. IPropertyTree *existing = root->queryPropTree(xpath.str());
  8957. if (existing) {
  8958. ForEachItemIn(e, *eps) {
  8959. const SocketEndpoint &ep = eps->item(e);
  8960. StringBuffer ipStr;
  8961. ep.getIpText(ipStr);
  8962. VStringBuffer xpath("Node[@ip=\"%s\"]", ipStr.str());
  8963. if (!existing->removeProp(xpath.str())) {
  8964. VStringBuffer errMsg("removeSpares: %s not found in spares", ipStr.str());
  8965. WARNLOG("%s", errMsg.str());
  8966. messages.append(errMsg).newline();
  8967. while (eps->zap(ep)); // delete any other duplicates
  8968. }
  8969. else
  8970. while (existing->removeProp(xpath.str())); // remove any others, shouldn't be any
  8971. }
  8972. }
  8973. break;
  8974. }
  8975. }
  8976. if (clusters->next()) {
  8977. VStringBuffer errMsg("resetThorGroup: more than one cluster named: %s", clusterName.get());
  8978. WARNLOG("%s", errMsg.str());
  8979. messages.append(errMsg).newline();
  8980. ret = false;
  8981. }
  8982. }
  8983. }
  8984. return ret;
  8985. }
  8986. bool resetClusterGroup(const char *clusterName, const char *type, bool spares, StringBuffer &messages)
  8987. {
  8988. return doClusterGroup(cg_reset, clusterName, type, spares, NULL, messages);
  8989. }
  8990. bool addSpares(const char *clusterName, const char *type, SocketEndpointArray &eps, StringBuffer &messages)
  8991. {
  8992. return doClusterGroup(cg_add, clusterName, type, true, &eps, messages);
  8993. }
  8994. bool removeSpares(const char *clusterName, const char *type, SocketEndpointArray &eps, StringBuffer &messages)
  8995. {
  8996. return doClusterGroup(cg_remove, clusterName, type, true, &eps, messages);
  8997. }
  8998. void constructGroups(bool force, StringBuffer &messages, IPropertyTree *oldEnvironment)
  8999. {
  9000. Owned<IRemoteConnection> conn = querySDS().connect("/Environment/Software", myProcessSession(), RTM_LOCK_READ, SDS_CONNECT_TIMEOUT);
  9001. if (!conn)
  9002. return;
  9003. clusternames.kill();
  9004. IPropertyTree* root = conn->queryRoot();
  9005. Owned<IPropertyTreeIterator> clusters;
  9006. if (loadMachineMap()) {
  9007. clusters.setown(root->getElements("ThorCluster"));
  9008. ForEach(*clusters) {
  9009. IPropertyTree &cluster = clusters->query();
  9010. IPropertyTree *oldCluster = NULL;
  9011. if (oldEnvironment) {
  9012. VStringBuffer xpath("Software/ThorCluster[@name=\"%s\"]", cluster.queryProp("@name"));
  9013. oldCluster = oldEnvironment->queryPropTree(xpath.str());
  9014. }
  9015. constructGroup(cluster,NULL,oldCluster,grp_thor,force,messages);
  9016. constructGroup(cluster,NULL,oldCluster,grp_thorspares,force,messages);
  9017. }
  9018. clusters.setown(root->getElements("RoxieCluster"));
  9019. ForEach(*clusters) {
  9020. IPropertyTree &cluster = clusters->query();
  9021. IPropertyTree *oldCluster = NULL;
  9022. if (oldEnvironment) {
  9023. VStringBuffer xpath("Software/RoxieCluster[@name=\"%s\"]", cluster.queryProp("@name"));
  9024. oldCluster = oldEnvironment->queryPropTree(xpath.str());
  9025. }
  9026. constructGroup(cluster,NULL,oldCluster,grp_roxie,force,messages);
  9027. }
  9028. clusters.setown(root->getElements("EclAgentProcess"));
  9029. ForEach(*clusters) {
  9030. IPropertyTree &cluster = clusters->query();
  9031. constructHThorGroups(cluster);
  9032. }
  9033. // correct cluster flags
  9034. // JCSMORE - why was this necessary, may well be legacy..
  9035. Owned<IPropertyTreeIterator> grps = groupsconnlock.conn->queryRoot()->getElements("Group");
  9036. ForEach(*grps) {
  9037. IPropertyTree &grp = grps->query();
  9038. const char *name = grp.queryProp("@name");
  9039. bool iscluster = NotFound != clusternames.find(name);
  9040. if (iscluster!=grp.getPropBool("@cluster"))
  9041. {
  9042. if (iscluster)
  9043. grp.setPropBool("@cluster", true);
  9044. else
  9045. grp.removeProp("@cluster");
  9046. }
  9047. }
  9048. }
  9049. }
  9050. IGroup *getGroupFromCluster(const char *type, IPropertyTree &cluster, bool expand)
  9051. {
  9052. loadMachineMap();
  9053. GroupType gt = getGroupType(type);
  9054. return getGroupFromCluster(gt, cluster, expand);
  9055. }
  9056. };
  9057. void initClusterGroups(bool force, StringBuffer &response, IPropertyTree *oldEnvironment, unsigned timems)
  9058. {
  9059. CInitGroups init(timems);
  9060. init.constructGroups(force, response, oldEnvironment);
  9061. }
  9062. bool resetClusterGroup(const char *clusterName, const char *type, bool spares, StringBuffer &response, unsigned timems)
  9063. {
  9064. CInitGroups init(timems);
  9065. return init.resetClusterGroup(clusterName, type, spares, response);
  9066. }
  9067. bool addClusterSpares(const char *clusterName, const char *type, SocketEndpointArray &eps, StringBuffer &response, unsigned timems)
  9068. {
  9069. CInitGroups init(timems);
  9070. return init.addSpares(clusterName, type, eps, response);
  9071. }
  9072. bool removeClusterSpares(const char *clusterName, const char *type, SocketEndpointArray &eps, StringBuffer &response, unsigned timems)
  9073. {
  9074. CInitGroups init(timems);
  9075. return init.removeSpares(clusterName, type, eps, response);
  9076. }
  9077. IGroup *getClusterNodeGroup(const char *clusterName, const char *type, unsigned timems)
  9078. {
  9079. VStringBuffer clusterPath("/Environment/Software/%s[@name=\"%s\"]", type, clusterName);
  9080. Owned<IRemoteConnection> conn = querySDS().connect(clusterPath.str(), myProcessSession(), RTM_LOCK_READ, SDS_CONNECT_TIMEOUT);
  9081. if (!conn)
  9082. return NULL;
  9083. IPropertyTree &cluster = *conn->queryRoot();
  9084. StringBuffer nodeGroupName;
  9085. getClusterGroupName(cluster, nodeGroupName);
  9086. if (0 == nodeGroupName.length())
  9087. throwUnexpected();
  9088. /* NB: Due to the way node groups and swapNode work, we need to return the IP's from the node group corresponding to the cluster
  9089. * which may no longer match the cluster IP's due to node swapping.
  9090. * As the node group is an expanded form of the cluster group (with a IP per partition/slave), with the cluster group repeated
  9091. * N times, where N is slavesPerNode*channelsPerSlave, return the first M (cluster group width) IP's of the node group.
  9092. * Ideally the node group representation would change to match the cluster group definition, but that require a lot of changes
  9093. * to DFS and elsewhere.
  9094. */
  9095. Owned<IGroup> nodeGroup = queryNamedGroupStore().lookup(nodeGroupName);
  9096. CInitGroups init(timems);
  9097. Owned<IGroup> expandedClusterGroup = init.getGroupFromCluster(type, cluster, true);
  9098. if (!expandedClusterGroup->equals(nodeGroup))
  9099. throwStringExceptionV(0, "DFS cluster topology for '%s', does not match existing DFS group layout for group '%s'", clusterName, nodeGroupName.str());
  9100. Owned<IGroup> clusterGroup = init.getGroupFromCluster(type, cluster, false);
  9101. ICopyArrayOf<INode> nodes;
  9102. for (unsigned n=0; n<clusterGroup->ordinality(); n++)
  9103. nodes.append(nodeGroup->queryNode(n));
  9104. return createIGroup(nodes.ordinality(), nodes.getArray());
  9105. }
  9106. class CDaliDFSServer: public Thread, public CTransactionLogTracker, implements IDaliServer, implements IExceptionHandler
  9107. { // Coven size
  9108. bool stopped;
  9109. unsigned defaultTimeout;
  9110. unsigned numThreads;
  9111. public:
  9112. IMPLEMENT_IINTERFACE;
  9113. CDaliDFSServer(IPropertyTree *config)
  9114. : Thread("CDaliDFSServer"), CTransactionLogTracker(MDFS_MAX)
  9115. {
  9116. stopped = true;
  9117. defaultTimeout = INFINITE; // server uses default
  9118. numThreads = config->getPropInt("DFS/@numThreads", DEFAULT_NUM_DFS_THREADS);
  9119. PROGLOG("DFS Server: numThreads=%d", numThreads);
  9120. }
  9121. ~CDaliDFSServer()
  9122. {
  9123. }
  9124. void start()
  9125. {
  9126. Thread::start();
  9127. }
  9128. void ready()
  9129. {
  9130. }
  9131. void suspend()
  9132. {
  9133. }
  9134. void stop()
  9135. {
  9136. if (!stopped) {
  9137. stopped = true;
  9138. queryCoven().cancel(RANK_ALL,MPTAG_DFS_REQUEST);
  9139. }
  9140. join();
  9141. }
  9142. int run()
  9143. {
  9144. ICoven &coven=queryCoven();
  9145. CMessageHandler<CDaliDFSServer> handler("CDaliDFSServer", this, &CDaliDFSServer::processMessage, this, numThreads, TIMEOUT_ON_CLOSEDOWN, INFINITE);
  9146. CMessageBuffer mb;
  9147. stopped = false;
  9148. while (!stopped)
  9149. {
  9150. try
  9151. {
  9152. mb.clear();
  9153. if (coven.recv(mb,RANK_ALL,MPTAG_DFS_REQUEST,NULL))
  9154. {
  9155. handler.handleMessage(mb);
  9156. mb.clear(); // ^ has copied mb
  9157. }
  9158. else
  9159. stopped = true;
  9160. }
  9161. catch (IException *e)
  9162. {
  9163. EXCLOG(e, "CDaliDFSServer");
  9164. e->Release();
  9165. }
  9166. }
  9167. return 0;
  9168. }
  9169. void iterateFiles(CMessageBuffer &mb,StringBuffer &trc)
  9170. {
  9171. TransactionLog transactionLog(*this, MDFS_ITERATE_FILES, mb.getSender());
  9172. StringAttr wildname;
  9173. bool recursive;
  9174. bool includesuper = false;
  9175. StringAttr attr;
  9176. mb.read(wildname).read(recursive).read(attr);
  9177. trc.appendf("iterateFiles(%s,%s,%s)",wildname.str(),recursive?"recursive":"",attr.str());
  9178. if (queryTransactionLogging())
  9179. transactionLog.log("%s", trc.str());
  9180. Owned<IUserDescriptor> udesc;
  9181. if (mb.getPos()<mb.length()) {
  9182. mb.read(includesuper);
  9183. if (mb.getPos()<mb.length()) {
  9184. udesc.setown(createUserDescriptor());
  9185. udesc->deserialize(mb);
  9186. }
  9187. }
  9188. mb.clear();
  9189. unsigned count=0;
  9190. mb.append(count);
  9191. CFileScanner scanner;
  9192. CSDSServerLockBlock sdsLock; // lock sds while scanning
  9193. unsigned start = msTick();
  9194. scanner.scan(sdsLock, wildname.get(),recursive,includesuper);
  9195. unsigned tookMs = msTick()-start;
  9196. if (tookMs>100)
  9197. PROGLOG("TIMING(filescan): %s: took %dms",trc.str(), tookMs);
  9198. sdsLock.unlock(); // unlock to perform authentification
  9199. bool auth = querySessionManager().checkScopeScansLDAP()&&getScopePermissions(NULL,udesc,(unsigned)-1);
  9200. StringArray authScopes;
  9201. CIArrayOf<CFileMatch> matchingFiles;
  9202. start = msTick();
  9203. scanner.getResults(auth, udesc, matchingFiles, authScopes, count, false);
  9204. tookMs = msTick()-start;
  9205. if (tookMs>100)
  9206. PROGLOG("TIMING(LDAP): %s: took %dms, %d lookups, file matches = %d", trc.str(), tookMs, authScopes.ordinality(), count);
  9207. sdsLock.lock(); // re-lock sds while serializing
  9208. start = msTick();
  9209. SerializeFileAttrOptions options; //The options is needed for the serializeFileAttributes()
  9210. ForEachItemIn(m, matchingFiles)
  9211. {
  9212. CFileMatch &fileMatch = matchingFiles.item(m);
  9213. CDFAttributeIterator::serializeFileAttributes(mb, fileMatch.queryFileTree(), fileMatch.queryName(), fileMatch.queryIsSuper(), options);
  9214. }
  9215. tookMs = msTick()-start;
  9216. if (tookMs>100)
  9217. PROGLOG("TIMING(filescan-serialization): %s: took %dms, %d files",trc.str(), tookMs, count);
  9218. mb.writeDirect(0,sizeof(count),&count);
  9219. }
  9220. void iterateFilteredFiles(TransactionLog &transactionLog, CMessageBuffer &mb,StringBuffer &trc, bool returnAllFilesFlag)
  9221. {
  9222. Owned<IUserDescriptor> udesc;
  9223. StringAttr filters;
  9224. bool recursive;
  9225. mb.read(filters).read(recursive);
  9226. trc.appendf("iterateFilteredFiles(%s,%s)",filters.str(),recursive?"recursive":"");
  9227. if (queryTransactionLogging())
  9228. transactionLog.log("%s", trc.str());
  9229. if (mb.getPos()<mb.length())
  9230. {
  9231. udesc.setown(createUserDescriptor());
  9232. udesc->deserialize(mb);
  9233. }
  9234. mb.clear();
  9235. unsigned count=0;
  9236. mb.append(count);
  9237. Owned<CIterateFileFilterContainer> iterateFileFilterContainer = new CIterateFileFilterContainer();
  9238. iterateFileFilterContainer->readFilters(filters);
  9239. CFileScanner scanner;
  9240. CSDSServerLockBlock sdsLock; // lock sds while scanning
  9241. unsigned start = msTick();
  9242. scanner.scan(sdsLock, iterateFileFilterContainer.getLink(), recursive);
  9243. unsigned tookMs = msTick()-start;
  9244. if (tookMs>100)
  9245. PROGLOG("TIMING(filescan): %s: took %dms",trc.str(), tookMs);
  9246. sdsLock.unlock(); // unlock to perform authentification
  9247. bool auth = querySessionManager().checkScopeScansLDAP()&&getScopePermissions(NULL,udesc,(unsigned)-1);
  9248. StringArray authScopes;
  9249. CIArrayOf<CFileMatch> matchingFiles;
  9250. start = msTick();
  9251. bool returnAllMatchingFiles = true;
  9252. try
  9253. {
  9254. scanner.getResults(auth, udesc, matchingFiles, authScopes, count, true);
  9255. }
  9256. catch(IException *e)
  9257. {
  9258. if (DFSERR_PassIterateFilesLimit != e->errorCode())
  9259. throw;
  9260. e->Release();
  9261. returnAllMatchingFiles = false;
  9262. }
  9263. if (returnAllFilesFlag)
  9264. mb.append(returnAllMatchingFiles);
  9265. tookMs = msTick()-start;
  9266. if (tookMs>100)
  9267. PROGLOG("TIMING(LDAP): %s: took %dms, %d lookups, file matches = %d", trc.str(), tookMs, authScopes.ordinality(), count);
  9268. sdsLock.lock(); // re-lock sds while serializing
  9269. start = msTick();
  9270. ForEachItemIn(m, matchingFiles)
  9271. {
  9272. CFileMatch &fileMatch = matchingFiles.item(m);
  9273. CDFAttributeIterator::serializeFileAttributes(mb, fileMatch.queryFileTree(), fileMatch.queryName(), fileMatch.queryIsSuper(), iterateFileFilterContainer->getSerializeFileAttrOptions());
  9274. }
  9275. tookMs = msTick()-start;
  9276. if (tookMs>100)
  9277. PROGLOG("TIMING(filescan-serialization): %s: took %dms, %d files",trc.str(), tookMs, count);
  9278. mb.writeDirect(0,sizeof(count),&count);
  9279. }
  9280. void iterateFilteredFiles(CMessageBuffer &mb,StringBuffer &trc)
  9281. {
  9282. TransactionLog transactionLog(*this, MDFS_ITERATE_FILTEREDFILES, mb.getSender());
  9283. iterateFilteredFiles(transactionLog, mb, trc, false);
  9284. }
  9285. void iterateFilteredFiles2(CMessageBuffer &mb,StringBuffer &trc)
  9286. {
  9287. TransactionLog transactionLog(*this, MDFS_ITERATE_FILTEREDFILES2, mb.getSender());
  9288. iterateFilteredFiles(transactionLog, mb, trc, true);
  9289. }
  9290. void iterateRelationships(CMessageBuffer &mb,StringBuffer &trc)
  9291. {
  9292. TransactionLog transactionLog(*this, MDFS_ITERATE_RELATIONSHIPS, mb.getSender());
  9293. StringAttr primary;
  9294. StringAttr secondary;
  9295. StringAttr primflds;
  9296. StringAttr secflds;
  9297. StringAttr kind;
  9298. StringAttr cardinality;
  9299. byte payloadb;
  9300. mb.read(primary).read(secondary).read(primflds).read(secflds).read(kind).read(cardinality).read(payloadb);
  9301. mb.clear();
  9302. bool payload = (payloadb==1);
  9303. trc.appendf("iterateRelationships(%s,%s,%s,%s,%s,%s,%d)",primary.str(),secondary.str(),primflds.str(),secflds.str(),kind.str(),cardinality.str(),(int)payloadb);
  9304. if (queryTransactionLogging())
  9305. transactionLog.log("%s", trc.str());
  9306. unsigned start = msTick();
  9307. unsigned count=0;
  9308. CSDSServerLockBlock sdsLock; // lock sds while scanning
  9309. StringBuffer xpath;
  9310. CDistributedFileDirectory::getFileRelationshipXPath(xpath,primary,secondary,primflds,secflds,kind,cardinality,((payloadb==0)||(payloadb==1))?&payload:NULL);
  9311. IPropertyTree *root = sdsLock->queryPropTree(querySdsRelationshipsRoot());
  9312. Owned<IPropertyTreeIterator> iter = root?root->getElements(xpath.str()):NULL;
  9313. mb.append(count);
  9314. // save as sequence of branches
  9315. if (iter) {
  9316. ForEach(*iter.get()) {
  9317. iter->query().serialize(mb);
  9318. count++;
  9319. }
  9320. }
  9321. if (msTick()-start>100) {
  9322. PROGLOG("TIMING(relationshipscan): %s: took %dms, %d relations",trc.str(),msTick()-start,count);
  9323. }
  9324. mb.writeDirect(0,sizeof(count),&count);
  9325. }
  9326. void setFileAccessed(CMessageBuffer &mb,StringBuffer &trc)
  9327. {
  9328. TransactionLog transactionLog(*this, MDFS_SET_FILE_ACCESSED, mb.getSender());
  9329. StringAttr lname;
  9330. mb.read(lname);
  9331. CDateTime dt;
  9332. dt.deserialize(mb);
  9333. trc.appendf("setFileAccessed(%s)",lname.str());
  9334. Owned<IUserDescriptor> udesc;
  9335. if (mb.getPos()<mb.length()) {
  9336. udesc.setown(createUserDescriptor());
  9337. udesc->deserialize(mb);
  9338. }
  9339. if (queryTransactionLogging())
  9340. transactionLog.log("%s", trc.str());
  9341. mb.clear();
  9342. StringBuffer tail;
  9343. CDfsLogicalFileName dlfn;
  9344. dlfn.set(lname);
  9345. if (!checkLogicalName(dlfn,udesc,true,false,true,"setFileAccessed on"))
  9346. return;
  9347. CScopeConnectLock sconnlock("setFileAccessed", dlfn, false, false, false, defaultTimeout);
  9348. IPropertyTree* sroot = sconnlock.conn()?sconnlock.conn()->queryRoot():NULL;
  9349. dlfn.getTail(tail);
  9350. Owned<IPropertyTree> tree = getNamedPropTree(sroot,queryDfsXmlBranchName(DXB_File),"@name",tail.str(),false);
  9351. if (tree) {
  9352. StringBuffer str;
  9353. tree->setProp("@accessed",dt.getString(str).str());
  9354. }
  9355. }
  9356. void setFileProtect(CMessageBuffer &mb,StringBuffer &trc)
  9357. {
  9358. TransactionLog transactionLog(*this, MDFS_SET_FILE_PROTECT, mb.getSender());
  9359. StringAttr lname;
  9360. StringAttr owner;
  9361. bool set;
  9362. mb.read(lname).read(owner).read(set);
  9363. trc.appendf("setFileProtect(%s,%s,%s)",lname.str(),owner.str(),set?"true":"false");
  9364. if (queryTransactionLogging())
  9365. transactionLog.log("%s", trc.str());
  9366. Owned<IUserDescriptor> udesc;
  9367. if (mb.getPos()<mb.length()) {
  9368. udesc.setown(createUserDescriptor());
  9369. udesc->deserialize(mb);
  9370. }
  9371. mb.clear();
  9372. StringBuffer tail;
  9373. CDfsLogicalFileName dlfn;
  9374. dlfn.set(lname);
  9375. if (!checkLogicalName(dlfn,udesc,true,false,true,"setFileProtect"))
  9376. return;
  9377. CScopeConnectLock sconnlock("setFileProtect", dlfn, false, false, false, defaultTimeout);
  9378. IPropertyTree* sroot = sconnlock.conn()?sconnlock.conn()->queryRoot():NULL;
  9379. dlfn.getTail(tail);
  9380. Owned<IPropertyTree> tree = getNamedPropTree(sroot,queryDfsXmlBranchName(DXB_File),"@name",tail.str(),false);
  9381. if (!tree)
  9382. tree.setown(getNamedPropTree(sroot,queryDfsXmlBranchName(DXB_SuperFile),"@name",tail.str(),false));
  9383. if (tree) {
  9384. IPropertyTree *pt = tree->queryPropTree("Attr");
  9385. if (pt)
  9386. setFileProtectTree(*pt,*owner?owner:owner,set);
  9387. }
  9388. }
  9389. void getFileTree(CMessageBuffer &mb,StringBuffer &trc)
  9390. {
  9391. TransactionLog transactionLog(*this, MDFS_GET_FILE_TREE, mb.getSender());
  9392. StringAttr lname;
  9393. mb.read(lname);
  9394. unsigned ver;
  9395. if (mb.length()<mb.getPos()+sizeof(unsigned))
  9396. ver = 0;
  9397. else {
  9398. mb.read(ver);
  9399. // this is a bit of a mess - for backward compatibility where user descriptor specified
  9400. if (ver>MDFS_GET_FILE_TREE_V2) {
  9401. mb.reset(mb.getPos()-sizeof(unsigned));
  9402. ver = 0;
  9403. }
  9404. }
  9405. trc.appendf("getFileTree(%s,%d)",lname.str(),ver);
  9406. if (queryTransactionLogging())
  9407. transactionLog.log("%s", trc.str());
  9408. Owned<IUserDescriptor> udesc;
  9409. if (mb.getPos()<mb.length()) {
  9410. udesc.setown(createUserDescriptor());
  9411. udesc->deserialize(mb);
  9412. }
  9413. mb.clear();
  9414. CDfsLogicalFileName dlfn;
  9415. dlfn.set(lname);
  9416. CDfsLogicalFileName *logicalname=&dlfn;
  9417. Owned<IDfsLogicalFileNameIterator> redmatch;
  9418. loop {
  9419. StringBuffer tail;
  9420. checkLogicalName(*logicalname,udesc,true,false,true,"getFileTree on");
  9421. CScopeConnectLock sconnlock("getFileTree", *logicalname, false, false, false, defaultTimeout);
  9422. IPropertyTree* sroot = sconnlock.conn()?sconnlock.conn()->queryRoot():NULL;
  9423. logicalname->getTail(tail);
  9424. Owned<IPropertyTree> tree = getNamedPropTree(sroot,queryDfsXmlBranchName(DXB_File),"@name",tail.str(),false);
  9425. if (tree) {
  9426. if (ver>=MDFS_GET_FILE_TREE_V2) {
  9427. Owned<IFileDescriptor> fdesc = deserializeFileDescriptorTree(tree,&queryNamedGroupStore(),IFDSF_EXCLUDE_CLUSTERNAMES);
  9428. if (fdesc) {
  9429. ver = MDFS_GET_FILE_TREE_V2;
  9430. mb.append((int)-2).append(ver);
  9431. fdesc->serialize(mb);
  9432. StringBuffer dts;
  9433. if (tree->getProp("@modified",dts)) {
  9434. CDateTime dt;
  9435. dt.setString(dts.str());
  9436. dt.serialize(mb);
  9437. }
  9438. }
  9439. else
  9440. ver = 0;
  9441. }
  9442. if (ver==0) {
  9443. tree.setown(createPTreeFromIPT(tree));
  9444. StringBuffer cname;
  9445. logicalname->getCluster(cname);
  9446. expandFileTree(tree,true,cname.str()); // resolve @node values that may not be set
  9447. tree->serialize(mb);
  9448. }
  9449. break;
  9450. }
  9451. else {
  9452. tree.setown(getNamedPropTree(sroot,queryDfsXmlBranchName(DXB_SuperFile),"@name",tail.str(),false));
  9453. if (tree) {
  9454. tree->serialize(mb);
  9455. break;
  9456. }
  9457. }
  9458. if (redmatch.get()) {
  9459. if (!redmatch->next())
  9460. break;
  9461. }
  9462. else {
  9463. redmatch.setown(queryDistributedFileDirectory().queryRedirection().getMatch(logicalname->get()));
  9464. if (!redmatch.get())
  9465. break;
  9466. if (!redmatch->first())
  9467. break;
  9468. }
  9469. logicalname = &redmatch->query();
  9470. }
  9471. }
  9472. void getGroupTree(CMessageBuffer &mb,StringBuffer &trc)
  9473. {
  9474. TransactionLog transactionLog(*this, MDFS_GET_GROUP_TREE, mb.getSender());
  9475. StringAttr gname;
  9476. mb.read(gname);
  9477. mb.clear();
  9478. trc.appendf("getGroupTree(%s)",gname.str());
  9479. if (queryTransactionLogging())
  9480. transactionLog.log("%s", trc.str());
  9481. byte ok;
  9482. CConnectLock connlock("getGroupTree",SDS_GROUPSTORE_ROOT,false,false,false,defaultTimeout);
  9483. Owned<IPropertyTree> pt = getNamedPropTree(connlock.conn->queryRoot(),"Group","@name",gname.get(),true);
  9484. if (pt) {
  9485. ok = 1;
  9486. mb.append(ok);
  9487. pt->serialize(mb);
  9488. }
  9489. else {
  9490. ok = 0;
  9491. mb.append(ok);
  9492. }
  9493. }
  9494. void processMessage(CMessageBuffer &mb)
  9495. {
  9496. CheckTime block0("CDaliDFSServer::processMessage ");
  9497. ICoven &coven=queryCoven();
  9498. StringBuffer trc;
  9499. int fn;
  9500. mb.read(fn);
  9501. try
  9502. {
  9503. switch (fn)
  9504. {
  9505. case MDFS_ITERATE_FILES:
  9506. {
  9507. iterateFiles(mb, trc);
  9508. break;
  9509. }
  9510. case MDFS_ITERATE_FILTEREDFILES: // legacy, newer clients will send MDFS_ITERATE_FILTEREDFILES2
  9511. {
  9512. iterateFilteredFiles(mb, trc);
  9513. break;
  9514. }
  9515. case MDFS_ITERATE_FILTEREDFILES2:
  9516. {
  9517. iterateFilteredFiles2(mb, trc);
  9518. break;
  9519. }
  9520. case MDFS_ITERATE_RELATIONSHIPS:
  9521. {
  9522. iterateRelationships(mb, trc);
  9523. break;
  9524. }
  9525. case MDFS_GET_FILE_TREE:
  9526. {
  9527. getFileTree(mb, trc);
  9528. break;
  9529. }
  9530. case MDFS_GET_GROUP_TREE:
  9531. {
  9532. getGroupTree(mb, trc);
  9533. break;
  9534. }
  9535. case MDFS_SET_FILE_ACCESSED:
  9536. {
  9537. setFileAccessed(mb, trc);
  9538. break;
  9539. }
  9540. case MDFS_SET_FILE_PROTECT:
  9541. {
  9542. setFileProtect(mb, trc);
  9543. break;
  9544. }
  9545. default:
  9546. {
  9547. mb.clear();
  9548. break;
  9549. }
  9550. }
  9551. }
  9552. catch (IException *e)
  9553. {
  9554. int err=-1; // exception marker
  9555. mb.clear().append(err);
  9556. serializeException(e, mb);
  9557. e->Release();
  9558. }
  9559. coven.reply(mb);
  9560. if (block0.slow())
  9561. {
  9562. SocketEndpoint ep = mb.getSender();
  9563. ep.getUrlStr(block0.appendMsg(trc).append(" from "));
  9564. }
  9565. }
  9566. void nodeDown(rank_t rank)
  9567. {
  9568. assertex(!"TBD");
  9569. }
  9570. // CTransactionLogTracker
  9571. virtual StringBuffer &getCmdText(unsigned cmd, StringBuffer &ret) const
  9572. {
  9573. switch (cmd)
  9574. {
  9575. case MDFS_ITERATE_FILES:
  9576. return ret.append("MDFS_ITERATE_FILES");
  9577. case MDFS_ITERATE_FILTEREDFILES:
  9578. return ret.append("MDFS_ITERATE_FILTEREDFILES");
  9579. case MDFS_ITERATE_FILTEREDFILES2:
  9580. return ret.append("MDFS_ITERATE_FILTEREDFILES2");
  9581. case MDFS_ITERATE_RELATIONSHIPS:
  9582. return ret.append("MDFS_ITERATE_RELATIONSHIPS");
  9583. case MDFS_GET_FILE_TREE:
  9584. return ret.append("MDFS_GET_FILE_TREE");
  9585. case MDFS_GET_GROUP_TREE:
  9586. return ret.append("MDFS_GET_GROUP_TREE");
  9587. case MDFS_SET_FILE_ACCESSED:
  9588. return ret.append("MDFS_SET_FILE_ACCESSED");
  9589. case MDFS_SET_FILE_PROTECT:
  9590. return ret.append("MDFS_SET_FILE_PROTECT");
  9591. default:
  9592. return ret.append("UNKNOWN");
  9593. }
  9594. }
  9595. // IExceptionHandler impl.
  9596. virtual bool fireException(IException *e)
  9597. {
  9598. EXCLOG(e, "CDaliDFSServer exception");
  9599. return true;
  9600. }
  9601. } *daliDFSServer = NULL;
  9602. IDFAttributesIterator *CDistributedFileDirectory::getDFAttributesIterator(const char *wildname, IUserDescriptor *user, bool recursive, bool includesuper,INode *foreigndali,unsigned foreigndalitimeout)
  9603. {
  9604. if (!wildname||!*wildname||(strcmp(wildname,"*")==0)) {
  9605. recursive = true;
  9606. }
  9607. CMessageBuffer mb;
  9608. mb.append((int)MDFS_ITERATE_FILES).append(wildname).append(recursive).append("").append(includesuper); // "" is legacy
  9609. if (user)
  9610. user->serialize(mb);
  9611. #ifdef NULL_DALIUSER_STACKTRACE
  9612. else
  9613. {
  9614. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp getDFAttributesIterator() line %d",__LINE__);
  9615. PrintStackReport();
  9616. }
  9617. #endif
  9618. if (foreigndali)
  9619. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  9620. else
  9621. queryCoven().sendRecv(mb,RANK_RANDOM,MPTAG_DFS_REQUEST);
  9622. checkDfsReplyException(mb);
  9623. return new CDFAttributeIterator(mb);
  9624. }
  9625. IDFScopeIterator *CDistributedFileDirectory::getScopeIterator(IUserDescriptor *user, const char *basescope, bool recursive,bool includeempty)
  9626. {
  9627. return new CDFScopeIterator(this,basescope,recursive,includeempty,defaultTimeout);
  9628. }
  9629. static bool isValidLFN(const char *lfn)
  9630. { // bit OTT
  9631. if (!lfn||!*lfn||(strcmp(lfn,".")==0))
  9632. return false;
  9633. StringBuffer tmp(".::");
  9634. tmp.append(lfn);
  9635. CDfsLogicalFileName dlfn;
  9636. return dlfn.setValidate(tmp.str());
  9637. }
  9638. bool CDistributedFileDirectory::loadScopeContents(const char *scopelfn,
  9639. StringArray *scopes,
  9640. StringArray *supers,
  9641. StringArray *files,
  9642. bool includeemptyscopes
  9643. )
  9644. {
  9645. StringBuffer baseq;
  9646. if (scopelfn&&*scopelfn) {
  9647. if (memcmp(scopelfn,".::",3)==0) // scopes not in .
  9648. scopelfn += 3;
  9649. StringBuffer tmp(scopelfn);
  9650. if (tmp.trim().length()) {
  9651. tmp.append("::.");
  9652. CDfsLogicalFileName dlfn;
  9653. if (!dlfn.setValidate(tmp.str()))
  9654. return false;
  9655. dlfn.makeScopeQuery(baseq,false);
  9656. }
  9657. }
  9658. CConnectLock connlock("CDistributedFileDirectory::loadScopeContents",querySdsFilesRoot(),false,false,false,defaultTimeout);
  9659. if (!connlock.conn)
  9660. return false;
  9661. IPropertyTree *root = connlock.conn->queryRoot();
  9662. if (!root)
  9663. return false;
  9664. if (baseq.length()) {
  9665. root = root->queryPropTree(baseq.str());
  9666. if (!root)
  9667. return false;
  9668. }
  9669. Owned<IPropertyTreeIterator> iter;
  9670. if (scopes) {
  9671. iter.setown(root->getElements(queryDfsXmlBranchName(DXB_Scope)));
  9672. ForEach(*iter) {
  9673. IPropertyTree &ct = iter->query();
  9674. if (includeemptyscopes||!recursiveCheckEmptyScope(ct)) {
  9675. StringBuffer name;
  9676. if (ct.getProp("@name",name)&&name.trim().length()&&isValidLFN(name.str()))
  9677. scopes->append(name.str());
  9678. }
  9679. }
  9680. }
  9681. if (!supers&&!files)
  9682. return true;
  9683. if (baseq.length()==0) { // bit odd but top level files are in '.'
  9684. CDfsLogicalFileName dlfn;
  9685. dlfn.set(".",".");
  9686. dlfn.makeScopeQuery(baseq,false);
  9687. root = root->queryPropTree(baseq.str());
  9688. if (!root)
  9689. return true;
  9690. }
  9691. if (supers) {
  9692. iter.setown(root->getElements(queryDfsXmlBranchName(DXB_SuperFile)));
  9693. ForEach(*iter) {
  9694. IPropertyTree &ct = iter->query();
  9695. StringBuffer name;
  9696. if (ct.getProp("@name",name)&&name.trim().length()&&isValidLFN(name.str()))
  9697. supers->append(name.str());
  9698. }
  9699. }
  9700. if (files) {
  9701. iter.setown(root->getElements(queryDfsXmlBranchName(DXB_File)));
  9702. ForEach(*iter) {
  9703. StringBuffer name;
  9704. IPropertyTree &ct = iter->query();
  9705. if (ct.getProp("@name",name)&&name.trim().length()&&isValidLFN(name.str()))
  9706. files->append(name.str());
  9707. }
  9708. }
  9709. return true;
  9710. }
  9711. void CDistributedFileDirectory::setFileAccessed(CDfsLogicalFileName &dlfn,IUserDescriptor *user, const CDateTime &dt, const INode *foreigndali,unsigned foreigndalitimeout)
  9712. {
  9713. // this accepts either a foreign dali node or a foreign lfn
  9714. Owned<INode> fnode;
  9715. SocketEndpoint ep;
  9716. const char *lname;
  9717. if (dlfn.isForeign()) {
  9718. if (!dlfn.getEp(ep))
  9719. throw MakeStringException(-1,"cannot resolve dali ip in foreign file name (%s)",dlfn.get());
  9720. fnode.setown(createINode(ep));
  9721. foreigndali = fnode;
  9722. lname = dlfn.get(true);
  9723. }
  9724. else if (dlfn.isExternal())
  9725. return;
  9726. else
  9727. lname = dlfn.get();
  9728. if (isLocalDali(foreigndali))
  9729. foreigndali = NULL;
  9730. CMessageBuffer mb;
  9731. mb.append((int)MDFS_SET_FILE_ACCESSED).append(lname);
  9732. dt.serialize(mb);
  9733. if (user)
  9734. user->serialize(mb);
  9735. #ifdef NULL_DALIUSER_STACKTRACE
  9736. else
  9737. {
  9738. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp setFileAccessed() line %d",__LINE__);
  9739. PrintStackReport();
  9740. }
  9741. #endif
  9742. if (foreigndali)
  9743. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  9744. else
  9745. queryCoven().sendRecv(mb,RANK_RANDOM,MPTAG_DFS_REQUEST);
  9746. checkDfsReplyException(mb);
  9747. }
  9748. void CDistributedFileDirectory::setFileProtect(CDfsLogicalFileName &dlfn,IUserDescriptor *user, const char *owner, bool set, const INode *foreigndali,unsigned foreigndalitimeout)
  9749. {
  9750. // this accepts either a foreign dali node or a foreign lfn
  9751. Owned<INode> fnode;
  9752. SocketEndpoint ep;
  9753. const char *lname;
  9754. if (dlfn.isForeign()) {
  9755. if (!dlfn.getEp(ep))
  9756. throw MakeStringException(-1,"cannot resolve dali ip in foreign file name (%s)",dlfn.get());
  9757. fnode.setown(createINode(ep));
  9758. foreigndali = fnode;
  9759. lname = dlfn.get(true);
  9760. }
  9761. else if (dlfn.isExternal())
  9762. return;
  9763. else
  9764. lname = dlfn.get();
  9765. if (isLocalDali(foreigndali))
  9766. foreigndali = NULL;
  9767. CMessageBuffer mb;
  9768. if (!owner)
  9769. owner = "";
  9770. mb.append((int)MDFS_SET_FILE_PROTECT).append(lname).append(owner).append(set);
  9771. if (user)
  9772. user->serialize(mb);
  9773. #ifdef NULL_DALIUSER_STACKTRACE
  9774. else
  9775. {
  9776. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp setFileProtect() line %d",__LINE__);
  9777. PrintStackReport();
  9778. }
  9779. #endif
  9780. if (foreigndali)
  9781. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  9782. else
  9783. queryCoven().sendRecv(mb,RANK_RANDOM,MPTAG_DFS_REQUEST);
  9784. checkDfsReplyException(mb);
  9785. }
  9786. IPropertyTree *CDistributedFileDirectory::getFileTree(const char *lname, IUserDescriptor *user, const INode *foreigndali,unsigned foreigndalitimeout, bool expandnodes, bool appendForeign)
  9787. {
  9788. // this accepts either a foreign dali node or a foreign lfn
  9789. Owned<INode> fnode;
  9790. CDfsLogicalFileName dlfn;
  9791. SocketEndpoint ep;
  9792. dlfn.set(lname);
  9793. if (dlfn.isForeign()) {
  9794. if (!dlfn.getEp(ep))
  9795. throw MakeStringException(-1,"cannot resolve dali ip in foreign file name (%s)",lname);
  9796. fnode.setown(createINode(ep));
  9797. foreigndali = fnode;
  9798. lname = dlfn.get(true);
  9799. }
  9800. if (isLocalDali(foreigndali))
  9801. foreigndali = NULL;
  9802. CMessageBuffer mb;
  9803. mb.append((int)MDFS_GET_FILE_TREE).append(lname);
  9804. mb.append(MDFS_GET_FILE_TREE_V2);
  9805. if (user)
  9806. user->serialize(mb);
  9807. #ifdef NULL_DALIUSER_STACKTRACE
  9808. else
  9809. {
  9810. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp getFileTree() line %d",__LINE__);
  9811. PrintStackReport();
  9812. }
  9813. #endif
  9814. if (foreigndali)
  9815. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  9816. else
  9817. queryCoven().sendRecv(mb,RANK_RANDOM,MPTAG_DFS_REQUEST);
  9818. checkDfsReplyException(mb);
  9819. if (mb.length()==0)
  9820. return NULL;
  9821. unsigned ver = 0;
  9822. if ((mb.length()>=sizeof(int))&&(*(int *)mb.bufferBase()) == -2) { // version indicator
  9823. int i;
  9824. mb.read(i);
  9825. mb.read(ver);
  9826. }
  9827. Owned<IPropertyTree> ret;
  9828. if (ver==0)
  9829. ret.setown(createPTree(mb));
  9830. else {
  9831. Owned<IFileDescriptor> fdesc;
  9832. CDateTime modified;
  9833. if (ver==MDFS_GET_FILE_TREE_V2) { // no longer in use but support for back compatibility
  9834. fdesc.setown(deserializeFileDescriptor(mb));
  9835. if (mb.remaining()>0)
  9836. modified.deserialize(mb);
  9837. }
  9838. else
  9839. throw MakeStringException(-1,"Unknown GetFileTree serialization version %d",ver);
  9840. ret.setown(createPTree(queryDfsXmlBranchName(DXB_File)));
  9841. fdesc->serializeTree(*ret,expandnodes?0:CPDMSF_packParts);
  9842. if (!modified.isNull()) {
  9843. StringBuffer dts;
  9844. ret->setProp("@modified",modified.getString(dts).str());
  9845. }
  9846. }
  9847. if (expandnodes) {
  9848. StringBuffer cname;
  9849. dlfn.getCluster(cname);
  9850. expandFileTree(ret,true,cname.str());
  9851. CDfsLogicalFileName dlfn2;
  9852. dlfn2.set(dlfn);
  9853. if (foreigndali)
  9854. dlfn2.setForeign(foreigndali->endpoint(),false);
  9855. ret->setProp("OrigName",dlfn.get());
  9856. }
  9857. if (foreigndali && appendForeign)
  9858. resolveForeignFiles(ret,foreigndali);
  9859. return ret.getClear();
  9860. }
  9861. IFileDescriptor *CDistributedFileDirectory::getFileDescriptor(const char *lname,IUserDescriptor *user,const INode *foreigndali,unsigned foreigndalitimeout)
  9862. {
  9863. Owned<IPropertyTree> tree = getFileTree(lname,user,foreigndali,foreigndalitimeout,false);
  9864. if (!tree)
  9865. return NULL;
  9866. if (strcmp(tree->queryName(),queryDfsXmlBranchName(DXB_SuperFile))==0) {
  9867. CDfsLogicalFileName dlfn;
  9868. dlfn.set(lname);
  9869. Owned<CDistributedSuperFile> sfile = new CDistributedSuperFile(this,tree, dlfn, user);
  9870. return sfile->getFileDescriptor(NULL);
  9871. }
  9872. if (strcmp(tree->queryName(),queryDfsXmlBranchName(DXB_File))!=0)
  9873. return NULL; // what is it?
  9874. IFileDescriptor * fdesc = deserializeFileDescriptorTree(tree,&queryNamedGroupStore(),0);
  9875. if (fdesc)
  9876. fdesc->setTraceName(lname);
  9877. return fdesc;
  9878. }
  9879. IDistributedFile *CDistributedFileDirectory::getFile(const char *lname,IUserDescriptor *user,const INode *foreigndali,unsigned foreigndalitimeout)
  9880. {
  9881. Owned<IPropertyTree> tree = getFileTree(lname,user,foreigndali,foreigndalitimeout,false);
  9882. if (!tree)
  9883. return NULL;
  9884. if (strcmp(tree->queryName(),queryDfsXmlBranchName(DXB_SuperFile))==0) {
  9885. CDfsLogicalFileName dlfn;
  9886. dlfn.set(lname);
  9887. return new CDistributedSuperFile(this,tree, dlfn, user);
  9888. }
  9889. if (strcmp(tree->queryName(),queryDfsXmlBranchName(DXB_File))!=0)
  9890. return NULL; // what is it?
  9891. Owned<IFileDescriptor> fdesc = deserializeFileDescriptorTree(tree,&queryNamedGroupStore(),IFDSF_FOREIGN_GROUP);
  9892. if (!fdesc)
  9893. return NULL;
  9894. fdesc->setTraceName(lname);
  9895. CDistributedFile *ret = new CDistributedFile(this, fdesc, user, false);
  9896. ret->setLogicalName(lname);
  9897. const char *date = tree->queryProp("@modified");
  9898. if (ret) {
  9899. CDateTime dt;
  9900. if (date&&*date)
  9901. dt.setString(date);
  9902. ret->setModificationTime(dt);
  9903. }
  9904. return ret;
  9905. }
  9906. static void addForeignName(IPropertyTree &t,const INode *foreigndali,const char *attr)
  9907. {
  9908. StringBuffer sb;
  9909. const char *name = t.queryProp(attr);
  9910. if (!name||!*name)
  9911. return;
  9912. CDfsLogicalFileName logicalname;
  9913. logicalname.set(name);
  9914. if (logicalname.isExternal()||logicalname.isQuery())
  9915. return; // how did that get in here?
  9916. if (logicalname.isForeign()) {
  9917. SocketEndpoint ep;
  9918. Owned<INode> fd = createINode(ep);
  9919. if (logicalname.getEp(ep)&&isLocalDali(fd)) { // see if pointing back at self
  9920. logicalname.clearForeign();
  9921. t.setProp(attr,logicalname.get());
  9922. }
  9923. }
  9924. else if (foreigndali) {
  9925. logicalname.setForeign(foreigndali->endpoint(),false);
  9926. t.setProp(attr,logicalname.get());
  9927. }
  9928. }
  9929. void CDistributedFileDirectory::resolveForeignFiles(IPropertyTree *tree,const INode *foreigndali)
  9930. {
  9931. if (!tree||!foreigndali)
  9932. return;
  9933. // now add to all sub files
  9934. Owned<IPropertyTreeIterator> pe = tree->getElements("SubFile");
  9935. ForEach(*pe)
  9936. addForeignName(pe->query(),foreigndali,"@name");
  9937. pe.setown(tree->getElements("SuperOwner"));
  9938. ForEach(*pe)
  9939. addForeignName(pe->query(),foreigndali,"@name");
  9940. // do origname?
  9941. }
  9942. SecAccessFlags CDistributedFileDirectory::getFilePermissions(const char *lname,IUserDescriptor *user,unsigned auditflags)
  9943. {
  9944. CDfsLogicalFileName dlfn;
  9945. dlfn.set(lname);
  9946. StringBuffer scopes;
  9947. dlfn.getScopes(scopes);
  9948. return getScopePermissions(scopes.str(),user,auditflags);
  9949. }
  9950. SecAccessFlags CDistributedFileDirectory::getNodePermissions(const IpAddress &ip,IUserDescriptor *user,unsigned auditflags)
  9951. {
  9952. if (ip.isNull())
  9953. return SecAccess_None;
  9954. CDfsLogicalFileName dlfn;
  9955. SocketEndpoint ep(0,ip);
  9956. dlfn.setExternal(ep,"/x");
  9957. StringBuffer scopes;
  9958. dlfn.getScopes(scopes,true);
  9959. return getScopePermissions(scopes.str(),user,auditflags);
  9960. }
  9961. SecAccessFlags CDistributedFileDirectory::getFDescPermissions(IFileDescriptor *fdesc,IUserDescriptor *user,unsigned auditflags)
  9962. {
  9963. // this checks have access to the nodes in the file descriptor
  9964. SecAccessFlags retPerms = SecAccess_Full;
  9965. unsigned np = fdesc->numParts();
  9966. for (unsigned i=0;i<np;i++) {
  9967. INode *node = fdesc->queryNode(i);
  9968. if (node) {
  9969. bool multi = false;
  9970. RemoteMultiFilename mfn;
  9971. unsigned n = 1;
  9972. if (fdesc->isMulti()) {
  9973. fdesc->getMultiFilename(i,0,mfn);
  9974. multi = true;
  9975. n = mfn.ordinality();
  9976. }
  9977. for (unsigned j = 0;j<n;j++) {
  9978. RemoteFilename rfn;
  9979. if (multi) {
  9980. rfn.set(mfn.item(j));
  9981. }
  9982. else
  9983. fdesc->getFilename(i,0,rfn);
  9984. StringBuffer localpath;
  9985. rfn.getLocalPath(localpath);
  9986. // translate wild cards
  9987. for (unsigned k=0;k<localpath.length();k++)
  9988. if ((localpath.charAt(k)=='?')||(localpath.charAt(k)=='*'))
  9989. localpath.setCharAt(k,'_');
  9990. CDfsLogicalFileName dlfn;
  9991. dlfn.setExternal(rfn.queryEndpoint(),localpath.str());
  9992. StringBuffer scopes;
  9993. dlfn.getScopes(scopes);
  9994. SecAccessFlags perm = getScopePermissions(scopes.str(),user,auditflags);
  9995. if (perm < retPerms) {
  9996. retPerms = perm;
  9997. if (retPerms == SecAccess_None)
  9998. return SecAccess_None;
  9999. }
  10000. }
  10001. }
  10002. }
  10003. return retPerms;
  10004. }
  10005. void CDistributedFileDirectory::setDefaultUser(IUserDescriptor *user)
  10006. {
  10007. if (user)
  10008. defaultudesc.set(user);
  10009. else
  10010. defaultudesc.setown(createUserDescriptor());
  10011. }
  10012. IUserDescriptor* CDistributedFileDirectory::queryDefaultUser()
  10013. {
  10014. return defaultudesc.get();
  10015. }
  10016. void CDistributedFileDirectory::setDefaultPreferredClusters(const char *clusters)
  10017. {
  10018. defprefclusters.set(clusters);
  10019. }
  10020. bool removePhysicalFiles(IGroup *grp,const char *_filemask,unsigned short port,ClusterPartDiskMapSpec &mspec,IMultiException *mexcept)
  10021. {
  10022. // TBD this won't remove repeated parts
  10023. PROGLOG("removePhysicalFiles(%s)",_filemask);
  10024. if (!isAbsolutePath(_filemask))
  10025. throw MakeStringException(-1,"removePhysicalFiles: Filename %s must be complete path",_filemask);
  10026. size32_t l = strlen(_filemask);
  10027. while (l&&isdigit(_filemask[l-1]))
  10028. l--;
  10029. unsigned width=0;
  10030. if (l&&(_filemask[l-1]=='_'))
  10031. width = atoi(_filemask+l);
  10032. if (!width)
  10033. width = grp->ordinality();
  10034. CriticalSection errcrit;
  10035. class casyncfor: public CAsyncFor
  10036. {
  10037. unsigned short port;
  10038. CriticalSection &errcrit;
  10039. IMultiException *mexcept;
  10040. unsigned width;
  10041. StringAttr filemask;
  10042. IGroup *grp;
  10043. ClusterPartDiskMapSpec &mspec;
  10044. public:
  10045. bool ok;
  10046. casyncfor(IGroup *_grp,const char *_filemask,unsigned _width,unsigned short _port,ClusterPartDiskMapSpec &_mspec,IMultiException *_mexcept,CriticalSection &_errcrit)
  10047. : mspec(_mspec),filemask(_filemask),errcrit(_errcrit)
  10048. {
  10049. grp = _grp;
  10050. port = _port;
  10051. ok = true;
  10052. mexcept = _mexcept;
  10053. width = _width;
  10054. }
  10055. void Do(unsigned i)
  10056. {
  10057. for (unsigned copy = 0; copy < 2; copy++) // ** TBD
  10058. {
  10059. RemoteFilename rfn;
  10060. constructPartFilename(grp,i+1,width,NULL,filemask,"",copy>0,mspec,rfn);
  10061. if (port)
  10062. rfn.setPort(port); // if daliservix
  10063. Owned<IFile> partfile = createIFile(rfn);
  10064. StringBuffer eps;
  10065. try
  10066. {
  10067. unsigned start = msTick();
  10068. #if 1
  10069. if (partfile->remove()) {
  10070. PROGLOG("Removed '%s'",partfile->queryFilename());
  10071. unsigned t = msTick()-start;
  10072. if (t>5*1000)
  10073. LOG(MCwarning, unknownJob, "Removing %s from %s took %ds", partfile->queryFilename(), rfn.queryEndpoint().getUrlStr(eps).str(), t/1000);
  10074. }
  10075. else
  10076. LOG(MCwarning, unknownJob, "Failed to remove file part %s from %s", partfile->queryFilename(),rfn.queryEndpoint().getUrlStr(eps).str());
  10077. #else
  10078. if (partfile->exists())
  10079. PROGLOG("Would remove '%s'",partfile->queryFilename());
  10080. #endif
  10081. }
  10082. catch (IException *e)
  10083. {
  10084. CriticalBlock block(errcrit);
  10085. if (mexcept)
  10086. mexcept->append(*e);
  10087. else {
  10088. StringBuffer s("Failed to remove file part ");
  10089. s.append(partfile->queryFilename()).append(" from ");
  10090. rfn.queryEndpoint().getUrlStr(s);
  10091. EXCLOG(e, s.str());
  10092. e->Release();
  10093. }
  10094. ok = false;
  10095. }
  10096. }
  10097. }
  10098. } afor(grp,_filemask,width,port,mspec,mexcept,errcrit);
  10099. afor.For(width,10,false,true);
  10100. return afor.ok;
  10101. }
  10102. IDaliServer *createDaliDFSServer(IPropertyTree *config)
  10103. {
  10104. assertex(!daliDFSServer); // initialization problem
  10105. daliDFSServer = new CDaliDFSServer(config);
  10106. return daliDFSServer;
  10107. }
  10108. IDistributedFileTransaction *createDistributedFileTransaction(IUserDescriptor *user, ICodeContext *ctx)
  10109. {
  10110. return new CDistributedFileTransaction(user, NULL, ctx);
  10111. }
  10112. static void encodeCompareResult(DistributedFileCompareResult &ret,bool differs,CDateTime &newestdt1,CDateTime &newestdt2)
  10113. {
  10114. if (ret!=DFS_COMPARE_RESULT_FAILURE) {
  10115. int cmp = 0;
  10116. if (!newestdt1.isNull()) {
  10117. if (!newestdt2.isNull()) {
  10118. int cmp = newestdt1.compare(newestdt2,false);
  10119. if (cmp>=0)
  10120. ret = DFS_COMPARE_RESULT_SAME_NEWER;
  10121. else
  10122. ret = DFS_COMPARE_RESULT_SAME_OLDER;
  10123. }
  10124. else
  10125. ret = DFS_COMPARE_RESULT_SAME_NEWER;
  10126. }
  10127. else if (!newestdt2.isNull())
  10128. ret = DFS_COMPARE_RESULT_SAME_OLDER;
  10129. if (differs) {
  10130. if (ret==DFS_COMPARE_RESULT_SAME_OLDER) // ok they could be same but seems rather unlikely!
  10131. ret = DFS_COMPARE_RESULT_DIFFER_OLDER;
  10132. else
  10133. ret = DFS_COMPARE_RESULT_DIFFER_NEWER;
  10134. }
  10135. }
  10136. }
  10137. DistributedFileCompareResult CDistributedFileDirectory::fileCompare(const char *lfn1,const char *lfn2,DistributedFileCompareMode mode,StringBuffer &errstr,IUserDescriptor *user)
  10138. {
  10139. DistributedFileCompareResult ret = DFS_COMPARE_RESULT_SAME;
  10140. StringBuffer msg;
  10141. try
  10142. {
  10143. Owned<IDistributedFile> file1 = lookup(lfn1, user, false, false, false, NULL, defaultTimeout);
  10144. Owned<IDistributedFile> file2 = lookup(lfn2, user, false, false, false, NULL, defaultTimeout);
  10145. if (!file1)
  10146. {
  10147. errstr.appendf("File %s not found",lfn1);
  10148. ret = DFS_COMPARE_RESULT_FAILURE;
  10149. }
  10150. else if (!file2)
  10151. {
  10152. errstr.appendf("File %s not found",lfn2);
  10153. ret = DFS_COMPARE_RESULT_FAILURE;
  10154. }
  10155. else
  10156. {
  10157. unsigned np = file1->numParts();
  10158. if (np!=file2->numParts())
  10159. {
  10160. errstr.appendf("Files %s and %s have differing number of parts",lfn1,lfn2);
  10161. ret = DFS_COMPARE_RESULT_FAILURE;
  10162. }
  10163. else
  10164. {
  10165. CDateTime newestdt1;
  10166. CDateTime newestdt2;
  10167. bool differs = false;
  10168. class casyncfor: public CAsyncFor
  10169. {
  10170. CriticalSection crit;
  10171. DistributedFileCompareResult &ret;
  10172. IDistributedFile *file1;
  10173. IDistributedFile *file2;
  10174. const char *lfn1;
  10175. const char *lfn2;
  10176. StringBuffer &errstr;
  10177. DistributedFileCompareMode mode;
  10178. bool physdatesize;
  10179. CDateTime &newestdt1;
  10180. CDateTime &newestdt2;
  10181. bool &differs;
  10182. public:
  10183. casyncfor(const char *_lfn1,const char *_lfn2,IDistributedFile *_file1,IDistributedFile *_file2,DistributedFileCompareMode _mode,DistributedFileCompareResult &_ret,StringBuffer &_errstr,
  10184. CDateTime &_newestdt1,CDateTime &_newestdt2,bool &_differs)
  10185. : ret(_ret), errstr(_errstr),newestdt1(_newestdt1),newestdt2(_newestdt2),differs(_differs)
  10186. {
  10187. lfn1 = _lfn1;
  10188. lfn2 = _lfn2;
  10189. file1 = _file1;
  10190. file2 = _file2;
  10191. mode = _mode;
  10192. physdatesize = (mode==DFS_COMPARE_FILES_PHYSICAL)||(mode==DFS_COMPARE_FILES_PHYSICAL_CRCS);
  10193. }
  10194. void Do(unsigned p)
  10195. {
  10196. CriticalBlock block (crit);
  10197. StringBuffer msg;
  10198. Owned<IDistributedFilePart> part1 = file1->getPart(p);
  10199. Owned<IDistributedFilePart> part2 = file2->getPart(p);
  10200. CDateTime dt1;
  10201. RemoteFilename rfn;
  10202. bool ok;
  10203. {
  10204. CriticalUnblock unblock(crit);
  10205. ok = part1->getModifiedTime(true,physdatesize,dt1);
  10206. }
  10207. if (!ok) {
  10208. if (errstr.length()==0) {
  10209. errstr.append("Could not find ");
  10210. part1->getFilename(rfn);
  10211. rfn.getPath(errstr);
  10212. }
  10213. ret = DFS_COMPARE_RESULT_FAILURE;
  10214. }
  10215. CDateTime dt2;
  10216. {
  10217. CriticalUnblock unblock(crit);
  10218. ok = part2->getModifiedTime(true,physdatesize,dt2);
  10219. }
  10220. if (!ok) {
  10221. if (errstr.length()==0) {
  10222. errstr.append("Could not find ");
  10223. part2->getFilename(rfn);
  10224. rfn.getPath(errstr);
  10225. }
  10226. ret = DFS_COMPARE_RESULT_FAILURE;
  10227. }
  10228. if (ret!=DFS_COMPARE_RESULT_FAILURE) {
  10229. int cmp = dt1.compare(dt2,false);
  10230. if (cmp>0) {
  10231. if (newestdt1.isNull()||(dt1.compare(newestdt1,false)>0))
  10232. newestdt1.set(dt1);
  10233. }
  10234. else if (cmp<0) {
  10235. if (newestdt2.isNull()||(dt2.compare(newestdt2,false)>0))
  10236. newestdt2.set(dt2);
  10237. }
  10238. }
  10239. if ((ret!=DFS_COMPARE_RESULT_FAILURE)&&!differs) {
  10240. offset_t sz1;
  10241. offset_t sz2;
  10242. {
  10243. CriticalUnblock unblock(crit);
  10244. sz1 = part1->getFileSize(true,physdatesize);
  10245. sz2 = part2->getFileSize(true,physdatesize);
  10246. }
  10247. if (sz1!=sz2)
  10248. differs = true;
  10249. }
  10250. if ((ret!=DFS_COMPARE_RESULT_FAILURE)&&!differs) {
  10251. unsigned crc1;
  10252. unsigned crc2;
  10253. if (mode==DFS_COMPARE_FILES_PHYSICAL_CRCS) {
  10254. {
  10255. CriticalUnblock unblock(crit);
  10256. crc1 = part1->getPhysicalCrc();
  10257. crc2 = part2->getPhysicalCrc();
  10258. }
  10259. }
  10260. else {
  10261. if (!part1->getCrc(crc1))
  10262. return;
  10263. if (!part2->getCrc(crc2))
  10264. return;
  10265. }
  10266. if (crc1!=crc2)
  10267. differs = true;
  10268. }
  10269. }
  10270. } afor(lfn1,lfn2,file1,file2,mode,ret,errstr,newestdt1,newestdt2,differs);
  10271. afor.For(np,20,false,false);
  10272. encodeCompareResult(ret,differs,newestdt1,newestdt2);
  10273. }
  10274. }
  10275. }
  10276. catch (IException *e) {
  10277. if (errstr.length()==0)
  10278. e->errorMessage(errstr);
  10279. else
  10280. EXCLOG(e,"CDistributedFileDirectory::fileCompare");
  10281. e->Release();
  10282. ret = DFS_COMPARE_RESULT_FAILURE;
  10283. }
  10284. return ret;
  10285. }
  10286. bool CDistributedFileDirectory::filePhysicalVerify(const char *lfn, IUserDescriptor *user, bool includecrc, StringBuffer &errstr)
  10287. {
  10288. bool differs = false;
  10289. Owned<IDistributedFile> file = lookup(lfn, user, false, false, false, NULL, defaultTimeout);
  10290. if (!file)
  10291. {
  10292. errstr.appendf("Could not find file: %s",lfn);
  10293. return false;
  10294. }
  10295. try
  10296. {
  10297. unsigned np = file->numParts();
  10298. class casyncfor: public CAsyncFor
  10299. {
  10300. CriticalSection crit;
  10301. IDistributedFile *file;
  10302. const char *lfn;
  10303. StringBuffer &errstr;
  10304. bool includecrc;
  10305. bool &differs;
  10306. unsigned defaultTimeout;
  10307. public:
  10308. casyncfor(const char *_lfn,IDistributedFile *_file,StringBuffer &_errstr, bool _includecrc,
  10309. bool &_differs, unsigned _defaultTimeout)
  10310. : errstr(_errstr), differs(_differs)
  10311. {
  10312. lfn = _lfn;
  10313. file = _file;
  10314. includecrc = _includecrc;
  10315. defaultTimeout = _defaultTimeout;
  10316. }
  10317. void Do(unsigned p)
  10318. {
  10319. CriticalBlock block (crit);
  10320. StringBuffer msg;
  10321. Owned<IDistributedFilePart> part = file->getPart(p);
  10322. CDateTime dt1; // logical
  10323. CDateTime dt2; // physical
  10324. RemoteFilename rfn;
  10325. bool ok;
  10326. bool nological = !part->getModifiedTime(false,false,dt1);
  10327. {
  10328. CriticalUnblock unblock(crit);
  10329. ok = part->getModifiedTime(true,true,dt2);
  10330. }
  10331. if (!ok) {
  10332. if (errstr.length()==0) {
  10333. errstr.append("Could not find part file: ");
  10334. part->getFilename(rfn);
  10335. rfn.getPath(errstr);
  10336. }
  10337. differs = true;
  10338. }
  10339. if (!differs&&!includecrc) {
  10340. if (nological) {
  10341. StringBuffer str;
  10342. // TODO: Create DistributedFilePropertyLock for parts
  10343. part->lockProperties(defaultTimeout);
  10344. part->queryAttributes().setProp("@modified",dt2.getString(str).str());
  10345. part->unlockProperties();
  10346. }
  10347. else {
  10348. if (dt1.compare(dt2,false)!=0) {
  10349. if (errstr.length()==0) {
  10350. errstr.append("Modified time differs for: ");
  10351. part->getFilename(rfn);
  10352. rfn.getPath(errstr);
  10353. }
  10354. differs = true;
  10355. }
  10356. }
  10357. }
  10358. if (!differs) {
  10359. offset_t sz1;
  10360. offset_t sz2;
  10361. {
  10362. CriticalUnblock unblock(crit);
  10363. sz1 = part->getFileSize(false,false);
  10364. sz2 = part->getFileSize(true,true);
  10365. }
  10366. if (sz1!=sz2) {
  10367. if (sz1==(offset_t)-1) {
  10368. // TODO: Create DistributedFilePropertyLock for parts
  10369. part->lockProperties(defaultTimeout);
  10370. part->queryAttributes().setPropInt64("@size",sz2);
  10371. part->unlockProperties();
  10372. }
  10373. else if (sz2!=(offset_t)-1) {
  10374. if (errstr.length()==0) {
  10375. errstr.append("File size differs for: ");
  10376. part->getFilename(rfn);
  10377. rfn.getPath(errstr);
  10378. }
  10379. differs = true;
  10380. }
  10381. }
  10382. }
  10383. if (!differs&&includecrc) {
  10384. unsigned crc1;
  10385. unsigned crc2;
  10386. {
  10387. CriticalUnblock unblock(crit);
  10388. crc2 = part->getPhysicalCrc();
  10389. }
  10390. if (!part->getCrc(crc1)) {
  10391. // TODO: Create DistributedFilePropertyLock for parts
  10392. part->lockProperties(defaultTimeout);
  10393. part->queryAttributes().setPropInt64("@fileCrc",(unsigned)crc2);
  10394. part->unlockProperties();
  10395. }
  10396. else if (crc1!=crc2) {
  10397. if (errstr.length()==0) {
  10398. errstr.append("File CRC differs for: ");
  10399. part->getFilename(rfn);
  10400. rfn.getPath(errstr);
  10401. }
  10402. differs = true;
  10403. }
  10404. }
  10405. }
  10406. } afor(lfn,file,errstr,includecrc,differs,defaultTimeout);
  10407. afor.For(np,10,false,false);
  10408. }
  10409. catch (IException *e) {
  10410. if (errstr.length()==0)
  10411. e->errorMessage(errstr);
  10412. else
  10413. EXCLOG(e,"CDistributedFileDirectory::fileCompare");
  10414. e->Release();
  10415. differs = true;
  10416. }
  10417. return !differs;
  10418. }
  10419. typedef MapStringTo<bool> SubfileSet;
  10420. class CFilterAttrIterator: implements IDFAttributesIterator, public CInterface
  10421. {
  10422. Owned<IDFAttributesIterator> iter;
  10423. Linked<IUserDescriptor> user;
  10424. SubfileSet sfset;
  10425. bool includesub;
  10426. public:
  10427. IMPLEMENT_IINTERFACE;
  10428. CFilterAttrIterator(IDFAttributesIterator *_iter,IUserDescriptor* _user,bool _includesub,unsigned timeoutms)
  10429. : iter(_iter), user(_user)
  10430. {
  10431. includesub = _includesub;
  10432. CDfsLogicalFileName lfn;
  10433. StringBuffer query;
  10434. Owned<IDFScopeIterator> siter = queryDistributedFileDirectory().getScopeIterator(user,NULL,true,false);
  10435. ForEach(*siter) {
  10436. lfn.set(siter->query(),"X");
  10437. lfn.makeScopeQuery(query.clear());
  10438. Owned<IRemoteConnection> conn = querySDS().connect(query.str(),myProcessSession(),0, timeoutms);
  10439. if (conn) {
  10440. IPropertyTree *t = conn->queryRoot();
  10441. Owned<IPropertyTreeIterator> iter = t->getElements("SuperFile/SubFile");
  10442. ForEach(*iter) {
  10443. const char *name = iter->query().queryProp("@name");
  10444. if (!sfset.getValue(name))
  10445. sfset.setValue(name, true);
  10446. }
  10447. }
  10448. }
  10449. }
  10450. inline bool match()
  10451. {
  10452. const char *name = iter->query().queryProp("@name");
  10453. return ((sfset.getValue(name)!=NULL)==includesub);
  10454. }
  10455. bool first()
  10456. {
  10457. if (!iter->first())
  10458. return false;
  10459. while (!match())
  10460. if (!iter->next())
  10461. return false;
  10462. return true;
  10463. }
  10464. bool next()
  10465. {
  10466. do {
  10467. if (!iter->next())
  10468. return false;
  10469. } while (!match());
  10470. return true;
  10471. }
  10472. bool isValid() { return iter->isValid(); }
  10473. IPropertyTree & query() { return iter->query(); }
  10474. };
  10475. IDFAttributesIterator *createSubFileFilter(IDFAttributesIterator *_iter,IUserDescriptor* _user, bool includesub, unsigned timeoutms)
  10476. {
  10477. return new CFilterAttrIterator(_iter,_user,includesub,timeoutms);
  10478. }
  10479. bool decodeChildGroupName(const char *gname,StringBuffer &parentname, StringBuffer &range)
  10480. {
  10481. if (!gname||!*gname)
  10482. return false;
  10483. size32_t l = strlen(gname);
  10484. if (gname[l-1]!=']')
  10485. return false;
  10486. const char *ss = strchr(gname,'[');
  10487. if (!ss||(ss==gname))
  10488. return false;
  10489. range.append(l-(ss-gname)-2,ss+1);
  10490. range.trim();
  10491. if (!range.length())
  10492. return false;
  10493. parentname.append(ss-gname,gname);
  10494. return true;
  10495. }
  10496. class CLightWeightSuperFileConn: implements ISimpleSuperFileEnquiry, public CInterface
  10497. {
  10498. CFileLock lock;
  10499. bool readonly;
  10500. IArrayOf<IRemoteConnection> children;
  10501. unsigned defaultTimeout;
  10502. Owned<IUserDescriptor> udesc;
  10503. static StringBuffer &getSubPath(StringBuffer &path,unsigned idx)
  10504. {
  10505. return path.append("SubFile[@num=\"").append(idx+1).append("\"]");
  10506. }
  10507. void migrateProp(const char *name, unsigned num,IPropertyTree *from,IPropertyTree *to,IPropertyTree *newt, bool allowunchanged)
  10508. {
  10509. StringBuffer aname("Attr/");
  10510. aname.append(name);
  10511. StringBuffer s;
  10512. StringBuffer o;
  10513. if (from->getProp(aname.str(),s))
  10514. if ((num==1)||(allowunchanged&&to->getProp(aname.str(),o)&&(strcmp(s.str(),o.str())==0)))
  10515. newt->setProp(name,s.str());
  10516. }
  10517. void migrateAttr(IPropertyTree *from,IPropertyTree *to)
  10518. {
  10519. // this tries hard to set what it knows but avoids sibling traversal
  10520. if (!to)
  10521. return;
  10522. const char *desc = to->queryProp("Attr/@description");
  10523. IPropertyTree* newt = getEmptyAttr();
  10524. if (desc)
  10525. newt->setProp("@description",desc);
  10526. if (from) {
  10527. unsigned num=to->getPropInt("@numsubfiles");
  10528. migrateProp("@size",num,from,to,newt,false);
  10529. migrateProp("@checkSum",num,from,to,newt,true);
  10530. migrateProp("@formatCrc",num,from,to,newt,true);
  10531. migrateProp("@recordSize",num,from,to,newt,true);
  10532. MemoryBuffer mb;
  10533. MemoryBuffer mbo;
  10534. const char *aname = "Attr/_record_layout";
  10535. if (from->getPropBin(aname,mb))
  10536. if ((num==1)||(to->getPropBin(aname,mbo)&&
  10537. (mb.length()==mbo.length())&&
  10538. (memcmp(mb.bufferBase(),mbo.bufferBase(),mb.length())==0)))
  10539. newt->setPropBin("_record_layout", mb.length(), mb.bufferBase());
  10540. }
  10541. to->setPropTree("Attr",newt);
  10542. }
  10543. void migrateSuperOwnersAttr(IPropertyTree *from)
  10544. {
  10545. if (!from)
  10546. return;
  10547. Owned<IPropertyTreeIterator> iter = from->getElements("SuperOwner");
  10548. StringBuffer pname;
  10549. StringBuffer query;
  10550. ForEach(*iter) {
  10551. if (iter->query().getProp("@name",pname.clear())) {
  10552. CDfsLogicalFileName lfn;
  10553. lfn.set(pname.str());
  10554. lfn.makeFullnameQuery(query.clear(),DXB_SuperFile,true);
  10555. Owned<IRemoteConnection> conn;
  10556. try {
  10557. conn.setown(querySDS().connect(query.str(),myProcessSession(),RTM_LOCK_WRITE,1000*60*5));
  10558. }
  10559. catch (ISDSException *e) {
  10560. if (SDSExcpt_LockTimeout != e->errorCode())
  10561. throw;
  10562. e->Release();
  10563. WARNLOG("migrateSuperOwnersAttr: Could not lock parent %s",query.str());
  10564. conn.setown(querySDS().connect(query.str(),myProcessSession(),0,defaultTimeout));
  10565. }
  10566. if (conn) {
  10567. migrateAttr(from,conn->queryRoot());
  10568. migrateSuperOwnersAttr(conn->queryRoot());
  10569. }
  10570. else
  10571. WARNLOG("migrateSuperOwnersAttr could not connect to parent superfile %s",lfn.get());
  10572. }
  10573. }
  10574. }
  10575. public:
  10576. IMPLEMENT_IINTERFACE;
  10577. CLightWeightSuperFileConn(unsigned _defaultTimeout, IUserDescriptor *_udesc)
  10578. {
  10579. defaultTimeout = _defaultTimeout;
  10580. readonly = false;
  10581. udesc.set(_udesc);
  10582. }
  10583. bool connect(CDistributedFileDirectory *parent,const char *title, const char *name, bool _readonly, bool *autocreate, unsigned timeout)
  10584. {
  10585. if (autocreate)
  10586. *autocreate = false;
  10587. readonly = _readonly;
  10588. disconnect(false);
  10589. CDfsLogicalFileName lfn;
  10590. if (!lfn.setValidate(name))
  10591. throw MakeStringException(-1,"%s: Invalid superfile name '%s'",title,name);
  10592. if (lfn.isMulti()||lfn.isExternal()||lfn.isForeign())
  10593. return false;
  10594. unsigned mode = RTM_SUB | (readonly ? RTM_LOCK_READ : RTM_LOCK_WRITE);
  10595. if (!lock.init(lfn, DXB_SuperFile, mode, timeout, title))
  10596. {
  10597. if (!autocreate) // NB not !*autocreate here !
  10598. return false;
  10599. IPropertyTree *root = createPTree();
  10600. root->setPropInt("@interleaved",2);
  10601. root->setPropInt("@numsubfiles",0);
  10602. root->setPropTree("Attr",getEmptyAttr());
  10603. parent->addEntry(lfn,root,true,false);
  10604. mode = RTM_SUB | RTM_LOCK_WRITE;
  10605. if (!lock.init(lfn, DXB_SuperFile, mode, timeout, title))
  10606. throw MakeStringException(-1,"%s: Cannot create superfile '%s'",title,name);
  10607. if (autocreate)
  10608. *autocreate = true;
  10609. }
  10610. StringBuffer reason;
  10611. if (!readonly&&checkProtectAttr(name,lock.queryRoot(),reason))
  10612. throw MakeStringException(-1,"CDistributedSuperFile::%s %s",title,reason.str());
  10613. return true;
  10614. }
  10615. void disconnect(bool commit)
  10616. {
  10617. if (lock.queryConnection()&&!readonly) {
  10618. if (commit) {
  10619. migrateSuperOwnersAttr(lock.queryRoot());
  10620. CDateTime dt;
  10621. dt.setNow();
  10622. StringBuffer s;
  10623. lock.queryRoot()->setProp("@modified",dt.getString(s).str());
  10624. }
  10625. else {
  10626. ForEachItemIn(i,children)
  10627. children.item(i).rollback();
  10628. lock.queryConnection()->rollback();
  10629. }
  10630. }
  10631. lock.clear();
  10632. children.kill();
  10633. }
  10634. unsigned numSubFiles() const
  10635. {
  10636. return (unsigned)lock.queryRoot()->getPropInt("@numsubfiles");
  10637. }
  10638. bool getSubFileName(unsigned num,StringBuffer &name) const
  10639. {
  10640. if ((unsigned)lock.queryRoot()->getPropInt("@numsubfiles")<=num)
  10641. return false;
  10642. StringBuffer xpath;
  10643. getSubPath(xpath,num);
  10644. IPropertyTree *sub = lock.queryRoot()->queryPropTree(xpath.str());
  10645. if (!sub)
  10646. return false;
  10647. name.append(sub->queryProp("@name"));
  10648. return true;
  10649. }
  10650. unsigned findSubName(const char *subname) const
  10651. {
  10652. unsigned n = findSubFileOrd(subname);
  10653. if (n!=NotFound)
  10654. return n;
  10655. StringBuffer lfn;
  10656. normalizeLFN(subname,lfn);
  10657. Owned<IPropertyTreeIterator> iter = lock.queryRoot()->getElements("SubFile");
  10658. ForEach(*iter) {
  10659. if (stricmp(iter->query().queryProp("@name"),lfn.str())==0) {
  10660. unsigned ret=iter->query().getPropInt("@num");
  10661. if (ret&&((unsigned)lock.queryRoot()->getPropInt("@numsubfiles")>=ret))
  10662. return ret-1;
  10663. }
  10664. }
  10665. return NotFound;
  10666. }
  10667. unsigned getContents(StringArray &contents) const
  10668. {
  10669. // slightly inefficient
  10670. unsigned n = lock.queryRoot()->getPropInt("@numsubfiles");
  10671. StringBuffer xpath;
  10672. for (unsigned sni=0;sni<n;sni++) {
  10673. getSubPath(xpath.clear(),sni);
  10674. IPropertyTree *sub = lock.queryRoot()->queryPropTree(xpath.str());
  10675. if (!sub)
  10676. break;
  10677. contents.append(sub->queryProp("@name"));
  10678. }
  10679. return contents.ordinality();
  10680. }
  10681. };
  10682. // Contention never expected for this function!
  10683. #define PROMOTE_CONN_TIMEOUT (60*1000) // how long to wait for a single superfile
  10684. #define PROMOTE_DELAY (30*1000)
  10685. // Check files don't share subfiles (MORE - make this part of swap files action?)
  10686. static int hasCommonSubChildren(IDistributedSuperFile *orig, IDistributedSuperFile *dest)
  10687. {
  10688. unsigned origSubs = orig->numSubFiles();
  10689. unsigned destSubs = dest->numSubFiles();
  10690. if (origSubs == 0)
  10691. return NotFound;
  10692. for (unsigned j=0; j<origSubs; j++) {
  10693. for (unsigned k=0; k<destSubs; k++) {
  10694. if (strcmp(orig->querySubFile(j).queryLogicalName(), dest->querySubFile(k).queryLogicalName())==0)
  10695. return j;
  10696. }
  10697. }
  10698. return NotFound;
  10699. }
  10700. // MORE - use string arrays, rather than char* arrays or comma-separated strings
  10701. void CDistributedFileDirectory::promoteSuperFiles(unsigned numsf,const char **sfnames,const char *addsubnames,bool delsub,bool createonlyonesuperfile,IUserDescriptor *user,unsigned timeout,StringArray &outunlinked)
  10702. {
  10703. if (!numsf)
  10704. return;
  10705. // Create a local transaction that will be destroyed
  10706. Owned<IDistributedFileTransactionExt> transaction = new CDistributedFileTransaction(user);
  10707. transaction->start();
  10708. // Lookup all files (keep them in transaction's cache)
  10709. bool created = false;
  10710. unsigned files = numsf;
  10711. for (unsigned i=0; i<numsf; i++) {
  10712. Owned<IDistributedSuperFile> super = transaction->lookupSuperFile(sfnames[i]);
  10713. if (!super.get()) {
  10714. if (created && createonlyonesuperfile) {
  10715. files = i;
  10716. break;
  10717. }
  10718. Owned<IDistributedSuperFile> sfile = createSuperFile(sfnames[i],user,false,false,transaction);
  10719. created = true;
  10720. }
  10721. }
  10722. // If last file had sub-files, clean and fill outlinked
  10723. Owned<IDistributedSuperFile> last = transaction->lookupSuperFile(sfnames[files-1]);
  10724. assertex(last.get());
  10725. unsigned lastSubs = last->numSubFiles();
  10726. if (files == numsf && lastSubs > 0) {
  10727. for (unsigned i=0; i<lastSubs; i++) {
  10728. outunlinked.append(last->querySubFile(i).queryLogicalName());
  10729. }
  10730. last->removeSubFile(NULL,false,false,transaction);
  10731. }
  10732. last.clear();
  10733. // Move up, starting from last
  10734. for (unsigned i=files-1; i; i--) {
  10735. Owned<IDistributedSuperFile> orig = transaction->lookupSuperFile(sfnames[i-1]);
  10736. Owned<IDistributedSuperFile> dest = transaction->lookupSuperFile(sfnames[i]);
  10737. assertex(orig.get());
  10738. assertex(dest.get());
  10739. int common = hasCommonSubChildren(orig, dest);
  10740. if (common != NotFound) {
  10741. throw MakeStringException(-1,"promoteSuperFiles: superfiles %s and %s share same subfile %s",
  10742. orig->queryLogicalName(), dest->queryLogicalName(), orig->querySubFile(common).queryLogicalName());
  10743. }
  10744. orig->swapSuperFile(dest, transaction);
  10745. }
  10746. // Move new subs to first super, if any
  10747. Owned<IDistributedSuperFile> first = transaction->lookupSuperFile(sfnames[0]);
  10748. assertex(first.get());
  10749. StringArray toadd;
  10750. toadd.appendListUniq(addsubnames, ",");
  10751. ForEachItemIn(i,toadd) {
  10752. CDfsLogicalFileName lfn;
  10753. if (!lfn.setValidate(toadd.item(i)))
  10754. throw MakeStringException(-1,"promoteSuperFiles: invalid logical name to add: %s",toadd.item(i));
  10755. first->addSubFile(toadd.item(i),false,NULL,false,transaction);
  10756. }
  10757. first.clear();
  10758. transaction->commit();
  10759. // MORE - once deletion of logic files are also in transaction we can move this up (and allow promote within transactions)
  10760. if (delsub) {
  10761. ForEachItemIn(j,outunlinked)
  10762. removeEntry(outunlinked.item(j),user,transaction,timeout);
  10763. }
  10764. }
  10765. ISimpleSuperFileEnquiry * CDistributedFileDirectory::getSimpleSuperFileEnquiry(const char *logicalname,const char *title,IUserDescriptor *udesc,unsigned timeout)
  10766. {
  10767. Owned<CLightWeightSuperFileConn> ret = new CLightWeightSuperFileConn(defaultTimeout,udesc);
  10768. if (ret->connect(this,title,logicalname,true,NULL,timeout))
  10769. return ret.getClear();
  10770. return NULL;
  10771. }
  10772. bool CDistributedFileDirectory::getFileSuperOwners(const char *logicalname, StringArray &owners)
  10773. {
  10774. CFileLock lock;
  10775. CDfsLogicalFileName lfn;
  10776. if (!lfn.setValidate(logicalname))
  10777. throw MakeStringException(-1,"CDistributedFileDirectory::getFileSuperOwners: Invalid file name '%s'",logicalname);
  10778. if (lfn.isMulti()||lfn.isExternal()||lfn.isForeign())
  10779. return false;
  10780. CTimeMon tm(defaultTimeout);
  10781. if (!lock.init(lfn, RTM_LOCK_READ, defaultTimeout, "CDistributedFileDirectory::getFileSuperOwners"))
  10782. return false;
  10783. CFileSuperOwnerLock superOwnerLock;
  10784. unsigned remaining;
  10785. tm.timedout(&remaining);
  10786. verifyex(superOwnerLock.initWithFileLock(lfn, remaining, "CDistributedFileDirectory::getFileSuperOwners(SuperOwnerLock)", lock, RTM_LOCK_READ));
  10787. Owned<IPropertyTreeIterator> iter = lock.queryRoot()->getElements("SuperOwner");
  10788. StringBuffer pname;
  10789. ForEach(*iter) {
  10790. iter->query().getProp("@name",pname.clear());
  10791. if (pname.length())
  10792. owners.append(pname.str());
  10793. }
  10794. return true;
  10795. }
  10796. class CFileRelationship: implements IFileRelationship, public CInterface
  10797. {
  10798. Linked<IPropertyTree> pt;
  10799. const char *queryProp(const char *name)
  10800. {
  10801. if (pt.get()) {
  10802. const char *ret = pt->queryProp(name);
  10803. if (ret)
  10804. return ret;
  10805. }
  10806. return "";
  10807. }
  10808. public:
  10809. IMPLEMENT_IINTERFACE;
  10810. CFileRelationship(IPropertyTree *_pt)
  10811. : pt(_pt)
  10812. {
  10813. }
  10814. virtual const char *queryKind() { return queryProp("@kind"); }
  10815. virtual const char *queryPrimaryFilename() { return queryProp("@primary"); }
  10816. virtual const char *querySecondaryFilename() { return queryProp("@secondary"); }
  10817. virtual const char *queryPrimaryFields() { return queryProp("@primflds"); }
  10818. virtual const char *querySecondaryFields() { return queryProp("@secflds"); }
  10819. virtual const char *queryCardinality() { return queryProp("@cardinality"); }
  10820. virtual bool isPayload() { return pt->getPropBool("@payload"); }
  10821. virtual const char *queryDescription() { return queryProp("Description"); }
  10822. virtual IPropertyTree *queryTree() { return pt.get(); }
  10823. };
  10824. class CFileRelationshipIterator: implements IFileRelationshipIterator, public CInterface
  10825. {
  10826. unsigned num;
  10827. unsigned idx;
  10828. CMessageBuffer mb;
  10829. Owned<CFileRelationship> r;
  10830. Owned<IPropertyTree> pt;
  10831. Linked<INode> foreigndali;
  10832. unsigned defaultTimeout;
  10833. bool setPT()
  10834. {
  10835. if (idx<num) {
  10836. pt.setown(createPTree(mb));
  10837. addForeignName(*pt,foreigndali,"@primary");
  10838. addForeignName(*pt,foreigndali,"@secondary");
  10839. }
  10840. return pt.get()!=NULL;
  10841. }
  10842. public:
  10843. IMPLEMENT_IINTERFACE;
  10844. CFileRelationshipIterator(unsigned timems)
  10845. {
  10846. num = 0;
  10847. idx = 0;
  10848. mb.append(num);
  10849. defaultTimeout = timems;
  10850. }
  10851. void init(
  10852. INode *_foreigndali,
  10853. unsigned foreigndalitimeout,
  10854. const char *primary,
  10855. const char *secondary,
  10856. const char *primflds,
  10857. const char *secflds,
  10858. const char *kind,
  10859. const char *cardinality,
  10860. const bool *payload )
  10861. {
  10862. foreigndali.set(_foreigndali);
  10863. if (isLocalDali(foreigndali)) {
  10864. CConnectLock connlock("lookupFileRelationships",querySdsRelationshipsRoot(),false,false,false,defaultTimeout);
  10865. StringBuffer xpath;
  10866. CDistributedFileDirectory::getFileRelationshipXPath(xpath,primary,secondary,primflds,secflds,kind,cardinality,payload);
  10867. Owned<IPropertyTreeIterator> iter = connlock.conn?connlock.conn->getElements(xpath.str()):NULL;
  10868. mb.clear();
  10869. unsigned count = 0;
  10870. mb.append(count);
  10871. // save as sequence of branches
  10872. if (iter) {
  10873. ForEach(*iter.get()) {
  10874. iter->query().serialize(mb);
  10875. count++;
  10876. }
  10877. mb.writeDirect(0,sizeof(count),&count);
  10878. }
  10879. }
  10880. else {
  10881. byte payloadb = 255;
  10882. if (payload)
  10883. payloadb = *payload?1:0;
  10884. mb.clear().append((int)MDFS_ITERATE_RELATIONSHIPS).append(primary).append(secondary).append(primflds).append(secflds).append(kind).append(cardinality).append(payloadb);
  10885. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  10886. checkDfsReplyException(mb);
  10887. if (mb.length()<sizeof(unsigned))
  10888. mb.clear().append((unsigned)0);
  10889. }
  10890. }
  10891. void initall(const char *filename)
  10892. {
  10893. StringBuffer xpath;
  10894. Owned<IPropertyTreeIterator> iter;
  10895. mb.clear();
  10896. unsigned count = 0;
  10897. mb.append(count);
  10898. {
  10899. CConnectLock connlock("lookupFileRelationships",querySdsRelationshipsRoot(),false,false,false,defaultTimeout);
  10900. CDistributedFileDirectory::getFileRelationshipXPath(xpath,filename,NULL,NULL,NULL,NULL,NULL,NULL);
  10901. // save as sequence of branches
  10902. iter.setown(connlock.conn?connlock.conn->getElements(xpath.str()):NULL);
  10903. if (iter) {
  10904. ForEach(*iter.get()) {
  10905. iter->query().serialize(mb);
  10906. count++;
  10907. }
  10908. }
  10909. }
  10910. { // Kludge - seems to be a bug in getElements without second conn lock
  10911. CConnectLock connlock("lookupFileRelationships",querySdsRelationshipsRoot(),false,false,false,defaultTimeout);
  10912. xpath.clear();
  10913. CDistributedFileDirectory::getFileRelationshipXPath(xpath,NULL,filename,NULL,NULL,NULL,NULL,NULL);
  10914. iter.clear();
  10915. iter.setown(connlock.conn?connlock.conn->getElements(xpath.str()):NULL);
  10916. if (iter) {
  10917. ForEach(*iter.get()) {
  10918. IPropertyTree &it = iter->query();
  10919. const char *fn1 = it.queryProp("@primary");
  10920. if (!fn1||(strcmp(fn1,filename)!=0)) { // see if already done
  10921. it.serialize(mb);
  10922. count++;
  10923. }
  10924. }
  10925. }
  10926. }
  10927. mb.writeDirect(0,sizeof(count),&count);
  10928. }
  10929. bool first()
  10930. {
  10931. r.clear();
  10932. pt.clear();
  10933. idx = 0;
  10934. mb.reset().read(num);
  10935. return setPT();
  10936. }
  10937. bool next()
  10938. {
  10939. r.clear();
  10940. pt.clear();
  10941. idx++;
  10942. return setPT();
  10943. }
  10944. bool isValid()
  10945. {
  10946. return pt.get()!=NULL;
  10947. }
  10948. IFileRelationship & query()
  10949. {
  10950. if (!r)
  10951. r.setown(new CFileRelationship(pt));
  10952. return *r;
  10953. }
  10954. };
  10955. static bool isWild(const char *path,bool emptydefault=false)
  10956. {
  10957. if (!path||!*path)
  10958. return emptydefault;
  10959. return ((strchr(path,'?')||strchr(path,'*')));
  10960. }
  10961. static void addRelationCondition(StringBuffer &xpath,const char *fld,const char *mask)
  10962. {
  10963. if (!mask||!*mask||((*mask=='*')&&(!mask[1])))
  10964. return;
  10965. xpath.append('[').append(fld).append('=');
  10966. if (isWild(mask))
  10967. xpath.append('~');
  10968. xpath.append('"').append(mask).append("\"]");
  10969. }
  10970. static void addRelationBoolCondition(StringBuffer &xpath,const char *fld,const bool *mask)
  10971. {
  10972. if (!mask)
  10973. return;
  10974. xpath.append('[').append(fld).append("=\"");
  10975. if (*mask)
  10976. xpath.append("1\"]");
  10977. else
  10978. xpath.append("0\"]");
  10979. }
  10980. static const char *normLFN(const char *name,CDfsLogicalFileName &logicalname,const char *title)
  10981. {
  10982. if (isWild(name,true))
  10983. return name;
  10984. if (!logicalname.setValidate(name))
  10985. throw MakeStringException(-1,"%s: invalid logical file name '%s'",title,name);
  10986. if (logicalname.isForeign()) {
  10987. SocketEndpoint ep;
  10988. Owned<INode> fd = createINode(ep);
  10989. if (logicalname.getEp(ep)&&isLocalDali(fd)) // see if pointing back at self
  10990. logicalname.clearForeign();
  10991. }
  10992. return logicalname.get();
  10993. }
  10994. StringBuffer &CDistributedFileDirectory::getFileRelationshipXPath(
  10995. StringBuffer &xpath,
  10996. const char *primary,
  10997. const char *secondary,
  10998. const char *primflds,
  10999. const char *secflds,
  11000. const char *kind,
  11001. const char *cardinality,
  11002. const bool *payload
  11003. )
  11004. {
  11005. xpath.append("Relationship");
  11006. CDfsLogicalFileName lfn;
  11007. addRelationCondition(xpath,"@kind",kind);
  11008. addRelationCondition(xpath,"@primary",normLFN(primary,lfn,"findFileRelationship(primary)"));
  11009. addRelationCondition(xpath,"@secondary",normLFN(secondary,lfn,"findFileRelationship(secondary)"));
  11010. addRelationCondition(xpath,"@primflds",primflds);
  11011. addRelationCondition(xpath,"@secflds",secflds);
  11012. addRelationCondition(xpath,"@cardinality",cardinality);
  11013. addRelationBoolCondition(xpath,"@payload",payload);
  11014. return xpath;
  11015. }
  11016. void CDistributedFileDirectory::doRemoveFileRelationship(
  11017. IRemoteConnection *conn,
  11018. const char *primary,
  11019. const char *secondary,
  11020. const char *primflds,
  11021. const char *secflds,
  11022. const char *kind
  11023. )
  11024. {
  11025. if (!conn)
  11026. return;
  11027. StringBuffer xpath;
  11028. CDistributedFileDirectory::getFileRelationshipXPath(xpath,primary,secondary,primflds,secflds,kind,NULL,NULL);
  11029. Owned<IPropertyTreeIterator> iter = conn->getElements(xpath.str());
  11030. IArrayOf<IPropertyTree> toremove;
  11031. ForEach(*iter) {
  11032. IPropertyTree &t = iter->query();
  11033. toremove.append(*LINK(&t));
  11034. }
  11035. ForEachItemIn(i, toremove) {
  11036. conn->queryRoot()->removeTree(&toremove.item(i));
  11037. }
  11038. }
  11039. void CDistributedFileDirectory::addFileRelationship(
  11040. const char *primary,
  11041. const char *secondary,
  11042. const char *primflds,
  11043. const char *secflds,
  11044. const char *kind,
  11045. const char *cardinality,
  11046. bool payload,
  11047. IUserDescriptor *user,
  11048. const char *description=NULL
  11049. )
  11050. {
  11051. if (!kind||!*kind)
  11052. kind = S_LINK_RELATIONSHIP_KIND;
  11053. Owned<IPropertyTree> pt = createPTree("Relationship");
  11054. if (isWild(primary,true)||isWild(secondary,true)||isWild(primflds,false)||isWild(secflds,false)||isWild(cardinality,false))
  11055. throw MakeStringException(-1,"Wildcard not allowed in addFileRelation");
  11056. CDfsLogicalFileName pfn;
  11057. if (!pfn.setValidate(primary))
  11058. throw MakeStringException(-1,"addFileRelationship invalid primary name '%s'",primary);
  11059. if (pfn.isExternal()||pfn.isForeign()||pfn.isQuery())
  11060. throw MakeStringException(-1,"addFileRelationship primary %s not allowed",pfn.get());
  11061. primary = pfn.get();
  11062. if (!exists(primary,user))
  11063. throw MakeStringException(-1,"addFileRelationship primary %s does not exist",primary);
  11064. CDfsLogicalFileName sfn;
  11065. if (!sfn.setValidate(secondary))
  11066. throw MakeStringException(-1,"addFileRelationship invalid secondary name '%s'",secondary);
  11067. if (sfn.isExternal()||sfn.isForeign()||sfn.isQuery())
  11068. throw MakeStringException(-1,"addFileRelationship secondary %s not allowed",sfn.get());
  11069. secondary = sfn.get();
  11070. if (!exists(secondary,user))
  11071. throw MakeStringException(-1,"addFileRelationship secondary %s does not exist",secondary);
  11072. if (cardinality&&*cardinality&&!strchr(cardinality,':'))
  11073. throw MakeStringException(-1,"addFileRelationship cardinality %s invalid",cardinality);
  11074. pt->setProp("@kind",kind);
  11075. pt->setProp("@primary",primary);
  11076. pt->setProp("@secondary",secondary);
  11077. pt->setProp("@cardinality",cardinality);
  11078. pt->setProp("@primflds",primflds);
  11079. pt->setProp("@secflds",secflds);
  11080. pt->setPropBool("@payload",payload);
  11081. if (description&&*description)
  11082. pt->setProp("Description",description);
  11083. StringBuffer xpath(querySdsFilesRoot());
  11084. for (unsigned i=0;i<2;i++) {
  11085. CConnectLock connlock("addFileRelation",querySdsRelationshipsRoot(),true,false,false,defaultTimeout);
  11086. if (!connlock.conn) {
  11087. CConnectLock connlock2("addFileRelation.2",querySdsFilesRoot(),true,false,false,defaultTimeout);
  11088. if (!connlock2.conn)
  11089. return;
  11090. Owned<IPropertyTree> ptr = createPTree("Relationships");
  11091. connlock2.conn->queryRoot()->addPropTree("Relationships",ptr.getClear());
  11092. continue;
  11093. }
  11094. StringBuffer query;
  11095. doRemoveFileRelationship(connlock.conn,primary,secondary,primflds,secflds,kind);
  11096. connlock.conn->queryRoot()->addPropTree("Relationship",pt.getClear());
  11097. break;
  11098. }
  11099. }
  11100. void CDistributedFileDirectory::removeFileRelationships(
  11101. const char *primary,
  11102. const char *secondary,
  11103. const char *primflds,
  11104. const char *secflds,
  11105. const char *kind
  11106. )
  11107. {
  11108. if ((!primary||!*primary||(strcmp(primary,"*")==0))&&
  11109. (!secondary||!*secondary||(strcmp(secondary,"*")==0)))
  11110. throw MakeStringException(-1,"removeFileRelationships primary and secondary cannot both be wild");
  11111. CConnectLock connlock("removeFileRelation",querySdsRelationshipsRoot(),true,false,false,defaultTimeout);
  11112. doRemoveFileRelationship(connlock.conn,primary,secondary,primflds,secflds,kind);
  11113. }
  11114. IFileRelationshipIterator *CDistributedFileDirectory::lookupFileRelationships(
  11115. const char *primary,
  11116. const char *secondary,
  11117. const char *primflds,
  11118. const char *secflds,
  11119. const char *kind,
  11120. const char *cardinality,
  11121. const bool *payload,
  11122. const char *foreigndali,
  11123. unsigned foreigndalitimeout
  11124. )
  11125. {
  11126. Owned<INode> foreign;
  11127. if (foreigndali&&*foreigndali) {
  11128. SocketEndpoint ep(foreigndali);
  11129. if (ep.isNull())
  11130. throw MakeStringException(-1,"lookupFileRelationships::Cannot resolve foreign dali %s",foreigndali);
  11131. foreign.setown(createINode(ep));
  11132. }
  11133. Owned<CFileRelationshipIterator> ret = new CFileRelationshipIterator(defaultTimeout);
  11134. ret->init(foreign,foreigndalitimeout,primary,secondary,primflds,secflds,kind,cardinality,payload);
  11135. return ret.getClear();
  11136. }
  11137. void CDistributedFileDirectory::removeAllFileRelationships(const char *filename)
  11138. {
  11139. if (!filename||!*filename||(strcmp(filename,"*")==0))
  11140. throw MakeStringException(-1,"removeAllFileRelationships filename cannot be wild");
  11141. {
  11142. CConnectLock connlock("removeFileRelation",querySdsRelationshipsRoot(),true,false,false,defaultTimeout);
  11143. doRemoveFileRelationship(connlock.conn,filename,NULL,NULL,NULL,NULL);
  11144. }
  11145. { // kludge bug in getElements if connection used twice
  11146. CConnectLock connlock("removeFileRelation",querySdsRelationshipsRoot(),true,false,false,defaultTimeout);
  11147. doRemoveFileRelationship(connlock.conn,NULL,filename,NULL,NULL,NULL);
  11148. }
  11149. }
  11150. IFileRelationshipIterator *CDistributedFileDirectory::lookupAllFileRelationships(
  11151. const char *filename)
  11152. {
  11153. if (isWild(filename,true))
  11154. throw MakeStringException(-1,"Wildcard filename not allowed in lookupAllFileRelationships");
  11155. CDfsLogicalFileName lfn;
  11156. normLFN(filename,lfn,"lookupAllFileRelationships");
  11157. Owned<CFileRelationshipIterator> ret = new CFileRelationshipIterator(defaultTimeout);
  11158. ret->initall(lfn.get());
  11159. return ret.getClear();
  11160. }
  11161. void CDistributedFileDirectory::renameFileRelationships(const char *oldname,const char *newname,IFileRelationshipIterator *reliter,IUserDescriptor*user)
  11162. {
  11163. CDfsLogicalFileName oldlfn;
  11164. normLFN(oldname,oldlfn,"renameFileRelationships(old name)");
  11165. CDfsLogicalFileName newlfn;
  11166. normLFN(newname,newlfn,"renameFileRelationships(new name)");
  11167. ForEach(*reliter) {
  11168. try {
  11169. IFileRelationship &r = reliter->query();
  11170. bool adj = false;
  11171. const char *pf = r.queryPrimaryFilename();
  11172. if (!pf)
  11173. continue;
  11174. if (strcmp(pf,oldlfn.get())==0) {
  11175. adj = true;
  11176. pf = newlfn.get();
  11177. }
  11178. const char *sf = r.querySecondaryFilename();
  11179. if (!sf)
  11180. continue;
  11181. if (strcmp(sf,oldlfn.get())==0) {
  11182. adj = true;
  11183. sf = newlfn.get();
  11184. }
  11185. if (adj)
  11186. addFileRelationship(pf,sf,r.queryPrimaryFields(),r.querySecondaryFields(),r.queryKind(),r.queryCardinality(),r.isPayload(),user,r.queryDescription());
  11187. }
  11188. catch (IException *e)
  11189. {
  11190. EXCLOG(e,"renameFileRelationships");
  11191. e->Release();
  11192. }
  11193. }
  11194. }
  11195. // JCSMORE what was this for, not called by anything afaics
  11196. bool CDistributedFileDirectory::publishMetaFileXML(const CDfsLogicalFileName &logicalname,IUserDescriptor *user)
  11197. {
  11198. if (logicalname.isExternal()||logicalname.isForeign()||logicalname.isQuery())
  11199. return false;
  11200. Owned<IPropertyTree> file = getFileTree(logicalname.get(),user,NULL,FOREIGN_DALI_TIMEOUT,true);
  11201. if (!file.get())
  11202. return false;
  11203. if (strcmp(file->queryName(),queryDfsXmlBranchName(DXB_SuperFile))==0)
  11204. return false;
  11205. unsigned max = file->getPropInt("@numparts");
  11206. SocketEndpointArray ips;
  11207. StringBuffer xpath;
  11208. StringBuffer ipstr;
  11209. for (unsigned i=0;i<max;i++) { // probably could be done better
  11210. xpath.clear().append("Part[@num=\"").append(i+1).append("\"]");
  11211. Owned<IPropertyTree> child = file->getPropTree(xpath.str());
  11212. SocketEndpoint ep;
  11213. if (child.get()&&child->getProp("@node",ipstr.clear()))
  11214. ep.ipset(ipstr.str());
  11215. ips.append(ep);
  11216. }
  11217. Owned<IException> exc;
  11218. CriticalSection errcrit;
  11219. class casyncfor: public CAsyncFor
  11220. {
  11221. IPropertyTree* file;
  11222. CriticalSection &errcrit;
  11223. Owned<IException> &exc;
  11224. SocketEndpointArray &ips;
  11225. public:
  11226. casyncfor(IPropertyTree* _file,SocketEndpointArray &_ips,Owned<IException> &_exc,CriticalSection &_errcrit)
  11227. : ips(_ips), exc(_exc), errcrit(_errcrit)
  11228. {
  11229. file = _file;
  11230. }
  11231. void Do(unsigned i)
  11232. {
  11233. UnsignedArray parts;
  11234. const SocketEndpoint &ep = ips.item(i);
  11235. if (ep.isNull())
  11236. return;
  11237. ForEachItemIn(j,ips) {
  11238. if (j==i)
  11239. parts.append(i);
  11240. else if (ep.ipequals(ips.item(j))) {
  11241. if (j<i)
  11242. return; // already done
  11243. parts.append(j);
  11244. }
  11245. }
  11246. try {
  11247. StringBuffer path;
  11248. StringBuffer mask;
  11249. if (file->getProp("@directory",path)&&file->getProp("@partmask",mask)) {
  11250. addPathSepChar(path).append(mask);
  11251. StringBuffer outpath;
  11252. StringBuffer tail("META__");
  11253. splitFilename(path.str(), &outpath, &outpath, &tail, NULL);
  11254. outpath.append(tail).append(".xml");
  11255. Owned<IPropertyTree> pt = createPTreeFromIPT(file);
  11256. filterParts(pt,parts);
  11257. StringBuffer str;
  11258. toXML(pt, str);
  11259. RemoteFilename rfn;
  11260. rfn.setPath(ep,outpath.str());
  11261. Owned<IFile> out = createIFile(rfn);
  11262. Owned<IFileIO> outio = out->open(IFOcreate);
  11263. if (outio)
  11264. outio->write(0,str.length(),str.str());
  11265. }
  11266. }
  11267. catch(IException *e)
  11268. {
  11269. CriticalBlock block(errcrit);
  11270. EXCLOG(e,"publishMetaFileXML");
  11271. if (!exc.get())
  11272. exc.setown(e);
  11273. else
  11274. e->Release();
  11275. }
  11276. }
  11277. } afor(file,ips,exc,errcrit);
  11278. afor.For(max,20);
  11279. if (exc)
  11280. throw exc.getClear();
  11281. return true;
  11282. }
  11283. IFileDescriptor *CDistributedFileDirectory::createDescriptorFromMetaFile(const CDfsLogicalFileName &logicalname,IUserDescriptor *user)
  11284. {
  11285. return NULL; // TBD
  11286. }
  11287. // Overwrite protection
  11288. bool CDistributedFileDirectory::isProtectedFile(const CDfsLogicalFileName &logicalName, unsigned timeout)
  11289. {
  11290. CFileAttrLock attrLock;
  11291. if (!attrLock.init(logicalName, RTM_LOCK_READ, NULL, timeout?timeout:INFINITE, "CDistributedFileDirectory::isProtectedFile"))
  11292. return false; // timeout will raise exception
  11293. Owned<IPropertyTreeIterator> wpiter = attrLock.queryRoot()->getElements("Protect");
  11294. bool prot = false;
  11295. ForEach(*wpiter) {
  11296. IPropertyTree &t = wpiter->query();
  11297. if (t.getPropInt("@count")) {
  11298. prot = true;
  11299. break;
  11300. }
  11301. }
  11302. // timeout retry TBD
  11303. return prot;
  11304. }
  11305. unsigned CDistributedFileDirectory::queryProtectedCount(const CDfsLogicalFileName &logicalName, const char *owner)
  11306. {
  11307. CFileAttrLock attrLock;
  11308. if (!attrLock.init(logicalName, RTM_LOCK_READ, NULL, defaultTimeout, "CDistributedFileDirectory::queryProtectedCount"))
  11309. return 0; // timeout will raise exception
  11310. Owned<IPropertyTreeIterator> wpiter = attrLock.queryRoot()->getElements("Protect");
  11311. unsigned count = 0;
  11312. ForEach(*wpiter) {
  11313. IPropertyTree &t = wpiter->query();
  11314. const char *name = t.queryProp("@name");
  11315. if (!owner||!*owner||(name&&(strcmp(owner,name)==0)))
  11316. count += t.getPropInt("@count");
  11317. }
  11318. return count;
  11319. }
  11320. bool CDistributedFileDirectory::getProtectedInfo(const CDfsLogicalFileName &logicalName, StringArray &names, UnsignedArray &counts)
  11321. {
  11322. CFileAttrLock attrLock;
  11323. if (!attrLock.init(logicalName, RTM_LOCK_READ, NULL, defaultTimeout, "CDistributedFileDirectory::getProtectedInfo"))
  11324. return false; // timeout will raise exception
  11325. Owned<IPropertyTreeIterator> wpiter = attrLock.queryRoot()->getElements("Protect");
  11326. bool prot = false;
  11327. ForEach(*wpiter) {
  11328. IPropertyTree &t = wpiter->query();
  11329. const char *name = t.queryProp("@name");
  11330. names.append(name?name:"<Unknown>");
  11331. unsigned c = t.getPropInt("@count");
  11332. if (c)
  11333. prot = true;
  11334. counts.append(c);
  11335. }
  11336. return prot;
  11337. }
  11338. IDFProtectedIterator *CDistributedFileDirectory::lookupProtectedFiles(const char *owner,bool notsuper,bool superonly)
  11339. {
  11340. return new CDFProtectedIterator(owner,notsuper,superonly,defaultTimeout);
  11341. }
  11342. const char* DFUQResultFieldNames[] = { "@name", "@description", "@group", "@kind", "@modified", "@job", "@owner",
  11343. "@DFUSFrecordCount", "@recordCount", "@recordSize", "@DFUSFsize", "@size", "@workunit", "@DFUSFcluster", "@numsubfiles",
  11344. "@accessed", "@numparts", "@compressedSize", "@directory", "@partmask", "@superowners", "@persistent", "@protect" };
  11345. extern da_decl const char* getDFUQResultFieldName(DFUQResultField feild)
  11346. {
  11347. return DFUQResultFieldNames[feild];
  11348. }
  11349. IPropertyTreeIterator *deserializeFileAttrIterator(MemoryBuffer& mb, unsigned numFiles, DFUQResultField* localFilters, const char* localFilterBuf)
  11350. {
  11351. class CFileAttrIterator: implements IPropertyTreeIterator, public CInterface
  11352. {
  11353. size32_t fileDataStart;
  11354. Owned<IPropertyTree> cur;
  11355. StringArray fileNodeGroups;
  11356. void setFileNodeGroup(IPropertyTree *attr, const char* group, StringArray& nodeGroupFilter)
  11357. {
  11358. if (!group || !*group)
  11359. return;
  11360. //The group may contain multiple clusters and some of them may match with the clusterFilter.
  11361. if (nodeGroupFilter.length() == 1)
  11362. attr->setProp(getDFUQResultFieldName(DFUQRFnodegroup), nodeGroupFilter.item(0));//Filter has been handled on server side.
  11363. else
  11364. {
  11365. StringArray groups;
  11366. groups.appendListUniq(group, ",");
  11367. ForEachItemIn(i,groups)
  11368. {
  11369. //Add a group if no group filter or the group matches with group filter
  11370. const char* node = groups.item(i);
  11371. if (node && *node && ((!nodeGroupFilter.length()) || (nodeGroupFilter.find(node) != NotFound)))
  11372. fileNodeGroups.append(node);
  11373. }
  11374. if (fileNodeGroups.length())
  11375. {
  11376. //if this file exists on multiple groups, set one of the groups as the "@DFUSFnodegroup" prop for
  11377. //this attr, leaving the rest inside the fileNodeGroups array. Those groups will be used by the
  11378. //duplicateFileAttrOnOtherNodeGroup() to duplicate this file attr on other groups.
  11379. attr->setProp(getDFUQResultFieldName(DFUQRFnodegroup), fileNodeGroups.item(fileNodeGroups.length() -1));
  11380. fileNodeGroups.pop();
  11381. }
  11382. }
  11383. }
  11384. void setRecordCount(IPropertyTree* file)
  11385. {
  11386. __int64 recordCount = 0;
  11387. if (file->hasProp(getDFUQResultFieldName(DFUQRForigrecordcount)))
  11388. recordCount = file->getPropInt64(getDFUQResultFieldName(DFUQRForigrecordcount));
  11389. else
  11390. {
  11391. __int64 recordSize=file->getPropInt64(getDFUQResultFieldName(DFUQRFrecordsize),0);
  11392. if(recordSize)
  11393. {
  11394. __int64 size=file->getPropInt64(getDFUQResultFieldName(DFUQRForigsize),-1);
  11395. recordCount = size/recordSize;
  11396. }
  11397. }
  11398. file->setPropInt64(getDFUQResultFieldName(DFUQRFrecordcount),recordCount);
  11399. return;
  11400. }
  11401. IPropertyTree *deserializeFileAttr(MemoryBuffer &mb, StringArray& nodeGroupFilter)
  11402. {
  11403. IPropertyTree *attr = getEmptyAttr();
  11404. StringAttr val;
  11405. unsigned n;
  11406. mb.read(val);
  11407. attr->setProp(getDFUQResultFieldName(DFUQRFname),val.get());
  11408. mb.read(val);
  11409. if (strieq(val,"!SF"))
  11410. {
  11411. mb.read(n);
  11412. attr->setPropInt(getDFUQResultFieldName(DFUQRFnumsubfiles),n);
  11413. mb.read(val); // not used currently
  11414. }
  11415. else
  11416. {
  11417. attr->setProp(getDFUQResultFieldName(DFUQRFdirectory),val.get());
  11418. mb.read(n);
  11419. attr->setPropInt(getDFUQResultFieldName(DFUQRFnumparts),n);
  11420. mb.read(val);
  11421. attr->setProp(getDFUQResultFieldName(DFUQRFpartmask),val.get());
  11422. }
  11423. mb.read(val);
  11424. attr->setProp(getDFUQResultFieldName(DFUQRFtimemodified),val.get());
  11425. unsigned count;
  11426. mb.read(count);
  11427. StringAttr at;
  11428. while (count--)
  11429. {
  11430. mb.read(at);
  11431. mb.read(val);
  11432. attr->setProp(at.get(),val.get());
  11433. if (strieq(at.get(), getDFUQResultFieldName(DFUQRFnodegroups)))
  11434. setFileNodeGroup(attr, val.get(), nodeGroupFilter);
  11435. }
  11436. attr->setPropInt64(getDFUQResultFieldName(DFUQRFsize), attr->getPropInt64(getDFUQResultFieldName(DFUQRForigsize), -1));//Sort the files with empty size to front
  11437. setRecordCount(attr);
  11438. return attr;
  11439. }
  11440. IPropertyTree *duplicateFileAttrOnOtherNodeGroup(IPropertyTree *previousAttr)
  11441. {
  11442. IPropertyTree *attr = getEmptyAttr();
  11443. Owned<IAttributeIterator> ai = previousAttr->getAttributes();
  11444. ForEach(*ai)
  11445. attr->setProp(ai->queryName(),ai->queryValue());
  11446. attr->setProp(getDFUQResultFieldName(DFUQRFnodegroup), fileNodeGroups.item(fileNodeGroups.length()-1));
  11447. fileNodeGroups.pop();
  11448. return attr;
  11449. }
  11450. public:
  11451. IMPLEMENT_IINTERFACE;
  11452. MemoryBuffer mb;
  11453. unsigned numfiles;
  11454. StringArray nodeGroupFilter;
  11455. CFileAttrIterator(MemoryBuffer &_mb, unsigned _numfiles) : numfiles(_numfiles)
  11456. {
  11457. /* not particuarly nice, but buffer contains extra meta info ahead of serialized file info
  11458. * record position to rewind to, if iterator reused.
  11459. */
  11460. fileDataStart = _mb.getPos();
  11461. mb.swapWith(_mb);
  11462. }
  11463. bool first()
  11464. {
  11465. mb.reset(fileDataStart);
  11466. return next();
  11467. }
  11468. bool next()
  11469. {
  11470. if (fileNodeGroups.length())
  11471. {
  11472. IPropertyTree *attr = duplicateFileAttrOnOtherNodeGroup(cur);
  11473. cur.clear();
  11474. cur.setown(attr);
  11475. return true;
  11476. }
  11477. cur.clear();
  11478. if (mb.getPos()>=mb.length())
  11479. return false;
  11480. cur.setown(deserializeFileAttr(mb, nodeGroupFilter));
  11481. return true;
  11482. }
  11483. bool isValid()
  11484. {
  11485. return cur.get()!=NULL;
  11486. }
  11487. IPropertyTree & query()
  11488. {
  11489. return *cur;
  11490. }
  11491. void setLocalFilters(DFUQResultField* localFilters, const char* localFilterBuf)
  11492. {
  11493. if (!localFilters || !localFilterBuf || !*localFilterBuf)
  11494. return;
  11495. const char *fv = localFilterBuf;
  11496. for (unsigned i=0;localFilters[i]!=DFUQRFterm;i++)
  11497. {
  11498. int fmt = localFilters[i];
  11499. int subfmt = (fmt&0xff);
  11500. if ((subfmt==DFUQRFnodegroup) && fv && *fv)
  11501. nodeGroupFilter.appendListUniq(fv, ",");
  11502. //Add more if needed
  11503. fv = fv + strlen(fv)+1;
  11504. }
  11505. }
  11506. } *fai = new CFileAttrIterator(mb, numFiles);
  11507. fai->setLocalFilters(localFilters, localFilterBuf);
  11508. return fai;
  11509. }
  11510. IPropertyTreeIterator *CDistributedFileDirectory::getDFAttributesTreeIterator(const char* filters, DFUQResultField* localFilters,
  11511. const char* localFilterBuf, IUserDescriptor* user, bool& allMatchingFilesReceived, INode* foreigndali, unsigned foreigndalitimeout)
  11512. {
  11513. CMessageBuffer mb;
  11514. CDaliVersion serverVersionNeeded("3.13");
  11515. bool legacy = (queryDaliServerVersion().compare(serverVersionNeeded) < 0);
  11516. if (legacy)
  11517. mb.append((int)MDFS_ITERATE_FILTEREDFILES);
  11518. else
  11519. mb.append((int)MDFS_ITERATE_FILTEREDFILES2);
  11520. mb.append(filters).append(true);
  11521. if (user)
  11522. user->serialize(mb);
  11523. if (foreigndali)
  11524. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  11525. else
  11526. queryCoven().sendRecv(mb,RANK_RANDOM,MPTAG_DFS_REQUEST);
  11527. checkDfsReplyException(mb);
  11528. unsigned numfiles;
  11529. mb.read(numfiles);
  11530. if (legacy)
  11531. allMatchingFilesReceived = true; // don't know any better
  11532. else
  11533. mb.read(allMatchingFilesReceived);
  11534. return deserializeFileAttrIterator(mb, numfiles, localFilters, localFilterBuf);
  11535. }
  11536. IDFAttributesIterator* CDistributedFileDirectory::getLogicalFilesSorted(
  11537. IUserDescriptor* udesc,
  11538. DFUQResultField *sortOrder, // list of fields to sort by (terminated by DFUSFterm)
  11539. const void *filters, // (appended) string values for filters used by dali server
  11540. DFUQResultField *localFilters, //used for filtering query result received from dali server.
  11541. const void *localFilterBuf,
  11542. unsigned startOffset,
  11543. unsigned maxNum,
  11544. __int64 *cacheHint,
  11545. unsigned *total,
  11546. bool *allMatchingFiles)
  11547. {
  11548. class CDFUPager : implements IElementsPager, public CSimpleInterface
  11549. {
  11550. IUserDescriptor* udesc;
  11551. //StringAttr clusterFilter;
  11552. StringAttr filters;
  11553. DFUQResultField *localFilters;
  11554. StringAttr localFilterBuf;
  11555. StringAttr sortOrder;
  11556. bool allMatchingFilesReceived;
  11557. public:
  11558. IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
  11559. CDFUPager(IUserDescriptor* _udesc, const char*_filters, DFUQResultField*_localFilters, const char*_localFilterBuf,
  11560. const char*_sortOrder) : udesc(_udesc), filters(_filters), localFilters(_localFilters), localFilterBuf(_localFilterBuf),
  11561. sortOrder(_sortOrder)
  11562. {
  11563. allMatchingFilesReceived = true;
  11564. }
  11565. virtual IRemoteConnection* getElements(IArrayOf<IPropertyTree> &elements)
  11566. {
  11567. Owned<IPropertyTreeIterator> fi = queryDistributedFileDirectory().getDFAttributesTreeIterator(filters.get(),
  11568. localFilters, localFilterBuf.get(), udesc, allMatchingFilesReceived);
  11569. StringArray unknownAttributes;
  11570. sortElements(fi, sortOrder.get(), NULL, NULL, unknownAttributes, elements);
  11571. return NULL;
  11572. }
  11573. virtual bool allMatchingElementsReceived() { return allMatchingFilesReceived; }
  11574. };
  11575. StringBuffer so;
  11576. if (sortOrder)
  11577. {
  11578. for (unsigned i=0;sortOrder[i]!=DFUQRFterm;i++)
  11579. {
  11580. if (so.length())
  11581. so.append(',');
  11582. int fmt = sortOrder[i];
  11583. if (fmt&DFUQRFreverse)
  11584. so.append('-');
  11585. if (fmt&DFUQRFnocase)
  11586. so.append('?');
  11587. if (fmt&DFUQRFnumeric)
  11588. so.append('#');
  11589. so.append(getDFUQResultFieldName((DFUQResultField) (fmt&0xff)));
  11590. }
  11591. }
  11592. IArrayOf<IPropertyTree> results;
  11593. Owned<IElementsPager> elementsPager = new CDFUPager(udesc, (const char*) filters, localFilters, (const char*) localFilterBuf,
  11594. so.length()?so.str():NULL );
  11595. Owned<IRemoteConnection> conn = getElementsPaged(elementsPager,startOffset,maxNum,NULL,"",cacheHint,results,total,allMatchingFiles,false);
  11596. return new CDFAttributeIterator(results);
  11597. }
  11598. #ifdef _USE_CPPUNIT
  11599. /*
  11600. * This method removes files only logically. removeEntry() used to do that, but the only
  11601. * external use for logical-files only is this test-suite, so I'd rather hack the test
  11602. * suite than expose the behaviour to more viewers.
  11603. */
  11604. extern da_decl void removeLogical(const char *fname, IUserDescriptor *user) {
  11605. if (queryDistributedFileDirectory().exists(fname, user)) {
  11606. Owned<IDistributedFile> file = queryDistributedFileDirectory().lookup(fname, user, true);
  11607. CDistributedFile *f = QUERYINTERFACE(file.get(),CDistributedFile);
  11608. assert(f);
  11609. f->detachLogical();
  11610. }
  11611. }
  11612. #endif // _USE_CPPUNIT