dadfs.cpp 383 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203
  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 __declspec(dllexport)
  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. #ifdef _DEBUG
  36. //#define EXTRA_LOGGING
  37. //#define TRACE_LOCKS
  38. #endif
  39. #define SDS_CONNECT_TIMEOUT (1000*60*60*2) // better than infinite
  40. #define SDS_SUB_LOCK_TIMEOUT (10000)
  41. #define SDS_TRANSACTION_RETRY (60000)
  42. #define DEFAULT_NUM_DFS_THREADS 30
  43. #define TIMEOUT_ON_CLOSEDOWN 120000 // On closedown, give up on trying to join a thread in CDaliDFSServer after two minutes
  44. #if _INTERNAL_EDITION == 1
  45. #ifndef _MSC_VER
  46. #warning Disabling Sub-file compatibility checking
  47. #endif
  48. #else
  49. #define SUBFILE_COMPATIBILITY_CHECKING
  50. #endif
  51. //#define PACK_ECL
  52. #define SDS_GROUPSTORE_ROOT "Groups" // followed by name
  53. class CDistributedFile;
  54. enum MDFSRequestKind
  55. {
  56. MDFS_ITERATE_FILES,
  57. MDFS_UNUSED1,
  58. MDFS_GET_FILE_TREE,
  59. MDFS_GET_GROUP_TREE,
  60. MDFS_SET_FILE_ACCESSED,
  61. MDFS_ITERATE_RELATIONSHIPS,
  62. MDFS_SET_FILE_PROTECT,
  63. MDFS_MAX
  64. };
  65. // Mutex for physical operations (remove/rename)
  66. static CriticalSection physicalChange;
  67. #define MDFS_GET_FILE_TREE_V2 ((unsigned)1)
  68. static int strcompare(const void * left, const void * right)
  69. {
  70. const char * l = (const char *)left;
  71. const char * r = (const char *)right;
  72. return stricmp(l,r);
  73. }
  74. inline unsigned ipGroupDistance(const IpAddress &ip,const IGroup *grp)
  75. {
  76. if (!grp)
  77. return (unsigned)-1;
  78. return grp->distance(ip);
  79. }
  80. inline unsigned groupDistance(IGroup *grp1,IGroup *grp2)
  81. {
  82. if (grp1==grp2)
  83. return 0;
  84. if (!grp1||!grp2)
  85. return (unsigned)-1;
  86. return grp1->distance(grp2);
  87. }
  88. static StringBuffer &normalizeFormat(StringBuffer &in)
  89. {
  90. in.toLowerCase();
  91. for (unsigned i = 0;i<in.length();)
  92. {
  93. switch (in.charAt(i)) {
  94. case '-':
  95. case '_':
  96. case ' ':
  97. in.remove(i,1);
  98. break;
  99. default:
  100. i++;
  101. break;
  102. }
  103. }
  104. return in;
  105. }
  106. static StringBuffer &getAttrQueryStr(StringBuffer &str,const char *sub,const char *key,const char *name)
  107. {
  108. assertex(key[0]=='@');
  109. str.appendf("%s[%s=\"%s\"]",sub,key,name);
  110. return str;
  111. }
  112. static IPropertyTree *getNamedPropTree(IPropertyTree *parent,const char *sub,const char *key,const char *name,bool preload)
  113. { // no create
  114. if (!parent)
  115. return NULL;
  116. StringBuffer query;
  117. getAttrQueryStr(query,sub,key,name);
  118. if (preload)
  119. return parent->getBranch(query.str());
  120. return parent->getPropTree(query.str());
  121. }
  122. static IPropertyTree *addNamedPropTree(IPropertyTree *parent,const char *sub,const char *key,const char *name, IPropertyTree* init=NULL)
  123. {
  124. IPropertyTree* ret = init?createPTreeFromIPT(init):createPTree(sub);
  125. assertex(key[0]=='@');
  126. ret->setProp(key,name);
  127. ret = parent->addPropTree(sub,ret);
  128. return LINK(ret);
  129. }
  130. const char *normalizeLFN(const char *s,StringBuffer &tmp)
  131. {
  132. CDfsLogicalFileName dlfn;
  133. dlfn.set(s);
  134. return dlfn.get(tmp).str();
  135. }
  136. static IPropertyTree *getEmptyAttr()
  137. {
  138. return createPTree("Attr");
  139. }
  140. RemoteFilename &constructPartFilename(IGroup *grp,unsigned partno,unsigned partmax,const char *name,const char *partmask,const char *partdir,unsigned copy,ClusterPartDiskMapSpec &mspec,RemoteFilename &rfn)
  141. {
  142. partno--;
  143. StringBuffer tmp;
  144. if (!name||!*name) {
  145. if (!partmask||!*partmask) {
  146. partmask = "!ERROR!._$P$_of_$N$"; // could use logical tail name if I had it
  147. ERRLOG("No partmask for constructPartFilename");
  148. }
  149. name = expandMask(tmp,partmask,partno,partmax).str();
  150. }
  151. StringBuffer fullname;
  152. if (findPathSepChar(name)==NULL)
  153. addPathSepChar(fullname.append(partdir));
  154. fullname.append(name);
  155. unsigned n;
  156. unsigned d;
  157. mspec.calcPartLocation(partno,partmax,copy,grp?grp->ordinality():partmax,n,d);
  158. setReplicateFilename(fullname,d);
  159. SocketEndpoint ep;
  160. if (grp)
  161. ep=grp->queryNode(n).endpoint();
  162. rfn.setPath(ep,fullname.toLowerCase().str());
  163. return rfn;
  164. }
  165. inline void LOGPTREE(const char *title,IPropertyTree *pt)
  166. {
  167. StringBuffer buf;
  168. if (pt) {
  169. toXML(pt,buf);
  170. PROGLOG("%s:\n%s\n",title,buf.str());
  171. }
  172. else
  173. PROGLOG("%s : NULL",title);
  174. }
  175. inline void LOGFDESC(const char *title,IFileDescriptor *fdesc)
  176. {
  177. if (fdesc) {
  178. Owned<IPropertyTree> pt = fdesc->getFileTree();
  179. LOGPTREE(title,pt);
  180. }
  181. else
  182. PROGLOG("%s : NULL",title);
  183. }
  184. class CDFS_Exception: public CInterface, implements IDFS_Exception
  185. {
  186. StringAttr errstr;
  187. int errcode;
  188. public:
  189. CDFS_Exception(int _errcode, const char *_errstr)
  190. : errstr(_errstr)
  191. {
  192. errcode = _errcode;
  193. }
  194. int errorCode() const { return errcode; }
  195. StringBuffer & errorMessage(StringBuffer &str) const
  196. {
  197. if (errcode==DFSERR_ok)
  198. return str;
  199. str.append("DFS Exception: ").append(errcode);
  200. switch(errcode) {
  201. case DFSERR_LogicalNameAlreadyExists:
  202. return str.append(": logical name ").append(errstr).append(" already exists");
  203. case DFSERR_CannotFindPartFileSize:
  204. return str.append(": Cannot find physical file size for ").append(errstr);
  205. case DFSERR_CannotFindPartFileCrc:
  206. return str.append(": Cannot find physical file crc for ").append(errstr);
  207. case DFSERR_LookupAccessDenied:
  208. return str.append(" Lookup access denied for scope ").append(errstr);
  209. case DFSERR_CreateAccessDenied:
  210. return str.append(" Create access denied for scope ").append(errstr);
  211. case DFSERR_PhysicalPartAlreadyExists:
  212. return str.append(": physical part ").append(errstr).append(" already exists");
  213. case DFSERR_PhysicalPartDoesntExist:
  214. return str.append(": physical part ").append(errstr).append(" doesnt exist");
  215. case DFSERR_ForeignDaliTimeout:
  216. return str.append(": Timeout connecting to Dali Server on ").append(errstr);
  217. case DFSERR_ClusterNotFound:
  218. return str.append(": Cluster not found: ").append(errstr);
  219. case DFSERR_ClusterAlreadyExists:
  220. return str.append(": Cluster already exists: ").append(errstr);
  221. case DFSERR_LookupConnectionTimout:
  222. return str.append(": Lookup connection timeout: ").append(errstr);
  223. }
  224. return str.append("Unknown DFS Exception");
  225. }
  226. MessageAudience errorAudience() const { return MSGAUD_user; }
  227. IMPLEMENT_IINTERFACE;
  228. };
  229. class CConnectLock
  230. {
  231. public:
  232. Owned<IRemoteConnection> conn;
  233. CConnectLock(const char *caller, const char *name, bool write, bool preload, bool hold, unsigned timeout)
  234. {
  235. unsigned start = msTick();
  236. bool first = true;
  237. loop
  238. {
  239. try
  240. {
  241. unsigned mode = write ? RTM_LOCK_WRITE : RTM_LOCK_READ;
  242. if (preload) mode |= RTM_SUB;
  243. if (hold) mode |= RTM_LOCK_HOLD;
  244. conn.setown(querySDS().connect(name, queryCoven().inCoven() ? 0 : myProcessSession(), mode, (timeout==INFINITE)?1000*60*5:timeout));
  245. #ifdef TRACE_LOCKS
  246. PROGLOG("%s: LOCKGOT(%x) %s %s",caller,(unsigned)(memsize_t)conn.get(),name,write?"WRITE":"");
  247. LogRemoteConn(conn);
  248. PrintStackReport();
  249. #endif
  250. break;
  251. }
  252. catch (ISDSException *e)
  253. {
  254. if (SDSExcpt_LockTimeout == e->errorCode())
  255. {
  256. #ifdef TRACE_LOCKS
  257. PROGLOG("%s: LOCKFAIL %s %s",caller,name,write?"WRITE":"");
  258. LogRemoteConn(conn);
  259. #endif
  260. unsigned tt = msTick()-start;
  261. if (timeout!=INFINITE) {
  262. StringBuffer tmp;
  263. e->errorMessage(tmp);
  264. CDFS_Exception *dfse = new CDFS_Exception(DFSERR_LookupConnectionTimout,tmp.str());
  265. e->Release();
  266. throw dfse;
  267. }
  268. WARNLOG("CConnectLock on %s waiting for %ds",name,tt/1000);
  269. if (first) {
  270. PrintStackReport();
  271. first = false;
  272. }
  273. if (tt>SDS_CONNECT_TIMEOUT)
  274. throw;
  275. e->Release();
  276. }
  277. else
  278. throw;
  279. }
  280. catch (IException *e) {
  281. StringBuffer tmp("CConnectLock ");
  282. tmp.append(caller).append(' ').append(name);
  283. EXCLOG(e, tmp.str());
  284. throw;
  285. }
  286. }
  287. }
  288. IRemoteConnection *detach()
  289. {
  290. #ifdef TRACE_LOCKS
  291. if (conn.get()) {
  292. PROGLOG("LOCKDETACH(%x)",(unsigned)(memsize_t)conn.get());
  293. LogRemoteConn(conn);
  294. }
  295. #endif
  296. return conn.getClear();
  297. }
  298. #ifdef TRACE_LOCKS
  299. ~CConnectLock()
  300. {
  301. if (conn.get()) {
  302. PROGLOG("LOCKDELETE(%x)",(unsigned)(memsize_t)conn.get());
  303. LogRemoteConn(conn);
  304. }
  305. }
  306. #endif
  307. };
  308. void ensureFileScope(const CDfsLogicalFileName &dlfn,unsigned timeout)
  309. {
  310. CConnectLock connlock("ensureFileScope",querySdsFilesRoot(),true,false,false,timeout);
  311. StringBuffer query;
  312. IPropertyTree *r = connlock.conn->getRoot();
  313. StringBuffer scopes;
  314. const char *s=dlfn.getScopes(scopes,true).str();
  315. loop {
  316. IPropertyTree *nr;
  317. const char *e = strstr(s,"::");
  318. query.clear();
  319. if (e)
  320. query.append(e-s,s);
  321. else
  322. query.append(s);
  323. nr = getNamedPropTree(r,queryDfsXmlBranchName(DXB_Scope),"@name",query.trim().toLowerCase().str(),false);
  324. if (!nr)
  325. nr = addNamedPropTree(r,queryDfsXmlBranchName(DXB_Scope),"@name",query.str());
  326. r->Release();
  327. if (!e) {
  328. ::Release(nr);
  329. break;
  330. }
  331. r = nr;
  332. s = e+2;
  333. }
  334. }
  335. void removeFileEmptyScope(const CDfsLogicalFileName &dlfn,unsigned timeout)
  336. {
  337. CConnectLock connlock("removeFileEmptyScope",querySdsFilesRoot(),true,false,false,timeout); //*1
  338. IPropertyTree *root = connlock.conn.get()?connlock.conn->queryRoot():NULL;
  339. if (!root)
  340. return;
  341. StringBuffer query;
  342. dlfn.makeScopeQuery(query.clear(),false);
  343. StringBuffer head;
  344. loop {
  345. if (query.length()) {
  346. const char *tail = splitXPath(query.str(),head.clear());
  347. if (!tail||!*tail)
  348. break;
  349. IPropertyTree *pt;
  350. if (head.length()) {
  351. query.set(head);
  352. pt = root->queryPropTree(query.str());
  353. }
  354. else
  355. pt = root;
  356. IPropertyTree *t = pt?pt->queryPropTree(tail):NULL;
  357. if (t) {
  358. if (t->hasChildren())
  359. break;
  360. pt->removeTree(t);
  361. if (root==pt)
  362. break;
  363. }
  364. else
  365. break;
  366. }
  367. else
  368. break;
  369. }
  370. }
  371. class CFileConnectLock
  372. {
  373. CConnectLock *lock;
  374. bool attronly;
  375. public:
  376. CFileConnectLock(bool _attronly=false)
  377. {
  378. lock = NULL;
  379. attronly = _attronly;
  380. }
  381. CFileConnectLock(const char *caller,const CDfsLogicalFileName &lname,DfsXmlBranchKind bkind,bool write,bool preload,bool hold,unsigned timeout,bool _attronly=false)
  382. {
  383. lock = NULL;
  384. attronly = _attronly;
  385. init(caller,lname,bkind,write,preload,hold,timeout);
  386. }
  387. ~CFileConnectLock()
  388. {
  389. delete lock;
  390. }
  391. bool init(const char *caller,const CDfsLogicalFileName &lname,DfsXmlBranchKind bkind,bool write,bool preload,bool hold,unsigned timeout)
  392. {
  393. kill();
  394. StringBuffer query;
  395. lname.makeFullnameQuery(query,bkind,true);
  396. if (attronly)
  397. query.append("/Attr");
  398. lock = new CConnectLock(caller,query.str(),write,preload,hold,timeout);
  399. return lock->conn.get()!=NULL;
  400. }
  401. bool initany(const char *caller,const CDfsLogicalFileName &lname,DfsXmlBranchKind &bkind,bool write,bool preload,bool hold,unsigned timeout)
  402. {
  403. if (init(caller, lname, DXB_File, write, preload, hold, timeout))
  404. {
  405. bkind = DXB_File;
  406. return true;
  407. }
  408. if (init(caller, lname, DXB_SuperFile, write, preload, hold, timeout))
  409. {
  410. bkind = DXB_SuperFile;
  411. return true;
  412. }
  413. return false;
  414. }
  415. IRemoteConnection *detach()
  416. {
  417. return lock?lock->detach():NULL;
  418. }
  419. IRemoteConnection *conn()
  420. {
  421. return lock?lock->conn:NULL;
  422. }
  423. IPropertyTree *queryRoot() const
  424. {
  425. return (lock&&lock->conn.get())?lock->conn->queryRoot():NULL;
  426. }
  427. void remove()
  428. {
  429. if (lock&&lock->conn.get()) {
  430. #ifdef TRACE_LOCKS
  431. PROGLOG("CFileConnectLock:remove%s",attronly?" Attr":"");
  432. LogRemoteConn(lock->conn);
  433. #endif
  434. lock->conn->close(true);
  435. }
  436. }
  437. void kill()
  438. {
  439. delete lock;
  440. lock = NULL;
  441. }
  442. };
  443. class CScopeConnectLock
  444. {
  445. CConnectLock *lock;
  446. public:
  447. CScopeConnectLock()
  448. {
  449. lock = NULL;
  450. }
  451. CScopeConnectLock(const char *caller, const CDfsLogicalFileName &lname, bool write, bool preload, bool hold, unsigned timeout)
  452. {
  453. lock = NULL;
  454. init(caller, lname, write, preload, hold, timeout);
  455. }
  456. ~CScopeConnectLock()
  457. {
  458. delete lock;
  459. }
  460. bool init(const char *caller, const CDfsLogicalFileName &lname, bool write, bool preload, bool hold, unsigned timeout)
  461. {
  462. delete lock;
  463. StringBuffer query;
  464. lname.makeScopeQuery(query,true);
  465. lock = new CConnectLock(caller, query.str(), write, preload,hold, timeout);
  466. if (lock->conn.get()==NULL)
  467. {
  468. delete lock;
  469. lock = NULL;
  470. ensureFileScope(lname);
  471. lock = new CConnectLock(caller, query.str(), write, preload, hold, timeout);
  472. }
  473. return lock->conn.get()!=NULL;
  474. }
  475. IRemoteConnection *detach()
  476. {
  477. return lock?lock->detach():NULL;
  478. }
  479. IRemoteConnection *conn()
  480. {
  481. return lock?lock->conn:NULL;
  482. }
  483. IPropertyTree *queryRoot()
  484. {
  485. return (lock&&lock->conn.get())?lock->conn->queryRoot():NULL;
  486. }
  487. void remove()
  488. {
  489. if (lock&&lock->conn.get())
  490. lock->conn->close(true);
  491. }
  492. IPropertyTree *queryFileRoot(const CDfsLogicalFileName &dlfn,DfsXmlBranchKind &bkind)
  493. {
  494. bool external;
  495. bool foreign;
  496. external = dlfn.isExternal();
  497. foreign = dlfn.isForeign();
  498. if (external||foreign)
  499. return NULL;
  500. IPropertyTree *sroot = queryRoot();
  501. if (!sroot)
  502. return NULL;
  503. StringBuffer tail;
  504. dlfn.getTail(tail);
  505. StringBuffer query;
  506. getAttrQueryStr(query,queryDfsXmlBranchName(DXB_File),"@name",tail.str());
  507. IPropertyTree *froot = sroot->queryPropTree(query.str());
  508. bkind = DXB_File;
  509. if (!froot) {
  510. // check for super file
  511. getAttrQueryStr(query.clear(),queryDfsXmlBranchName(DXB_SuperFile),"@name",tail.str());
  512. froot = sroot->queryPropTree(query.str());
  513. if (froot)
  514. bkind = DXB_SuperFile;
  515. }
  516. return froot;
  517. }
  518. };
  519. class CClustersLockedSection
  520. {
  521. Owned<IRemoteConnection> conn;
  522. public:
  523. CClustersLockedSection(CDfsLogicalFileName &dlfn)
  524. {
  525. StringBuffer xpath;
  526. dlfn.makeFullnameQuery(xpath,DXB_File,true).append("/ClusterLock");
  527. /* Avoid RTM_CREATE_QUERY connect() if possible by making 1st call without. This is to avoid write contention caused by RTM_CREATE*
  528. * NB: RTM_CREATE_QUERY should probably only gain exclusive access in Dali if node is missing.
  529. */
  530. conn.setown(querySDS().connect(xpath.str(), myProcessSession(), RTM_LOCK_WRITE, SDS_CONNECT_TIMEOUT));
  531. if (!conn.get()) // NB: ClusterLock is now created at File create time, so this can only be true for pre-existing File's
  532. conn.setown(querySDS().connect(xpath.str(), myProcessSession(), RTM_CREATE_QUERY | RTM_LOCK_WRITE, SDS_CONNECT_TIMEOUT));
  533. }
  534. };
  535. static void checkDfsReplyException(MemoryBuffer &mb)
  536. {
  537. if (mb.length()<=sizeof(int))
  538. return;
  539. if ((*(int *)mb.bufferBase()) == -1) { // exception indicator
  540. int i;
  541. mb.read(i);
  542. throw deserializeException(mb);
  543. }
  544. }
  545. static void foreignDaliSendRecv(const INode *foreigndali,CMessageBuffer &mb, unsigned foreigndalitimeout)
  546. {
  547. SocketEndpoint ep = foreigndali->endpoint();
  548. if (ep.port==0)
  549. ep.port = DALI_SERVER_PORT;
  550. Owned<IGroup> grp = createIGroup(1,&ep);
  551. Owned<ICommunicator> comm = createCommunicator(grp,true);
  552. if (!comm->verifyConnection(0,foreigndalitimeout)) {
  553. StringBuffer tmp;
  554. IDFS_Exception *e = new CDFS_Exception(DFSERR_ForeignDaliTimeout, foreigndali->endpoint().getUrlStr(tmp).str());
  555. throw e;
  556. }
  557. comm->sendRecv(mb,0,MPTAG_DFS_REQUEST);
  558. }
  559. static bool isLocalDali(const INode *foreigndali)
  560. {
  561. if (!foreigndali)
  562. return true;
  563. Owned<INode> node;
  564. SocketEndpoint ep = foreigndali->endpoint();
  565. if (ep.port==0) {
  566. ep.port = DALI_SERVER_PORT;
  567. node.setown(createINode(ep));
  568. foreigndali = node.get();
  569. }
  570. return queryCoven().inCoven((INode *)foreigndali);
  571. }
  572. class FileClusterInfoArray: public IArrayOf<IClusterInfo>
  573. {
  574. ClusterPartDiskMapSpec defaultmapping;
  575. bool singleclusteroverride;
  576. public:
  577. FileClusterInfoArray()
  578. {
  579. singleclusteroverride = false;
  580. }
  581. void clear()
  582. {
  583. IArrayOf<IClusterInfo>::kill();
  584. }
  585. unsigned getNames(StringArray &clusternames)
  586. {
  587. StringBuffer name;
  588. ForEachItem(i) {
  589. clusternames.append(item(i).getClusterLabel(name.clear()).str());
  590. if (singleclusteroverride)
  591. break;
  592. }
  593. return clusternames.ordinality();
  594. }
  595. unsigned find(const char *_clusterName)
  596. {
  597. StringAttr clusterName = _clusterName;
  598. clusterName.toLowerCase();
  599. StringBuffer name;
  600. ForEachItem(i) {
  601. if (strcmp(item(i).getClusterLabel(name.clear()).str(),clusterName)==0)
  602. return i;
  603. if (singleclusteroverride)
  604. break;
  605. }
  606. return NotFound;
  607. }
  608. IGroup *queryGroup(unsigned clusternum)
  609. {
  610. if (clusternum>=ordinality())
  611. return NULL;
  612. if (singleclusteroverride&&clusternum)
  613. return NULL;
  614. return item(clusternum).queryGroup();
  615. }
  616. IGroup *getGroup(unsigned clusternum)
  617. {
  618. IGroup *ret = queryGroup(clusternum);
  619. return LINK(ret);
  620. }
  621. unsigned copyNum(unsigned part,unsigned copy,unsigned maxparts, unsigned *replicate)
  622. {
  623. ForEachItem(i) {
  624. IGroup *g = queryGroup(i);
  625. unsigned cw = g?g->ordinality():1;
  626. unsigned mc = item(i).queryPartDiskMapping().numCopies(part,cw,maxparts);
  627. if (copy<mc) {
  628. if (replicate)
  629. *replicate = copy;
  630. return i;
  631. }
  632. copy -= mc;
  633. if (singleclusteroverride)
  634. break;
  635. }
  636. return NotFound;
  637. }
  638. ClusterPartDiskMapSpec &queryPartDiskMapping(unsigned clusternum)
  639. {
  640. if (clusternum>=ordinality()||(singleclusteroverride&&clusternum))
  641. return defaultmapping;
  642. return item(clusternum).queryPartDiskMapping();
  643. }
  644. void updatePartDiskMapping(unsigned clusternum,const ClusterPartDiskMapSpec &spec)
  645. {
  646. if (clusternum<ordinality())
  647. item(clusternum).queryPartDiskMapping() = spec;
  648. }
  649. StringBuffer &getName(unsigned clusternum,StringBuffer &name)
  650. {
  651. if (clusternum<ordinality())
  652. item(clusternum).getClusterLabel(name);
  653. return name;
  654. }
  655. void setPreferred(const char *clusters,CDfsLogicalFileName &lfname)
  656. {
  657. unsigned nc = ordinality();
  658. if (nc<=1)
  659. return;
  660. StringBuffer cname;
  661. StringArray clustlist;
  662. if (lfname.getCluster(cname).length())
  663. clustlist.append(cname.str());
  664. unsigned i;
  665. if (clusters) {
  666. loop {
  667. const char *s = clusters;
  668. while (*s&&(*s!=','))
  669. s++;
  670. if (s!=clusters) {
  671. cname.clear().append(s-clusters,clusters);
  672. for (i=0;i<clustlist.ordinality();i++)
  673. if (strcmp(clustlist.item(i),cname.str())==0)
  674. break;
  675. if (i==clustlist.ordinality())
  676. clustlist.append(cname.str());
  677. }
  678. if (!*s)
  679. break;
  680. clusters = s+1;
  681. }
  682. }
  683. if (clustlist.ordinality()==0) {
  684. // sort by closest to this node
  685. const IpAddress &myip = queryMyNode()->endpoint();
  686. unsigned *d=new unsigned[nc];
  687. for (i=0;i<nc;i++)
  688. d[i] = ipGroupDistance(myip,item(i).queryGroup());
  689. // bubble sort it - only a few
  690. for (i=0;i+1<nc;i++)
  691. for (unsigned j=0;j+i+1<nc;j++)
  692. if (d[j+1]<d[j]) {
  693. unsigned bd = d[j+1];
  694. d[j+1] = d[j];
  695. d[j] = bd;
  696. swap(j,j+1);
  697. }
  698. delete [] d;
  699. return;
  700. }
  701. Owned<IGroup> firstgrp;
  702. unsigned done = 0;
  703. StringBuffer name;
  704. StringBuffer name2;
  705. ForEachItemIn(ci,clustlist) {
  706. const char *cls = clustlist.item(ci);
  707. Owned<IGroup> grp = queryNamedGroupStore().lookup(cls);
  708. if (!grp) {
  709. ERRLOG("IDistributedFile::setPreferred - cannot find cluster %s",cls);
  710. return;
  711. }
  712. if (!firstgrp.get())
  713. firstgrp.set(grp);
  714. for (i=done;i<nc;i++) {
  715. IClusterInfo &info=item(i);
  716. if (stricmp(info.getClusterLabel(name2.clear()).str(),name.str())==0)
  717. break;
  718. IGroup *grp2 = info.queryGroup();
  719. if (grp2&&(grp->compare(grp2)!=GRdisjoint))
  720. break;
  721. }
  722. if (i<nc) {
  723. if (i) {
  724. Linked<IClusterInfo> tmp = &item(i);
  725. remove(i);
  726. add(*tmp.getClear(),done);
  727. }
  728. done++;
  729. if (done+1>=nc)
  730. break;
  731. }
  732. }
  733. if (done+1<nc) { // sort remaining by nearest to first group
  734. unsigned *d=new unsigned[nc]; // only use done to nc
  735. for (i=done;i<nc;i++)
  736. d[i] = groupDistance(firstgrp,item(i).queryGroup());
  737. // bubble sort it - only a few
  738. for (i=done;i+1<nc;i++)
  739. for (unsigned j=done;j+i+1<nc;j++)
  740. if (d[j+1]<d[j]) {
  741. unsigned bd = d[j+1];
  742. d[j+1] = d[j];
  743. d[j] = bd;
  744. swap(j,j+1);
  745. }
  746. delete [] d;
  747. }
  748. }
  749. void setSingleClusterOnly(bool set=true)
  750. {
  751. singleclusteroverride = set;
  752. }
  753. unsigned numCopies(unsigned part,unsigned maxparts)
  754. {
  755. unsigned ret = 0;
  756. ForEachItem(i) {
  757. IGroup *g = queryGroup(i);
  758. unsigned cw = g?g->ordinality():1;
  759. ret += item(i).queryPartDiskMapping().numCopies(part,cw,maxparts);
  760. if (singleclusteroverride)
  761. break;
  762. }
  763. return ret;
  764. }
  765. };
  766. // Internal extension of transaction interface, used to manipulate and track transaction
  767. interface IDistributedFileTransactionExt : extends IDistributedFileTransaction
  768. {
  769. virtual IUserDescriptor *queryUser()=0;
  770. virtual void descend()=0; // descend into a recursive call (can't autoCommit if depth is not zero)
  771. virtual void ascend()=0; // ascend back from the deep, one step at a time
  772. virtual void autoCommit()=0; // if transaction not active, commit straight away
  773. virtual void addAction(CDFAction *action)=0;
  774. virtual void addFile(IDistributedFile *file)=0;
  775. virtual void ensureFile(IDistributedFile *file)=0;
  776. virtual void clearFile(IDistributedFile *file)=0;
  777. virtual void clearFiles()=0;
  778. virtual void noteAddSubFile(IDistributedSuperFile *super, const char *superName, IDistributedFile *sub) = 0;
  779. virtual void noteRemoveSubFile(IDistributedSuperFile *super, IDistributedFile *sub) = 0;
  780. virtual void noteSuperSwap(IDistributedSuperFile *super1, IDistributedSuperFile *super2) = 0;
  781. virtual void clearSubFiles(IDistributedSuperFile *super) = 0;
  782. virtual void noteRename(IDistributedFile *file, const char *newName) = 0;
  783. virtual void validateAddSubFile(IDistributedSuperFile *super, IDistributedFile *sub, const char *subName) = 0;
  784. virtual bool isSubFile(IDistributedSuperFile *super, const char *subFile, bool sub) = 0;
  785. virtual bool addDelayedDelete(CDfsLogicalFileName &lfn,unsigned timeoutms=INFINITE)=0; // used internally to delay deletes until commit
  786. virtual bool prepareActions()=0;
  787. virtual void retryActions()=0;
  788. virtual void runActions()=0;
  789. virtual void commitAndClearup()=0;
  790. };
  791. class CDistributedFileDirectory: public CInterface, implements IDistributedFileDirectory
  792. {
  793. Owned<IUserDescriptor> defaultudesc;
  794. Owned<IDFSredirection> redirection;
  795. IDistributedFile *createExternal(const CDfsLogicalFileName &logicalname);
  796. void resolveForeignFiles(IPropertyTree *tree,const INode *foreigndali);
  797. protected: friend class CDistributedFile;
  798. StringAttr defprefclusters;
  799. unsigned defaultTimeout;
  800. public:
  801. IMPLEMENT_IINTERFACE;
  802. CDistributedFileDirectory()
  803. {
  804. defaultTimeout = INFINITE;
  805. defaultudesc.setown(createUserDescriptor());
  806. redirection.setown(createDFSredirection());
  807. }
  808. IDistributedFile *dolookup(CDfsLogicalFileName &logicalname, IUserDescriptor *user, bool writeattr, bool hold, IDistributedFileTransaction *transaction, unsigned timeout);
  809. IDistributedFile *lookup(const char *_logicalname, IUserDescriptor *user, bool writeattr, bool hold, IDistributedFileTransaction *transaction, unsigned timeout);
  810. IDistributedFile *lookup(CDfsLogicalFileName &logicalname, IUserDescriptor *user, bool writeattr, bool hold, IDistributedFileTransaction *transaction, unsigned timeout);
  811. IDistributedFile *createNew(IFileDescriptor * fdesc, const char *lname,bool includeports=false);
  812. IDistributedFile *createNew(IFileDescriptor * fdesc, bool includeports=false)
  813. {
  814. return createNew(fdesc,NULL,includeports);
  815. }
  816. IDistributedFile *createNew(IPropertyTree *tree,bool ignoregroup);
  817. IDistributedSuperFile *createSuperFile(const char *logicalname,IUserDescriptor *user,bool interleaved,bool ifdoesnotexist,IDistributedFileTransaction *transaction=NULL);
  818. void removeSuperFile(const char *_logicalname, bool delSubs, IUserDescriptor *user, IDistributedFileTransaction *transaction);
  819. IDistributedFileIterator *getIterator(const char *wildname, bool includesuper,IUserDescriptor *user);
  820. IDFAttributesIterator *getDFAttributesIterator(const char *wildname, IUserDescriptor *user, bool recursive, bool includesuper,INode *foreigndali,unsigned foreigndalitimeout);
  821. IDFAttributesIterator *getForeignDFAttributesIterator(const char *wildname, IUserDescriptor *user, bool recursive=true, bool includesuper=false, const char *foreigndali="", unsigned foreigndalitimeout=FOREIGN_DALI_TIMEOUT)
  822. {
  823. Owned<INode> foreign;
  824. if (foreigndali&&*foreigndali) {
  825. SocketEndpoint ep(foreigndali);
  826. foreign.setown(createINode(ep));
  827. }
  828. return getDFAttributesIterator(wildname, user, recursive, includesuper,foreign,foreigndalitimeout);
  829. }
  830. IDFScopeIterator *getScopeIterator(IUserDescriptor *user, const char *subscope,bool recursive,bool includeempty);
  831. bool loadScopeContents(const char *scopelfn,StringArray *scopes, StringArray *supers,StringArray *files, bool includeemptyscopes);
  832. IPropertyTree *getFileTree(const char *lname,IUserDescriptor *user,const INode *foreigndali,unsigned foreigndalitimeout,bool expandnodes=false, bool appendForeign=true);
  833. void setFileAccessed(CDfsLogicalFileName &dlfn, IUserDescriptor *user,const CDateTime &dt,const INode *foreigndali=NULL,unsigned foreigndalitimeout=FOREIGN_DALI_TIMEOUT);
  834. IFileDescriptor *getFileDescriptor(const char *lname,IUserDescriptor *user,const INode *foreigndali=NULL,unsigned foreigndalitimeout=FOREIGN_DALI_TIMEOUT);
  835. IDistributedFile *getFile(const char *lname,IUserDescriptor *user,const INode *foreigndali=NULL,unsigned foreigndalitimeout=FOREIGN_DALI_TIMEOUT);
  836. bool exists(const char *_logicalname,IUserDescriptor *user,bool notsuper=false,bool superonly=false);
  837. bool existsPhysical(const char *_logicalname,IUserDescriptor *user);
  838. void addEntry(CDfsLogicalFileName &lfn,IPropertyTree *root,bool superfile, bool ignoreexists);
  839. bool removeEntry(const char *name, IUserDescriptor *user, IDistributedFileTransaction *transaction=NULL, unsigned timeoutms=INFINITE, bool throwException=false);
  840. void renamePhysical(const char *oldname,const char *newname,IUserDescriptor *user,IDistributedFileTransaction *transaction);
  841. void removeEmptyScope(const char *name);
  842. IDistributedSuperFile *lookupSuperFile(const char *logicalname,IUserDescriptor *user,IDistributedFileTransaction *transaction,unsigned timeout=INFINITE);
  843. int getFilePermissions(const char *lname,IUserDescriptor *user,unsigned auditflags);
  844. int getNodePermissions(const IpAddress &ip,IUserDescriptor *user,unsigned auditflags);
  845. int getFDescPermissions(IFileDescriptor *,IUserDescriptor *user,unsigned auditflags=0);
  846. void setDefaultUser(IUserDescriptor *user);
  847. IUserDescriptor* queryDefaultUser();
  848. DistributedFileCompareResult fileCompare(const char *lfn1,const char *lfn2,DistributedFileCompareMode mode,StringBuffer &errstr,IUserDescriptor *user);
  849. bool filePhysicalVerify(const char *lfn1,IUserDescriptor *user,bool includecrc,StringBuffer &errstr);
  850. void setDefaultPreferredClusters(const char *clusters);
  851. void fixDates(IDistributedFile *fil);
  852. GetFileClusterNamesType getFileClusterNames(const char *logicalname,StringArray &out); // returns 0 for normal file, 1 for
  853. bool isSuperFile( const char *logicalname, IUserDescriptor *user, INode *foreigndali, unsigned timeout);
  854. void promoteSuperFiles(unsigned numsf,const char **sfnames,const char *addsubnames,bool delsub,bool createonlyonesuperfile,IUserDescriptor *user, unsigned timeout, StringArray &outunlinked);
  855. ISimpleSuperFileEnquiry * getSimpleSuperFileEnquiry(const char *logicalname,const char *title,IUserDescriptor *udesc,unsigned timeout);
  856. bool getFileSuperOwners(const char *logicalname, StringArray &owners);
  857. IDFSredirection & queryRedirection() { return *redirection; }
  858. static StringBuffer &getFileRelationshipXPath(StringBuffer &xpath, const char *primary, const char *secondary,const char *primflds,const char *secflds,
  859. const char *kind, const char *cardinality, const bool *payload
  860. );
  861. void doRemoveFileRelationship( IRemoteConnection *conn, const char *primary,const char *secondary,const char *primflds,const char *secflds, const char *kind);
  862. void removeFileRelationships(const char *primary,const char *secondary, const char *primflds, const char *secflds, const char *kind);
  863. 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);
  864. IFileRelationshipIterator *lookupFileRelationships(const char *primary,const char *secondary,const char *primflds,const char *secflds,
  865. const char *kind,const char *cardinality,const bool *payload,
  866. const char *foreigndali,unsigned foreigndalitimeout);
  867. void removeAllFileRelationships(const char *filename);
  868. IFileRelationshipIterator *lookupAllFileRelationships(const char *filenames);
  869. void renameFileRelationships(const char *oldname,const char *newname,IFileRelationshipIterator *reliter, IUserDescriptor *user);
  870. bool publishMetaFileXML(const CDfsLogicalFileName &logicalname,IUserDescriptor *user);
  871. IFileDescriptor *createDescriptorFromMetaFile(const CDfsLogicalFileName &logicalname,IUserDescriptor *user);
  872. bool isProtectedFile(const CDfsLogicalFileName &logicalname, unsigned timeout) ;
  873. unsigned queryProtectedCount(const CDfsLogicalFileName &logicalname, const char *owner);
  874. bool getProtectedInfo(const CDfsLogicalFileName &logicalname, StringArray &names, UnsignedArray &counts);
  875. IDFProtectedIterator *lookupProtectedFiles(const char *owner=NULL,bool notsuper=false,bool superonly=false);
  876. void setFileProtect(CDfsLogicalFileName &dlfn,IUserDescriptor *user, const char *owner, bool set, const INode *foreigndali=NULL,unsigned foreigndalitimeout=FOREIGN_DALI_TIMEOUT);
  877. unsigned setDefaultTimeout(unsigned timems)
  878. {
  879. unsigned ret = defaultTimeout;
  880. defaultTimeout = timems;
  881. return ret;
  882. }
  883. };
  884. // === Transactions
  885. class CDFAction: public CInterface
  886. {
  887. unsigned locked;
  888. protected:
  889. IDistributedFileTransactionExt *transaction;
  890. IArrayOf<IDistributedFile> lockedFiles;
  891. DFTransactionState state;
  892. void addFileLock(IDistributedFile *file)
  893. {
  894. // derived's prepare must call this before locking
  895. lockedFiles.append(*LINK(file));
  896. }
  897. bool lock()
  898. {
  899. // Files most have been acquired already by derived's class prepare
  900. ForEachItemIn(i,lockedFiles)
  901. {
  902. try
  903. {
  904. lockedFiles.item(i).lockProperties(0);
  905. }
  906. catch (ISDSException *e)
  907. {
  908. if (SDSExcpt_LockTimeout != e->errorCode())
  909. throw;
  910. e->Release();
  911. PROGLOG("CDFAction lock timed out on %s",lockedFiles.item(i).queryLogicalName());
  912. return false;
  913. }
  914. locked++;
  915. }
  916. return true;
  917. }
  918. void unlock()
  919. {
  920. for(unsigned i=0; i<locked; i++)
  921. lockedFiles.item(i).unlockProperties(state);
  922. locked = 0;
  923. lockedFiles.kill();
  924. }
  925. public:
  926. CDFAction() : locked(0), state(TAS_NONE)
  927. {
  928. transaction = NULL;
  929. }
  930. // Clear all locked files (when re-using transaction on auto-commit mode)
  931. virtual ~CDFAction()
  932. {
  933. if (transaction)
  934. unlock();
  935. }
  936. void setTransaction(IDistributedFileTransactionExt *_transaction)
  937. {
  938. assertex(_transaction);
  939. assertex(!transaction);
  940. transaction = _transaction;
  941. }
  942. virtual bool prepare()=0; // should call lock
  943. virtual void run()=0; // must override this
  944. // If some lock fails, call this
  945. virtual void retry()
  946. {
  947. state = TAS_RETRY;
  948. unlock();
  949. }
  950. // MORE: In the rare event of a commit failure, not all actions can be rolled back.
  951. // Since all actions today occur during "run", and since commit phases does very little,
  952. // this chance is minimal and will probably be caused by corrupted file descriptors.
  953. // The problem is that the state of the sub removals and the order in which they occur might not
  954. // be trivial on such a low level error, and there's no way to atomically do operations in SDS
  955. // at present time. We need more thought about this.
  956. virtual void commit()
  957. {
  958. state = TAS_SUCCESS;
  959. unlock();
  960. }
  961. virtual void rollback()
  962. {
  963. state = TAS_FAILURE;
  964. unlock();
  965. }
  966. };
  967. static void setUserDescriptor(Linked<IUserDescriptor> &udesc,IUserDescriptor *user)
  968. {
  969. if (!user)
  970. {
  971. #ifndef _NO_DALIUSER_STACKTRACE
  972. StringBuffer sb;
  973. if (user)
  974. user->getUserName(sb);
  975. if (sb.length()==0)
  976. {
  977. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp setUserDescriptor() %d",__LINE__);
  978. //following debug code to be removed
  979. PrintStackReport();
  980. }
  981. #endif
  982. user = queryDistributedFileDirectory().queryDefaultUser();
  983. }
  984. udesc.set(user);
  985. }
  986. static int getScopePermissions(const char *scopename,IUserDescriptor *user,unsigned auditflags)
  987. { // scope must be normalized already
  988. static bool permissionsavail=true;
  989. if (auditflags==(unsigned)-1)
  990. return permissionsavail?1:0;
  991. int ret = 255;
  992. if (permissionsavail&&scopename&&*scopename&&((*scopename!='.')||scopename[1])) {
  993. if (!user)
  994. {
  995. #ifndef _NO_DALIUSER_STACKTRACE
  996. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp getScopePermissions() line %d",__LINE__);
  997. //following debug code to be removed
  998. PrintStackReport();
  999. #endif
  1000. user = queryDistributedFileDirectory().queryDefaultUser();
  1001. }
  1002. ret = querySessionManager().getPermissionsLDAP(queryDfsXmlBranchName(DXB_Scope),scopename,user,auditflags);
  1003. if (ret<0) {
  1004. if (ret==-1) {
  1005. permissionsavail=false;
  1006. ret = 255;
  1007. }
  1008. else
  1009. ret = 0;
  1010. }
  1011. }
  1012. return ret;
  1013. }
  1014. static void checkLogicalScope(const char *scopename,IUserDescriptor *user,bool readreq,bool createreq)
  1015. {
  1016. // scope must be normalized already
  1017. if (!readreq&&!createreq)
  1018. return;
  1019. unsigned auditflags = 0;
  1020. if (readreq)
  1021. auditflags |= (DALI_LDAP_AUDIT_REPORT|DALI_LDAP_READ_WANTED);
  1022. if (createreq)
  1023. auditflags |= (DALI_LDAP_AUDIT_REPORT|DALI_LDAP_WRITE_WANTED);
  1024. #ifndef _NO_DALIUSER_STACKTRACE
  1025. if (!user)
  1026. {
  1027. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp checkLogicalScope() line %d",__LINE__);
  1028. PrintStackReport();
  1029. }
  1030. #endif
  1031. int perm = getScopePermissions(scopename,user,auditflags);
  1032. IDFS_Exception *e = NULL;
  1033. if (readreq&&!HASREADPERMISSION(perm))
  1034. e = new CDFS_Exception(DFSERR_LookupAccessDenied,scopename);
  1035. else if (createreq&&!HASWRITEPERMISSION(perm))
  1036. e = new CDFS_Exception(DFSERR_CreateAccessDenied,scopename);
  1037. if (e)
  1038. throw e;
  1039. }
  1040. static bool checkLogicalName(CDfsLogicalFileName &dlfn,IUserDescriptor *user,bool readreq,bool createreq,bool allowquery,const char *specialnotallowedmsg)
  1041. {
  1042. bool ret = true;
  1043. if (dlfn.isMulti()) { //is temporary superFile?
  1044. if (specialnotallowedmsg)
  1045. throw MakeStringException(-1,"cannot %s a multi file name (%s)",specialnotallowedmsg,dlfn.get());
  1046. if (!dlfn.isExpanded())
  1047. dlfn.expand(user);//expand wildcards
  1048. unsigned i = dlfn.multiOrdinality();
  1049. while (--i)//continue looping even when ret is false, in order to check for illegal elements (foreigns/externals), and to check each scope permission
  1050. ret = checkLogicalName((CDfsLogicalFileName &)dlfn.multiItem(i),user,readreq,createreq,allowquery,specialnotallowedmsg)&&ret;
  1051. }
  1052. else {
  1053. if (specialnotallowedmsg) {
  1054. if (dlfn.isExternal()) {
  1055. if (dlfn.isQuery()&&allowquery)
  1056. ret = false;
  1057. else
  1058. throw MakeStringException(-1,"cannot %s an external file name (%s)",specialnotallowedmsg,dlfn.get());
  1059. }
  1060. if (dlfn.isForeign()) {
  1061. throw MakeStringException(-1,"cannot %s a foreign file name (%s)",specialnotallowedmsg,dlfn.get());
  1062. }
  1063. }
  1064. StringBuffer scopes;
  1065. dlfn.getScopes(scopes);
  1066. checkLogicalScope(scopes.str(),user,readreq,createreq);
  1067. }
  1068. return ret;
  1069. }
  1070. /*
  1071. * This class removes all files marked for deletion during transactions.
  1072. *
  1073. * TODO: the doDelete method re-acquires the lock to remove the files, and
  1074. * that creates a window (between end of commit and deletion) where other
  1075. * processes can acquire locks and blow things up. To fix this, you'd have
  1076. * to be selective on what files you unlock during commit, so that you
  1077. * can still keep an unified cache AND release the deletions later on.
  1078. */
  1079. class CDelayedDelete: public CInterface
  1080. {
  1081. CDfsLogicalFileName lfn;
  1082. Linked<IUserDescriptor> user;
  1083. unsigned timeoutms;
  1084. public:
  1085. CDelayedDelete(CDfsLogicalFileName &_lfn,IUserDescriptor *_user,unsigned _timeoutms)
  1086. : user(_user), timeoutms(_timeoutms)
  1087. {
  1088. lfn.set(_lfn);
  1089. }
  1090. void doDelete() // Throw on error!
  1091. {
  1092. const char *logicalname = lfn.get();
  1093. if (!checkLogicalName(lfn,user,true,true,true,"remove"))
  1094. ThrowStringException(-1, "Logical Name fails for removal on %s", lfn.get());
  1095. // Transaction files have already been unlocked at this point, delete all remaining files
  1096. Owned<IDistributedFile> file = queryDistributedFileDirectory().lookup(lfn, user, true, false, NULL, SDS_SUB_LOCK_TIMEOUT);
  1097. if (!file.get())
  1098. return;
  1099. StringBuffer reason;
  1100. if (!file->canRemove(reason, false))
  1101. ThrowStringException(-1, "Can't remove %s: %s", lfn.get(), reason.str());
  1102. // This will do the right thing for either super-files and logical-files.
  1103. file->detach();
  1104. }
  1105. };
  1106. class CDistributedFileTransaction: public CInterface, implements IDistributedFileTransactionExt
  1107. {
  1108. class CTransactionFile : public CSimpleInterface
  1109. {
  1110. class HTMapping : public CInterface
  1111. {
  1112. IDistributedFile *file;
  1113. StringAttr name;
  1114. public:
  1115. HTMapping(const char *_name, IDistributedFile *_file) : name(_name), file(_file) { }
  1116. IDistributedFile &query() { return *file; }
  1117. const char *queryFindString() const { return name; }
  1118. const void *queryFindParam() const { return &file; }
  1119. };
  1120. class CSubFileIter : protected SuperHashIteratorOf<HTMapping>, implements IDistributedFileIterator
  1121. {
  1122. typedef SuperHashIteratorOf<HTMapping> PARENT;
  1123. public:
  1124. IMPLEMENT_IINTERFACE_USING(PARENT);
  1125. CSubFileIter(OwningStringSuperHashTableOf<HTMapping> &table) : PARENT(table)
  1126. {
  1127. }
  1128. // IDistributedFileIterator impl.
  1129. virtual IDistributedFile &query()
  1130. {
  1131. HTMapping &map = PARENT::query();
  1132. return map.query();
  1133. }
  1134. virtual bool first() { return PARENT::first(); }
  1135. virtual bool isValid() { return PARENT::isValid(); }
  1136. virtual bool next() { return PARENT::next(); }
  1137. virtual StringBuffer &getName(StringBuffer &name)
  1138. {
  1139. HTMapping &map = PARENT::query();
  1140. return name.append(map.queryFindString());
  1141. }
  1142. };
  1143. CDistributedFileTransaction &owner;
  1144. OwningStringSuperHashTableOf<HTMapping> subFilesByName;
  1145. StringAttr name;
  1146. Linked<IDistributedFile> file;
  1147. public:
  1148. CTransactionFile(CDistributedFileTransaction &_owner, const char *_name, IDistributedFile *_file) : owner(_owner), name(_name), file(_file)
  1149. {
  1150. }
  1151. const char *queryName() const { return name; }
  1152. IDistributedFile *queryFile() { return file; }
  1153. IDistributedFileIterator *getSubFiles()
  1154. {
  1155. IDistributedSuperFile *super = file->querySuperFile();
  1156. if (!super)
  1157. return NULL;
  1158. return new CSubFileIter(subFilesByName);
  1159. }
  1160. void clearSubs()
  1161. {
  1162. subFilesByName.kill();
  1163. }
  1164. unsigned numSubFiles() const { return subFilesByName.count(); }
  1165. void noteAddSubFile(IDistributedFile *sub)
  1166. {
  1167. if (NULL == subFilesByName.find(sub->queryLogicalName()))
  1168. {
  1169. Owned<HTMapping> map = new HTMapping(sub->queryLogicalName(), sub);
  1170. subFilesByName.replace(*map.getLink());
  1171. }
  1172. }
  1173. void noteRemoveSubFile(IDistributedFile *sub)
  1174. {
  1175. HTMapping *map = subFilesByName.find(sub->queryLogicalName());
  1176. if (map)
  1177. verifyex(subFilesByName.removeExact(map));
  1178. }
  1179. bool find(const char *subFile, bool sub)
  1180. {
  1181. HTMapping *match = subFilesByName.find(subFile);
  1182. if (match)
  1183. return &match->query();
  1184. else if (sub)
  1185. {
  1186. SuperHashIteratorOf<HTMapping> iter(subFilesByName);
  1187. ForEach(iter)
  1188. {
  1189. HTMapping &map = iter.query();
  1190. IDistributedFile &file = map.query();
  1191. IDistributedSuperFile *super = file.querySuperFile();
  1192. if (super)
  1193. {
  1194. if (owner.isSubFile(super, subFile, sub))
  1195. return true;
  1196. }
  1197. }
  1198. }
  1199. return false;
  1200. }
  1201. const void *queryFindParam() const { return &file; }
  1202. const char *queryFindString() const { return name; }
  1203. };
  1204. CIArrayOf<CDFAction> actions;
  1205. OwningSimpleHashTableOf<CTransactionFile, IDistributedFile *> trackedFiles;
  1206. OwningStringSuperHashTableOf<CTransactionFile> trackedFilesByName;
  1207. bool isactive;
  1208. Linked<IUserDescriptor> udesc;
  1209. CIArrayOf<CDelayedDelete> delayeddelete;
  1210. // auto-commit only works at depth zero (for recursive calls)
  1211. // MORE: Maybe this needs a context object (descend on c-tor, ascend on d-tor)
  1212. // But we need all actions within transactions first to find out if there is
  1213. // any exception to the rule used by addSubFile / removeSubFile
  1214. unsigned depth;
  1215. unsigned prepared;
  1216. /* 'owner' is set if, transaction object is implicitly created, because none provided
  1217. * The owner cannot be release or unlocked. The transaction can still retry if other files are locked,
  1218. * so need to ensure 'owner' remains in tracked file cache.
  1219. */
  1220. IDistributedSuperFile *owner;
  1221. void validateAddSubFile(IDistributedSuperFile *super, IDistributedFile *sub, const char *subName);
  1222. CTransactionFile *queryCreate(const char *name, IDistributedFile *file, bool recreate=false)
  1223. {
  1224. Owned<CTransactionFile> trackedFile;
  1225. if (!recreate)
  1226. trackedFile.set(trackedFiles.find(file));
  1227. if (!trackedFile)
  1228. {
  1229. StringBuffer tmp;
  1230. name = normalizeLFN(name, tmp);
  1231. trackedFile.setown(new CTransactionFile(*this, tmp.str(), file));
  1232. trackedFiles.replace(*trackedFile.getLink());
  1233. trackedFilesByName.replace(*trackedFile.getLink());
  1234. }
  1235. return trackedFile;
  1236. }
  1237. CTransactionFile *lookupTrackedFile(IDistributedFile *file)
  1238. {
  1239. return trackedFiles.find(file);
  1240. }
  1241. public:
  1242. IMPLEMENT_IINTERFACE;
  1243. CDistributedFileTransaction(IUserDescriptor *user, IDistributedSuperFile *_owner=NULL)
  1244. : isactive(false), depth(0), prepared(0), owner(_owner)
  1245. {
  1246. setUserDescriptor(udesc,user);
  1247. }
  1248. ~CDistributedFileTransaction()
  1249. {
  1250. // New files should be removed automatically if not committed
  1251. // MORE - refactor cCreateSuperFileAction to avoid this
  1252. if (isactive)
  1253. rollback();
  1254. assert(depth == 0);
  1255. }
  1256. void ensureFile(IDistributedFile *file)
  1257. {
  1258. if (!trackedFiles.find(file))
  1259. addFile(file);
  1260. }
  1261. void addFile(IDistributedFile *file)
  1262. {
  1263. CTransactionFile *trackedFile = queryCreate(file->queryLogicalName(), file, false);
  1264. // Also add subfiles to cache
  1265. IDistributedSuperFile *sfile = file->querySuperFile();
  1266. if (sfile)
  1267. {
  1268. Owned<IDistributedFileIterator> iter = sfile->getSubFileIterator();
  1269. ForEach(*iter)
  1270. {
  1271. IDistributedFile *f = &iter->query();
  1272. trackedFile->noteAddSubFile(f);
  1273. addFile(f);
  1274. }
  1275. }
  1276. }
  1277. void noteAddSubFile(IDistributedSuperFile *super, const char *superName, IDistributedFile *sub)
  1278. {
  1279. CTransactionFile *trackedSuper = queryCreate(superName, super);
  1280. trackedSuper->noteAddSubFile(sub);
  1281. }
  1282. void noteRemoveSubFile(IDistributedSuperFile *super, IDistributedFile *sub)
  1283. {
  1284. CTransactionFile *trackedSuper = lookupTrackedFile(super);
  1285. if (trackedSuper)
  1286. trackedSuper->noteRemoveSubFile(sub);
  1287. }
  1288. virtual void clearSubFiles(IDistributedSuperFile *super)
  1289. {
  1290. CTransactionFile *trackedSuper = lookupTrackedFile(super);
  1291. if (trackedSuper)
  1292. trackedSuper->clearSubs();
  1293. }
  1294. virtual void noteSuperSwap(IDistributedSuperFile *super1, IDistributedSuperFile *super2)
  1295. {
  1296. CTransactionFile *trackedSuper1 = lookupTrackedFile(super1);
  1297. CTransactionFile *trackedSuper2 = lookupTrackedFile(super2);
  1298. assertex(trackedSuper1 && trackedSuper2);
  1299. ICopyArrayOf<IDistributedFile> super1Subs, super2Subs;
  1300. Owned<IDistributedFileIterator> iter = trackedSuper1->getSubFiles();
  1301. ForEach(*iter)
  1302. super1Subs.append(iter->query());
  1303. trackedSuper1->clearSubs();
  1304. iter.setown(trackedSuper2->getSubFiles());
  1305. ForEach(*iter)
  1306. super2Subs.append(iter->query());
  1307. trackedSuper2->clearSubs();
  1308. ForEachItemIn(s, super2Subs)
  1309. trackedSuper1->noteAddSubFile(&super2Subs.item(s));
  1310. ForEachItemIn(s2, super1Subs)
  1311. trackedSuper2->noteAddSubFile(&super1Subs.item(s2));
  1312. }
  1313. void noteRename(IDistributedFile *file, const char *newName)
  1314. {
  1315. CTransactionFile *trackedFile = lookupTrackedFile(file);
  1316. if (trackedFile)
  1317. {
  1318. trackedFiles.removeExact(trackedFile);
  1319. trackedFilesByName.removeExact(trackedFile);
  1320. trackedFile = queryCreate(newName, file);
  1321. }
  1322. }
  1323. void addAction(CDFAction *action)
  1324. {
  1325. actions.append(*action); // takes ownership
  1326. action->setTransaction(this);
  1327. }
  1328. void start()
  1329. {
  1330. if (isactive)
  1331. throw MakeStringException(-1,"Transaction already started");
  1332. clearFiles();
  1333. actions.kill();
  1334. isactive = true;
  1335. prepared = 0;
  1336. assertex(actions.ordinality()==0);
  1337. }
  1338. bool prepareActions()
  1339. {
  1340. prepared = 0;
  1341. unsigned toPrepare = actions.ordinality();
  1342. ForEachItemIn(i0,actions)
  1343. {
  1344. if (actions.item(i0).prepare())
  1345. ++prepared;
  1346. else
  1347. break;
  1348. }
  1349. return prepared == toPrepare;
  1350. }
  1351. void retryActions()
  1352. {
  1353. clearFiles(); // clear all previously tracked pending file changes, e.g. renames, super file additions/removals
  1354. while (prepared) // unlock for retry
  1355. actions.item(--prepared).retry();
  1356. }
  1357. void runActions()
  1358. {
  1359. ForEachItemIn(i,actions)
  1360. actions.item(i).run();
  1361. }
  1362. void commitActions()
  1363. {
  1364. while (actions.ordinality()) // if we get here everything should work!
  1365. {
  1366. Owned<CDFAction> action = &actions.popGet();
  1367. action->commit();
  1368. }
  1369. }
  1370. void commit()
  1371. {
  1372. if (!isactive)
  1373. return;
  1374. IException *rete=NULL;
  1375. // =============== PREPARE AND RETRY UNTIL READY
  1376. try
  1377. {
  1378. loop
  1379. {
  1380. if (prepareActions())
  1381. break;
  1382. else
  1383. retryActions();
  1384. PROGLOG("CDistributedFileTransaction: Transaction pausing");
  1385. Sleep(SDS_TRANSACTION_RETRY/2+(getRandom()%SDS_TRANSACTION_RETRY));
  1386. }
  1387. runActions();
  1388. commitAndClearup();
  1389. return;
  1390. }
  1391. catch (IException *e)
  1392. {
  1393. rete = e;
  1394. }
  1395. rollback();
  1396. throw rete;
  1397. }
  1398. void commitAndClearup()
  1399. {
  1400. // =============== COMMIT and CLEANUP
  1401. commitActions();
  1402. clearFiles();
  1403. isactive = false;
  1404. actions.kill();
  1405. deleteFiles();
  1406. }
  1407. void rollback()
  1408. {
  1409. // =============== ROLLBACK AND CLEANUP
  1410. while (actions.ordinality())
  1411. {
  1412. try
  1413. {
  1414. // we don't want to unlock what hasn't been locked
  1415. // if an exception was thrown while locking, but we
  1416. // do want to pop them all
  1417. Owned<CDFAction> action = &actions.popGet();
  1418. if (actions.ordinality()<prepared)
  1419. action->rollback();
  1420. }
  1421. catch (IException *e)
  1422. {
  1423. e->Release();
  1424. }
  1425. }
  1426. actions.kill(); // should be empty
  1427. clearFiles(); // release locks
  1428. if (!isactive)
  1429. return;
  1430. isactive = false;
  1431. // this we only want to do if active
  1432. delayeddelete.kill();
  1433. }
  1434. void autoCommit()
  1435. {
  1436. // Recursive calls to transaction will not commit until
  1437. // all calls have finished (gone back to zero depth)
  1438. if (!depth && !isactive) {
  1439. try {
  1440. isactive = true;
  1441. commit();
  1442. }
  1443. catch (IException *) {
  1444. rollback();
  1445. throw;
  1446. }
  1447. }
  1448. }
  1449. // Call this when you're recurring
  1450. void descend()
  1451. {
  1452. depth++;
  1453. }
  1454. // Call this at the end of the block that started recursion
  1455. void ascend()
  1456. {
  1457. assertex(depth);
  1458. depth--;
  1459. }
  1460. IDistributedFile *findFile(const char *name)
  1461. {
  1462. StringBuffer tmp;
  1463. name = normalizeLFN(name, tmp);
  1464. CTransactionFile *trackedFile = trackedFilesByName.find(tmp.str());
  1465. if (!trackedFile)
  1466. return NULL;
  1467. return trackedFile->queryFile();
  1468. }
  1469. IDistributedFile *lookupFile(const char *name,unsigned timeout)
  1470. {
  1471. IDistributedFile *ret = findFile(name);
  1472. if (ret)
  1473. return LINK(ret);
  1474. else
  1475. {
  1476. ret = queryDistributedFileDirectory().lookup(name, udesc, false, false, this, timeout);
  1477. if (ret)
  1478. queryCreate(name, ret, true);
  1479. return ret;
  1480. }
  1481. }
  1482. IDistributedSuperFile *lookupSuperFile(const char *name, unsigned timeout)
  1483. {
  1484. IDistributedFile *f = findFile(name);
  1485. if (f)
  1486. return LINK(f->querySuperFile());
  1487. else
  1488. {
  1489. IDistributedSuperFile *ret = queryDistributedFileDirectory().lookupSuperFile(name,udesc,this,timeout);
  1490. if (ret)
  1491. addFile(ret);
  1492. return ret;
  1493. }
  1494. }
  1495. virtual bool isSubFile(IDistributedSuperFile *super, const char *subFile, bool sub)
  1496. {
  1497. CTransactionFile *trackedSuper = lookupTrackedFile(super);
  1498. if (!trackedSuper)
  1499. return false;
  1500. return trackedSuper->find(subFile, sub);
  1501. }
  1502. public:
  1503. bool active()
  1504. {
  1505. return isactive;
  1506. }
  1507. void clearFiles()
  1508. {
  1509. trackedFiles.kill();
  1510. trackedFilesByName.kill();
  1511. if (owner)
  1512. addFile(owner); // ensure remains tracked
  1513. }
  1514. void clearFile(IDistributedFile *file)
  1515. {
  1516. CTransactionFile *trackedFile = lookupTrackedFile(file);
  1517. IDistributedSuperFile *sfile = file->querySuperFile();
  1518. if (trackedFile)
  1519. {
  1520. Owned<IDistributedFileIterator> iter = trackedFile->getSubFiles();
  1521. if (iter)
  1522. {
  1523. ForEach(*iter)
  1524. clearFile(&iter->query());
  1525. }
  1526. trackedFiles.removeExact(trackedFile);
  1527. trackedFilesByName.removeExact(trackedFile);
  1528. }
  1529. }
  1530. IUserDescriptor *queryUser()
  1531. {
  1532. return udesc;
  1533. }
  1534. bool addDelayedDelete(CDfsLogicalFileName &lfn,unsigned timeoutms)
  1535. {
  1536. delayeddelete.append(*new CDelayedDelete(lfn,udesc,timeoutms));
  1537. return true;
  1538. }
  1539. void deleteFiles() // no rollback at this point
  1540. {
  1541. Owned<IMultiException> me = MakeMultiException("Transaction");
  1542. ForEachItemIn(i,delayeddelete) {
  1543. try {
  1544. delayeddelete.item(i).doDelete();
  1545. } catch (IException *e) {
  1546. me->append(*e);
  1547. }
  1548. }
  1549. delayeddelete.kill();
  1550. if (me->ordinality())
  1551. throw me.getClear();
  1552. }
  1553. };
  1554. static bool recursiveCheckEmptyScope(IPropertyTree &ct)
  1555. {
  1556. Owned<IPropertyTreeIterator> iter = ct.getElements("*");
  1557. ForEach(*iter) {
  1558. IPropertyTree &item = iter->query();
  1559. const char *n = item.queryName();
  1560. if (!n||(strcmp(n,queryDfsXmlBranchName(DXB_Scope))!=0))
  1561. return false;
  1562. if (!recursiveCheckEmptyScope(item))
  1563. return false;
  1564. }
  1565. return true;
  1566. }
  1567. class CDFScopeIterator: public CInterface, implements IDFScopeIterator
  1568. {
  1569. PointerArray scopes;
  1570. unsigned index;
  1571. IDistributedFileDirectory *dir;
  1572. bool includeempty;
  1573. void add(IPropertyTree &t, bool recursive, StringBuffer &name)
  1574. {
  1575. name.trim();
  1576. size32_t nl = name.length();
  1577. size32_t l=nl;
  1578. if (nl) {
  1579. name.append("::");
  1580. l+=2;
  1581. }
  1582. Owned<IPropertyTreeIterator> iter = t.getElements(queryDfsXmlBranchName(DXB_Scope));
  1583. ForEach(*iter) {
  1584. IPropertyTree &ct = iter->query();
  1585. if (includeempty||!recursiveCheckEmptyScope(ct)) {
  1586. name.append(ct.queryProp("@name"));
  1587. scopes.append(strdup(name.str()));
  1588. if (recursive)
  1589. add(ct,recursive,name);
  1590. name.setLength(l);
  1591. }
  1592. }
  1593. name.setLength(nl);
  1594. }
  1595. public:
  1596. IMPLEMENT_IINTERFACE;
  1597. CDFScopeIterator(IDistributedFileDirectory *_dir,const char *base,bool recursive, bool _includeempty,unsigned timeout) // attrib not yet implemented
  1598. {
  1599. includeempty = _includeempty;
  1600. dir = _dir;
  1601. StringBuffer baseq;
  1602. StringBuffer tmp;
  1603. if (base&&*base) {
  1604. CDfsLogicalFileName dlfn;
  1605. dlfn.set(base,".");
  1606. dlfn.makeScopeQuery(baseq,false);
  1607. }
  1608. {
  1609. CConnectLock connlock("CDFScopeIterator",querySdsFilesRoot(),false,false,false,timeout);
  1610. // could use CScopeConnectLock here probably
  1611. StringBuffer name;
  1612. IPropertyTree *root = connlock.conn->queryRoot();
  1613. if (baseq.length())
  1614. root = root->queryPropTree(baseq.str());
  1615. if (root)
  1616. add(*root,recursive,name);
  1617. }
  1618. if (scopes.ordinality()>1)
  1619. qsortvec(scopes.getArray(),scopes.ordinality(),strcompare);
  1620. index = 0;
  1621. }
  1622. ~CDFScopeIterator()
  1623. {
  1624. ForEachItemIn(i,scopes) {
  1625. free(scopes.item(i));
  1626. }
  1627. }
  1628. bool first()
  1629. {
  1630. index = 0;
  1631. return isValid();
  1632. }
  1633. bool next()
  1634. {
  1635. index++;
  1636. return isValid();
  1637. }
  1638. bool isValid()
  1639. {
  1640. return (index<scopes.ordinality());
  1641. }
  1642. const char *query()
  1643. {
  1644. return (const char *)scopes.item(index);
  1645. }
  1646. };
  1647. class CDFAttributeIterator: public CInterface, implements IDFAttributesIterator
  1648. {
  1649. IArrayOf<IPropertyTree> attrs;
  1650. unsigned index;
  1651. public:
  1652. IMPLEMENT_IINTERFACE;
  1653. static MemoryBuffer &serializeFileAttributes(MemoryBuffer &mb, IPropertyTree &root, const char *name, bool issuper)
  1654. {
  1655. StringBuffer buf;
  1656. mb.append(name);
  1657. if (issuper) {
  1658. mb.append("!SF");
  1659. mb.append(root.getPropInt("@numsubfiles",0));
  1660. mb.append("");
  1661. }
  1662. else {
  1663. mb.append(root.queryProp("@directory"));
  1664. mb.append(root.getPropInt("@numparts",0));
  1665. mb.append(root.queryProp("@partmask"));
  1666. }
  1667. mb.append(root.queryProp("@modified"));
  1668. Owned<IPropertyTree> attrs = root.getPropTree("Attr");;
  1669. Owned<IAttributeIterator> attriter;
  1670. if (attrs)
  1671. attriter.setown(attrs->getAttributes());
  1672. unsigned count=0;
  1673. size32_t countpos = mb.length();
  1674. mb.append(count);
  1675. if (attriter.get()&&attriter->first()) {
  1676. do {
  1677. mb.append(attriter->queryName());
  1678. mb.append(attriter->queryValue());
  1679. count++;
  1680. } while (attriter->next());
  1681. }
  1682. const char *ps = root.queryProp("@group");
  1683. if (ps&&*ps) {
  1684. count++;
  1685. mb.append("@group");
  1686. mb.append(ps);
  1687. }
  1688. // add protected
  1689. if (attrs) {
  1690. Owned<IPropertyTreeIterator> piter = attrs->getElements("Protect");
  1691. StringBuffer plist;
  1692. ForEach(*piter) {
  1693. const char *name = piter->get().queryProp("@name");
  1694. if (name&&*name) {
  1695. unsigned count = piter->get().getPropInt("@count");
  1696. if (count) {
  1697. if (plist.length())
  1698. plist.append(',');
  1699. plist.append(name);
  1700. if (count>1)
  1701. plist.append(':').append(count);
  1702. }
  1703. }
  1704. }
  1705. if (plist.length()) {
  1706. count++;
  1707. mb.append("@protect");
  1708. mb.append(plist.str());
  1709. }
  1710. }
  1711. mb.writeDirect(countpos,sizeof(count),&count);
  1712. return mb;
  1713. }
  1714. CDFAttributeIterator(MemoryBuffer &mb) // attrib not yet implemented
  1715. {
  1716. unsigned numfiles;
  1717. mb.read(numfiles);
  1718. while (numfiles--) {
  1719. IPropertyTree *attr = getEmptyAttr();
  1720. StringAttr val;
  1721. unsigned n;
  1722. mb.read(val);
  1723. attr->setProp("@name",val.get());
  1724. mb.read(val);
  1725. if (stricmp(val,"!SF")==0) {
  1726. mb.read(n);
  1727. attr->setPropInt("@numsubfiles",n);
  1728. mb.read(val); // not used currently
  1729. }
  1730. else {
  1731. attr->setProp("@directory",val.get());
  1732. mb.read(n);
  1733. attr->setPropInt("@numparts",n);
  1734. mb.read(val);
  1735. attr->setProp("@partmask",val.get());
  1736. }
  1737. mb.read(val);
  1738. attr->setProp("@modified",val.get());
  1739. unsigned count;
  1740. mb.read(count);
  1741. StringAttr at;
  1742. while (count--) {
  1743. mb.read(at);
  1744. mb.read(val);
  1745. attr->setProp(at.get(),val.get());
  1746. }
  1747. attrs.append(*attr);
  1748. }
  1749. index = 0;
  1750. }
  1751. ~CDFAttributeIterator()
  1752. {
  1753. attrs.kill();
  1754. }
  1755. bool first()
  1756. {
  1757. index = 0;
  1758. return (attrs.ordinality()!=0);
  1759. }
  1760. bool next()
  1761. {
  1762. index++;
  1763. return (index<attrs.ordinality());
  1764. }
  1765. bool isValid()
  1766. {
  1767. return (index<attrs.ordinality());
  1768. }
  1769. IPropertyTree & query()
  1770. {
  1771. return attrs.item(index);
  1772. }
  1773. };
  1774. class CDFProtectedIterator: public CInterface, implements IDFProtectedIterator
  1775. {
  1776. StringAttr owner;
  1777. StringAttr fn;
  1778. unsigned count;
  1779. bool issuper;
  1780. Owned<IRemoteConnection> conn;
  1781. Owned<IPropertyTreeIterator> fiter;
  1782. Owned<IPropertyTreeIterator> piter;
  1783. unsigned defaultTimeout;
  1784. bool notsuper;
  1785. bool superonly;
  1786. void fill()
  1787. {
  1788. IPropertyTree &t = fiter->query();
  1789. fn.set(t.queryProp("OrigName"));
  1790. IPropertyTree &pt = piter->query();
  1791. owner.set(pt.queryProp("@name"));
  1792. count = pt.getPropInt("@count");
  1793. }
  1794. void clear()
  1795. {
  1796. piter.clear();
  1797. fiter.clear();
  1798. conn.clear();
  1799. issuper = false;
  1800. }
  1801. public:
  1802. IMPLEMENT_IINTERFACE;
  1803. CDFProtectedIterator(const char *_owner,bool _notsuper,bool _superonly,unsigned _defaultTimeout)
  1804. : owner(_owner)
  1805. {
  1806. count = 0;
  1807. issuper = false;
  1808. notsuper=_notsuper;
  1809. superonly=_superonly;
  1810. defaultTimeout = _defaultTimeout;
  1811. }
  1812. ~CDFProtectedIterator()
  1813. {
  1814. clear();
  1815. }
  1816. bool first()
  1817. {
  1818. clear();
  1819. conn.setown(querySDS().connect("Files",myProcessSession(),0, defaultTimeout));
  1820. if (!conn)
  1821. return false;
  1822. IPropertyTree *t = conn->queryRoot();
  1823. if (!superonly) {
  1824. fiter.setown(t->getElements("//File[Attr/Protect]", iptiter_remote));
  1825. if (fiter->first()) {
  1826. piter.setown(fiter->query().getElements("Attr/Protect"));
  1827. if (piter->first()) {
  1828. fill();
  1829. return true;
  1830. }
  1831. }
  1832. }
  1833. if (!notsuper) {
  1834. issuper = true;
  1835. fiter.clear();
  1836. fiter.setown(t->getElements("//SuperFile[Attr/Protect]", iptiter_remote));
  1837. if (fiter->first()) {
  1838. piter.setown(fiter->query().getElements("Attr/Protect"));
  1839. if (piter->first()) {
  1840. fill();
  1841. return true;
  1842. }
  1843. }
  1844. }
  1845. clear();
  1846. return false;
  1847. }
  1848. bool next()
  1849. {
  1850. if (!fiter.get())
  1851. return false;
  1852. if (piter->next()) {
  1853. fill();
  1854. return true;
  1855. }
  1856. loop {
  1857. if (fiter->next()) {
  1858. piter.setown(fiter->query().getElements("Attr/Protect"));
  1859. if (piter->first()) {
  1860. fill();
  1861. return true;
  1862. }
  1863. }
  1864. else if (!notsuper&&!issuper) {
  1865. issuper = true;
  1866. fiter.clear();
  1867. fiter.setown(conn->queryRoot()->getElements("//SuperFile[Attr/Protect]", iptiter_remote));
  1868. if (fiter->first()) {
  1869. piter.setown(fiter->query().getElements("Attr/Protect"));
  1870. if (piter->first()) {
  1871. fill();
  1872. return true;
  1873. }
  1874. }
  1875. else
  1876. break;
  1877. }
  1878. else
  1879. break;
  1880. }
  1881. clear();
  1882. return false;
  1883. }
  1884. bool isValid()
  1885. {
  1886. return fiter.get()!=NULL;
  1887. }
  1888. const char *queryFilename()
  1889. {
  1890. return fn;
  1891. }
  1892. const char *queryOwner()
  1893. {
  1894. return owner;
  1895. }
  1896. unsigned getCount()
  1897. {
  1898. return count;
  1899. }
  1900. bool isSuper()
  1901. {
  1902. return issuper;
  1903. }
  1904. };
  1905. // --------------------------------------------------------
  1906. class CDistributedFilePart: public CInterface, implements IDistributedFilePart
  1907. {
  1908. unsigned partIndex;
  1909. CDistributedFile &parent;
  1910. Owned<IPropertyTree> attr;
  1911. CriticalSection sect;
  1912. StringAttr overridename; // may or not be relative to directory
  1913. bool dirty; // whether needs updating in tree
  1914. offset_t getSize(bool checkCompressed);
  1915. public:
  1916. virtual void Link(void) const;
  1917. virtual bool Release(void) const;
  1918. void set(IPropertyTree *pt,FileClusterInfoArray &clusters,unsigned maxcluster);
  1919. RemoteFilename &getFilename(RemoteFilename &ret,unsigned copy);
  1920. void renameFile(IFile *file);
  1921. IPropertyTree &queryAttributes();
  1922. bool lockProperties(unsigned timems);
  1923. void unlockProperties(DFTransactionState state);
  1924. bool isHost(unsigned copy);
  1925. offset_t getFileSize(bool allowphysical,bool forcephysical);
  1926. offset_t getDiskSize(bool allowphysical,bool forcephysical);
  1927. bool getModifiedTime(bool allowphysical,bool forcephysical,CDateTime &dt);
  1928. bool getCrc(unsigned &crc);
  1929. unsigned getPhysicalCrc();
  1930. IPartDescriptor *getPartDescriptor();
  1931. unsigned numCopies();
  1932. INode *queryNode(unsigned copy);
  1933. unsigned queryDrive(unsigned copy);
  1934. StringBuffer &getPartName(StringBuffer &name);
  1935. StringBuffer &getPartDirectory(StringBuffer &name,unsigned copy);
  1936. const char *queryOverrideName() { return overridename; }
  1937. void clearOverrideName()
  1938. {
  1939. if (overridename.get()&&overridename.length()) {
  1940. dirty = true;
  1941. overridename.clear();
  1942. }
  1943. }
  1944. unsigned bestCopyNum(const IpAddress &ip,unsigned rel=0);
  1945. unsigned copyClusterNum(unsigned copy,unsigned *replicate=NULL);
  1946. void childLink(void) { CInterface::Link(); }
  1947. bool childRelease(void) { return CInterface::Release(); }
  1948. CDistributedFilePart(CDistributedFile &_parent,unsigned _part,IPartDescriptor *pd);
  1949. unsigned getPartIndex()
  1950. {
  1951. return partIndex;
  1952. }
  1953. INode *getNode(unsigned copy)
  1954. {
  1955. INode *ret = queryNode(copy);
  1956. if (ret)
  1957. return LINK(ret);
  1958. return NULL;
  1959. }
  1960. void setAttr(IPropertyTree &pt)
  1961. {
  1962. attr.setown(createPTreeFromIPT(&pt)); // take a copy
  1963. dirty = false;
  1964. }
  1965. IPropertyTree *queryAttr()
  1966. {
  1967. return attr;
  1968. }
  1969. inline CDistributedFile &queryParent()
  1970. {
  1971. return parent;
  1972. }
  1973. inline bool isDirty()
  1974. {
  1975. return dirty;
  1976. }
  1977. inline bool clearDirty()
  1978. {
  1979. bool ret=dirty;
  1980. dirty = false;
  1981. return ret;
  1982. }
  1983. };
  1984. // --------------------------------------------------------
  1985. class CDistributedFilePartArray: public CIArrayOf<CDistributedFilePart>
  1986. {
  1987. public:
  1988. virtual ~CDistributedFilePartArray() // this shouldn't be needed - points to problem in CIArrayOf?
  1989. {
  1990. kill();
  1991. }
  1992. void kill(bool nodel = false)
  1993. {
  1994. if (nodel)
  1995. CIArrayOf<CDistributedFilePart>::kill(true);
  1996. else {
  1997. while (ordinality()) {
  1998. CDistributedFilePart &part = popGet();
  1999. part.Release();
  2000. }
  2001. }
  2002. }
  2003. };
  2004. // --------------------------------------------------------
  2005. /**
  2006. * Base Iterator class for all iterator types. Implements basic iteration
  2007. * logic and forces all iterators to behave similarly. This will simplify
  2008. * future compatibility with STL containers/algorithms.
  2009. *
  2010. * INTERFACE needs to be extended from IIteratorOf<>
  2011. * ARRAYTY need to be extended from IArrayOf<>
  2012. */
  2013. template <class INTERFACE, class ARRAYTY>
  2014. class CDistributedFileIteratorBase: public CInterface, implements INTERFACE
  2015. {
  2016. protected:
  2017. unsigned index;
  2018. ARRAYTY list;
  2019. virtual bool set() { return isValid(); }
  2020. public:
  2021. IMPLEMENT_IINTERFACE;
  2022. CDistributedFileIteratorBase()
  2023. : index(0)
  2024. {
  2025. }
  2026. virtual ~CDistributedFileIteratorBase()
  2027. {
  2028. list.kill();
  2029. }
  2030. bool first()
  2031. {
  2032. if (list.ordinality() == 0)
  2033. return false;
  2034. index = 0;
  2035. return set();
  2036. }
  2037. bool next()
  2038. {
  2039. index++;
  2040. set();
  2041. return isValid();
  2042. }
  2043. bool isValid()
  2044. {
  2045. return (index < list.ordinality());
  2046. }
  2047. };
  2048. /**
  2049. * FilePart Iterator, used by files to manipulate its parts.
  2050. */
  2051. class CDistributedFilePartIterator: public CDistributedFileIteratorBase<IDistributedFilePartIterator, CDistributedFilePartArray>
  2052. {
  2053. public:
  2054. CDistributedFilePartIterator(CDistributedFilePartArray &parts, IDFPartFilter *filter)
  2055. {
  2056. ForEachItemIn(i,parts) {
  2057. if (!filter||filter->includePart(i))
  2058. list.append(*LINK(&parts.item(i)));
  2059. }
  2060. }
  2061. CDistributedFilePartIterator()
  2062. {
  2063. }
  2064. IDistributedFilePart & query()
  2065. {
  2066. return list.item(index);
  2067. }
  2068. CDistributedFilePartArray &queryParts()
  2069. {
  2070. return list;
  2071. }
  2072. };
  2073. /**
  2074. * File Iterator, used by directory to list file search results.
  2075. */
  2076. class CDistributedFileIterator: public CDistributedFileIteratorBase<IDistributedFileIterator, PointerArray>
  2077. {
  2078. Owned<IDistributedFile> cur;
  2079. IDistributedFileDirectory *parent;
  2080. Linked<IUserDescriptor> udesc;
  2081. Linked<IDistributedFileTransaction> transaction;
  2082. bool set()
  2083. {
  2084. while (isValid()) {
  2085. cur.setown(parent->lookup(queryName(),udesc,false,NULL));
  2086. if (cur)
  2087. return true;
  2088. index++;
  2089. }
  2090. return false;
  2091. }
  2092. public:
  2093. CDistributedFileIterator(IDistributedFileDirectory *_dir,const char *wildname,bool includesuper,IUserDescriptor *user,IDistributedFileTransaction *_transaction=NULL)
  2094. : transaction(_transaction)
  2095. {
  2096. setUserDescriptor(udesc,user);
  2097. if (!wildname||!*wildname)
  2098. wildname = "*";
  2099. parent = _dir;
  2100. bool recursive = (stricmp(wildname,"*")==0);
  2101. Owned<IDFAttributesIterator> attriter = parent->getDFAttributesIterator(wildname,user,recursive,includesuper,NULL);
  2102. ForEach(*attriter) {
  2103. IPropertyTree &pt = attriter->query();
  2104. list.append(strdup(pt.queryProp("@name")));
  2105. }
  2106. index = 0;
  2107. if (list.ordinality()>1)
  2108. qsortvec(list.getArray(),list.ordinality(),strcompare);
  2109. }
  2110. const char *queryName()
  2111. {
  2112. return (const char *)list.item(index);
  2113. }
  2114. StringBuffer & getName(StringBuffer &name)
  2115. {
  2116. return name.append(queryName());
  2117. }
  2118. IDistributedFile & query()
  2119. {
  2120. return *cur;
  2121. }
  2122. };
  2123. /**
  2124. * SuperFile Iterator, used by CDistributedFile to list all its super-owners by name.
  2125. */
  2126. class CDistributedSuperFileIterator: public CDistributedFileIteratorBase<IDistributedSuperFileIterator, StringAttrArray>
  2127. {
  2128. CDistributedFileDirectory *parent;
  2129. Linked<IUserDescriptor> udesc;
  2130. Linked<IDistributedFileTransaction> transaction;
  2131. Owned<IDistributedSuperFile> cur;
  2132. public:
  2133. CDistributedSuperFileIterator(CDistributedFileDirectory *_parent,IPropertyTree *root,IUserDescriptor *user, IDistributedFileTransaction *_transaction)
  2134. : transaction(_transaction)
  2135. {
  2136. setUserDescriptor(udesc,user);
  2137. parent = _parent;
  2138. if (root) {
  2139. Owned<IPropertyTreeIterator> iter = root->getElements("SuperOwner");
  2140. StringBuffer pname;
  2141. ForEach(*iter) {
  2142. iter->query().getProp("@name",pname.clear());
  2143. if (pname.length())
  2144. list.append(* new StringAttrItem(pname.str()));
  2145. }
  2146. }
  2147. }
  2148. IDistributedSuperFile & query()
  2149. {
  2150. // NOTE: This used to include a do/while (!cur.get()&&next()) loop
  2151. // this should never be needed but match previous semantics
  2152. // throwing an exception now, to catch the error early on
  2153. if (transaction.get())
  2154. cur.setown(transaction->lookupSuperFile(queryName()));
  2155. else
  2156. cur.setown(parent->lookupSuperFile(queryName(),udesc,NULL));
  2157. if (!cur.get())
  2158. throw MakeStringException(-1,"superFileIter: invalid super-file on query at %s", queryName());
  2159. return *cur;
  2160. }
  2161. virtual const char *queryName()
  2162. {
  2163. if (isValid())
  2164. return list.item(index).text.get();
  2165. return NULL;
  2166. }
  2167. };
  2168. //-----------------------------------------------------------------------------
  2169. inline void dfCheckRoot(const char *trc,Owned<IPropertyTree> &root,IRemoteConnection *conn)
  2170. {
  2171. if (root.get()!=conn->queryRoot()) {
  2172. WARNLOG("%s - root changed",trc);
  2173. #ifdef _DEBUG
  2174. PrintStackReport();
  2175. #endif
  2176. root.setown(conn->getRoot());
  2177. }
  2178. }
  2179. static bool setFileProtectTree(IPropertyTree &p,const char *owner, bool protect)
  2180. {
  2181. bool ret = false;
  2182. CDateTime dt;
  2183. dt.setNow();
  2184. if (owner&&*owner) {
  2185. Owned<IPropertyTree> t = getNamedPropTree(&p,"Protect","@name",owner,false);
  2186. if (t) {
  2187. unsigned c = t->getPropInt("@count");
  2188. if (protect)
  2189. c++;
  2190. else {
  2191. if (c>=1) {
  2192. p.removeTree(t);
  2193. c = 0;
  2194. }
  2195. else
  2196. c--;
  2197. }
  2198. if (c) {
  2199. t->setPropInt("@count",c);
  2200. StringBuffer str;
  2201. t->setProp("@modified",dt.getString(str).str());
  2202. }
  2203. }
  2204. else if (protect) {
  2205. t.setown(addNamedPropTree(&p,"Protect","@name",owner));
  2206. t->setPropInt("@count",1);
  2207. StringBuffer str;
  2208. t->setProp("@modified",dt.getString(str).str());
  2209. }
  2210. ret = true;
  2211. }
  2212. else if (!protect) {
  2213. unsigned n=0;
  2214. IPropertyTree *pt;
  2215. while ((pt=p.queryPropTree("Protect[1]"))!=NULL) {
  2216. p.removeTree(pt);
  2217. n++;
  2218. }
  2219. if (n)
  2220. ret = true;
  2221. }
  2222. return ret;
  2223. }
  2224. static bool checkProtectAttr(const char *logicalname,IPropertyTree *froot,StringBuffer &reason)
  2225. {
  2226. Owned<IPropertyTreeIterator> wpiter = froot->getElements("Attr/Protect");
  2227. bool prot = false;
  2228. ForEach(*wpiter) {
  2229. IPropertyTree &t = wpiter->query();
  2230. if (t.getPropInt("@count")) {
  2231. const char *wpname = t.queryProp("@name");
  2232. if (!wpname||!*wpname)
  2233. wpname = "<Unknown>";
  2234. if (prot)
  2235. reason.appendf(", %s",wpname);
  2236. else {
  2237. reason.appendf("file %s protected by %s",logicalname,wpname);
  2238. prot = true;
  2239. }
  2240. }
  2241. }
  2242. return prot;
  2243. }
  2244. /**
  2245. * A template class which implements the common methods of an IDistributedFile interface.
  2246. * The actual interface (extended from IDistributedFile) is provided as a template argument.
  2247. */
  2248. template <class INTERFACE>
  2249. class CDistributedFileBase : public CInterface, implements INTERFACE
  2250. {
  2251. protected:
  2252. Owned<IPropertyTree> root;
  2253. Owned<IRemoteConnection> conn; // kept connected during lifetime for attributes
  2254. CDfsLogicalFileName logicalName;
  2255. CriticalSection sect;
  2256. CDistributedFileDirectory *parent;
  2257. unsigned proplockcount;
  2258. unsigned transactionnest;
  2259. Linked<IUserDescriptor> udesc;
  2260. unsigned defaultTimeout;
  2261. bool dirty;
  2262. public:
  2263. IPropertyTree *queryRoot() { return root; }
  2264. CDistributedFileBase<INTERFACE>()
  2265. {
  2266. parent = NULL;
  2267. proplockcount = 0;
  2268. transactionnest = 0;
  2269. defaultTimeout = INFINITE;
  2270. dirty = false;
  2271. }
  2272. ~CDistributedFileBase<INTERFACE>()
  2273. {
  2274. root.clear();
  2275. }
  2276. unsigned setPropLockCount(unsigned _propLockCount)
  2277. {
  2278. unsigned prevPropLockCount = proplockcount;
  2279. proplockcount = _propLockCount;
  2280. return prevPropLockCount;
  2281. }
  2282. bool isCompressed(bool *blocked)
  2283. {
  2284. return ::isCompressed(queryAttributes(),blocked);
  2285. }
  2286. StringBuffer &getLogicalName(StringBuffer &lname)
  2287. {
  2288. lname.append(logicalName.get());
  2289. return lname;
  2290. }
  2291. void setLogicalName(const char *lname)
  2292. {
  2293. logicalName.set(lname);
  2294. }
  2295. const char *queryLogicalName()
  2296. {
  2297. return logicalName.get();
  2298. }
  2299. IPropertyTree &queryAttributes()
  2300. {
  2301. IPropertyTree *t = root->queryPropTree("Attr");
  2302. if (!t)
  2303. t = root->setPropTree("Attr",createPTree("Attr")); // takes ownership
  2304. return *t;
  2305. }
  2306. protected:
  2307. class CFileChangeWriteLock
  2308. {
  2309. IRemoteConnection *conn;
  2310. unsigned timeoutMs, prevMode;
  2311. public:
  2312. CFileChangeWriteLock(IRemoteConnection *_conn, unsigned _timeoutMs)
  2313. : conn(_conn), timeoutMs(_timeoutMs)
  2314. {
  2315. prevMode = conn->queryMode();
  2316. unsigned newMode = (prevMode & ~RTM_LOCKBASIC_MASK) | RTM_LOCK_WRITE;
  2317. conn->changeMode(RTM_LOCK_WRITE, timeoutMs);
  2318. }
  2319. ~CFileChangeWriteLock()
  2320. {
  2321. if (conn)
  2322. conn->changeMode(prevMode, timeoutMs);
  2323. }
  2324. void clear() { conn = NULL; }
  2325. };
  2326. IPropertyTree *closeConnection(bool removeFile)
  2327. {
  2328. Owned<IPropertyTree> detachedRoot = createPTreeFromIPT(root);
  2329. root.clear();
  2330. conn->close(removeFile);
  2331. conn.clear();
  2332. return detachedRoot.getClear();
  2333. }
  2334. IPropertyTree *resetFileAttr(IPropertyTree *prop=NULL)
  2335. {
  2336. if (prop)
  2337. return root->setPropTree("Attr", prop);
  2338. root->removeProp("Attr");
  2339. return NULL;
  2340. }
  2341. void updateFS(const CDfsLogicalFileName &lfn, unsigned timeoutMs)
  2342. {
  2343. // Update the file system
  2344. removeFileEmptyScope(lfn, timeoutMs);
  2345. // MORE: We shouldn't have to update all relationships if we had done a better job making sure
  2346. // that all correct relationships were properly cleaned up
  2347. queryDistributedFileDirectory().removeAllFileRelationships(lfn.get());
  2348. }
  2349. public:
  2350. bool isAnon()
  2351. {
  2352. return !logicalName.isSet();
  2353. }
  2354. /*
  2355. * Change connection to write-mode, allowing multiple writers only on the same instance.
  2356. * Returns true if the lock was lost at least once before succeeding, hinting that some
  2357. * resources might need reload (like sub-files list, etc).
  2358. *
  2359. * WARN: This is not thread-safe
  2360. *
  2361. * @deprecated : use DistributedFilePropertyLock instead, when possible
  2362. */
  2363. bool lockProperties(unsigned timeoutms)
  2364. {
  2365. bool reload = false;
  2366. if (timeoutms==INFINITE)
  2367. timeoutms = defaultTimeout;
  2368. if (proplockcount++==0)
  2369. {
  2370. if (conn)
  2371. {
  2372. conn->rollback(); // changes chouldn't be done outside lock properties
  2373. #ifdef TRACE_LOCKS
  2374. PROGLOG("lockProperties: pre safeChangeModeWrite(%x)",(unsigned)(memsize_t)conn.get());
  2375. #endif
  2376. try
  2377. {
  2378. if (0 == timeoutms)
  2379. conn->changeMode(RTM_LOCK_WRITE, 0, true); // 0 timeout, test and fail immediately if contention
  2380. else
  2381. safeChangeModeWrite(conn,queryLogicalName(),reload,timeoutms);
  2382. }
  2383. catch(IException *)
  2384. {
  2385. proplockcount--;
  2386. dfCheckRoot("lockProperties",root,conn);
  2387. if (reload)
  2388. dirty = true; // safeChangeModeWrite unlocked, and reload will be need if retried
  2389. throw;
  2390. }
  2391. if (dirty) // a previous attempt unlocked and did not reload
  2392. {
  2393. dirty = false;
  2394. if (!reload) // if reload=true, safeChangeModeWrite has just reloaded, so no need to again here
  2395. {
  2396. conn->reload();
  2397. reload = true;
  2398. }
  2399. }
  2400. #ifdef TRACE_LOCKS
  2401. PROGLOG("lockProperties: done safeChangeModeWrite(%x)",(unsigned)(memsize_t)conn.get());
  2402. LogRemoteConn(conn);
  2403. #endif
  2404. dfCheckRoot("lockProperties",root,conn);
  2405. }
  2406. }
  2407. return reload;
  2408. }
  2409. /*
  2410. * Change connection back to read mode on the last unlock. There should never be
  2411. * an uneven number of locks/unlocks, since that will leave the connection with
  2412. * the DFS locked until the instance's destruction.
  2413. *
  2414. * WARN: This is not thread-safe
  2415. *
  2416. * @deprecated : use DistributedFilePropertyLock instead, when possible
  2417. */
  2418. void unlockProperties(DFTransactionState state=TAS_NONE)
  2419. {
  2420. savePartsAttr();
  2421. if (--proplockcount==0) {
  2422. if (conn) {
  2423. // Transactional logic, if any
  2424. switch(state) {
  2425. case TAS_SUCCESS:
  2426. conn->commit();
  2427. break;
  2428. case TAS_FAILURE:
  2429. conn->rollback();
  2430. break;
  2431. case TAS_RETRY:
  2432. conn->changeMode(RTM_NONE,defaultTimeout,true);
  2433. return;
  2434. // TAS_NONE, do nothing
  2435. }
  2436. #ifdef TRACE_LOCKS
  2437. PROGLOG("unlockProperties: pre changeMode(%x)",(unsigned)(memsize_t)conn.get());
  2438. #endif
  2439. conn->changeMode(RTM_LOCK_READ,defaultTimeout,true);
  2440. #ifdef TRACE_LOCKS
  2441. PROGLOG("unlockProperties: post changeMode(%x)",(unsigned)(memsize_t)conn.get());
  2442. LogRemoteConn(conn);
  2443. #endif
  2444. dfCheckRoot("unlockProperties",root,conn);
  2445. }
  2446. }
  2447. }
  2448. bool getModificationTime(CDateTime &dt)
  2449. {
  2450. StringBuffer str;
  2451. if (!root->getProp("@modified",str))
  2452. return false;
  2453. dt.setString(str.str());
  2454. return true;
  2455. }
  2456. void setModificationTime(const CDateTime &dt)
  2457. {
  2458. DistributedFilePropertyLock lock(this);
  2459. if (dt.isNull())
  2460. root->removeProp("@modified");
  2461. else {
  2462. StringBuffer str;
  2463. root->setProp("@modified",dt.getString(str).str());
  2464. }
  2465. root->removeProp("@verified");
  2466. }
  2467. void setModified()
  2468. {
  2469. CDateTime dt;
  2470. dt.setNow();
  2471. setModificationTime(dt);
  2472. }
  2473. virtual StringBuffer &getECL(StringBuffer &buf)
  2474. {
  2475. MemoryBuffer mb;
  2476. if (queryAttributes().getPropBin("ECLbin",mb))
  2477. buf.deserialize(mb);
  2478. else
  2479. queryAttributes().getProp("ECL",buf);
  2480. return buf;
  2481. }
  2482. virtual void setECL(const char *ecl)
  2483. {
  2484. DistributedFilePropertyLock lock(this);
  2485. IPropertyTree &p = queryAttributes();
  2486. #ifdef PACK_ECL
  2487. p.removeProp("ECL");
  2488. if (!ecl||!*ecl)
  2489. p.removeProp("ECLbin");
  2490. else {
  2491. MemoryBuffer mb; // could be better
  2492. StringBuffer buf(ecl);
  2493. buf.serialize(mb);
  2494. root->setPropBin("ECLbin",mb.length(),mb.toByteArray());
  2495. }
  2496. #else
  2497. p.setProp("ECL",ecl);
  2498. #endif
  2499. }
  2500. virtual bool isSubFile()
  2501. {
  2502. CriticalBlock block(sect);
  2503. return root&&root->hasProp("SuperOwner[1]");
  2504. }
  2505. void setProtect(const char *owner, bool protect, unsigned timems)
  2506. {
  2507. if (logicalName.isForeign()) {
  2508. parent->setFileProtect(logicalName,udesc,owner,protect);
  2509. }
  2510. else {
  2511. bool ret=false;
  2512. if (conn) {
  2513. DistributedFilePropertyLock lock(this);
  2514. IPropertyTree &p = queryAttributes();
  2515. CDateTime dt;
  2516. dt.setNow();
  2517. if (setFileProtectTree(p,owner,protect))
  2518. conn->commit();
  2519. dfCheckRoot("setProtect.1",root,conn);
  2520. }
  2521. else
  2522. ERRLOG("setProtect - cannot protect %s (no connection in file)",owner?owner:"");
  2523. }
  2524. }
  2525. virtual IDistributedSuperFileIterator *getOwningSuperFiles(IDistributedFileTransaction *_transaction)
  2526. {
  2527. CriticalBlock block(sect);
  2528. return new CDistributedSuperFileIterator(parent,root,udesc,_transaction);
  2529. }
  2530. virtual void checkFormatAttr(IDistributedFile *sub, const char* exprefix="")
  2531. {
  2532. // check file has same (or similar) format
  2533. IPropertyTree &superProp = queryAttributes();
  2534. IPropertyTree &subProp = sub->queryAttributes();
  2535. if (!exprefix)
  2536. exprefix = "CheckFormatAttr";
  2537. bool superBlocked = false;
  2538. bool superComp = ::isCompressed(superProp,&superBlocked);
  2539. bool subBlocked = false;
  2540. bool subComp = ::isCompressed(subProp,&subBlocked);
  2541. // FIXME: this may fail if an empty superfile added to a compressed superfile
  2542. if (superComp != subComp)
  2543. throw MakeStringException(-1,"%s: %s's compression setting (%s) is different than %s's (%s)",
  2544. exprefix, sub->queryLogicalName(), (subComp?"compressed":"uncompressed"),
  2545. queryLogicalName(), (superComp?"compressed":"uncompressed"));
  2546. if (superBlocked != subBlocked)
  2547. throw MakeStringException(-1,"%s: %s's blocked setting (%s) is different than %s's (%s)",
  2548. exprefix, sub->queryLogicalName(), (subBlocked?"blocked":"unblocked"),
  2549. queryLogicalName(), (superBlocked?"blocked":"unblocked"));
  2550. #ifdef SUBFILE_COMPATIBILITY_CHECKING
  2551. bool subSoft = subProp.hasProp("_record_layout");
  2552. bool superSoft = superProp.hasProp("_record_layout");
  2553. if (superSoft != subSoft)
  2554. throw MakeStringException(-1,"%s: %s's record layout (%s) is different than %s's (%s)",
  2555. exprefix, sub->queryLogicalName(), (subSoft?"dynamic":"fixed"),
  2556. queryLogicalName(), (superSoft?"dynamic":"fixed"));
  2557. // If they don't, they must have the same size
  2558. if (!superSoft) {
  2559. unsigned superSize = superProp.getPropInt("@recordSize",0);
  2560. unsigned subSize = subProp.getPropInt("@recordSize",0);
  2561. // Variable length files (CSV, etc) have zero record size
  2562. if (superSize && subSize && (superSize != subSize))
  2563. throw MakeStringException(-1,"%s: %s's record size (%d) is different than %s's (%d)",
  2564. exprefix, sub->queryLogicalName(), subSize, queryLogicalName(), superSize);
  2565. }
  2566. StringBuffer superFmt;
  2567. bool superHasFmt = superProp.getProp("@format",superFmt);
  2568. StringBuffer subFmt;
  2569. bool subHasFmt = subProp.getProp("@format",subFmt);
  2570. if (subHasFmt && superHasFmt)
  2571. if (strcmp(normalizeFormat(superFmt).str(),normalizeFormat(subFmt).str()) != 0)
  2572. throw MakeStringException(-1,"%s: %s's format (%s) is different than %s's (%s)",
  2573. exprefix, sub->queryLogicalName(), superFmt.str(),
  2574. queryLogicalName(), subFmt.str());
  2575. #endif
  2576. bool superLocal = superProp.getPropBool("@local",false);
  2577. bool subLocal = subProp.getPropBool("@local",false);
  2578. if (subLocal != superLocal)
  2579. throw MakeStringException(-1,"%s: %s's local setting (%s) is different than %s's (%s)",
  2580. exprefix, sub->queryLogicalName(), (subLocal?"local":"global"),
  2581. queryLogicalName(), (superLocal?"local":"global"));
  2582. int superRepO = superProp.getPropInt("@replicateOffset",1);
  2583. int subRepO = subProp.getPropInt("@replicateOffset",1);
  2584. if (subRepO != superRepO)
  2585. throw MakeStringException(-1,"%s: %s's replication offset (%d) is different than %s's (%d)",
  2586. exprefix, sub->queryLogicalName(), subRepO,
  2587. queryLogicalName(), superRepO);
  2588. }
  2589. virtual void getSuperOwners(StringArray &owners)
  2590. {
  2591. if (root)
  2592. {
  2593. StringBuffer owner;
  2594. Owned<IPropertyTreeIterator> iter = root->getElements("SuperOwner");
  2595. ForEach (*iter)
  2596. {
  2597. iter->query().getProp("@name", owner.clear());
  2598. if (owner.length())
  2599. {
  2600. if (NotFound == owners.find(owner))
  2601. owners.append(owner);
  2602. }
  2603. }
  2604. }
  2605. }
  2606. void linkSuperOwner(const char *superfile,bool link)
  2607. {
  2608. if (!superfile||!*superfile)
  2609. return;
  2610. if (conn) {
  2611. Owned<IPropertyTree> t = getNamedPropTree(root,"SuperOwner","@name",superfile,false);
  2612. if (t && !link)
  2613. root->removeTree(t);
  2614. else if (!t && link)
  2615. t.setown(addNamedPropTree(root,"SuperOwner","@name",superfile));
  2616. }
  2617. else
  2618. ERRLOG("linkSuperOwner - cannot link to %s (no connection in file)",superfile);
  2619. }
  2620. void setAccessed()
  2621. {
  2622. CDateTime dt;
  2623. dt.setNow();
  2624. setAccessedTime(dt);
  2625. }
  2626. virtual StringBuffer &getColumnMapping(StringBuffer &mapping)
  2627. {
  2628. queryAttributes().getProp("@columnMapping",mapping);
  2629. return mapping;
  2630. }
  2631. virtual void setColumnMapping(const char *mapping)
  2632. {
  2633. DistributedFilePropertyLock lock(this);
  2634. if (!mapping||!*mapping)
  2635. queryAttributes().removeProp("@columnMapping");
  2636. else
  2637. queryAttributes().setProp("@columnMapping",mapping);
  2638. }
  2639. unsigned setDefaultTimeout(unsigned timems)
  2640. {
  2641. unsigned ret = defaultTimeout;
  2642. defaultTimeout = timems;
  2643. return ret;
  2644. }
  2645. // MORE - simplify this, after removing CLightWeightSuperFileConn
  2646. bool canModify(StringBuffer &reason)
  2647. {
  2648. return !checkProtectAttr(logicalName.get(),root,reason);
  2649. }
  2650. bool canRemove(StringBuffer &reason,bool ignoresub=false)
  2651. {
  2652. CriticalBlock block(sect);
  2653. if (!canModify(reason))
  2654. return false;
  2655. const char *logicalname = logicalName.get();
  2656. if (!logicalname||!*logicalname) {
  2657. reason.appendf("empty filename");
  2658. return false;
  2659. }
  2660. if (logicalName.isQuery()) {
  2661. reason.appendf("%s is query",logicalname);
  2662. return false;
  2663. }
  2664. if (logicalName.isExternal()) {
  2665. reason.appendf("%s is external",logicalname);
  2666. return false;
  2667. }
  2668. if (logicalName.isForeign()) {
  2669. reason.appendf("%s is foreign",logicalname);
  2670. return false;
  2671. }
  2672. if (logicalName.isMulti()) {
  2673. reason.appendf("%s is multi",logicalname);
  2674. return false;
  2675. }
  2676. if (!ignoresub) {
  2677. // And has super owners
  2678. Owned<IPropertyTreeIterator> iter = root->getElements("SuperOwner");
  2679. if (iter->first()) {
  2680. reason.append("Cannot remove file ").append(logicalname).append(" as owned by SuperFile(s): ");
  2681. loop {
  2682. reason.append(iter->query().queryProp("@name"));
  2683. if (!iter->next())
  2684. break;
  2685. reason.append(", ");
  2686. }
  2687. return false;
  2688. }
  2689. }
  2690. return true;
  2691. }
  2692. virtual const char *queryDefaultDir() = 0;
  2693. virtual unsigned numParts() = 0;
  2694. virtual IDistributedFilePart &queryPart(unsigned idx) = 0;
  2695. virtual IDistributedFilePart* getPart(unsigned idx) = 0;
  2696. virtual void savePartsAttr(bool force=false) = 0;
  2697. virtual IDistributedFilePartIterator *getIterator(IDFPartFilter *filter=NULL) = 0;
  2698. virtual IDistributedSuperFile *querySuperFile() = 0;
  2699. virtual ClusterPartDiskMapSpec &queryPartDiskMapping(unsigned clusternum)=0;
  2700. virtual void updatePartDiskMapping(const char *clustername,const ClusterPartDiskMapSpec &spec)=0;
  2701. virtual void enqueueReplicate()=0;
  2702. virtual bool getAccessedTime(CDateTime &dt) = 0; // get date and time last accessed (returns false if not set)
  2703. virtual void setAccessedTime(const CDateTime &dt) = 0; // set date and time last accessed
  2704. };
  2705. class CDistributedFile: public CDistributedFileBase<IDistributedFile>
  2706. {
  2707. protected:
  2708. CDistributedFilePartArray parts; // use queryParts to access
  2709. CriticalSection sect;
  2710. StringAttr directory;
  2711. StringAttr partmask;
  2712. FileClusterInfoArray clusters;
  2713. void savePartsAttr(bool force)
  2714. {
  2715. CriticalBlock block (sect);
  2716. IPropertyTree *pt;
  2717. if (parts.ordinality()==1) { // single part saved as part
  2718. if (parts.item(0).clearDirty()||force) {
  2719. CDistributedFilePart &part = parts.item(0);
  2720. while ((pt=root->queryPropTree("Part[1]"))!=NULL)
  2721. root->removeTree(pt);
  2722. pt = createPTreeFromIPT(part.queryAttr());
  2723. pt->setPropInt("@num",1);
  2724. const char *grp = root->queryProp("@group");
  2725. if (!grp||!*grp) {
  2726. StringBuffer eps;
  2727. pt->addProp("@node",part.queryNode(0)->endpoint().getUrlStr(eps).str()); // legacy
  2728. }
  2729. const char *override = part.queryOverrideName();
  2730. if (override&&*override)
  2731. pt->setProp("@name",override);
  2732. else {
  2733. pt->removeProp("@name");
  2734. const char *mask=queryPartMask();
  2735. if (mask&&*mask) {
  2736. StringBuffer tmp;
  2737. expandMask(tmp,mask,0,1);
  2738. pt->setProp("@name",tmp.str());
  2739. }
  2740. }
  2741. root->setPropTree("Part",pt);
  2742. }
  2743. }
  2744. else {
  2745. unsigned n = parts.ordinality();
  2746. unsigned i1;
  2747. for (i1=0;i1<n;i1++) {
  2748. if (parts.item(i1).clearDirty()||force) {
  2749. MemoryBuffer mb;
  2750. CriticalBlock block (sect);
  2751. ForEachItemIn(i2,parts)
  2752. serializePartAttr(mb,parts.item(i2).queryAttr());
  2753. root->setPropBin("Parts",mb.length(),mb.toByteArray());
  2754. while ((pt=root->queryPropTree("Part[1]"))!=NULL)
  2755. root->removeTree(pt);
  2756. break;
  2757. }
  2758. }
  2759. while (i1<n)
  2760. parts.item(i1++).clearDirty();
  2761. }
  2762. }
  2763. void detach(unsigned timeoutMs=INFINITE, bool removePhysicals=true)
  2764. {
  2765. // Removes either a cluster in case of multi cluster file or the whole File entry from DFS
  2766. assert(proplockcount == 0 && "CDistributedFile detach: Some properties are still locked");
  2767. assertex(!isAnon()); // not attached!
  2768. if (removePhysicals)
  2769. {
  2770. // Avoid removing physically when there is no physical representation
  2771. if (logicalName.isMulti() || logicalName.isExternal())
  2772. removePhysicals = false;
  2773. }
  2774. StringBuffer clusterName;
  2775. Owned<IFileDescriptor> fileDescCopy;
  2776. #ifdef EXTRA_LOGGING
  2777. PROGLOG("CDistributedFile::detach(%s)",logicalName.get());
  2778. LOGPTREE("CDistributedFile::detach root.1",root);
  2779. #endif
  2780. {
  2781. CriticalBlock block(sect); // JCSMORE - not convinced this is still necessary
  2782. CFileChangeWriteLock writeLock(conn, timeoutMs);
  2783. logicalName.getCluster(clusterName);
  2784. // copy file descriptor before altered, used by physical file removal routines
  2785. if (removePhysicals)
  2786. {
  2787. MemoryBuffer mb;
  2788. Owned<IFileDescriptor> fdesc = getFileDescriptor(clusterName);
  2789. fdesc->serialize(mb);
  2790. fileDescCopy.setown(deserializeFileDescriptor(mb));
  2791. }
  2792. bool removeFile=true;
  2793. if (clusterName.length())
  2794. {
  2795. // Remove just cluster specified, unless it's the last, in which case detach below will remove File entry.
  2796. if (clusters.ordinality()>1)
  2797. {
  2798. if (removeCluster(clusterName.str()))
  2799. removeFile=false;
  2800. else
  2801. ThrowStringException(-1, "Cluster %s not present in file %s", clusterName.str(), logicalName.get());
  2802. }
  2803. }
  2804. if (removeFile)
  2805. {
  2806. // check can remove, e.g. cannot if this is a subfile of a super
  2807. StringBuffer reason;
  2808. if (!canRemove(reason))
  2809. throw MakeStringException(-1,"detach: %s", reason.str());
  2810. }
  2811. // detach this IDistributeFile
  2812. writeLock.clear();
  2813. root.setown(closeConnection(removeFile));
  2814. // NB: The file is now unlocked
  2815. if (removeFile)
  2816. updateFS(logicalName, timeoutMs);
  2817. logicalName.clear();
  2818. }
  2819. // NB: beyond unlock
  2820. if (removePhysicals)
  2821. {
  2822. CriticalBlock block(physicalChange);
  2823. Owned<IMultiException> exceptions = MakeMultiException("CDistributedFile::detach");
  2824. removePhysicalPartFiles(fileDescCopy, exceptions);
  2825. if (exceptions->ordinality())
  2826. throw exceptions.getClear();
  2827. }
  2828. }
  2829. bool removePhysicalPartFiles(IFileDescriptor *fileDesc, IMultiException *mexcept)
  2830. {
  2831. if (logicalName.isExternal())
  2832. {
  2833. if (logicalName.isQuery())
  2834. return false;
  2835. throw MakeStringException(-1,"cannot remove an external file (%s)",logicalName.get());
  2836. }
  2837. if (logicalName.isForeign())
  2838. throw MakeStringException(-1,"cannot remove a foreign file (%s)",logicalName.get());
  2839. class casyncfor: public CAsyncFor
  2840. {
  2841. IFileDescriptor *fileDesc;
  2842. CriticalSection errcrit;
  2843. IMultiException *mexcept;
  2844. public:
  2845. bool ok;
  2846. bool islazy;
  2847. casyncfor(IFileDescriptor *_fileDesc, IMultiException *_mexcept)
  2848. {
  2849. fileDesc = _fileDesc;
  2850. ok = true;
  2851. islazy = false;
  2852. mexcept = _mexcept;
  2853. }
  2854. void Do(unsigned i)
  2855. {
  2856. IPartDescriptor *part = fileDesc->queryPart(i);
  2857. unsigned nc = part->numCopies();
  2858. for (unsigned copy = 0; copy < nc; copy++)
  2859. {
  2860. RemoteFilename rfn;
  2861. part->getFilename(copy, rfn);
  2862. Owned<IFile> partfile = createIFile(rfn);
  2863. StringBuffer eps;
  2864. try
  2865. {
  2866. unsigned start = msTick();
  2867. if (!partfile->remove()&&(copy==0)&&!islazy) // only warn about missing primary files
  2868. LOG(MCwarning, unknownJob, "Failed to remove file part %s from %s", partfile->queryFilename(),rfn.queryEndpoint().getUrlStr(eps).str());
  2869. else
  2870. {
  2871. unsigned t = msTick()-start;
  2872. if (t>5*1000)
  2873. LOG(MCwarning, unknownJob, "Removing %s from %s took %ds", partfile->queryFilename(), rfn.queryEndpoint().getUrlStr(eps).str(), t/1000);
  2874. }
  2875. }
  2876. catch (IException *e)
  2877. {
  2878. CriticalBlock block(errcrit);
  2879. if (mexcept)
  2880. mexcept->append(*e);
  2881. else
  2882. {
  2883. StringBuffer s("Failed to remove file part ");
  2884. s.append(partfile->queryFilename()).append(" from ");
  2885. rfn.queryEndpoint().getUrlStr(s);
  2886. EXCLOG(e, s.str());
  2887. e->Release();
  2888. }
  2889. ok = false;
  2890. }
  2891. }
  2892. }
  2893. } afor(fileDesc, mexcept);
  2894. afor.islazy = fileDesc->queryProperties().getPropBool("@lazy");
  2895. afor.For(fileDesc->numParts(),10,false,true);
  2896. return afor.ok;
  2897. }
  2898. protected: friend class CDistributedFilePart;
  2899. CDistributedFilePartArray &queryParts()
  2900. {
  2901. return parts;
  2902. }
  2903. public:
  2904. IMPLEMENT_IINTERFACE;
  2905. CDistributedFile(CDistributedFileDirectory *_parent, IRemoteConnection *_conn,const CDfsLogicalFileName &lname,IUserDescriptor *user) // takes ownership of conn
  2906. {
  2907. setUserDescriptor(udesc,user);
  2908. logicalName.set(lname);
  2909. parent = _parent;
  2910. conn.setown(_conn);
  2911. CClustersLockedSection sect(logicalName);
  2912. root.setown(conn->getRoot());
  2913. root->queryBranch("."); // load branch
  2914. #ifdef EXTRA_LOGGING
  2915. LOGPTREE("CDistributedFile.a root",root);
  2916. #endif
  2917. Owned<IFileDescriptor> fdesc = deserializeFileDescriptorTree(root,&queryNamedGroupStore(),0);
  2918. #ifdef EXTRA_LOGGING
  2919. LOGFDESC("CDistributedFile.a fdesc",fdesc);
  2920. #endif
  2921. setFileAttrs(fdesc,false);
  2922. setClusters(fdesc);
  2923. setPreferredClusters(_parent->defprefclusters);
  2924. setParts(fdesc,false);
  2925. //shrinkFileTree(root); // enable when safe!
  2926. }
  2927. CDistributedFile(CDistributedFileDirectory *_parent, IFileDescriptor *fdesc, bool includeports)
  2928. {
  2929. #ifdef EXTRA_LOGGING
  2930. LOGFDESC("CDistributedFile.b fdesc",fdesc);
  2931. #endif
  2932. parent = _parent;
  2933. root.setown(createPTree(queryDfsXmlBranchName(DXB_File)));
  2934. root->setPropTree("ClusterLock", createPTree());
  2935. // fdesc->serializeTree(*root,IFDSF_EXCLUDE_NODES);
  2936. setFileAttrs(fdesc,true);
  2937. setClusters(fdesc);
  2938. setPreferredClusters(_parent->defprefclusters);
  2939. saveClusters();
  2940. setParts(fdesc,true);
  2941. #ifdef EXTRA_LOGGING
  2942. LOGPTREE("CDistributedFile.b root.1",root);
  2943. #endif
  2944. offset_t totalsize=0;
  2945. unsigned checkSum = ~0;
  2946. bool useableCheckSum = true;
  2947. MemoryBuffer pmb;
  2948. unsigned n = fdesc->numParts();
  2949. for (unsigned i=0;i<n;i++) {
  2950. IPropertyTree *partattr = &fdesc->queryPart(i)->queryProperties();
  2951. if (!partattr)
  2952. {
  2953. totalsize = (unsigned)-1;
  2954. useableCheckSum = false;
  2955. }
  2956. else
  2957. {
  2958. offset_t psz;
  2959. if (totalsize!=(offset_t)-1) {
  2960. psz = (offset_t)partattr->getPropInt64("@size", -1);
  2961. if (psz==(offset_t)-1)
  2962. totalsize = psz;
  2963. else
  2964. totalsize += psz;
  2965. }
  2966. if (useableCheckSum) {
  2967. unsigned crc;
  2968. if (fdesc->queryPart(i)->getCrc(crc))
  2969. checkSum ^= crc;
  2970. else
  2971. useableCheckSum = false;
  2972. }
  2973. }
  2974. }
  2975. shrinkFileTree(root);
  2976. if (totalsize!=(offset_t)-1)
  2977. queryAttributes().setPropInt64("@size", totalsize);
  2978. if (useableCheckSum)
  2979. queryAttributes().setPropInt64("@checkSum", checkSum);
  2980. setModified();
  2981. #ifdef EXTRA_LOGGING
  2982. LOGPTREE("CDistributedFile.b root.2",root);
  2983. #endif
  2984. }
  2985. void killParts()
  2986. {
  2987. ForEachItemIn(i,parts)
  2988. parts.item(i).childRelease();
  2989. parts.kill(true);
  2990. }
  2991. ~CDistributedFile()
  2992. {
  2993. assert(proplockcount == 0 && "CDistributedFile destructor: Some properties are still locked");
  2994. if (conn)
  2995. conn->rollback(); // changes should always be done in locked properties
  2996. killParts();
  2997. clusters.kill();
  2998. }
  2999. IFileDescriptor *getFileDescriptor(const char *_clusterName)
  3000. {
  3001. CriticalBlock block (sect);
  3002. Owned<IFileDescriptor> fdesc = deserializeFileDescriptorTree(root,&queryNamedGroupStore(),0);
  3003. fdesc->setTraceName(logicalName.get());
  3004. StringArray cnames;
  3005. if (_clusterName&&*_clusterName)
  3006. {
  3007. StringAttr clusterName = _clusterName;
  3008. clusterName.toLowerCase();
  3009. cnames.append(clusterName);
  3010. }
  3011. else
  3012. getClusterNames(cnames);
  3013. fdesc->setClusterOrder(cnames,_clusterName&&*_clusterName);
  3014. return fdesc.getClear();
  3015. }
  3016. void setFileAttrs(IFileDescriptor *fdesc,bool save)
  3017. {
  3018. directory.set(fdesc->queryDefaultDir());
  3019. partmask.set(fdesc->queryPartMask());
  3020. const char *lfn = logicalName.get();
  3021. if (lfn&&*lfn) {
  3022. if (partmask.isEmpty()) {
  3023. StringBuffer mask;
  3024. getPartMask(mask,lfn,0);
  3025. partmask.set(mask);
  3026. }
  3027. }
  3028. if (!save)
  3029. return;
  3030. if (directory.isEmpty())
  3031. root->removeProp("@directory");
  3032. else
  3033. root->setProp("@directory",directory);
  3034. if (partmask.isEmpty())
  3035. root->removeProp("@partmask");
  3036. else
  3037. root->setProp("@partmask",partmask);
  3038. IPropertyTree *t = &fdesc->queryProperties();
  3039. if (isEmptyPTree(t))
  3040. resetFileAttr();
  3041. else
  3042. resetFileAttr(createPTreeFromIPT(t));
  3043. }
  3044. void setClusters(IFileDescriptor *fdesc)
  3045. {
  3046. clusters.clear();
  3047. unsigned nc = fdesc->numClusters();
  3048. if (nc) {
  3049. for (unsigned i=0;i<nc;i++) {
  3050. StringBuffer cname;
  3051. StringBuffer clabel;
  3052. IClusterInfo &cluster = *createClusterInfo(
  3053. fdesc->getClusterGroupName(i,cname,NULL).str(),
  3054. fdesc->queryClusterGroup(i),
  3055. fdesc->queryPartDiskMapping(i),
  3056. &queryNamedGroupStore()
  3057. );
  3058. #ifdef EXTRA_LOGGING
  3059. PROGLOG("setClusters(%d,%s)",i,cname.str());
  3060. #endif
  3061. if (!cluster.queryGroup(&queryNamedGroupStore())) {
  3062. ERRLOG("IDistributedFileDescriptor cannot set cluster for %s",logicalName.get());
  3063. }
  3064. clusters.append(cluster);
  3065. }
  3066. }
  3067. else
  3068. ERRLOG("No cluster specified for %s",logicalName.get());
  3069. }
  3070. unsigned numClusters()
  3071. {
  3072. return clusters.ordinality();
  3073. }
  3074. unsigned findCluster(const char *clustername)
  3075. {
  3076. return clusters.find(clustername);
  3077. }
  3078. unsigned getClusterNames(StringArray &clusternames)
  3079. {
  3080. return clusters.getNames(clusternames);
  3081. }
  3082. void reloadClusters()
  3083. {
  3084. // called from CClustersLockedSection
  3085. if (!CDistributedFileBase<IDistributedFile>::conn)
  3086. return;
  3087. assertex(CDistributedFileBase<IDistributedFile>::proplockcount==0); // cannot reload clusters if properties locked
  3088. CDistributedFileBase<IDistributedFile>::conn->reload(); // should only be cluster changes but a bit dangerous
  3089. IPropertyTree *t = CDistributedFileBase<IDistributedFile>::conn->queryRoot(); // NB not CDistributedFileBase<IDistributedFile>::queryRoot();
  3090. if (!t)
  3091. return;
  3092. clusters.clear();
  3093. getClusterInfo(*t,&queryNamedGroupStore(),0,clusters);
  3094. }
  3095. void saveClusters()
  3096. {
  3097. // called from CClustersLockedSection
  3098. IPropertyTree *t;
  3099. if (CDistributedFileBase<IDistributedFile>::conn)
  3100. t = CDistributedFileBase<IDistributedFile>::conn->queryRoot();
  3101. else
  3102. t = CDistributedFileBase<IDistributedFile>::queryRoot(); //cache
  3103. if (!t)
  3104. return;
  3105. IPropertyTree *pt;
  3106. IPropertyTree *tc = CDistributedFileBase<IDistributedFile>::queryRoot(); //cache
  3107. IPropertyTree *t0 = t;
  3108. StringBuffer grplist;
  3109. // the following is complicated by fact there is a cache of the file branch
  3110. loop {
  3111. while ((pt=t->queryPropTree("Cluster[1]"))!=NULL)
  3112. t->removeTree(pt);
  3113. ForEachItemIn(i,clusters) {
  3114. IPropertyTree *pt = createPTree("Cluster");
  3115. clusters.item(i).serializeTree(pt,IFDSF_EXCLUDE_GROUPS);
  3116. if (!isEmptyPTree(pt)) {
  3117. t->addPropTree("Cluster",pt);
  3118. if (t==t0) {
  3119. StringBuffer clabel;
  3120. clusters.item(i).getClusterLabel(clabel);
  3121. if (clabel.length()) {
  3122. if (grplist.length())
  3123. grplist.append(',');
  3124. grplist.append(clabel);
  3125. }
  3126. }
  3127. }
  3128. else
  3129. WARNLOG("CFileClusterOwner::saveClusters - empty cluster");
  3130. }
  3131. if (grplist.length())
  3132. t->setProp("@group",grplist.str());
  3133. else
  3134. t->removeProp("@group");
  3135. t->setPropInt("@numclusters",clusters.ordinality());
  3136. t->setProp("@directory", directory);
  3137. if (t==tc)
  3138. break;
  3139. t = tc; // now fix cache
  3140. }
  3141. if (CDistributedFileBase<IDistributedFile>::conn)
  3142. CDistributedFileBase<IDistributedFile>::conn->commit(); // should only be cluster changes but a bit dangerous
  3143. }
  3144. void addCluster(const char *clustername,const ClusterPartDiskMapSpec &mspec)
  3145. {
  3146. if (!clustername&&!*clustername)
  3147. return;
  3148. CClustersLockedSection cls(CDistributedFileBase<IDistributedFile>::logicalName);
  3149. reloadClusters();
  3150. if (findCluster(clustername)!=NotFound) {
  3151. IDFS_Exception *e = new CDFS_Exception(DFSERR_ClusterAlreadyExists,clustername);
  3152. throw e;
  3153. }
  3154. Owned<IClusterInfo> cluster = createClusterInfo(clustername,NULL,mspec,&queryNamedGroupStore());
  3155. if (cluster->queryGroup(&queryNamedGroupStore())) {
  3156. clusters.append(*cluster.getClear());
  3157. }
  3158. else {
  3159. IDFS_Exception *e = new CDFS_Exception(DFSERR_ClusterNotFound,clustername);
  3160. throw e;
  3161. }
  3162. saveClusters();
  3163. }
  3164. bool removeCluster(const char *clustername)
  3165. {
  3166. CClustersLockedSection cls(CDistributedFileBase<IDistributedFile>::logicalName);
  3167. reloadClusters();
  3168. unsigned i = findCluster(clustername);
  3169. if (i!=NotFound) {
  3170. if (clusters.ordinality()==1)
  3171. throw MakeStringException(-1,"CFileClusterOwner::removeCluster cannot remove sole cluster %s",clustername);
  3172. // If the cluster is the 'default' one we need to update the directory too
  3173. StringBuffer oldBaseDir;
  3174. char pathSepChar = getPathSepChar(directory.get());
  3175. DFD_OS os = SepCharBaseOs(pathSepChar);
  3176. clusters.item(i).getBaseDir(oldBaseDir, os);
  3177. unsigned oldLen = oldBaseDir.length();
  3178. clusters.remove(i);
  3179. if (oldLen && strncmp(directory, oldBaseDir, oldLen)==0 && (directory[oldLen]==pathSepChar || directory[oldLen]=='\0'))
  3180. {
  3181. StringBuffer newBaseDir;
  3182. clusters.item(0).getBaseDir(newBaseDir, os);
  3183. newBaseDir.append(directory.get() + oldBaseDir.length());
  3184. directory.set(newBaseDir);
  3185. }
  3186. saveClusters();
  3187. return true;
  3188. }
  3189. return false;
  3190. }
  3191. void setPreferredClusters(const char *clusterlist)
  3192. {
  3193. clusters.setPreferred(clusterlist,CDistributedFileBase<IDistributedFile>::logicalName);
  3194. }
  3195. INode *queryNode(unsigned idx,unsigned copy)
  3196. {
  3197. unsigned rep;
  3198. unsigned cluster = copyClusterNum(idx,copy,&rep);
  3199. if (cluster==NotFound)
  3200. return queryNullNode();
  3201. unsigned nn;
  3202. unsigned dn;
  3203. IGroup *grp = clusters.queryGroup(cluster);
  3204. if (!grp)
  3205. return queryNullNode();
  3206. if (!clusters.item(cluster).queryPartDiskMapping().calcPartLocation (idx, numParts(),rep, grp->ordinality(), nn, dn))
  3207. return queryNullNode();
  3208. return &grp->queryNode(nn);
  3209. }
  3210. unsigned queryDrive(unsigned idx,unsigned copy,const char *dir)
  3211. {
  3212. // this is odd routine
  3213. unsigned dn = dir?getPathDrive(dir):0;
  3214. if (dn)
  3215. return dn;
  3216. unsigned rep;
  3217. unsigned cluster = copyClusterNum(idx,copy,&rep);
  3218. if (cluster==NotFound)
  3219. return 0;
  3220. unsigned nn;
  3221. IGroup *grp = clusters.queryGroup(cluster);
  3222. if (!grp)
  3223. return 0;
  3224. if (!clusters.item(cluster).queryPartDiskMapping().calcPartLocation (idx, numParts(),rep, grp->ordinality(), nn, dn))
  3225. return 0;
  3226. return dn;
  3227. }
  3228. StringBuffer &getClusterName(unsigned clusternum,StringBuffer &name)
  3229. {
  3230. return clusters.getName(clusternum,name);
  3231. }
  3232. unsigned copyClusterNum(unsigned part, unsigned copy,unsigned *replicate)
  3233. {
  3234. return clusters.copyNum(part,copy, numParts(),replicate);
  3235. }
  3236. ClusterPartDiskMapSpec &queryPartDiskMapping(unsigned clusternum)
  3237. {
  3238. assertex(clusternum<clusters.ordinality());
  3239. return clusters.queryPartDiskMapping(clusternum);
  3240. }
  3241. void updatePartDiskMapping(const char *clustername,const ClusterPartDiskMapSpec &spec)
  3242. {
  3243. CClustersLockedSection cls(CDistributedFileBase<IDistributedFile>::logicalName);
  3244. reloadClusters();
  3245. unsigned i = findCluster(clustername);
  3246. if (i!=NotFound) {
  3247. clusters.updatePartDiskMapping(i,spec);
  3248. saveClusters();
  3249. }
  3250. }
  3251. IGroup *queryClusterGroup(unsigned clusternum)
  3252. {
  3253. return clusters.queryGroup(clusternum);
  3254. }
  3255. virtual unsigned numCopies(unsigned partno)
  3256. {
  3257. return clusters.numCopies(partno,numParts());
  3258. }
  3259. void setSingleClusterOnly()
  3260. {
  3261. clusters.setSingleClusterOnly();
  3262. }
  3263. unsigned numClusterCopies(unsigned cnum,unsigned partnum)
  3264. {
  3265. IClusterInfo &cluster = clusters.item(cnum);
  3266. IGroup *grp = cluster.queryGroup();
  3267. return cluster.queryPartDiskMapping().numCopies(partnum,grp?grp->ordinality():1,numParts());
  3268. }
  3269. void adjustClusterDir(unsigned partno,unsigned copy, StringBuffer &path)
  3270. {
  3271. // this corrects the directory for a copy
  3272. // assumes default dir matches one of clusters
  3273. unsigned rep=0;
  3274. unsigned cluster = NotFound;
  3275. const char *ds = path.str();
  3276. unsigned nc = clusters.ordinality();
  3277. if (nc>1) {
  3278. StringAttr matched;
  3279. StringAttr toadd;
  3280. unsigned i=0;
  3281. bool c = 0;
  3282. int cp = (int)copy;
  3283. while (i<nc) {
  3284. StringBuffer dcmp;
  3285. clusters.item(i).getBaseDir(dcmp,SepCharBaseOs(getPathSepChar(ds))); // no trailing sep
  3286. const char *t = dcmp.str();
  3287. const char *d = ds;
  3288. while (*d&&(*t==*d)) {
  3289. d++;
  3290. t++;
  3291. }
  3292. if (!*t&&(!*d||isPathSepChar(*d))&&(dcmp.length()>matched.length()))
  3293. matched.set(dcmp);
  3294. unsigned mc = numClusterCopies(i,partno);
  3295. if ((cp>=0)&&(cp<(int)mc)) {
  3296. toadd.set(dcmp);
  3297. rep = (unsigned)cp;
  3298. cluster = i;
  3299. }
  3300. cp -= mc;
  3301. i++;
  3302. }
  3303. if (!matched.isEmpty()&&!toadd.isEmpty()&&(strcmp(matched,toadd)!=0)) {
  3304. StringBuffer tmp(toadd);
  3305. tmp.append(ds+matched.length());
  3306. path.swapWith(tmp);
  3307. }
  3308. }
  3309. else {
  3310. rep = copy;
  3311. cluster = 0;
  3312. }
  3313. // now set replicate
  3314. if (cluster!=NotFound) {
  3315. unsigned n;
  3316. unsigned d;
  3317. ClusterPartDiskMapSpec& mspec = clusters.item(cluster).queryPartDiskMapping();
  3318. mspec.calcPartLocation(partno,numParts(),rep,clusters.queryGroup(cluster)?clusters.queryGroup(cluster)->ordinality():numParts(),n,d);
  3319. if ((d==1) && (mspec.flags&CPDMSF_overloadedConfig) && mspec.defaultReplicateDir.length())
  3320. path.set(mspec.defaultReplicateDir.get());
  3321. else
  3322. setReplicateFilename(path,d);
  3323. }
  3324. }
  3325. void setParts(IFileDescriptor *fdesc,bool save)
  3326. {
  3327. unsigned np = fdesc->numParts();
  3328. for (unsigned i = 0;i<np;i++) {
  3329. CDistributedFilePart &part = *new CDistributedFilePart(*this,i,fdesc->queryPart(i));
  3330. parts.append(part);
  3331. }
  3332. if (save) {
  3333. root->setPropInt("@numparts",parts.ordinality());
  3334. savePartsAttr(true);
  3335. }
  3336. }
  3337. unsigned numParts()
  3338. {
  3339. return parts.ordinality();
  3340. }
  3341. IDistributedFilePart &queryPart(unsigned idx)
  3342. {
  3343. if (idx<parts.ordinality())
  3344. return queryParts().item(idx);
  3345. return *(IDistributedFilePart *)NULL;
  3346. }
  3347. IDistributedFilePart* getPart(unsigned idx)
  3348. {
  3349. if (idx>=parts.ordinality())
  3350. return NULL;
  3351. IDistributedFilePart *ret = &queryParts().item(idx);
  3352. return LINK(ret);
  3353. }
  3354. IDistributedFilePartIterator *getIterator(IDFPartFilter *filter=NULL)
  3355. {
  3356. return new CDistributedFilePartIterator(queryParts(),filter);
  3357. }
  3358. void rename(const char *_logicalname,IUserDescriptor *user)
  3359. {
  3360. StringBuffer prevname;
  3361. Owned<IFileRelationshipIterator> reliter;
  3362. // set prevname
  3363. if (!isAnon()) {
  3364. getLogicalName(prevname);
  3365. try {
  3366. IFileRelationshipIterator *iter = parent->lookupAllFileRelationships(prevname.str());
  3367. reliter.setown(iter);
  3368. }
  3369. catch (IException *e) {
  3370. EXCLOG(e,"CDistributedFileDirectory::rename");
  3371. e->Release();
  3372. }
  3373. detachLogical();
  3374. }
  3375. attach(_logicalname,user);
  3376. if (prevname.length()) {
  3377. DistributedFilePropertyLock lock(this);
  3378. IPropertyTree &pt = queryAttributes();
  3379. StringBuffer list;
  3380. if (pt.getProp("@renamedFrom",list)&&list.length())
  3381. list.append(',');
  3382. pt.setProp("@renamedFrom",list.append(prevname).str());
  3383. }
  3384. if (reliter.get()) {
  3385. // add back any relationships with new name
  3386. parent->renameFileRelationships(prevname.str(),_logicalname,reliter,user);
  3387. }
  3388. }
  3389. const char *queryDefaultDir()
  3390. {
  3391. CriticalBlock block (sect);
  3392. return directory.get();
  3393. }
  3394. const char *queryPartMask()
  3395. {
  3396. CriticalBlock block (sect);
  3397. if (partmask.isEmpty()) {
  3398. assertex(root);
  3399. partmask.set(root->queryProp("@partmask"));
  3400. }
  3401. return partmask.get();
  3402. }
  3403. bool isAnon()
  3404. {
  3405. return (!logicalName.isSet());
  3406. }
  3407. void attach(const char *_logicalname,IUserDescriptor *user)
  3408. {
  3409. CriticalBlock block (sect);
  3410. assertex(isAnon()); // already attached!
  3411. logicalName.set(_logicalname);
  3412. if (!checkLogicalName(logicalName,user,true,true,true,"attach"))
  3413. return; // query
  3414. #ifdef EXTRA_LOGGING
  3415. PROGLOG("CDistributedFile::attach(%s)",_logicalname);
  3416. LOGPTREE("CDistributedFile::attach root.1",root);
  3417. #endif
  3418. parent->addEntry(logicalName,root.getClear(),false,false);
  3419. killParts();
  3420. clusters.kill();
  3421. CFileConnectLock fcl("CDistributedFile::attach",logicalName,DXB_File, false, false, false, defaultTimeout);
  3422. conn.setown(fcl.detach());
  3423. root.setown(conn->getRoot());
  3424. root->queryBranch("."); // load branch
  3425. Owned<IFileDescriptor> fdesc = deserializeFileDescriptorTree(root,&queryNamedGroupStore(),0);
  3426. setFileAttrs(fdesc,false);
  3427. setClusters(fdesc);
  3428. setParts(fdesc,false);
  3429. #ifdef EXTRA_LOGGING
  3430. LOGFDESC("CDistributedFile::attach fdesc",fdesc);
  3431. LOGPTREE("CDistributedFile::attach root.2",root);
  3432. #endif
  3433. }
  3434. /*
  3435. * Internal method (not in IDistributedFile interface) that is used
  3436. * when renaming files (so don't delete the physical representation).
  3437. *
  3438. * This is also used during CPPUINT tests, so we need to make them public
  3439. * only when tests are enabled (ie. non-production mode).
  3440. *
  3441. * See removeLogical()
  3442. */
  3443. public:
  3444. void detachLogical(unsigned timeoutms=INFINITE)
  3445. {
  3446. detach(timeoutms, false);
  3447. }
  3448. public:
  3449. virtual void detach(unsigned timeoutMs=INFINITE)
  3450. {
  3451. detach(timeoutMs, true);
  3452. }
  3453. bool existsPhysicalPartFiles(unsigned short port)
  3454. {
  3455. unsigned width = numParts();
  3456. CriticalSection errcrit;
  3457. class casyncfor: public CAsyncFor
  3458. {
  3459. IDistributedFile *file;
  3460. unsigned short port;
  3461. CriticalSection &errcrit;
  3462. unsigned width;
  3463. public:
  3464. bool ok;
  3465. casyncfor(IDistributedFile *_file,unsigned _width,unsigned short _port,CriticalSection &_errcrit)
  3466. : errcrit(_errcrit)
  3467. {
  3468. file = _file;
  3469. port = _port;
  3470. ok = true;
  3471. width = _width;
  3472. ok = true;
  3473. }
  3474. void Do(unsigned i)
  3475. {
  3476. {
  3477. CriticalBlock block(errcrit);
  3478. if (!ok)
  3479. return;
  3480. }
  3481. Owned<IDistributedFilePart> part = file->getPart(i);
  3482. unsigned nc = part->numCopies();
  3483. for (unsigned copy = 0; copy < nc; copy++)
  3484. {
  3485. RemoteFilename rfn;
  3486. part->getFilename(rfn,copy);
  3487. if (port)
  3488. rfn.setPort(port); // if daliservix
  3489. Owned<IFile> partfile = createIFile(rfn);
  3490. try
  3491. {
  3492. if (partfile->exists())
  3493. return;
  3494. }
  3495. catch (IException *e)
  3496. {
  3497. CriticalBlock block(errcrit);
  3498. StringBuffer s("Failed to find file part ");
  3499. s.append(partfile->queryFilename()).append(" on ");
  3500. rfn.queryEndpoint().getUrlStr(s);
  3501. EXCLOG(e, s.str());
  3502. e->Release();
  3503. }
  3504. }
  3505. CriticalBlock block(errcrit);
  3506. ok = false;
  3507. }
  3508. } afor(this,width,port,errcrit);
  3509. afor.For(width,10,false,true);
  3510. return afor.ok;
  3511. }
  3512. // This method takes an existing physical directory path for a logical file
  3513. // and a constructed path to the same logical file created in this context
  3514. // and deduces the original base path e.g. /var/lib/HPCCSystems/hpcc-data/thor
  3515. // This is necessary, because there is no not enough context to directly fetch the
  3516. // original base path to construct new paths for the rename
  3517. bool getBase(const char *oldPath, const char *thisPath, StringBuffer &baseDir)
  3518. {
  3519. const char *oldEnd = oldPath+strlen(oldPath)-1;
  3520. const char *thisEnd = thisPath+strlen(thisPath)-1;
  3521. if (isPathSepChar(*oldEnd))
  3522. oldEnd--;
  3523. if (isPathSepChar(*thisEnd))
  3524. thisEnd--;
  3525. const char *oldP = oldEnd, *thisP = thisEnd;
  3526. loop {
  3527. if (oldP==oldPath || thisP==thisPath)
  3528. break;
  3529. if (*oldP != *thisP) {
  3530. // unless last was separator, continue until find one
  3531. if (isPathSepChar(*(oldP+1)))
  3532. oldP++;
  3533. else {
  3534. while (oldP != oldPath && (!isPathSepChar(*oldP)))
  3535. oldP--;
  3536. }
  3537. baseDir.append(oldP-oldPath, oldPath);
  3538. return true;
  3539. }
  3540. --oldP;
  3541. --thisP;
  3542. }
  3543. return false;
  3544. }
  3545. bool renamePhysicalPartFiles(const char *newname,
  3546. const char *cluster,
  3547. IMultiException *mexcept,
  3548. const char *newbasedir)
  3549. {
  3550. // cluster TBD
  3551. unsigned width = numParts();
  3552. StringBuffer newdir;
  3553. StringBuffer newmask;
  3554. const char *diroverride = NULL;
  3555. char psc = getPathSepChar(directory.get());
  3556. DFD_OS os = SepCharBaseOs(psc);
  3557. StringBuffer basedir;
  3558. if (newbasedir)
  3559. diroverride = newbasedir;
  3560. const char *myBase = queryBaseDirectory(grp_unknown, 0, os);
  3561. StringBuffer baseDir, newPath;
  3562. makePhysicalPartName(logicalName.get(), 0, 0, newPath, false, os, diroverride);
  3563. if (!getBase(directory, newPath, baseDir))
  3564. baseDir.append(myBase); // getBase returns false, if directory==newPath, so have common base
  3565. getPartMask(newmask,newname,width);
  3566. if (newmask.length()==0)
  3567. return false;
  3568. makePhysicalPartName(newname, 0, 0, newPath.clear(), false, os, diroverride);
  3569. if (newPath.length()==0)
  3570. return false;
  3571. if (isPathSepChar(newPath.charAt(newPath.length()-1)))
  3572. newPath.setLength(newPath.length()-1);
  3573. newPath.remove(0, strlen(myBase));
  3574. newdir.append(baseDir).append(newPath);
  3575. StringBuffer fullname;
  3576. CIArrayOf<CIStringArray> newNames;
  3577. unsigned i;
  3578. for (i=0;i<width;i++) {
  3579. newNames.append(*new CIStringArray);
  3580. CDistributedFilePart &part = parts.item(i);
  3581. for (unsigned copy=0; copy<part.numCopies(); copy++) {
  3582. makePhysicalPartName(newname, i+1, width, newPath.clear(), false, os, myBase);
  3583. newPath.remove(0, strlen(myBase));
  3584. StringBuffer copyDir(baseDir);
  3585. adjustClusterDir(i, copy, copyDir);
  3586. fullname.clear().append(copyDir).append(newPath);
  3587. PROGLOG("fullname = %s", fullname.str());
  3588. newNames.item(i).append(fullname);
  3589. }
  3590. }
  3591. // NB: the code below, specifically deals with 1 primary + 1 replicate
  3592. // it will need refactoring if it's to deal with multiple clusters/copies
  3593. // first check file doestn't exist for any new part
  3594. CriticalSection crit;
  3595. class casyncforbase: public CAsyncFor
  3596. {
  3597. protected:
  3598. CriticalSection &crit;
  3599. CIArrayOf<CIStringArray> &newNames;
  3600. IDistributedFile *file;
  3601. unsigned width;
  3602. IMultiException *mexcept;
  3603. bool *ignoreprim;
  3604. bool *ignorerep;
  3605. public:
  3606. bool ok;
  3607. bool * doneprim;
  3608. bool * donerep;
  3609. IException *except;
  3610. casyncforbase(IDistributedFile *_file,CIArrayOf<CIStringArray> &_newNames,unsigned _width,IMultiException *_mexcept,CriticalSection &_crit,bool *_ignoreprim,bool *_ignorerep)
  3611. : newNames(_newNames),crit(_crit)
  3612. {
  3613. width = _width;
  3614. file = _file;
  3615. ok = true;
  3616. mexcept = _mexcept;
  3617. doneprim = (bool *)calloc(sizeof(bool),width);
  3618. donerep = (bool *)calloc(sizeof(bool),width);
  3619. except = NULL;
  3620. ignoreprim = _ignoreprim;
  3621. ignorerep = _ignorerep;
  3622. }
  3623. ~casyncforbase()
  3624. {
  3625. free(doneprim);
  3626. free(donerep);
  3627. }
  3628. virtual bool doPart(IDistributedFilePart *,bool,RemoteFilename &,RemoteFilename &, bool &)
  3629. #ifdef _WIN32
  3630. {
  3631. assertex(!"doPart"); // stupid microsoft error
  3632. return false;
  3633. }
  3634. #else
  3635. = 0;
  3636. #endif
  3637. void Do(unsigned idx)
  3638. {
  3639. {
  3640. CriticalBlock block(crit);
  3641. if (!ok)
  3642. return;
  3643. }
  3644. Owned<IDistributedFilePart> part = file->getPart(idx);
  3645. unsigned copies = part->numCopies();
  3646. for (int copy = copies-1; copy>=0; copy--)
  3647. {
  3648. if ((copy==0)&&ignoreprim&&ignoreprim[idx])
  3649. continue;
  3650. if ((copy!=0)&&ignorerep&&ignorerep[idx])
  3651. continue;
  3652. bool pok=false;
  3653. IException *ex = NULL;
  3654. RemoteFilename oldrfn;
  3655. part->getFilename(oldrfn,(unsigned)copy);
  3656. const char *newfn = newNames.item(idx).item(copy);
  3657. if (!newfn||!*newfn)
  3658. continue;
  3659. RemoteFilename newrfn;
  3660. newrfn.setPath(part->queryNode(copy)->endpoint(),newfn);
  3661. try {
  3662. pok = doPart(part,copy!=0,oldrfn,newrfn,(copy==0)?doneprim[idx]:donerep[idx]);
  3663. }
  3664. catch (IException *e) {
  3665. EXCLOG(e, NULL);
  3666. ex = e;
  3667. }
  3668. CriticalBlock block(crit);
  3669. if (!pok||ex) {
  3670. ok = false;
  3671. if (ex) {
  3672. StringBuffer s("renamePhysicalPartFiles ");
  3673. s.append(file->queryLogicalName()).append(" part ").append(newfn);
  3674. EXCLOG(ex, s.str());
  3675. if (mexcept)
  3676. mexcept->append(*ex);
  3677. else {
  3678. if (except)
  3679. ex->Release();
  3680. else
  3681. except = ex;
  3682. }
  3683. }
  3684. }
  3685. }
  3686. }
  3687. };
  3688. class casyncfor1: public casyncforbase
  3689. {
  3690. public:
  3691. casyncfor1(IDistributedFile *_file,CIArrayOf<CIStringArray> &_newNames,unsigned _width,IMultiException *_mexcept,CriticalSection &_crit,bool *_ignoreprim,bool *_ignorerep)
  3692. : casyncforbase(_file,_newNames,_width,_mexcept,_crit,_ignoreprim,_ignorerep)
  3693. {
  3694. }
  3695. bool doPart(IDistributedFilePart *part,bool isrep,RemoteFilename &oldrfn,RemoteFilename &newrfn, bool &done)
  3696. {
  3697. done = false;
  3698. Owned<IFile> src = createIFile(oldrfn);
  3699. if (src->exists())
  3700. done = true;
  3701. else {
  3702. StringBuffer s;
  3703. oldrfn.getRemotePath(s);
  3704. WARNLOG("renamePhysicalPartFiles: %s doesn't exist",s.str());
  3705. return true;
  3706. }
  3707. Owned<IFile> dest = createIFile(newrfn);
  3708. StringBuffer newname;
  3709. newrfn.getRemotePath(newname);
  3710. if (dest->exists()) {
  3711. IDFS_Exception *e = new CDFS_Exception(DFSERR_PhysicalPartAlreadyExists,newname.str());
  3712. throw e;
  3713. }
  3714. // check destination directory exists
  3715. StringBuffer newdir;
  3716. splitDirTail(newname.str(),newdir);
  3717. Owned<IFile> destdir = createIFile(newdir.str());
  3718. destdir->createDirectory();
  3719. return true;
  3720. }
  3721. } afor1 (this,newNames,width,mexcept,crit,NULL,NULL);
  3722. afor1.For(width,10,false,true);
  3723. if (afor1.except)
  3724. throw afor1.except; // no recovery needed
  3725. if (!afor1.ok)
  3726. return false; // no recovery needed
  3727. MemoryAttr ignorebuf;
  3728. bool *ignoreprim = (bool *)ignorebuf.allocate(width*sizeof(bool)*2);
  3729. bool *ignorerep = ignoreprim+width;
  3730. for (i=0;i<width;i++) {
  3731. if (afor1.donerep[i]) {
  3732. ignorerep[i] = false;
  3733. ignoreprim[i] = !afor1.doneprim[i];
  3734. }
  3735. else if (afor1.doneprim[i]) {
  3736. ignorerep[i] = true;
  3737. ignoreprim[i] = false;
  3738. }
  3739. else {
  3740. StringBuffer s(queryLogicalName());
  3741. s.append(" Part ").append(i+1);
  3742. IDFS_Exception *e = new CDFS_Exception(DFSERR_PhysicalPartDoesntExist,s.str());
  3743. throw e;
  3744. }
  3745. }
  3746. // now do the rename
  3747. class casyncfor2: public casyncforbase
  3748. {
  3749. public:
  3750. casyncfor2(IDistributedFile *_file,CIArrayOf<CIStringArray> &_newNames,unsigned _width,IMultiException *_mexcept,CriticalSection &_crit,bool *_ignoreprim,bool *_ignorerep)
  3751. : casyncforbase(_file,_newNames,_width,_mexcept,_crit,_ignoreprim,_ignorerep)
  3752. {
  3753. }
  3754. bool doPart(IDistributedFilePart *part,bool isrep,RemoteFilename &oldrfn,RemoteFilename &newrfn, bool &done)
  3755. {
  3756. done = false;
  3757. StringBuffer oldfn;
  3758. oldrfn.getRemotePath(oldfn);
  3759. StringBuffer newfn;
  3760. newrfn.getRemotePath(newfn);
  3761. Owned<IFile> f = createIFile(oldrfn);
  3762. if (!isrep||f->exists()) { // ignore non-existant replicates
  3763. f->move(newfn.str());
  3764. PROGLOG("Succeeded rename %s to %s",oldfn.str(),newfn.str());
  3765. }
  3766. done = true;
  3767. return true;;
  3768. }
  3769. } afor2 (this,newNames,width,mexcept,crit,ignoreprim,ignorerep);
  3770. afor2.For(width,10,false,true);
  3771. if (afor2.ok) {
  3772. // now rename directory and partmask
  3773. DistributedFilePropertyLock lock(this);
  3774. root->setProp("@directory",newdir.str());
  3775. root->setProp("@partmask",newmask.str());
  3776. partmask.set(newmask.str());
  3777. directory.set(newdir.str());
  3778. StringBuffer mask;
  3779. for (unsigned i=0;i<width;i++) {
  3780. mask.appendf("Part[%d]/@name",i+1);
  3781. parts.item(i).clearOverrideName();
  3782. }
  3783. savePartsAttr(false);
  3784. }
  3785. else {
  3786. // attempt recovery
  3787. // do this synchronously to maximize chance of success (I don't expect many to have been done)
  3788. for (i=0;i<width;i++) {
  3789. Owned<IDistributedFilePart> part = getPart(i);
  3790. unsigned copies = part->numCopies();
  3791. for (int copy = copies-1; copy>=0; copy--) {
  3792. bool done = (copy==0)?afor2.doneprim[i]:afor2.donerep[i];
  3793. if (done) {
  3794. RemoteFilename oldrfn;
  3795. part->getFilename(oldrfn,(unsigned)copy);
  3796. const char *newfn = newNames.item(i).item(copy);
  3797. if (!newfn||!*newfn)
  3798. continue;
  3799. RemoteFilename newrfn;
  3800. newrfn.setPath(part->queryNode(copy)->endpoint(),newfn);
  3801. for (unsigned t=1;t<3;t++) { // 3 goes
  3802. try {
  3803. StringBuffer oldfn;
  3804. oldrfn.getRemotePath(oldfn);
  3805. StringBuffer newfn;
  3806. newrfn.getRemotePath(newfn);
  3807. Owned<IFile> f = createIFile(newrfn);
  3808. f->move(oldfn.str());
  3809. PROGLOG("Succeeded rename %s back to %s",newfn.str(),oldfn.str());
  3810. break;
  3811. }
  3812. catch (IException *e) {
  3813. if (!afor2.except)
  3814. afor2.except = e;
  3815. else
  3816. e->Release();
  3817. }
  3818. }
  3819. }
  3820. }
  3821. }
  3822. }
  3823. if (afor2.except)
  3824. throw afor2.except;
  3825. return afor2.ok;
  3826. }
  3827. IPropertyTree *queryRoot() { return root; }
  3828. __int64 getFileSize(bool allowphysical,bool forcephysical)
  3829. {
  3830. __int64 ret = (__int64)(forcephysical?-1:queryAttributes().getPropInt64("@size",-1));
  3831. if (ret==-1)
  3832. {
  3833. ret = 0;
  3834. unsigned n = numParts();
  3835. for (unsigned i=0;i<n;i++)
  3836. {
  3837. Owned<IDistributedFilePart> part = getPart(i);
  3838. __int64 ps = part->getFileSize(allowphysical,forcephysical);
  3839. if (ps == -1)
  3840. {
  3841. ret = ps;
  3842. break;
  3843. }
  3844. ret += ps;
  3845. }
  3846. }
  3847. return ret;
  3848. }
  3849. __int64 getDiskSize(bool allowphysical,bool forcephysical)
  3850. {
  3851. if (!isCompressed(NULL))
  3852. return getFileSize(allowphysical, forcephysical);
  3853. __int64 ret = (__int64)(forcephysical?-1:queryAttributes().getPropInt64("@compressedSize",-1));
  3854. if (ret==-1)
  3855. {
  3856. ret = 0;
  3857. unsigned n = numParts();
  3858. for (unsigned i=0;i<n;i++)
  3859. {
  3860. Owned<IDistributedFilePart> part = getPart(i);
  3861. __int64 ps = part->getDiskSize(allowphysical,forcephysical);
  3862. if (ps == -1)
  3863. {
  3864. ret = ps;
  3865. break;
  3866. }
  3867. ret += ps;
  3868. }
  3869. }
  3870. return ret;
  3871. }
  3872. bool getFileCheckSum(unsigned &checkSum)
  3873. {
  3874. if (queryAttributes().hasProp("@checkSum"))
  3875. checkSum = (unsigned)queryAttributes().getPropInt64("@checkSum");
  3876. else
  3877. {
  3878. checkSum = ~0;
  3879. unsigned n = numParts();
  3880. for (unsigned i=0;i<n;i++) {
  3881. Owned<IDistributedFilePart> part = getPart(i);
  3882. unsigned crc;
  3883. if (!part->getCrc(crc))
  3884. return false;
  3885. checkSum ^= crc;
  3886. }
  3887. }
  3888. return true;
  3889. }
  3890. virtual bool getFormatCrc(unsigned &crc)
  3891. {
  3892. if (queryAttributes().hasProp("@formatCrc")) {
  3893. // NB pre record_layout CRCs are not valid
  3894. crc = (unsigned)queryAttributes().getPropInt("@formatCrc");
  3895. return true;
  3896. }
  3897. return false;
  3898. }
  3899. virtual bool getRecordLayout(MemoryBuffer &layout)
  3900. {
  3901. return queryAttributes().getPropBin("_record_layout",layout);
  3902. }
  3903. virtual bool getRecordSize(size32_t &rsz)
  3904. {
  3905. if (queryAttributes().hasProp("@recordSize")) {
  3906. rsz = (size32_t)queryAttributes().getPropInt("@recordSize");
  3907. return true;
  3908. }
  3909. return false;
  3910. }
  3911. virtual unsigned getPositionPart(offset_t pos, offset_t &base)
  3912. {
  3913. unsigned n = numParts();
  3914. base = 0;
  3915. for (unsigned i=0;i<n;i++) {
  3916. Owned<IDistributedFilePart> part = getPart(i);
  3917. offset_t ps = part->getFileSize(true,false);
  3918. if (ps==(offset_t)-1)
  3919. break;
  3920. if (ps>pos)
  3921. return i;
  3922. pos -= ps;
  3923. base += ps;
  3924. }
  3925. return NotFound;
  3926. }
  3927. IDistributedSuperFile *querySuperFile()
  3928. {
  3929. return NULL; // i.e. this isn't super file
  3930. }
  3931. virtual bool checkClusterCompatible(IFileDescriptor &fdesc, StringBuffer &err)
  3932. {
  3933. unsigned n = numParts();
  3934. if (fdesc.numParts()!=n) {
  3935. err.appendf("Different cluster width (%d/%d)",n,fdesc.numParts());
  3936. return false;
  3937. }
  3938. if (fdesc.numClusters()!=1) {
  3939. err.append("Cannot merge more than one cluster");
  3940. return false;
  3941. }
  3942. StringBuffer cname;
  3943. fdesc.getClusterLabel(0,cname);
  3944. if (cname.length()&&(findCluster(cname.str())!=NotFound)) {
  3945. err.append("File already contains cluster");
  3946. err.append(cname.str());
  3947. return false;
  3948. }
  3949. StringBuffer pname;
  3950. StringBuffer fdtail;
  3951. for (unsigned pn=0;pn<n;pn++) {
  3952. IDistributedFilePart &part = queryPart(pn);
  3953. part.getPartName(pname.clear());
  3954. fdesc.queryPart(pn)->getTail(fdtail.clear());
  3955. if (strcmp(pname.str(),fdtail.str())!=0) {
  3956. err.appendf("Part name mismatch (%s,%s)",pname.str(),fdtail.str());
  3957. return false;
  3958. }
  3959. RemoteFilename fdrfn;
  3960. fdesc.getFilename(pn,0,fdrfn);
  3961. unsigned nc = numCopies(pn);
  3962. for (unsigned c = 0;c<nc;c++) {
  3963. RemoteFilename rfn;
  3964. part.getFilename(rfn,c);
  3965. if (rfn.equals(fdrfn)) {
  3966. err.appendf("Parts overlap %s and %s",pname.str(),fdtail.str());
  3967. return false;
  3968. }
  3969. }
  3970. }
  3971. return true;
  3972. }
  3973. void enqueueReplicate()
  3974. {
  3975. MemoryBuffer mb;
  3976. mb.append((byte)DRQ_REPLICATE).append(queryLogicalName());
  3977. udesc->serialize(mb);
  3978. CDateTime filedt;
  3979. getModificationTime(filedt);
  3980. filedt.serialize(mb);
  3981. Owned<INamedQueueConnection> qconn = createNamedQueueConnection(0);
  3982. Owned<IQueueChannel> qchannel = qconn->open(DFS_REPLICATE_QUEUE);
  3983. qchannel->put(mb);
  3984. }
  3985. bool getAccessedTime(CDateTime &dt)
  3986. {
  3987. StringBuffer str;
  3988. if (!root->getProp("@accessed",str))
  3989. return false;
  3990. dt.setString(str.str());
  3991. return true;
  3992. }
  3993. virtual void setAccessedTime(const CDateTime &dt)
  3994. {
  3995. if (logicalName.isForeign())
  3996. parent->setFileAccessed(logicalName,udesc,dt);
  3997. else
  3998. {
  3999. CFileConnectLock fconnattrlock(true);
  4000. bool performedLock = false;
  4001. if (conn && !proplockcount) // NB: If locked, already have exclusive access to file
  4002. {
  4003. DfsXmlBranchKind bkind;
  4004. if (!fconnattrlock.initany("CDistributedFile::setAccessedTime", logicalName, bkind, true, false, false, defaultTimeout))
  4005. return; // timeout will raise exception
  4006. performedLock = true;
  4007. }
  4008. if (dt.isNull())
  4009. queryAttributes().removeProp("@accessed");
  4010. else
  4011. {
  4012. StringBuffer str;
  4013. queryAttributes().setProp("@accessed",dt.getString(str).str());
  4014. }
  4015. if (performedLock)
  4016. conn->commit();
  4017. }
  4018. }
  4019. void setAccessed()
  4020. {
  4021. CDateTime dt;
  4022. dt.setNow();
  4023. setAccessedTime(dt);
  4024. }
  4025. };
  4026. static unsigned findSubFileOrd(const char *name)
  4027. {
  4028. if (*name=='#') {
  4029. const char *n = name+1;
  4030. if (*n) {
  4031. do { n++; } while (*n&&isdigit(*n));
  4032. if (!*n)
  4033. return atoi(name+1)-1;
  4034. }
  4035. }
  4036. return NotFound;
  4037. }
  4038. class CDistributedSuperFile: public CDistributedFileBase<IDistributedSuperFile>
  4039. {
  4040. void checkNotForeign()
  4041. {
  4042. if (!conn)
  4043. throw MakeStringException(-1,"Operation not allowed on foreign file");
  4044. }
  4045. CDistributedFilePartArray partscache;
  4046. FileClusterInfoArray clusterscache;
  4047. /**
  4048. * Adds a sub-file to a super-file within a transaction.
  4049. */
  4050. class cAddSubFileAction: public CDFAction
  4051. {
  4052. StringAttr parentlname;
  4053. Owned<IDistributedSuperFile> parent;
  4054. Owned<IDistributedFile> sub;
  4055. StringAttr subfile;
  4056. bool before;
  4057. StringAttr other;
  4058. public:
  4059. cAddSubFileAction(const char *_parentlname,const char *_subfile,bool _before,const char *_other)
  4060. : parentlname(_parentlname), subfile(_subfile), before(_before), other(_other)
  4061. {
  4062. }
  4063. bool prepare()
  4064. {
  4065. parent.setown(transaction->lookupSuperFile(parentlname));
  4066. if (!parent)
  4067. throw MakeStringException(-1,"addSubFile: SuperFile %s cannot be found",parentlname.get());
  4068. if (!subfile.isEmpty())
  4069. {
  4070. try
  4071. {
  4072. sub.setown(transaction->lookupFile(subfile,SDS_SUB_LOCK_TIMEOUT));
  4073. if (!sub)
  4074. throw MakeStringException(-1,"cAddSubFileAction: sub file %s not found", subfile.sget());
  4075. // Must validate before locking for update below, to check sub is not already in parent (and therefore locked already)
  4076. transaction->validateAddSubFile(parent, sub, subfile);
  4077. }
  4078. catch (IDFS_Exception *e)
  4079. {
  4080. if (e->errorCode()!=DFSERR_LookupConnectionTimout)
  4081. throw;
  4082. e->Release();
  4083. return false;
  4084. }
  4085. if (!sub.get())
  4086. throw MakeStringException(-1,"addSubFile: File %s cannot be found to add",subfile.get());
  4087. }
  4088. // Try to lock all files
  4089. addFileLock(parent);
  4090. addFileLock(sub);
  4091. if (lock())
  4092. {
  4093. transaction->noteAddSubFile(parent, parentlname, sub);
  4094. return true;
  4095. }
  4096. unlock();
  4097. parent.clear();
  4098. sub.clear();
  4099. return false;
  4100. }
  4101. void run()
  4102. {
  4103. if (!sub)
  4104. throw MakeStringException(-1,"addSubFile(2): File %s cannot be found to add",subfile.get());
  4105. CDistributedSuperFile *sf = QUERYINTERFACE(parent.get(),CDistributedSuperFile);
  4106. if (sf)
  4107. sf->doAddSubFile(LINK(sub),before,other,transaction);
  4108. }
  4109. void commit()
  4110. {
  4111. CDistributedSuperFile *sf = QUERYINTERFACE(parent.get(),CDistributedSuperFile);
  4112. if (sf)
  4113. sf->updateParentFileAttrs(transaction);
  4114. CDFAction::commit();
  4115. }
  4116. };
  4117. /**
  4118. * Removes a sub-file of a super-file within a transaction.
  4119. */
  4120. class cRemoveSubFileAction: public CDFAction
  4121. {
  4122. StringAttr parentlname;
  4123. Owned<IDistributedSuperFile> parent;
  4124. Owned<IDistributedFile> sub;
  4125. StringAttr subfile;
  4126. bool remsub;
  4127. public:
  4128. cRemoveSubFileAction(const char *_parentlname,const char *_subfile,bool _remsub=false)
  4129. : parentlname(_parentlname), subfile(_subfile), remsub(_remsub)
  4130. {
  4131. }
  4132. bool prepare()
  4133. {
  4134. parent.setown(transaction->lookupSuperFile(parentlname));
  4135. if (!parent)
  4136. throw MakeStringException(-1,"removeSubFile: SuperFile %s cannot be found",parentlname.get());
  4137. if (!subfile.isEmpty())
  4138. {
  4139. try
  4140. {
  4141. sub.setown(transaction->lookupFile(subfile,SDS_SUB_LOCK_TIMEOUT));
  4142. }
  4143. catch (IDFS_Exception *e)
  4144. {
  4145. if (e->errorCode()!=DFSERR_LookupConnectionTimout)
  4146. throw;
  4147. e->Release();
  4148. return false;
  4149. }
  4150. if (!transaction->isSubFile(parent, subfile, true))
  4151. WARNLOG("addSubFile: File %s is not a subfile of %s", subfile.get(), parent->queryLogicalName());
  4152. }
  4153. // Try to lock all files
  4154. addFileLock(parent);
  4155. if (sub)
  4156. addFileLock(sub);
  4157. if (lock())
  4158. {
  4159. if (sub)
  4160. transaction->noteRemoveSubFile(parent, sub);
  4161. else
  4162. transaction->clearSubFiles(parent);
  4163. return true;
  4164. }
  4165. unlock();
  4166. parent.clear();
  4167. sub.clear();
  4168. return false;
  4169. }
  4170. void run()
  4171. {
  4172. CDistributedSuperFile *sf = QUERYINTERFACE(parent.get(),CDistributedSuperFile);
  4173. if (sf) {
  4174. // Delay the deletion of the subs until commit
  4175. if (remsub) {
  4176. if (subfile) {
  4177. CDfsLogicalFileName lname;
  4178. lname.set(subfile.get());
  4179. transaction->addDelayedDelete(lname, SDS_SUB_LOCK_TIMEOUT);
  4180. } else { // Remove all subfiles
  4181. Owned<IDistributedFileIterator> iter = parent->getSubFileIterator(false);
  4182. ForEach (*iter) {
  4183. CDfsLogicalFileName lname;
  4184. IDistributedFile *f = &iter->query();
  4185. lname.set(f->queryLogicalName());
  4186. transaction->addDelayedDelete(lname, SDS_SUB_LOCK_TIMEOUT);
  4187. }
  4188. }
  4189. }
  4190. // Now we clean the subs
  4191. if (subfile.get())
  4192. sf->doRemoveSubFile(subfile.get(), transaction);
  4193. else
  4194. sf->doRemoveSubFiles(transaction);
  4195. }
  4196. }
  4197. };
  4198. /**
  4199. * Removes all subfiles exclusively owned by named superfile within a transaction.
  4200. */
  4201. class cRemoveOwnedSubFilesAction: public CDFAction
  4202. {
  4203. StringAttr parentlname;
  4204. Owned<IDistributedSuperFile> parent;
  4205. bool remsub;
  4206. public:
  4207. cRemoveOwnedSubFilesAction(IDistributedFileTransaction *_transaction, const char *_parentlname,bool _remsub=false)
  4208. : parentlname(_parentlname), remsub(_remsub)
  4209. {
  4210. }
  4211. bool prepare()
  4212. {
  4213. parent.setown(transaction->lookupSuperFile(parentlname));
  4214. if (!parent)
  4215. throw MakeStringException(-1,"removeOwnedSubFiles: SuperFile %s cannot be found", parentlname.get());
  4216. // Try to lock all files
  4217. addFileLock(parent);
  4218. if (lock())
  4219. return true;
  4220. unlock();
  4221. parent.clear();
  4222. return false;
  4223. }
  4224. void run()
  4225. {
  4226. CDistributedSuperFile *sf = QUERYINTERFACE(parent.get(),CDistributedSuperFile);
  4227. if (sf)
  4228. {
  4229. StringArray toRemove;
  4230. Owned<IDistributedFileIterator> iter = parent->getSubFileIterator(false);
  4231. ForEach (*iter)
  4232. {
  4233. IDistributedFile *file = &iter->query();
  4234. CDistributedFile *_file = QUERYINTERFACE(file, CDistributedFile);
  4235. StringArray owners;
  4236. _file->getSuperOwners(owners);
  4237. if (NotFound == owners.find(parentlname))
  4238. ThrowStringException(-1, "removeOwnedSubFiles: SuperFile %s, subfile %s - subfile not owned by superfile", parentlname.get(), file->queryLogicalName());
  4239. if (1 == owners.ordinality()) // just me
  4240. {
  4241. const char *logicalName = file->queryLogicalName();
  4242. toRemove.append(logicalName);
  4243. // Delay the deletion of the subs until commit
  4244. if (remsub)
  4245. {
  4246. CDfsLogicalFileName lname;
  4247. lname.set(logicalName);
  4248. transaction->addDelayedDelete(lname, SDS_SUB_LOCK_TIMEOUT);
  4249. }
  4250. }
  4251. }
  4252. // Now we clean the subs
  4253. if (sf->numSubFiles(false) == toRemove.ordinality())
  4254. sf->doRemoveSubFiles(transaction); // remove all
  4255. else
  4256. {
  4257. ForEachItemIn(r, toRemove)
  4258. sf->doRemoveSubFile(toRemove.item(r), transaction);
  4259. }
  4260. }
  4261. }
  4262. };
  4263. /**
  4264. * Swaps sub-files between two super-files within a transaction.
  4265. */
  4266. class cSwapFileAction: public CDFAction
  4267. {
  4268. Linked<IDistributedSuperFile> super1, super2;
  4269. StringAttr super1Name, super2Name;
  4270. public:
  4271. cSwapFileAction(const char *_super1Name, const char *_super2Name)
  4272. : super1Name(_super1Name), super2Name(_super2Name)
  4273. {
  4274. }
  4275. bool prepare()
  4276. {
  4277. super1.setown(transaction->lookupSuperFile(super1Name));
  4278. if (!super1)
  4279. throw MakeStringException(-1,"swapSuperFile: SuperFile %s cannot be found", super1Name.get());
  4280. super2.setown(transaction->lookupSuperFile(super2Name));
  4281. if (!super2)
  4282. {
  4283. super1.clear();
  4284. throw MakeStringException(-1,"swapSuperFile: SuperFile %s cannot be found", super2Name.get());
  4285. }
  4286. // Try to lock all files
  4287. addFileLock(super1);
  4288. for (unsigned i=0; i<super1->numSubFiles(); i++)
  4289. addFileLock(&super1->querySubFile(i));
  4290. addFileLock(super2);
  4291. for (unsigned i=0; i<super2->numSubFiles(); i++)
  4292. addFileLock(&super2->querySubFile(i));
  4293. if (lock())
  4294. {
  4295. transaction->noteSuperSwap(super1, super2);
  4296. return true;
  4297. }
  4298. unlock();
  4299. super1.clear();
  4300. super2.clear();
  4301. return false;
  4302. }
  4303. void run()
  4304. {
  4305. CDistributedSuperFile *sf = QUERYINTERFACE(super1.get(),CDistributedSuperFile);
  4306. if (sf)
  4307. sf->doSwapSuperFile(super2,transaction);
  4308. }
  4309. };
  4310. /**
  4311. * SubFile Iterator, used only to list sub-files of a super-file.
  4312. */
  4313. class cSubFileIterator: public CDistributedFileIteratorBase< IDistributedFileIterator, IArrayOf<IDistributedFile> >
  4314. {
  4315. public:
  4316. cSubFileIterator(IArrayOf<IDistributedFile> &_subfiles, bool supersub)
  4317. {
  4318. ForEachItemIn(i,_subfiles) {
  4319. IDistributedSuperFile* super = supersub?_subfiles.item(i).querySuperFile():NULL;
  4320. if (super) {
  4321. Owned<IDistributedFileIterator> iter = super->getSubFileIterator(true);
  4322. ForEach(*iter)
  4323. list.append(iter->get());
  4324. }
  4325. else
  4326. list.append(*LINK(&_subfiles.item(i)));
  4327. }
  4328. }
  4329. StringBuffer & getName(StringBuffer &name)
  4330. {
  4331. return list.item(index).getLogicalName(name);
  4332. }
  4333. IDistributedFile & query()
  4334. {
  4335. return list.item(index);
  4336. }
  4337. };
  4338. void checkModify(const char *title)
  4339. {
  4340. StringBuffer reason;
  4341. if (!canModify(reason)) {
  4342. #ifdef EXTRA_LOGGING
  4343. PROGLOG("CDistributedSuperFile::%s(canModify) %s",title,reason.str());
  4344. #endif
  4345. if (reason.length())
  4346. throw MakeStringException(-1,"CDistributedSuperFile::%s %s",title,reason.str());
  4347. }
  4348. }
  4349. protected:
  4350. int interleaved; // 0 not interleaved, 1 interleaved old, 2 interleaved new
  4351. IArrayOf<IDistributedFile> subfiles;
  4352. void clearSuperOwners(unsigned timeoutMs)
  4353. {
  4354. Owned<IPropertyTreeIterator> iter = root->getElements("SubFile");
  4355. StringBuffer oquery;
  4356. oquery.append("SuperOwner[@name=\"").append(logicalName.get()).append("\"]");
  4357. Owned<IMultiException> exceptions = MakeMultiException("CDelayedDelete::doRemoveEntry::SuperOwners");
  4358. ForEach(*iter)
  4359. {
  4360. const char *name = iter->query().queryProp("@name");
  4361. if (name&&*name)
  4362. {
  4363. CDfsLogicalFileName subfn;
  4364. subfn.set(name);
  4365. CFileConnectLock fconnlockSub;
  4366. DfsXmlBranchKind subbkind;
  4367. // MORE: Use CDistributedSuperFile::linkSuperOwner(false) - ie. unlink
  4368. if (fconnlockSub.initany("CDelayedDelete::doRemoveEntry", subfn, subbkind, false, false, false, timeoutMs))
  4369. {
  4370. IPropertyTree *subfroot = fconnlockSub.queryRoot();
  4371. if (subfroot)
  4372. {
  4373. if (!subfroot->removeProp(oquery.str()))
  4374. exceptions->append(*MakeStringException(-1, "CDelayedDelete::removeEntry: SubFile %s of %s not found for removal",name?name:"(NULL)", logicalName.get()));
  4375. }
  4376. }
  4377. }
  4378. }
  4379. if (exceptions->ordinality())
  4380. throw exceptions.getClear();
  4381. }
  4382. virtual void getSuperOwners(StringArray &owners)
  4383. {
  4384. ForEachItemIn(i, subfiles)
  4385. {
  4386. IDistributedFile *file = &subfiles.item(i);
  4387. IDistributedSuperFile *super = file->querySuperFile();
  4388. if (super)
  4389. {
  4390. CDistributedSuperFile *_super = QUERYINTERFACE(super, CDistributedSuperFile);
  4391. if (_super)
  4392. _super->getSuperOwners(owners);
  4393. }
  4394. else
  4395. {
  4396. CDistributedFile *_file = QUERYINTERFACE(file, CDistributedFile);
  4397. if (_file)
  4398. _file->getSuperOwners(owners);
  4399. }
  4400. }
  4401. }
  4402. static StringBuffer &getSubPath(StringBuffer &path,unsigned idx)
  4403. {
  4404. return path.append("SubFile[@num=\"").append(idx+1).append("\"]");
  4405. }
  4406. void loadSubFiles(IDistributedFileTransaction *transaction, unsigned timeout)
  4407. {
  4408. partscache.kill();
  4409. StringBuffer path;
  4410. StringBuffer subname;
  4411. subfiles.kill();
  4412. unsigned n = root->getPropInt("@numsubfiles");
  4413. if (n == 0)
  4414. return;
  4415. try
  4416. {
  4417. // Find all reported indexes and bail on bad range (before we lock any file)
  4418. Owned<IPropertyTreeIterator> subit = root->getElements("SubFile");
  4419. // Adding a sub 'before' another get the list out of order (but still valid)
  4420. OwnedMalloc<IPropertyTree *> orderedSubFiles(n, true);
  4421. ForEach (*subit)
  4422. {
  4423. IPropertyTree &sub = subit->query();
  4424. unsigned sn = sub.getPropInt("@num",0);
  4425. if (sn == 0)
  4426. ThrowStringException(-1, "CDistributedSuperFile: SuperFile %s: bad subfile part number %d of %d", logicalName.get(), sn, n);
  4427. if (sn > n)
  4428. ThrowStringException(-1, "CDistributedSuperFile: SuperFile %s: out-of-range subfile part number %d of %d", logicalName.get(), sn, n);
  4429. if (orderedSubFiles[sn-1])
  4430. ThrowStringException(-1, "CDistributedSuperFile: SuperFile %s: duplicated subfile part number %d of %d", logicalName.get(), sn, n);
  4431. orderedSubFiles[sn-1] = &sub;
  4432. }
  4433. for (unsigned i=0; i<n; i++)
  4434. {
  4435. if (!orderedSubFiles[i])
  4436. ThrowStringException(-1, "CDistributedSuperFile: SuperFile %s: missing subfile part number %d of %d", logicalName.get(), i+1, n);
  4437. }
  4438. // Now try to resolve them all (file/superfile)
  4439. for (unsigned f=0; f<n; f++)
  4440. {
  4441. IPropertyTree &sub = *(orderedSubFiles[f]);
  4442. sub.getProp("@name",subname.clear());
  4443. Owned<IDistributedFile> subfile;
  4444. subfile.setown(transaction?transaction->lookupFile(subname.str(),timeout):parent->lookup(subname.str(), udesc, false, false, transaction, timeout));
  4445. if (!subfile.get())
  4446. subfile.setown(transaction?transaction->lookupSuperFile(subname.str(),timeout):parent->lookupSuperFile(subname.str(),udesc,transaction,timeout));
  4447. // Some files are ok not to exist
  4448. if (!subfile.get())
  4449. {
  4450. CDfsLogicalFileName cdfsl;
  4451. cdfsl.set(subname);
  4452. if (cdfsl.isForeign())
  4453. {
  4454. // MORE - This foreign treatment seems flaky at best
  4455. WARNLOG("CDistributedSuperFile: SuperFile %s's sub-file file '%s' is foreign, removing it from super", logicalName.get(), subname.str());
  4456. root->removeTree(&sub);
  4457. continue;
  4458. }
  4459. else
  4460. ThrowStringException(-1, "CDistributedSuperFile: SuperFile %s: corrupt subfile file '%s' cannot be found", logicalName.get(), subname.str());
  4461. }
  4462. subfiles.append(*subfile.getClear());
  4463. }
  4464. // This is *only* due to foreign files
  4465. if (subfiles.ordinality() != n)
  4466. {
  4467. WARNLOG("CDistributedSuperFile: SuperFile %s's number of sub-files updated to %d", logicalName.get(), subfiles.ordinality());
  4468. root->setPropInt("@numsubfiles", subfiles.ordinality());
  4469. }
  4470. }
  4471. catch (IException *)
  4472. {
  4473. partscache.kill();
  4474. subfiles.kill(); // one out, all out
  4475. throw;
  4476. }
  4477. }
  4478. void addItem(unsigned pos,IDistributedFile *_file)
  4479. {
  4480. Owned<IDistributedFile> file = _file;
  4481. partscache.kill();
  4482. // first renumber all above
  4483. StringBuffer path;
  4484. IPropertyTree *sub;
  4485. for (unsigned i=subfiles.ordinality();i>pos;i--) {
  4486. sub = root->queryPropTree(getSubPath(path.clear(),i-1).str());
  4487. if (!sub)
  4488. throw MakeStringException(-1,"C(2): Corrupt subfile file part %d cannot be found",i);
  4489. sub->setPropInt("@num",i+1);
  4490. }
  4491. sub = createPTree();
  4492. sub->setPropInt("@num",pos+1);
  4493. sub->setProp("@name",file->queryLogicalName());
  4494. if (pos==0) {
  4495. resetFileAttr(createPTreeFromIPT(&file->queryAttributes()));
  4496. }
  4497. root->addPropTree("SubFile",sub);
  4498. subfiles.add(*file.getClear(),pos);
  4499. root->setPropInt("@numsubfiles",subfiles.ordinality());
  4500. }
  4501. void removeItem(unsigned pos)
  4502. {
  4503. partscache.kill();
  4504. StringBuffer path;
  4505. IPropertyTree* sub = root->queryPropTree(getSubPath(path,pos).str());
  4506. if (!sub)
  4507. throw MakeStringException(-1,"CDistributedSuperFile(3): Corrupt subfile file part %d cannot be found",pos+1);
  4508. root->removeTree(sub);
  4509. // now renumber all above
  4510. for (unsigned i=pos+1; i<subfiles.ordinality(); i++) {
  4511. sub = root->queryPropTree(getSubPath(path.clear(),i).str());
  4512. if (!sub)
  4513. throw MakeStringException(-1,"CDistributedSuperFile(2): Corrupt subfile file part %d cannot be found",i+1);
  4514. sub->setPropInt("@num",i);
  4515. }
  4516. subfiles.remove(pos);
  4517. if (pos==0) {
  4518. if (subfiles.ordinality())
  4519. resetFileAttr(createPTreeFromIPT(&subfiles.item(0).queryAttributes()));
  4520. else
  4521. resetFileAttr(getEmptyAttr());
  4522. }
  4523. root->setPropInt("@numsubfiles",subfiles.ordinality());
  4524. }
  4525. void loadParts(CDistributedFilePartArray &partsret, IDFPartFilter *filter)
  4526. {
  4527. unsigned p = 0;
  4528. if (interleaved) { // a bit convoluted but should work
  4529. IArrayOf<IDistributedFile> allsubfiles;
  4530. ForEachItemIn(i,subfiles) {
  4531. // if old format keep original interleaving
  4532. IDistributedSuperFile* super = (interleaved==1)?NULL:subfiles.item(i).querySuperFile();
  4533. if (super) {
  4534. Owned<IDistributedFileIterator> iter = super->getSubFileIterator(true);
  4535. ForEach(*iter)
  4536. allsubfiles.append(iter->get());
  4537. }
  4538. else
  4539. allsubfiles.append(*LINK(&subfiles.item(i)));
  4540. }
  4541. unsigned *pn = new unsigned[allsubfiles.ordinality()];
  4542. ForEachItemIn(j,allsubfiles)
  4543. pn[j] = allsubfiles.item(j).numParts();
  4544. unsigned f=0;
  4545. bool found=false;
  4546. loop {
  4547. if (f==allsubfiles.ordinality()) {
  4548. if (!found)
  4549. break; // no more
  4550. found = false;
  4551. f = 0;
  4552. }
  4553. if (pn[f]) {
  4554. found = true;
  4555. if (!filter||filter->includePart(p)) {
  4556. IDistributedFile &subfile = allsubfiles.item(f);
  4557. IDistributedFilePart *part = subfile.getPart(subfile.numParts()-pn[f]);
  4558. partsret.append(*QUERYINTERFACE(part,CDistributedFilePart)); // bit kludgy
  4559. }
  4560. p++;
  4561. pn[f]--;
  4562. }
  4563. f++;
  4564. }
  4565. delete [] pn;
  4566. }
  4567. else { // sequential
  4568. ForEachItemIn(i,subfiles) { // not wonderfully quick
  4569. IDistributedFile &subfile = subfiles.item(i);
  4570. unsigned n = subfile.numParts();
  4571. unsigned j = 0;
  4572. while (n--) {
  4573. if (!filter||filter->includePart(p)) {
  4574. IDistributedFilePart *part = subfile.getPart(j++);
  4575. partsret.append(*QUERYINTERFACE(part,CDistributedFilePart)); // bit kludgy
  4576. }
  4577. p++;
  4578. }
  4579. }
  4580. }
  4581. }
  4582. void linkSubFile(unsigned pos,IDistributedFileTransactionExt *transaction,bool link=true)
  4583. {
  4584. IDistributedFile *subfile = &subfiles.item(pos);
  4585. DistributedFilePropertyLock lock(subfile);
  4586. IDistributedSuperFile *ssub = subfile->querySuperFile();
  4587. if (ssub) {
  4588. CDistributedSuperFile *cdsuper = QUERYINTERFACE(ssub,CDistributedSuperFile);
  4589. cdsuper->linkSuperOwner(queryLogicalName(),link);
  4590. }
  4591. else {
  4592. CDistributedFile *cdfile = QUERYINTERFACE(subfile,CDistributedFile);
  4593. cdfile->linkSuperOwner(queryLogicalName(),link);
  4594. }
  4595. if (!transaction || !transaction->active())
  4596. lock.commit();
  4597. }
  4598. void unlinkSubFile(unsigned pos,IDistributedFileTransactionExt *transaction)
  4599. {
  4600. linkSubFile(pos, transaction, false);
  4601. }
  4602. void checkSubFormatAttr(IDistributedFile *sub, const char* exprefix="")
  4603. {
  4604. // empty super files now pass
  4605. ForEachItemIn(i,subfiles) {
  4606. IDistributedSuperFile* super = subfiles.item(i).querySuperFile();
  4607. if (super) {
  4608. CDistributedSuperFile *cdsuper = QUERYINTERFACE(super,CDistributedSuperFile);
  4609. if (cdsuper)
  4610. cdsuper->checkSubFormatAttr(sub,exprefix);
  4611. return;
  4612. }
  4613. CDistributedFile *cdfile = QUERYINTERFACE(&subfiles.item(0),CDistributedFile);
  4614. if (cdfile)
  4615. cdfile->checkFormatAttr(sub,exprefix); // any file will do
  4616. }
  4617. }
  4618. public:
  4619. void checkFormatAttr(IDistributedFile *sub, const char* exprefix="")
  4620. {
  4621. // only check sub files not siblings, which is excessive (format checking is really only debug aid)
  4622. checkSubFormatAttr(sub,exprefix);
  4623. }
  4624. unsigned findSubFile(const char *name)
  4625. {
  4626. StringBuffer lfn;
  4627. normalizeLFN(name,lfn);
  4628. ForEachItemIn(i,subfiles)
  4629. if (stricmp(subfiles.item(i).queryLogicalName(),lfn.str())==0)
  4630. return i;
  4631. return NotFound;
  4632. }
  4633. IMPLEMENT_IINTERFACE;
  4634. void init(CDistributedFileDirectory *_parent, IPropertyTree *_root, const CDfsLogicalFileName &_name, IUserDescriptor* user, IDistributedFileTransaction *transaction, unsigned timeout=INFINITE)
  4635. {
  4636. assertex(_name.isSet());
  4637. setUserDescriptor(udesc,user);
  4638. logicalName.set(_name);
  4639. parent = _parent;
  4640. root.set(_root);
  4641. const char *val = root->queryProp("@interleaved");
  4642. if (val&&isdigit(*val))
  4643. interleaved = atoi(val);
  4644. else
  4645. interleaved = strToBool(val)?1:0;
  4646. loadSubFiles(transaction,timeout);
  4647. }
  4648. CDistributedSuperFile(CDistributedFileDirectory *_parent, IPropertyTree *_root,const CDfsLogicalFileName &_name,IUserDescriptor* user)
  4649. {
  4650. init(_parent,_root,_name,user,NULL);
  4651. }
  4652. CDistributedSuperFile(CDistributedFileDirectory *_parent, IRemoteConnection *_conn,const CDfsLogicalFileName &_name,IUserDescriptor* user, IDistributedFileTransaction *transaction,unsigned timeout)
  4653. {
  4654. conn.setown(_conn);
  4655. init(_parent,conn->queryRoot(),_name,user,transaction,timeout);
  4656. }
  4657. CDistributedSuperFile(CDistributedFileDirectory *_parent, CDfsLogicalFileName &_name, IUserDescriptor* user, IDistributedFileTransaction *transaction)
  4658. {
  4659. // temp super file
  4660. assertex(_name.isMulti());
  4661. if (!_name.isExpanded())
  4662. _name.expand(user);//expand wildcards
  4663. Owned<IPropertyTree> tree = _name.createSuperTree();
  4664. init(_parent,tree,_name,user,transaction);
  4665. }
  4666. ~CDistributedSuperFile()
  4667. {
  4668. partscache.kill();
  4669. subfiles.kill();
  4670. }
  4671. StringBuffer &getClusterName(unsigned clusternum,StringBuffer &name)
  4672. {
  4673. // returns the cluster name if all the same
  4674. CriticalBlock block (sect);
  4675. if (subfiles.ordinality()==1)
  4676. return subfiles.item(0).getClusterName(clusternum,name);
  4677. size32_t rl = name.length();
  4678. StringBuffer test;
  4679. ForEachItemIn(i,subfiles) {
  4680. if (i) {
  4681. subfiles.item(i).getClusterName(clusternum,test.clear());
  4682. if (strcmp(name.str(),test.str())!=0) {
  4683. name.setLength(rl);
  4684. break;
  4685. }
  4686. }
  4687. else
  4688. subfiles.item(i).getClusterName(clusternum,name);
  4689. }
  4690. return name;
  4691. }
  4692. IFileDescriptor *getFileDescriptor(const char *clustername)
  4693. {
  4694. CriticalBlock block (sect);
  4695. if (subfiles.ordinality()==1)
  4696. return subfiles.item(0).getFileDescriptor(clustername);
  4697. // superfiles assume consistant replication & compression
  4698. UnsignedArray subcounts;
  4699. bool mixedwidth = false;
  4700. unsigned width = 0;
  4701. bool first = true;
  4702. Owned<IPropertyTree> at = getEmptyAttr();
  4703. Owned<IDistributedFileIterator> fiter = getSubFileIterator(true);
  4704. ForEach(*fiter)
  4705. {
  4706. IDistributedFile &file = fiter->query();
  4707. if (first)
  4708. {
  4709. first = false;
  4710. Owned<IAttributeIterator> ait = file.queryAttributes().getAttributes();
  4711. ForEach(*ait)
  4712. {
  4713. const char *name = ait->queryName();
  4714. if ((stricmp(name,"@size")!=0)&&(stricmp(name,"@recordCount")!=0))
  4715. {
  4716. const char *v = ait->queryValue();
  4717. if (!v)
  4718. continue;
  4719. bool ok = true;
  4720. // add attributes that are common
  4721. for (unsigned i=1;i<subfiles.ordinality();i++)
  4722. {
  4723. IDistributedFile &file = subfiles.item(i);
  4724. IDistributedSuperFile *sFile = file.querySuperFile();
  4725. if (!sFile || sFile->numSubFiles(true)) // skip empty super files
  4726. {
  4727. const char *p = file.queryAttributes().queryProp(name);
  4728. if (!p||(strcmp(p,v)!=0))
  4729. {
  4730. ok = false;
  4731. break;
  4732. }
  4733. }
  4734. }
  4735. if (ok)
  4736. at->setProp(name,v);
  4737. }
  4738. }
  4739. }
  4740. unsigned np = file.numParts();
  4741. if (width)
  4742. width = np;
  4743. else if (np!=width)
  4744. mixedwidth = true;
  4745. subcounts.append(np);
  4746. }
  4747. // need common attributes
  4748. Owned<ISuperFileDescriptor> fdesc=createSuperFileDescriptor(at.getClear());
  4749. if (interleaved&&(interleaved!=2))
  4750. WARNLOG("getFileDescriptor: Unsupported interleave value (1)");
  4751. fdesc->setSubMapping(subcounts,interleaved!=0);
  4752. fdesc->setTraceName(logicalName.get());
  4753. Owned<IDistributedFilePartIterator> iter = getIterator(NULL);
  4754. unsigned n = 0;
  4755. SocketEndpointArray reps;
  4756. ForEach(*iter) {
  4757. IDistributedFilePart &part = iter->query();
  4758. CDistributedFilePart *cpart = (clustername&&*clustername)?QUERYINTERFACE(&part,CDistributedFilePart):NULL;
  4759. unsigned copy = 0;
  4760. if (cpart) {
  4761. IDistributedFile &f = cpart->queryParent();
  4762. unsigned cn = f.findCluster(clustername);
  4763. if (cn!=NotFound) {
  4764. for (unsigned i = 0;i<cpart->numCopies();i++)
  4765. if (cpart->copyClusterNum(i,NULL)==cn) {
  4766. copy = i;
  4767. break;
  4768. }
  4769. }
  4770. }
  4771. if (mixedwidth) {
  4772. SocketEndpoint rep;
  4773. if (copy+1<part.numCopies())
  4774. rep = part.queryNode(copy+1)->endpoint();
  4775. reps.append(rep);
  4776. }
  4777. RemoteFilename rfn;
  4778. fdesc->setPart(n,part.getFilename(rfn,copy),&part.queryAttributes());
  4779. n++;
  4780. }
  4781. ClusterPartDiskMapSpec mspec;
  4782. if (subfiles.ordinality()) {
  4783. mspec = subfiles.item(0).queryPartDiskMapping(0);
  4784. }
  4785. mspec.interleave = numSubFiles(true);
  4786. fdesc->endCluster(mspec);
  4787. if (mixedwidth) { // bleah - have to add replicate node numbers
  4788. Owned<IGroup> group = fdesc->getGroup();
  4789. unsigned gw = group->ordinality();
  4790. for (unsigned pn=0;pn<reps.ordinality();pn++) {
  4791. const SocketEndpoint &ep=reps.item(pn);
  4792. if (!ep.isNull()) {
  4793. unsigned gn = pn;
  4794. if (gn<gw) {
  4795. do {
  4796. gn++;
  4797. if (gn==gw)
  4798. gn = 0;
  4799. if (ep.equals(group->queryNode((rank_t)gn).endpoint())) {
  4800. IPartDescriptor *part = fdesc->queryPart(pn);
  4801. if (part)
  4802. part->queryProperties().setPropInt("@rn",(unsigned)gn);
  4803. break;
  4804. }
  4805. } while (gn!=pn);
  4806. }
  4807. }
  4808. }
  4809. }
  4810. return fdesc.getClear();
  4811. }
  4812. unsigned numParts()
  4813. {
  4814. CriticalBlock block(sect);
  4815. unsigned ret=0;
  4816. ForEachItemIn(i,subfiles)
  4817. ret += subfiles.item(i).numParts();
  4818. return ret;
  4819. }
  4820. IDistributedFilePart &queryPart(unsigned idx)
  4821. {
  4822. CriticalBlock block(sect);
  4823. if (subfiles.ordinality()==1)
  4824. return subfiles.item(0).queryPart(idx);
  4825. if (partscache.ordinality()==0)
  4826. loadParts(partscache,NULL);
  4827. if (idx>=partscache.ordinality())
  4828. return *(IDistributedFilePart *)NULL;
  4829. return partscache.item(idx);
  4830. }
  4831. IDistributedFilePart* getPart(unsigned idx)
  4832. {
  4833. IDistributedFilePart* ret = &queryPart(idx);
  4834. return LINK(ret);
  4835. }
  4836. IDistributedFilePartIterator *getIterator(IDFPartFilter *filter=NULL)
  4837. {
  4838. CriticalBlock block(sect);
  4839. if (subfiles.ordinality()==1)
  4840. return subfiles.item(0).getIterator(filter);
  4841. CDistributedFilePartIterator *ret = new CDistributedFilePartIterator();
  4842. loadParts(ret->queryParts(),filter);
  4843. return ret;
  4844. }
  4845. void rename(const char *_logicalname,IUserDescriptor *user)
  4846. {
  4847. StringBuffer prevname;
  4848. Owned<IFileRelationshipIterator> reliter;
  4849. // set prevname
  4850. if (!isAnon()) {
  4851. getLogicalName(prevname);
  4852. try {
  4853. IFileRelationshipIterator *iter = parent->lookupAllFileRelationships(prevname.str());
  4854. reliter.setown(iter);
  4855. }
  4856. catch (IException *e) {
  4857. EXCLOG(e,"CDistributedFileDirectory::rename");
  4858. e->Release();
  4859. }
  4860. detach();
  4861. }
  4862. attach(_logicalname,user);
  4863. if (reliter.get()) {
  4864. // add back any relationships with new name
  4865. parent->renameFileRelationships(prevname.str(),_logicalname,reliter,user);
  4866. }
  4867. }
  4868. const char *queryDefaultDir()
  4869. {
  4870. // returns the directory if all the same
  4871. const char *ret = NULL;
  4872. CriticalBlock block (sect);
  4873. ForEachItemIn(i,subfiles) {
  4874. if (subfiles.item(i).numParts())
  4875. {
  4876. const char *s = subfiles.item(i).queryDefaultDir();
  4877. if (!s)
  4878. return NULL;
  4879. if (!ret)
  4880. ret = s;
  4881. else if (strcmp(ret,s)!=0)
  4882. return NULL;
  4883. }
  4884. }
  4885. return ret;
  4886. }
  4887. const char *queryPartMask()
  4888. {
  4889. // returns the part mask if all the same
  4890. const char *ret = NULL;
  4891. CriticalBlock block (sect);
  4892. ForEachItemIn(i,subfiles) {
  4893. const char *s = subfiles.item(i).queryPartMask();
  4894. if (!s)
  4895. return NULL;
  4896. if (!ret)
  4897. ret = s;
  4898. else if (stricmp(ret,s)!=0)
  4899. return NULL;
  4900. }
  4901. return ret;
  4902. }
  4903. void attach(const char *_logicalname,IUserDescriptor *user)
  4904. {
  4905. // will need more thought but this gives limited support for anon
  4906. if (isAnon())
  4907. return;
  4908. assertex(!conn.get()); // already attached
  4909. CriticalBlock block (sect);
  4910. StringBuffer tail;
  4911. StringBuffer lfn;
  4912. logicalName.set(_logicalname);
  4913. checkLogicalName(logicalName,user,true,true,false,"attach");
  4914. parent->addEntry(logicalName,root.getClear(),true,false);
  4915. conn.clear();
  4916. CFileConnectLock fcl("CDistributedSuperFile::attach",logicalName,DXB_SuperFile, false, false, false, defaultTimeout);
  4917. conn.setown(fcl.detach());
  4918. assertex(conn.get()); // must have been attached
  4919. root.setown(conn->getRoot());
  4920. }
  4921. void detach(unsigned timeoutMs=INFINITE)
  4922. {
  4923. // will need more thought but this gives limited support for anon
  4924. if (isAnon())
  4925. return;
  4926. assertex(conn.get()); // must be attached
  4927. CriticalBlock block(sect);
  4928. checkModify("CDistributedSuperFile::detach");
  4929. subfiles.kill();
  4930. // Remove from SDS
  4931. CFileChangeWriteLock writeLock(conn, timeoutMs);
  4932. clearSuperOwners(timeoutMs);
  4933. writeLock.clear();
  4934. root.setown(closeConnection(true));
  4935. updateFS(logicalName, timeoutMs);
  4936. logicalName.clear();
  4937. }
  4938. bool existsPhysicalPartFiles(unsigned short port)
  4939. {
  4940. CriticalBlock block (sect);
  4941. ForEachItemIn(i,subfiles) {
  4942. IDistributedFile &f=subfiles.item(i);
  4943. if (!f.existsPhysicalPartFiles(port))
  4944. return false;
  4945. }
  4946. return true;
  4947. }
  4948. bool renamePhysicalPartFiles(const char *newlfn,const char *cluster,IMultiException *mexcept,const char *newbasedir)
  4949. {
  4950. throw MakeStringException(-1,"renamePhysicalPartFiles not supported for SuperFiles");
  4951. return false;
  4952. }
  4953. void serialize(MemoryBuffer &mb)
  4954. {
  4955. UNIMPLEMENTED; // not yet needed
  4956. }
  4957. virtual unsigned numCopies(unsigned partno)
  4958. {
  4959. unsigned ret = (unsigned)-1;
  4960. CriticalBlock block (sect);
  4961. ForEachItemIn(i,subfiles) {
  4962. IDistributedFile &f=subfiles.item(i);
  4963. unsigned fnc = f.numCopies(partno);
  4964. if (fnc<ret)
  4965. ret = fnc;
  4966. }
  4967. return (ret==(unsigned)-1)?1:ret;
  4968. }
  4969. __int64 getFileSize(bool allowphysical,bool forcephysical)
  4970. {
  4971. __int64 ret = (__int64)(forcephysical?-1:queryAttributes().getPropInt64("@size",-1));
  4972. if (ret==-1)
  4973. {
  4974. ret = 0;
  4975. ForEachItemIn(i,subfiles)
  4976. {
  4977. __int64 ps = subfiles.item(i).getFileSize(allowphysical,forcephysical);
  4978. if (ps == -1)
  4979. return -1; // i.e. if cannot determine size of any part, total is unknown
  4980. ret += ps;
  4981. }
  4982. }
  4983. return ret;
  4984. }
  4985. __int64 getDiskSize(bool allowphysical,bool forcephysical)
  4986. {
  4987. if (!isCompressed(NULL))
  4988. return getFileSize(allowphysical, forcephysical);
  4989. __int64 ret = (__int64)(forcephysical?-1:queryAttributes().getPropInt64("@compressedSize",-1));
  4990. if (ret==-1)
  4991. {
  4992. ret = 0;
  4993. ForEachItemIn(i,subfiles)
  4994. {
  4995. __int64 ps = subfiles.item(i).getDiskSize(allowphysical,forcephysical);
  4996. if (ps == -1)
  4997. return -1; // i.e. if cannot determine size of any part, total is unknown
  4998. ret += ps;
  4999. }
  5000. }
  5001. return ret;
  5002. }
  5003. __int64 getRecordCount()
  5004. {
  5005. __int64 ret = queryAttributes().getPropInt64("@recordCount",-1);
  5006. if (ret==-1) {
  5007. ret = 0;
  5008. ForEachItemIn(i,subfiles) {
  5009. __int64 rc = subfiles.item(i).queryAttributes().getPropInt64("@recordCount",-1);
  5010. if (rc == -1) {
  5011. ret = rc;
  5012. break;
  5013. }
  5014. ret += rc;
  5015. }
  5016. }
  5017. return ret;
  5018. }
  5019. bool getFileCheckSum(unsigned &checkSum)
  5020. {
  5021. if (queryAttributes().hasProp("@checkSum"))
  5022. checkSum = (unsigned)queryAttributes().getPropInt64("@checkSum");
  5023. else
  5024. {
  5025. checkSum = ~0;
  5026. ForEachItemIn(i,subfiles) {
  5027. unsigned cs;
  5028. if (!subfiles.item(i).getFileCheckSum(cs))
  5029. return false;
  5030. checkSum ^= cs;
  5031. }
  5032. }
  5033. return true;
  5034. }
  5035. IDistributedSuperFile *querySuperFile()
  5036. {
  5037. return this;
  5038. }
  5039. virtual IDistributedFile &querySubFile(unsigned idx,bool sub)
  5040. {
  5041. CriticalBlock block (sect);
  5042. if (sub) {
  5043. ForEachItemIn(i,subfiles) {
  5044. IDistributedFile &f=subfiles.item(i);
  5045. IDistributedSuperFile *super = f.querySuperFile();
  5046. if (super) {
  5047. unsigned ns = super->numSubFiles(true);
  5048. if (ns>idx)
  5049. return super->querySubFile(idx,true);
  5050. idx -= ns;
  5051. }
  5052. else if (idx--==0)
  5053. return f;
  5054. }
  5055. // fall through to error
  5056. }
  5057. return subfiles.item(idx);
  5058. }
  5059. virtual IDistributedFile *querySubFileNamed(const char *name, bool sub)
  5060. {
  5061. CriticalBlock block (sect);
  5062. unsigned idx=findSubFileOrd(name);
  5063. if ((idx!=NotFound)&&(idx<subfiles.ordinality()))
  5064. return &subfiles.item(idx);
  5065. idx=findSubFile(name);
  5066. if (idx!=NotFound)
  5067. return &subfiles.item(idx);
  5068. if (sub) {
  5069. ForEachItemIn(i,subfiles) {
  5070. IDistributedFile &f=subfiles.item(i);
  5071. IDistributedSuperFile *super = f.querySuperFile();
  5072. if (super) {
  5073. IDistributedFile *ret = super->querySubFileNamed(name);
  5074. if (ret)
  5075. return ret;
  5076. }
  5077. }
  5078. }
  5079. return NULL;
  5080. }
  5081. virtual IDistributedFile *getSubFile(unsigned idx,bool sub)
  5082. {
  5083. CriticalBlock block (sect);
  5084. return LINK(&querySubFile(idx,sub));
  5085. }
  5086. virtual unsigned numSubFiles(bool sub)
  5087. {
  5088. CriticalBlock block (sect);
  5089. unsigned ret = 0;
  5090. if (sub) {
  5091. ForEachItemIn(i,subfiles) {
  5092. IDistributedFile &f=subfiles.item(i);
  5093. IDistributedSuperFile *super = f.querySuperFile();
  5094. if (super)
  5095. ret += super->numSubFiles();
  5096. else
  5097. ret++;
  5098. }
  5099. }
  5100. else
  5101. ret = subfiles.ordinality();
  5102. return ret;
  5103. }
  5104. virtual bool getFormatCrc(unsigned &crc)
  5105. {
  5106. if (queryAttributes().hasProp("@formatCrc")) {
  5107. crc = (unsigned)queryAttributes().getPropInt("@formatCrc");
  5108. return true;
  5109. }
  5110. bool found = false;
  5111. ForEachItemIn(i,subfiles) {
  5112. unsigned c;
  5113. if (subfiles.item(i).getFormatCrc(c)) {
  5114. if (found&&(c!=crc))
  5115. return false;
  5116. found = true;
  5117. crc = c;
  5118. }
  5119. }
  5120. return found;
  5121. }
  5122. virtual bool getRecordLayout(MemoryBuffer &layout)
  5123. {
  5124. layout.clear();
  5125. if (queryAttributes().getPropBin("_record_layout",layout))
  5126. return true;
  5127. bool found = false;
  5128. ForEachItemIn(i,subfiles) {
  5129. MemoryBuffer b;
  5130. if (subfiles.item(i).getRecordLayout(found?b:layout)) {
  5131. if (found) {
  5132. if ((b.length()!=layout.length())||(memcmp(b.bufferBase(),layout.bufferBase(),b.length())!=0))
  5133. return false;
  5134. }
  5135. else
  5136. found = true;
  5137. }
  5138. }
  5139. return found;
  5140. }
  5141. virtual bool getRecordSize(size32_t &rsz)
  5142. {
  5143. if (queryAttributes().hasProp("@recordSize")) {
  5144. rsz = (size32_t)queryAttributes().getPropInt("@recordSize");
  5145. return true;
  5146. }
  5147. bool found = false;
  5148. ForEachItemIn(i,subfiles) {
  5149. size32_t sz;
  5150. if (subfiles.item(i).getRecordSize(sz)) {
  5151. if (found&&(sz!=rsz))
  5152. return false;
  5153. found = true;
  5154. rsz = sz;
  5155. }
  5156. }
  5157. return found;
  5158. }
  5159. virtual bool isInterleaved()
  5160. {
  5161. return interleaved!=0;
  5162. }
  5163. virtual IDistributedFile *querySubPart(unsigned partidx,unsigned &subfileidx)
  5164. {
  5165. CriticalBlock block (sect);
  5166. subfileidx = 0;
  5167. Owned<IDistributedFilePart> part = getPart(partidx);
  5168. if (!part)
  5169. return NULL;
  5170. CDistributedFilePart *cpart = QUERYINTERFACE(part.get(),CDistributedFilePart);
  5171. if (!cpart)
  5172. return NULL;
  5173. IDistributedFile &ret = cpart->queryParent();
  5174. unsigned n = ret.numParts();
  5175. for (unsigned i=0;i<n;i++) {
  5176. Owned<IDistributedFilePart> spart = ret.getPart(i);
  5177. if (spart.get()==part.get()) {
  5178. subfileidx = i;
  5179. return &ret;
  5180. }
  5181. }
  5182. return NULL;
  5183. }
  5184. virtual unsigned getPositionPart(offset_t pos, offset_t &base)
  5185. { // not very quick!
  5186. CriticalBlock block (sect);
  5187. unsigned n = numParts();
  5188. base = 0;
  5189. for (unsigned i=0;i<n;i++) {
  5190. Owned<IDistributedFilePart> part = getPart(i);
  5191. offset_t ps = part->getFileSize(true,false);
  5192. if (ps==(offset_t)-1)
  5193. break;
  5194. if (ps>pos)
  5195. return i;
  5196. pos -= ps;
  5197. base += ps;
  5198. }
  5199. return NotFound;
  5200. }
  5201. IDistributedFileIterator *getSubFileIterator(bool supersub=false)
  5202. {
  5203. CriticalBlock block (sect);
  5204. return new cSubFileIterator(subfiles,supersub);
  5205. }
  5206. void updateFileAttrs()
  5207. {
  5208. if (subfiles.ordinality()==0) {
  5209. StringBuffer desc;
  5210. root->getProp("Attr/@description",desc);
  5211. root->removeProp("Attr"); // remove all other attributes if superfile empty
  5212. IPropertyTree *t=resetFileAttr(getEmptyAttr());
  5213. if (desc.length())
  5214. t->setProp("@description",desc.str());
  5215. return;
  5216. }
  5217. root->removeProp("Attr/@size");
  5218. root->removeProp("Attr/@compressedSize");
  5219. root->removeProp("Attr/@checkSum");
  5220. root->removeProp("Attr/@recordCount"); // recordCount not currently supported by superfiles
  5221. root->removeProp("Attr/@formatCrc"); // formatCrc set if all consistant
  5222. root->removeProp("Attr/@recordSize"); // record size set if all consistant
  5223. root->removeProp("Attr/_record_layout");
  5224. __int64 fs = getFileSize(false,false);
  5225. if (fs!=-1)
  5226. root->setPropInt64("Attr/@size",fs);
  5227. if (isCompressed(NULL))
  5228. {
  5229. fs = getDiskSize(false,false);
  5230. if (fs!=-1)
  5231. root->setPropInt64("Attr/@compressedSize",fs);
  5232. }
  5233. unsigned checkSum;
  5234. if (getFileCheckSum(checkSum))
  5235. root->setPropInt64("Attr/@checkSum", checkSum);
  5236. __int64 rc = getRecordCount();
  5237. if (rc!=-1)
  5238. root->setPropInt64("Attr/@recordCount",rc);
  5239. unsigned fcrc;
  5240. if (getFormatCrc(fcrc))
  5241. root->setPropInt("Attr/@formatCrc", fcrc);
  5242. size32_t rsz;
  5243. if (getRecordSize(rsz))
  5244. root->setPropInt("Attr/@recordSize", rsz);
  5245. MemoryBuffer mb;
  5246. if (getRecordLayout(mb))
  5247. root->setPropBin("Attr/_record_layout", mb.length(), mb.bufferBase());
  5248. }
  5249. void updateParentFileAttrs(IDistributedFileTransaction *transaction)
  5250. {
  5251. Owned<IPropertyTreeIterator> iter = root->getElements("SuperOwner");
  5252. StringBuffer pname;
  5253. ForEach(*iter) {
  5254. iter->query().getProp("@name",pname.clear());
  5255. Owned<IDistributedSuperFile> psfile = transaction?transaction->lookupSuperFile(pname.str()):
  5256. queryDistributedFileDirectory().lookupSuperFile(pname.str(),udesc,NULL);
  5257. CDistributedSuperFile *file = QUERYINTERFACE(psfile.get(),CDistributedSuperFile);
  5258. if (file) {
  5259. {
  5260. DistributedFilePropertyLock lock(file);
  5261. file->setModified();
  5262. file->updateFileAttrs();
  5263. }
  5264. file->updateParentFileAttrs(transaction);
  5265. }
  5266. }
  5267. }
  5268. void validateAddSubFile(IDistributedFile *sub)
  5269. {
  5270. if (strcmp(sub->queryLogicalName(),queryLogicalName())==0)
  5271. throw MakeStringException(-1,"addSubFile: Cannot add file %s to itself", queryLogicalName());
  5272. if (subfiles.ordinality())
  5273. checkFormatAttr(sub,"addSubFile");
  5274. if (NotFound!=findSubFile(sub->queryLogicalName()))
  5275. throw MakeStringException(-1,"addSubFile: File %s is already a subfile of %s", sub->queryLogicalName(),queryLogicalName());
  5276. }
  5277. private:
  5278. void doAddSubFile(IDistributedFile *_sub,bool before,const char *other,IDistributedFileTransactionExt *transaction) // takes ownership of sub
  5279. {
  5280. Owned<IDistributedFile> sub = _sub;
  5281. validateAddSubFile(sub); // shouldn't really be necessary, was validated in transaction before here
  5282. unsigned pos;
  5283. if (other&&*other) {
  5284. pos = findSubFileOrd(other);
  5285. if (pos==NotFound)
  5286. pos = findSubFile(other);
  5287. if (pos==NotFound)
  5288. pos = before?0:subfiles.ordinality();
  5289. else if (!before&&(pos<subfiles.ordinality()))
  5290. pos++;
  5291. }
  5292. else
  5293. pos = before?0:subfiles.ordinality();
  5294. if (pos > subfiles.ordinality())
  5295. throw MakeStringException(-1,"addSubFile: Insert position %d out of range for file %s in superfile %s", pos+1, sub->queryLogicalName(), queryLogicalName());
  5296. addItem(pos,sub.getClear()); // remove if failure TBD?
  5297. setModified();
  5298. updateFileAttrs();
  5299. linkSubFile(pos, transaction);
  5300. }
  5301. bool doRemoveSubFiles(IDistributedFileTransactionExt *transaction)
  5302. {
  5303. // have to be quite careful here
  5304. unsigned pos = subfiles.ordinality();
  5305. if (pos)
  5306. {
  5307. DistributedFilePropertyLock lock(this);
  5308. if (lock.needsReload())
  5309. loadSubFiles(transaction,1000*60*10);
  5310. pos = subfiles.ordinality();
  5311. if (pos)
  5312. {
  5313. do
  5314. {
  5315. pos--;
  5316. unlinkSubFile(pos,transaction);
  5317. removeItem(pos);
  5318. } while (pos);
  5319. setModified();
  5320. updateFileAttrs();
  5321. lock.unlock();
  5322. updateParentFileAttrs(transaction);
  5323. }
  5324. }
  5325. return true;
  5326. }
  5327. bool doRemoveSubFile(const char *subfile,
  5328. IDistributedFileTransactionExt *transaction)
  5329. {
  5330. // have to be quite careful here
  5331. unsigned pos=findSubFileOrd(subfile);
  5332. if ((pos==NotFound)||(pos>=subfiles.ordinality()))
  5333. pos = findSubFile(subfile);
  5334. if (pos==NotFound)
  5335. return false;
  5336. {
  5337. DistributedFilePropertyLock lock(this);
  5338. // don't reload subfiles here
  5339. pos=findSubFileOrd(subfile);
  5340. if ((pos==NotFound)||(pos>=subfiles.ordinality()))
  5341. pos = findSubFile(subfile);
  5342. if (pos==NotFound)
  5343. return false;
  5344. unlinkSubFile(pos,transaction);
  5345. removeItem(pos);
  5346. setModified();
  5347. updateFileAttrs();
  5348. }
  5349. updateParentFileAttrs(transaction);
  5350. return true;
  5351. }
  5352. bool doSwapSuperFile(IDistributedSuperFile *_file,
  5353. IDistributedFileTransactionExt *transaction)
  5354. {
  5355. assertex(transaction);
  5356. CDistributedSuperFile *file = QUERYINTERFACE(_file,CDistributedSuperFile);
  5357. if (!file)
  5358. return false;
  5359. // Cache names (so we can delete without problems)
  5360. StringArray subnames1;
  5361. StringArray subnames2;
  5362. for (unsigned i=0; i<this->numSubFiles(false); i++)
  5363. subnames1.append(querySubFile(i, false).queryLogicalName());
  5364. for (unsigned i=0; i<file->numSubFiles(false); i++)
  5365. subnames2.append(file->querySubFile(i, false).queryLogicalName());
  5366. // Delete all files
  5367. ForEachItemIn(d1,subnames1) {
  5368. Owned<IDistributedFile> sub = transaction->lookupFile(subnames1.item(d1));
  5369. if (!doRemoveSubFile(sub->queryLogicalName(), transaction))
  5370. return false;
  5371. }
  5372. ForEachItemIn(d2,subnames2) {
  5373. Owned<IDistributedFile> sub = transaction->lookupFile(subnames2.item(d2));
  5374. if (!file->doRemoveSubFile(sub->queryLogicalName(), transaction))
  5375. return false;
  5376. }
  5377. // Add files swapped
  5378. ForEachItemIn(a1,subnames1) {
  5379. Owned<IDistributedFile> sub = transaction->lookupFile(subnames1.item(a1));
  5380. file->doAddSubFile(LINK(sub), false, NULL, transaction);
  5381. }
  5382. ForEachItemIn(a2,subnames2) {
  5383. Owned<IDistributedFile> sub = transaction->lookupFile(subnames2.item(a2));
  5384. doAddSubFile(LINK(sub), false, NULL, transaction);
  5385. }
  5386. return true;
  5387. }
  5388. public:
  5389. void addSubFile(const char * subfile,
  5390. bool before=false, // if true before other
  5391. const char *other=NULL, // in NULL add at end (before=false) or start(before=true)
  5392. bool addcontents=false,
  5393. IDistributedFileTransaction *transaction=NULL
  5394. )
  5395. {
  5396. CriticalBlock block (sect);
  5397. if (!subfile||!*subfile)
  5398. return;
  5399. checkModify("addSubFile");
  5400. partscache.kill();
  5401. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  5402. Linked<IDistributedFileTransactionExt> localtrans;
  5403. if (transaction)
  5404. {
  5405. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  5406. localtrans.set(_transaction);
  5407. }
  5408. else
  5409. localtrans.setown(new CDistributedFileTransaction(udesc, this));
  5410. localtrans->ensureFile(this);
  5411. if (addcontents)
  5412. {
  5413. localtrans->descend();
  5414. StringArray subs;
  5415. Owned<IDistributedSuperFile> sfile = localtrans->lookupSuperFile(subfile);
  5416. if (sfile)
  5417. {
  5418. Owned<IDistributedFileIterator> iter = sfile->getSubFileIterator();
  5419. ForEach(*iter)
  5420. subs.append(iter->query().queryLogicalName());
  5421. }
  5422. sfile.clear();
  5423. ForEachItemIn(i,subs)
  5424. addSubFile(subs.item(i),before,other,false,localtrans);
  5425. localtrans->ascend();
  5426. }
  5427. else
  5428. {
  5429. cAddSubFileAction *action = new cAddSubFileAction(queryLogicalName(),subfile,before,other);
  5430. localtrans->addAction(action); // takes ownership
  5431. }
  5432. localtrans->autoCommit();
  5433. }
  5434. virtual bool removeSubFile(const char *subfile, // if NULL removes all
  5435. bool remsub, // if true removes subfiles from DFS
  5436. bool remcontents, // if true, recurse super-files
  5437. IDistributedFileTransaction *transaction)
  5438. {
  5439. CriticalBlock block (sect);
  5440. if (subfile&&!*subfile)
  5441. return false;
  5442. checkModify("removeSubFile");
  5443. partscache.kill();
  5444. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  5445. Linked<IDistributedFileTransactionExt> localtrans;
  5446. if (transaction)
  5447. {
  5448. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  5449. localtrans.set(_transaction);
  5450. }
  5451. else
  5452. localtrans.setown(new CDistributedFileTransaction(udesc, this));
  5453. // Make sure this file is in cache (reuse below)
  5454. localtrans->ensureFile(this);
  5455. // If recurring, traverse super-file subs (if super)
  5456. if (remcontents)
  5457. {
  5458. localtrans->descend();
  5459. CDfsLogicalFileName logicalname;
  5460. logicalname.set(subfile);
  5461. IDistributedFile *sub = querySubFileNamed(logicalname.get(),false);
  5462. if (!sub)
  5463. return false;
  5464. IDistributedSuperFile *sfile = sub->querySuperFile();
  5465. if (sfile)
  5466. {
  5467. Owned<IDistributedFileIterator> iter = sfile->getSubFileIterator(true);
  5468. bool ret = true;
  5469. StringArray toremove;
  5470. ForEach(*iter)
  5471. toremove.append(iter->query().queryLogicalName());
  5472. iter.clear();
  5473. ForEachItemIn(i,toremove)
  5474. {
  5475. if (!sfile->removeSubFile(toremove.item(i),remsub,false,localtrans))
  5476. ret = false;
  5477. }
  5478. if (!ret||!remsub)
  5479. return ret;
  5480. }
  5481. localtrans->ascend();
  5482. }
  5483. cRemoveSubFileAction *action = new cRemoveSubFileAction(queryLogicalName(),subfile,remsub);
  5484. localtrans->addAction(action); // takes ownership
  5485. localtrans->autoCommit();
  5486. // MORE - auto-commit will throw an exception, change this to void
  5487. return true;
  5488. }
  5489. virtual bool removeOwnedSubFiles(bool remsub, // if true removes subfiles from DFS
  5490. IDistributedFileTransaction *transaction)
  5491. {
  5492. CriticalBlock block (sect);
  5493. checkModify("removeOwnedSubFiles");
  5494. partscache.kill();
  5495. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  5496. Linked<IDistributedFileTransactionExt> localtrans;
  5497. if (transaction)
  5498. {
  5499. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  5500. localtrans.set(_transaction);
  5501. }
  5502. else
  5503. localtrans.setown(new CDistributedFileTransaction(udesc, this));
  5504. // Make sure this file is in cache (reuse below)
  5505. localtrans->addFile(this);
  5506. cRemoveOwnedSubFilesAction *action = new cRemoveOwnedSubFilesAction(localtrans, queryLogicalName(), remsub);
  5507. localtrans->addAction(action); // takes ownership
  5508. localtrans->autoCommit();
  5509. // MORE - auto-commit will throw an exception, change this to void
  5510. return true;
  5511. }
  5512. virtual bool swapSuperFile( IDistributedSuperFile *_file,
  5513. IDistributedFileTransaction *transaction)
  5514. {
  5515. CriticalBlock block (sect);
  5516. if (!_file)
  5517. return false;
  5518. checkModify("swapSuperFile");
  5519. partscache.kill();
  5520. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  5521. Linked<IDistributedFileTransactionExt> localtrans;
  5522. if (transaction)
  5523. {
  5524. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  5525. localtrans.set(_transaction);
  5526. }
  5527. else
  5528. localtrans.setown(new CDistributedFileTransaction(udesc, this));
  5529. // Make sure this file is in cache
  5530. localtrans->ensureFile(this);
  5531. cSwapFileAction *action = new cSwapFileAction(queryLogicalName(),_file->queryLogicalName());
  5532. localtrans->addAction(action); // takes ownership
  5533. localtrans->autoCommit();
  5534. return true;
  5535. }
  5536. void savePartsAttr(bool force)
  5537. {
  5538. }
  5539. void fillClustersCache()
  5540. {
  5541. if (clusterscache.ordinality()==0) {
  5542. StringBuffer name;
  5543. ForEachItemIn(i,subfiles) {
  5544. StringArray clusters;
  5545. IDistributedFile &f=subfiles.item(i);
  5546. unsigned nc = f.numClusters();
  5547. for(unsigned j=0;j<nc;j++) {
  5548. f.getClusterName(j,name.clear());
  5549. if (clusterscache.find(name.str())==NotFound) {
  5550. IClusterInfo &cluster = *createClusterInfo(name.str(),f.queryClusterGroup(j),f.queryPartDiskMapping(j),&queryNamedGroupStore());
  5551. clusterscache.append(cluster);
  5552. }
  5553. }
  5554. }
  5555. }
  5556. }
  5557. unsigned getClusterNames(StringArray &clusters)
  5558. {
  5559. CriticalBlock block (sect);
  5560. fillClustersCache();
  5561. return clusterscache.getNames(clusters);
  5562. }
  5563. unsigned numClusters()
  5564. {
  5565. CriticalBlock block (sect);
  5566. fillClustersCache();
  5567. return clusterscache.ordinality();
  5568. }
  5569. unsigned findCluster(const char *clustername)
  5570. {
  5571. CriticalBlock block (sect);
  5572. fillClustersCache();
  5573. return clusterscache.find(clustername);
  5574. }
  5575. ClusterPartDiskMapSpec &queryPartDiskMapping(unsigned clusternum)
  5576. {
  5577. CriticalBlock block (sect);
  5578. fillClustersCache();
  5579. return clusterscache.queryPartDiskMapping(clusternum);
  5580. }
  5581. void updatePartDiskMapping(const char *clustername,const ClusterPartDiskMapSpec &spec)
  5582. {
  5583. if (!clustername||!*clustername)
  5584. return;
  5585. CriticalBlock block (sect);
  5586. fillClustersCache();
  5587. ForEachItemIn(i,subfiles) {
  5588. IDistributedFile &f=subfiles.item(i);
  5589. f.updatePartDiskMapping(clustername,spec);
  5590. }
  5591. }
  5592. IGroup *queryClusterGroup(unsigned clusternum)
  5593. {
  5594. CriticalBlock block (sect);
  5595. fillClustersCache();
  5596. return clusterscache.queryGroup(clusternum);
  5597. }
  5598. void addCluster(const char *clustername,const ClusterPartDiskMapSpec &mspec)
  5599. {
  5600. if (!clustername||!*clustername)
  5601. return;
  5602. CriticalBlock block (sect);
  5603. clusterscache.clear();
  5604. subfiles.item(0).addCluster(clustername,mspec);
  5605. }
  5606. virtual bool removeCluster(const char *clustername)
  5607. {
  5608. bool clusterRemoved=false;
  5609. CriticalBlock block (sect);
  5610. clusterscache.clear();
  5611. ForEachItemIn(i,subfiles) {
  5612. IDistributedFile &f=subfiles.item(i);
  5613. clusterRemoved |= f.removeCluster(clustername);
  5614. }
  5615. return clusterRemoved;
  5616. }
  5617. void setPreferredClusters(const char *clusters)
  5618. {
  5619. CriticalBlock block (sect);
  5620. clusterscache.clear();
  5621. ForEachItemIn(i,subfiles) {
  5622. IDistributedFile &f=subfiles.item(i);
  5623. f.setPreferredClusters(clusters);
  5624. }
  5625. }
  5626. virtual bool checkClusterCompatible(IFileDescriptor &fdesc, StringBuffer &err)
  5627. {
  5628. CriticalBlock block (sect);
  5629. if (subfiles.ordinality()!=1) {
  5630. err.append("only singleton superfiles allowed");
  5631. return false;
  5632. }
  5633. ForEachItemIn(i,subfiles) {
  5634. IDistributedFile &f=subfiles.item(i);
  5635. if (!f.checkClusterCompatible(fdesc,err))
  5636. return false;
  5637. }
  5638. return true;
  5639. }
  5640. void setSingleClusterOnly()
  5641. {
  5642. CriticalBlock block (sect);
  5643. ForEachItemIn(i,subfiles) {
  5644. IDistributedFile &f=subfiles.item(i);
  5645. f.setSingleClusterOnly();
  5646. }
  5647. }
  5648. void enqueueReplicate()
  5649. {
  5650. CriticalBlock block (sect);
  5651. ForEachItemIn(i,subfiles) {
  5652. IDistributedFile &f=subfiles.item(i);
  5653. f.enqueueReplicate();
  5654. }
  5655. }
  5656. bool getAccessedTime(CDateTime &dt)
  5657. {
  5658. bool set=false;
  5659. CriticalBlock block (sect);
  5660. ForEachItemIn(i,subfiles) {
  5661. IDistributedFile &f=subfiles.item(i);
  5662. if (set)
  5663. set = f.getAccessedTime(dt);
  5664. else {
  5665. CDateTime cmp;
  5666. if (f.getAccessedTime(cmp)) {
  5667. if (cmp.compare(dt)>0)
  5668. dt.set(cmp);
  5669. }
  5670. }
  5671. }
  5672. return false;
  5673. }
  5674. void setAccessedTime(const CDateTime &dt)
  5675. {
  5676. {
  5677. CriticalBlock block (sect);
  5678. ForEachItemIn(i,subfiles) {
  5679. IDistributedFile &f=subfiles.item(i);
  5680. f.setAccessedTime(dt);
  5681. }
  5682. }
  5683. }
  5684. };
  5685. // --------------------------------------------------------
  5686. void CDistributedFileTransaction::validateAddSubFile(IDistributedSuperFile *super, IDistributedFile *sub, const char *subName)
  5687. {
  5688. CTransactionFile *trackedSuper = lookupTrackedFile(super);
  5689. if (!trackedSuper)
  5690. return;
  5691. const char *superName = trackedSuper->queryName();
  5692. if (strcmp(subName, superName)==0)
  5693. throw MakeStringException(-1,"addSubFile: Cannot add file %s to itself", superName);
  5694. if (trackedSuper->numSubFiles())
  5695. {
  5696. CDistributedSuperFile *sf = dynamic_cast<CDistributedSuperFile *>(super);
  5697. sf->checkFormatAttr(sub, "addSubFile");
  5698. if (trackedSuper->find(subName, false))
  5699. throw MakeStringException(-1,"addSubFile: File %s is already a subfile of %s", subName, superName);
  5700. }
  5701. }
  5702. // --------------------------------------------------------
  5703. CDistributedFilePart::CDistributedFilePart(CDistributedFile &_parent,unsigned _part,IPartDescriptor *pd)
  5704. : parent(_parent)
  5705. {
  5706. partIndex = _part;
  5707. dirty = false;
  5708. if (pd) {
  5709. if (pd->isMulti())
  5710. ERRLOG("Multi filenames not supported in Dali DFS Part %d of %s",_part+1,_parent.queryLogicalName());
  5711. overridename.set(pd->queryOverrideName());
  5712. setAttr(*pd->getProperties());
  5713. }
  5714. else
  5715. ERRLOG("CDistributedFilePart::CDistributedFilePart no IPartDescriptor for part");
  5716. }
  5717. void CDistributedFilePart::Link(void) const
  5718. {
  5719. parent.Link();
  5720. CInterface::Link();
  5721. }
  5722. bool CDistributedFilePart::Release(void) const
  5723. {
  5724. parent.Release();
  5725. return CInterface::Release();
  5726. }
  5727. offset_t CDistributedFilePart::getSize(bool checkCompressed)
  5728. {
  5729. offset_t ret = (offset_t)-1;
  5730. StringBuffer firstname;
  5731. bool compressed = ::isCompressed(parent.queryAttributes());
  5732. unsigned nc=parent.numCopies(partIndex);
  5733. for (unsigned copy=0;copy<nc;copy++)
  5734. {
  5735. RemoteFilename rfn;
  5736. try
  5737. {
  5738. Owned<IFile> partfile = createIFile(getFilename(rfn,copy));
  5739. if (checkCompressed && compressed)
  5740. {
  5741. Owned<ICompressedFileIO> compressedIO = createCompressedFileReader(partfile);
  5742. if (compressedIO)
  5743. ret = compressedIO->size();
  5744. }
  5745. else
  5746. ret = partfile->size();
  5747. if (ret!=(offset_t)-1)
  5748. return ret;
  5749. }
  5750. catch (IException *e)
  5751. {
  5752. StringBuffer s("CDistributedFilePart::getSize ");
  5753. rfn.getRemotePath(s);
  5754. EXCLOG(e, s.str());
  5755. e->Release();
  5756. }
  5757. if (copy==0)
  5758. rfn.getRemotePath(firstname);
  5759. }
  5760. throw new CDFS_Exception(DFSERR_CannotFindPartFileSize,firstname.str());;
  5761. }
  5762. StringBuffer & CDistributedFilePart::getPartName(StringBuffer &partname)
  5763. {
  5764. if (!overridename.isEmpty()) {
  5765. if (isSpecialPath(overridename)) {
  5766. // bit of a kludge
  5767. if (isPathSepChar(*overridename)&&partname.length()&&isPathSepChar(partname.charAt(partname.length()-1)))
  5768. partname.setLength(partname.length()-1);
  5769. return partname.append(overridename);
  5770. }
  5771. return partname.append(pathTail(overridename));
  5772. }
  5773. const char *mask=parent.queryPartMask();
  5774. if (!mask||!*mask) {
  5775. const char *err ="CDistributedFilePart::getPartName cannot determine part name (no mask)";
  5776. ERRLOG("%s", err);
  5777. throw MakeStringExceptionDirect(-1, err);
  5778. }
  5779. expandMask(partname,mask,partIndex,parent.numParts());
  5780. return partname;
  5781. }
  5782. unsigned CDistributedFilePart::bestCopyNum(const IpAddress &ip,unsigned rel)
  5783. {
  5784. unsigned n = numCopies();
  5785. unsigned *dist = new unsigned[n];
  5786. unsigned *idx = new unsigned[n];
  5787. for (unsigned c=0;c<n;c++) {
  5788. dist[c] = ip.ipdistance(queryNode(c)->endpoint());
  5789. idx[c] = c;
  5790. }
  5791. if (rel>=n)
  5792. rel = n-1;
  5793. // do bubble sort as not that many!
  5794. for (unsigned i=0; i<n-1; i++)
  5795. for (unsigned j=0; j<n-1-i; j++)
  5796. if (dist[idx[j+1]] < dist[idx[j]]) {
  5797. unsigned t = idx[j];
  5798. idx[j] = idx[j+1];
  5799. idx[j+1] = t;
  5800. }
  5801. unsigned ret = idx[rel];
  5802. delete [] idx;
  5803. delete [] dist;
  5804. return ret;
  5805. }
  5806. unsigned CDistributedFilePart::copyClusterNum(unsigned copy,unsigned *replicate)
  5807. {
  5808. return parent.copyClusterNum(partIndex,copy,replicate);
  5809. }
  5810. StringBuffer &CDistributedFilePart::getPartDirectory(StringBuffer &ret,unsigned copy)
  5811. {
  5812. const char *defdir = parent.queryDefaultDir();
  5813. StringBuffer dir;
  5814. const char *pn;
  5815. if (overridename.isEmpty())
  5816. pn = parent.queryPartMask();
  5817. else {
  5818. pn = overridename.get();
  5819. if (isSpecialPath(pn)) // its a query
  5820. return ret; // ret.append('/'); // not sure if really need '/' here
  5821. }
  5822. if (pn&&*pn) {
  5823. StringBuffer odir;
  5824. splitDirTail(pn,odir);
  5825. if (odir.length()) {
  5826. if (isAbsolutePath(pn))
  5827. dir.append(odir);
  5828. else if (defdir&&*defdir)
  5829. addPathSepChar(dir.append(defdir)).append(odir);
  5830. }
  5831. else
  5832. dir.append(defdir);
  5833. }
  5834. if (dir.length()==0)
  5835. ERRLOG("IDistributedFilePart::getPartDirectory unable to determine part directory");
  5836. else {
  5837. parent.adjustClusterDir(partIndex,copy,dir);
  5838. ret.append(dir);
  5839. }
  5840. return ret;
  5841. }
  5842. unsigned CDistributedFilePart::numCopies()
  5843. {
  5844. return parent.numCopies(partIndex);
  5845. }
  5846. INode *CDistributedFilePart::queryNode(unsigned copy)
  5847. {
  5848. return parent.queryNode(partIndex,copy);
  5849. }
  5850. unsigned CDistributedFilePart::queryDrive(unsigned copy)
  5851. {
  5852. return parent.queryDrive(partIndex,copy,parent.directory);
  5853. }
  5854. bool CDistributedFilePart::isHost(unsigned copy)
  5855. {
  5856. return (queryNode(copy)->isHost());
  5857. }
  5858. IPropertyTree &CDistributedFilePart::queryAttributes()
  5859. {
  5860. CriticalBlock block (sect); // avoid nested blocks
  5861. if (attr)
  5862. return *attr;
  5863. WARNLOG("CDistributedFilePart::queryAttributes missing part attributes");
  5864. attr.setown(getEmptyAttr());
  5865. return *attr;
  5866. }
  5867. RemoteFilename &CDistributedFilePart::getFilename(RemoteFilename &ret,unsigned copy)
  5868. {
  5869. // this is probably not as efficient as could be
  5870. StringBuffer fullpath;
  5871. getPartDirectory(fullpath,copy);
  5872. addPathSepChar(fullpath);
  5873. getPartName(fullpath);
  5874. SocketEndpoint ep;
  5875. INode *node=queryNode(copy);
  5876. if (node)
  5877. ep = node->endpoint();
  5878. ret.setPath(ep,fullpath.str());
  5879. return ret;
  5880. }
  5881. bool CDistributedFilePart::getCrc(unsigned &crc)
  5882. {
  5883. return getCrcFromPartProps(parent.queryAttributes(),queryAttributes(), crc);
  5884. }
  5885. unsigned CDistributedFilePart::getPhysicalCrc()
  5886. {
  5887. StringBuffer firstname;
  5888. unsigned nc=parent.numCopies(partIndex);
  5889. for (unsigned copy=0;copy<nc;copy++) {
  5890. RemoteFilename rfn;
  5891. try {
  5892. Owned<IFile> partfile = createIFile(getFilename(rfn,copy));
  5893. if (partfile&&partfile->exists())
  5894. return partfile->getCRC();
  5895. }
  5896. catch (IException *e)
  5897. {
  5898. StringBuffer s("CDistributedFilePart::getPhysicalCrc ");
  5899. rfn.getRemotePath(s);
  5900. EXCLOG(e, s.str());
  5901. e->Release();
  5902. }
  5903. if (copy==0)
  5904. rfn.getRemotePath(firstname);
  5905. }
  5906. IDFS_Exception *e = new CDFS_Exception(DFSERR_CannotFindPartFileCrc,firstname.str());
  5907. throw e;
  5908. }
  5909. // TODO: Create DistributedFilePropertyLock for parts
  5910. bool CDistributedFilePart::lockProperties(unsigned timeoutms)
  5911. {
  5912. dirty = true;
  5913. return parent.lockProperties(timeoutms);
  5914. }
  5915. // TODO: Create DistributedFilePropertyLock for parts
  5916. void CDistributedFilePart::unlockProperties(DFTransactionState state=TAS_NONE)
  5917. {
  5918. parent.unlockProperties(state);
  5919. }
  5920. offset_t CDistributedFilePart::getFileSize(bool allowphysical,bool forcephysical)
  5921. {
  5922. offset_t ret = (offset_t)((forcephysical&&allowphysical)?-1:queryAttributes().getPropInt64("@size", -1));
  5923. if (allowphysical&&(ret==(offset_t)-1))
  5924. ret = getSize(true);
  5925. return ret;
  5926. }
  5927. offset_t CDistributedFilePart::getDiskSize(bool allowphysical,bool forcephysical)
  5928. {
  5929. if (!::isCompressed(parent.queryAttributes()))
  5930. return getFileSize(allowphysical, forcephysical);
  5931. if (forcephysical && allowphysical)
  5932. return getSize(false); // i.e. only if force, because all compressed should have @compressedSize attribute
  5933. // NB: compressSize is disk size
  5934. return queryAttributes().getPropInt64("@compressedSize", -1);
  5935. }
  5936. bool CDistributedFilePart::getModifiedTime(bool allowphysical,bool forcephysical, CDateTime &dt)
  5937. {
  5938. StringBuffer s;
  5939. if (!forcephysical&&queryAttributes().getProp("@modified", s)) {
  5940. dt.setString(s.str());
  5941. if (!dt.isNull())
  5942. return true;
  5943. }
  5944. if (allowphysical) {
  5945. unsigned nc=parent.numCopies(partIndex);
  5946. for (unsigned copy=0;copy<nc;copy++) {
  5947. RemoteFilename rfn;
  5948. try {
  5949. Owned<IFile> partfile = createIFile(getFilename(rfn,copy));
  5950. if (partfile->getTime(NULL,&dt,NULL))
  5951. return true;
  5952. }
  5953. catch (IException *e)
  5954. {
  5955. StringBuffer s("CDistributedFilePart::getFileTime ");
  5956. rfn.getRemotePath(s);
  5957. EXCLOG(e, s.str());
  5958. e->Release();
  5959. }
  5960. }
  5961. }
  5962. return false;
  5963. }
  5964. // --------------------------------------------------------
  5965. class CNamedGroupIterator: public CInterface, implements INamedGroupIterator
  5966. {
  5967. Owned<IPropertyTreeIterator> pe;
  5968. Linked<IRemoteConnection> conn;
  5969. Linked<IGroup> matchgroup;
  5970. bool exactmatch;
  5971. bool match();
  5972. public:
  5973. IMPLEMENT_IINTERFACE;
  5974. CNamedGroupIterator(IRemoteConnection *_conn,IGroup *_matchgroup=NULL,bool _exactmatch=false)
  5975. : conn(_conn), matchgroup(_matchgroup)
  5976. {
  5977. exactmatch = _exactmatch;
  5978. if (matchgroup.get()) {
  5979. StringBuffer query;
  5980. query.append("Group[Node/@ip=\"");
  5981. matchgroup->queryNode(0).endpoint().getUrlStr(query);
  5982. query.append("\"]");
  5983. pe.setown(conn->getElements(query.str()));
  5984. }
  5985. else
  5986. pe.setown(conn->queryRoot()->getElements("Group"));
  5987. }
  5988. bool first()
  5989. {
  5990. if (!pe->first())
  5991. return false;
  5992. if (match())
  5993. return true;
  5994. return next();
  5995. }
  5996. bool next()
  5997. {
  5998. while (pe->next())
  5999. if (match())
  6000. return true;
  6001. return false;
  6002. }
  6003. bool isValid()
  6004. {
  6005. return pe->isValid();
  6006. }
  6007. StringBuffer &get(StringBuffer &name)
  6008. {
  6009. pe->query().getProp("@name",name);
  6010. return name;
  6011. }
  6012. StringBuffer &getdir(StringBuffer &dir)
  6013. {
  6014. pe->query().getProp("@dir",dir);
  6015. return dir;
  6016. }
  6017. bool isCluster()
  6018. {
  6019. return pe->query().getPropBool("@cluster");
  6020. }
  6021. };
  6022. // --------------------------------------------------------
  6023. #define GROUP_CACHE_INTERVAL (1000*60)
  6024. #define GROUP_EXCEPTION_CACHE_INTERVAL (1000*60*10)
  6025. static GroupType translateGroupType(const char *groupType)
  6026. {
  6027. if (!groupType)
  6028. return grp_unknown;
  6029. if (strieq(groupType, "Thor"))
  6030. return grp_thor;
  6031. else if (strieq(groupType, "Roxie"))
  6032. return grp_roxie;
  6033. else if (strieq(groupType, "hthor"))
  6034. return grp_hthor;
  6035. else
  6036. return grp_unknown;
  6037. }
  6038. class CNamedGroupCacheEntry: public CInterface
  6039. {
  6040. public:
  6041. Linked<IGroup> group;
  6042. StringAttr name;
  6043. StringAttr groupDir;
  6044. GroupType groupType;
  6045. Linked<IException> exception;
  6046. CNamedGroupCacheEntry(IGroup *_group, const char *_name, const char *_dir, GroupType _groupType)
  6047. : group(_group), name(_name), groupDir(_dir), groupType(_groupType)
  6048. {
  6049. cachedtime = msTick();
  6050. }
  6051. CNamedGroupCacheEntry(IException *_exception, const char *_name)
  6052. : exception(_exception), name(_name), groupType(grp_unknown)
  6053. {
  6054. cachedtime = msTick();
  6055. }
  6056. bool expired(unsigned timeNow)
  6057. {
  6058. if (exception)
  6059. return timeNow-cachedtime > GROUP_EXCEPTION_CACHE_INTERVAL;
  6060. else
  6061. return timeNow-cachedtime > GROUP_CACHE_INTERVAL;
  6062. }
  6063. protected:
  6064. unsigned cachedtime;
  6065. };
  6066. class CNamedGroupStore: public CInterface, implements INamedGroupStore
  6067. {
  6068. CriticalSection cachesect;
  6069. CIArrayOf<CNamedGroupCacheEntry> cache;
  6070. unsigned defaultTimeout;
  6071. unsigned defaultRemoteTimeout;
  6072. public:
  6073. IMPLEMENT_IINTERFACE;
  6074. CNamedGroupStore()
  6075. {
  6076. defaultTimeout = INFINITE;
  6077. defaultRemoteTimeout = FOREIGN_DALI_TIMEOUT;
  6078. }
  6079. IGroup *dolookup(const char *logicalgroupname,IRemoteConnection *conn, StringBuffer *dirret, GroupType &groupType)
  6080. {
  6081. SocketEndpointArray epa;
  6082. StringBuffer gname(logicalgroupname);
  6083. gname.trim();
  6084. if (!gname.length())
  6085. return NULL;
  6086. gname.toLowerCase();
  6087. logicalgroupname = gname.str();
  6088. bool isiprange = (*logicalgroupname!=0);
  6089. for (const char *s1=logicalgroupname;*s1;s1++)
  6090. if (isalpha(*s1)) {
  6091. isiprange = false;
  6092. break;
  6093. }
  6094. if (isiprange) {
  6095. // allow IP or IP list instead of group name
  6096. // I don't think this is a security problem as groups not checked
  6097. // NB ports not allowed here
  6098. char *buf = strdup(logicalgroupname);
  6099. char *s = buf;
  6100. while (*s) {
  6101. char *next = strchr(s,',');
  6102. if (next)
  6103. *next = 0;
  6104. SocketEndpoint ep;
  6105. unsigned n = ep.ipsetrange(s);
  6106. for (unsigned i=0;i<n;i++) {
  6107. if (ep.isNull()) { // failed
  6108. epa.kill();
  6109. break;
  6110. }
  6111. epa.append(ep);
  6112. ep.ipincrement(1);
  6113. }
  6114. if (!next)
  6115. break;
  6116. s = next+1;
  6117. }
  6118. free(buf);
  6119. if (epa.ordinality())
  6120. {
  6121. groupType = grp_unknown;
  6122. return createIGroup(epa);
  6123. }
  6124. }
  6125. StringBuffer range;
  6126. StringBuffer parent;
  6127. if (decodeChildGroupName(gname.str(),parent,range)) {
  6128. gname.clear().append(parent);
  6129. logicalgroupname = gname.str();
  6130. }
  6131. StringAttr groupdir;
  6132. GroupType type;
  6133. bool cached = false;
  6134. unsigned timeNow = msTick();
  6135. {
  6136. CriticalBlock block(cachesect);
  6137. ForEachItemInRev(idx, cache)
  6138. {
  6139. CNamedGroupCacheEntry &entry = cache.item(idx);
  6140. if (entry.expired(timeNow))
  6141. {
  6142. cache.remove(idx);
  6143. }
  6144. else if (strcmp(gname.str(),entry.name.get())==0)
  6145. {
  6146. cached = true;
  6147. if (entry.exception)
  6148. throw LINK(entry.exception);
  6149. if (range.length()==0)
  6150. {
  6151. if (dirret)
  6152. dirret->append(entry.groupDir);
  6153. groupType = entry.groupType;
  6154. return entry.group.getLink();
  6155. }
  6156. // there is a range so copy to epa
  6157. entry.group->getSocketEndpoints(epa);
  6158. groupdir.set(entry.groupDir);
  6159. type = entry.groupType;
  6160. break;
  6161. }
  6162. }
  6163. }
  6164. try
  6165. {
  6166. if ((gname.length()>9)&&(memcmp(logicalgroupname,"foreign::",9)==0))
  6167. {
  6168. StringBuffer eps;
  6169. const char *s = logicalgroupname+9;
  6170. while (*s&&((*s!=':')||(s[1]!=':')))
  6171. eps.append(*(s++));
  6172. if (*s)
  6173. {
  6174. s+=2;
  6175. if (*s)
  6176. {
  6177. Owned<INode> dali = createINode(eps.str());
  6178. if (!dali || !getRemoteGroup(dali, s, defaultRemoteTimeout, groupdir, type, epa))
  6179. {
  6180. if (!cached)
  6181. {
  6182. CriticalBlock block(cachesect);
  6183. cache.append(*new CNamedGroupCacheEntry(NULL, gname, NULL, grp_unknown));
  6184. }
  6185. return NULL;
  6186. }
  6187. }
  6188. }
  6189. }
  6190. else if (epa.ordinality()==0) {
  6191. struct sLock
  6192. {
  6193. sLock() { lock = NULL; };
  6194. ~sLock() { delete lock; };
  6195. CConnectLock *lock;
  6196. } slock;
  6197. if (!conn)
  6198. {
  6199. slock.lock = new CConnectLock("CNamedGroup::lookup", SDS_GROUPSTORE_ROOT, false, false, false, defaultTimeout);
  6200. conn = slock.lock->conn;
  6201. if (!conn)
  6202. {
  6203. if (!cached)
  6204. {
  6205. CriticalBlock block(cachesect);
  6206. cache.append(*new CNamedGroupCacheEntry(NULL, gname, NULL, grp_unknown));
  6207. }
  6208. return NULL;
  6209. }
  6210. }
  6211. Owned<IPropertyTree> pt = getNamedPropTree(conn->queryRoot(),"Group","@name",gname.str(),true);
  6212. if (!pt)
  6213. return NULL;
  6214. type = translateGroupType(pt->queryProp("@kind"));
  6215. groupdir.set(pt->queryProp("@dir"));
  6216. if (groupdir.isEmpty())
  6217. groupdir.set(queryBaseDirectory(type));
  6218. Owned<IPropertyTreeIterator> pe2 = pt->getElements("Node");
  6219. ForEach(*pe2)
  6220. {
  6221. SocketEndpoint ep(pe2->query().queryProp("@ip"));
  6222. epa.append(ep);
  6223. }
  6224. }
  6225. }
  6226. catch (IException *E)
  6227. {
  6228. // cache the exception
  6229. CriticalBlock block(cachesect);
  6230. cache.append(*new CNamedGroupCacheEntry(E, gname));
  6231. throw;
  6232. }
  6233. Owned<IGroup> ret = createIGroup(epa);
  6234. if (!cached)
  6235. {
  6236. CriticalBlock block(cachesect);
  6237. cache.append(*new CNamedGroupCacheEntry(ret, gname, groupdir, type));
  6238. }
  6239. if (range.length())
  6240. {
  6241. SocketEndpointArray epar;
  6242. const char *s = range.str();
  6243. while (*s)
  6244. {
  6245. unsigned start = 0;
  6246. while (isdigit(*s))
  6247. {
  6248. start = start*10+*s-'0';
  6249. s++;
  6250. }
  6251. if (!start)
  6252. break;
  6253. unsigned end;
  6254. if (*s=='-')
  6255. {
  6256. s++;
  6257. end = 0;
  6258. while (isdigit(*s))
  6259. {
  6260. end = end*10+*s-'0';
  6261. s++;
  6262. }
  6263. if (!end)
  6264. end = epa.ordinality();
  6265. }
  6266. else
  6267. end = start;
  6268. if ((start>epa.ordinality())||(end>epa.ordinality()))
  6269. {
  6270. s = range.str();
  6271. break;
  6272. }
  6273. if (*s==',')
  6274. s++;
  6275. unsigned i=start-1;
  6276. do { // allow 400-1 etc
  6277. i++;
  6278. if (i>epa.ordinality())
  6279. i = 1;
  6280. epar.append(epa.item(i-1));
  6281. } while (i!=end);
  6282. }
  6283. if (*s)
  6284. throw MakeStringException(-1,"Invalid group range %s",range.str());
  6285. ret.setown(createIGroup(epar));
  6286. }
  6287. if (dirret)
  6288. dirret->append(groupdir);
  6289. groupType = type;
  6290. return ret.getClear();
  6291. }
  6292. IGroup *lookup(const char *logicalgroupname)
  6293. {
  6294. GroupType dummy;
  6295. return dolookup(logicalgroupname, NULL, NULL, dummy);
  6296. }
  6297. IGroup *lookup(const char *logicalgroupname, StringBuffer &dir, GroupType &groupType)
  6298. {
  6299. return dolookup(logicalgroupname, NULL, &dir, groupType);
  6300. }
  6301. INamedGroupIterator *getIterator()
  6302. {
  6303. CConnectLock connlock("CNamedGroup::getIterator", SDS_GROUPSTORE_ROOT, false, true, false, defaultTimeout);
  6304. return new CNamedGroupIterator(connlock.conn); // links connection
  6305. }
  6306. INamedGroupIterator *getIterator(IGroup *match,bool exact)
  6307. {
  6308. CConnectLock connlock("CNamedGroup::getIterator", SDS_GROUPSTORE_ROOT, false, false, false, defaultTimeout);
  6309. return new CNamedGroupIterator(connlock.conn,match,exact); // links connection
  6310. }
  6311. void doadd(CConnectLock &connlock,const char *name,IGroup *group,bool cluster,const char *dir)
  6312. {
  6313. if (!group)
  6314. return;
  6315. IPropertyTree *val = createPTree("Group");
  6316. val->setProp("@name",name);
  6317. if (cluster)
  6318. val->setPropBool("@cluster", true);
  6319. if (dir)
  6320. val->setProp("@dir",dir);
  6321. INodeIterator &gi = *group->getIterator();
  6322. StringBuffer str;
  6323. ForEach(gi) {
  6324. IPropertyTree *n = createPTree("Node");
  6325. n = val->addPropTree("Node",n);
  6326. gi.query().endpoint().getIpText(str.clear());
  6327. n->setProp("@ip",str.str());
  6328. }
  6329. gi.Release();
  6330. connlock.conn->queryRoot()->addPropTree("Group",val);
  6331. }
  6332. void addUnique(IGroup *group,StringBuffer &lname, const char *dir)
  6333. {
  6334. if (group->ordinality()==1)
  6335. {
  6336. group->getText(lname);
  6337. return;
  6338. }
  6339. CConnectLock connlock("CNamedGroup::addUnique", SDS_GROUPSTORE_ROOT, true, false, false, defaultTimeout);
  6340. StringBuffer name;
  6341. StringBuffer prop;
  6342. unsigned scale = 16;
  6343. loop {
  6344. name.clear();
  6345. if (lname.length()) { // try suggested name
  6346. name.append(lname);
  6347. name.toLowerCase();
  6348. lname.clear();
  6349. }
  6350. else
  6351. name.append("__anon").append(getRandom()%scale);
  6352. prop.clear().appendf("Group[@name=\"%s\"]",name.str());
  6353. if (!connlock.conn->queryRoot()->hasProp(prop.str()))
  6354. break;
  6355. scale*=2;
  6356. }
  6357. doadd(connlock,name.str(),group,false,dir);
  6358. lname.append(name);
  6359. }
  6360. void add(const char *logicalgroupname, IGroup *group, bool cluster, const char *dir, GroupType groupType)
  6361. {
  6362. StringBuffer name(logicalgroupname);
  6363. name.toLowerCase();
  6364. name.trim();
  6365. StringBuffer prop;
  6366. prop.appendf("Group[@name=\"%s\"]",name.str());
  6367. CConnectLock connlock("CNamedGroup::add", SDS_GROUPSTORE_ROOT, true, false, false, defaultTimeout);
  6368. connlock.conn->queryRoot()->removeProp(prop.str());
  6369. doadd(connlock,name.str(),group,cluster,dir);
  6370. {
  6371. CriticalBlock block(cachesect);
  6372. cache.kill();
  6373. if (group)
  6374. cache.append(*new CNamedGroupCacheEntry(group, name.str(), dir, groupType));
  6375. }
  6376. }
  6377. void remove(const char *logicalgroupname)
  6378. {
  6379. add(logicalgroupname, NULL, false, NULL, grp_unknown);
  6380. }
  6381. bool find(IGroup *grp, StringBuffer &gname, bool add)
  6382. {
  6383. // gname on entry is suggested name for add if set
  6384. unsigned n = grp->ordinality();
  6385. if (!grp||!n)
  6386. return false;
  6387. Owned<INamedGroupIterator> iter=getIterator(grp,(n==1)); // one node clusters must be exact match
  6388. StringAttr bestname;
  6389. StringBuffer name;
  6390. ForEach(*iter) {
  6391. bool iscluster = iter->isCluster();
  6392. if (iscluster||(bestname.isEmpty())) {
  6393. iter->get(name.clear());
  6394. if (name.length()) {
  6395. bestname.set(name);
  6396. if (iscluster)
  6397. break;
  6398. }
  6399. }
  6400. }
  6401. iter.clear();
  6402. if (bestname.isEmpty()) {
  6403. if (add||(n==1)) // single-nodes always have implicit group of IP
  6404. addUnique(grp,gname,NULL);
  6405. return false;
  6406. }
  6407. gname.clear().append(bestname);
  6408. return true;
  6409. }
  6410. void swapNode(const IpAddress &from, const IpAddress &to)
  6411. {
  6412. if (from.ipequals(to))
  6413. return;
  6414. CConnectLock connlock("CNamedGroup::swapNode", SDS_GROUPSTORE_ROOT, true, false, false, defaultTimeout);
  6415. StringBuffer froms;
  6416. from.getIpText(froms);
  6417. StringBuffer tos;
  6418. to.getIpText(tos);
  6419. Owned<IPropertyTreeIterator> pe = connlock.conn->queryRoot()->getElements("Group");
  6420. ForEach(*pe) {
  6421. IPropertyTree &group = pe->query();
  6422. const char *kind = group.queryProp("@kind");
  6423. if (kind && streq("Spare", kind))
  6424. continue;
  6425. StringBuffer name;
  6426. group.getProp("@name",name);
  6427. StringBuffer xpath("Node[@ip = \"");
  6428. xpath.append(froms).append("\"]");
  6429. for (unsigned guard=0; guard<1000; guard++) {
  6430. Owned<IPropertyTreeIterator> ne = group.getElements(xpath.str());
  6431. if (!ne->first())
  6432. break;
  6433. ne->query().setProp("@ip",tos.str());
  6434. PROGLOG("swapNode swapping %s for %s in group %s",froms.str(),tos.str(),name.str());
  6435. }
  6436. }
  6437. CriticalBlock block(cachesect);
  6438. cache.kill();
  6439. }
  6440. unsigned setDefaultTimeout(unsigned timems)
  6441. {
  6442. unsigned ret = defaultTimeout;
  6443. defaultTimeout = timems;
  6444. return ret;
  6445. }
  6446. unsigned setRemoteTimeout(unsigned timems)
  6447. {
  6448. unsigned ret = defaultRemoteTimeout;
  6449. defaultRemoteTimeout = timems;
  6450. return ret;
  6451. }
  6452. void resetCache()
  6453. {
  6454. CriticalBlock block(cachesect);
  6455. cache.kill();
  6456. }
  6457. private:
  6458. bool getRemoteGroup(const INode *foreigndali, const char *gname, unsigned foreigndalitimeout,
  6459. StringAttr &groupdir, GroupType &type, SocketEndpointArray &epa)
  6460. {
  6461. StringBuffer lcname(gname);
  6462. gname = lcname.trim().toLowerCase().str();
  6463. CMessageBuffer mb;
  6464. mb.append((int)MDFS_GET_GROUP_TREE).append(gname);
  6465. size32_t mbsz = mb.length();
  6466. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  6467. checkDfsReplyException(mb);
  6468. if (mb.length()==0)
  6469. return false;
  6470. byte ok;
  6471. mb.read(ok);
  6472. if (ok!=1) {
  6473. // kludge for prev bug
  6474. if ((ok==(byte)MDFS_GET_GROUP_TREE)&&mb.length()>mbsz) {
  6475. mb.skip(mbsz-1);
  6476. mb.read(ok);
  6477. if (ok!=1)
  6478. return false;
  6479. }
  6480. else
  6481. return false;
  6482. }
  6483. Owned<IPropertyTree> pt = createPTree(mb);
  6484. Owned<IPropertyTreeIterator> pe = pt->getElements("Node");
  6485. groupdir.set(pt->queryProp("@dir"));
  6486. type = translateGroupType(pt->queryProp("@kind"));
  6487. ForEach(*pe) {
  6488. SocketEndpoint ep(pe->query().queryProp("@ip"));
  6489. epa.append(ep);
  6490. }
  6491. return epa.ordinality() > 0;
  6492. }
  6493. };
  6494. static CNamedGroupStore *groupStore = NULL;
  6495. static CriticalSection groupsect;
  6496. bool CNamedGroupIterator::match()
  6497. {
  6498. if (conn.get()) {
  6499. if (matchgroup.get()) {
  6500. if (!groupStore)
  6501. return false;
  6502. const char *name = pe->query().queryProp("@name");
  6503. if (!name||!*name)
  6504. return false;
  6505. GroupType dummy;
  6506. Owned<IGroup> lgrp = groupStore->dolookup(name, conn, NULL, dummy);
  6507. if (lgrp) {
  6508. if (exactmatch)
  6509. return lgrp->equals(matchgroup);
  6510. GroupRelation gr = matchgroup->compare(lgrp);
  6511. return (gr==GRidentical)||(gr==GRbasesubset)||(gr==GRwrappedsuperset);
  6512. }
  6513. }
  6514. else
  6515. return true;
  6516. }
  6517. return false;
  6518. }
  6519. INamedGroupStore &queryNamedGroupStore()
  6520. {
  6521. if (!groupStore) {
  6522. CriticalBlock block(groupsect);
  6523. if (!groupStore)
  6524. groupStore = new CNamedGroupStore();
  6525. }
  6526. return *groupStore;
  6527. }
  6528. // --------------------------------------------------------
  6529. IDistributedFile *CDistributedFileDirectory::createExternal(const CDfsLogicalFileName &logicalname)
  6530. {
  6531. //authentication already done
  6532. SocketEndpoint ep;
  6533. Owned<IGroup> group;
  6534. if (!logicalname.getEp(ep)) {
  6535. StringBuffer grp;
  6536. if (logicalname.getGroupName(grp).length()==0)
  6537. throw MakeStringException(-1,"missing node in external file name (%s)",logicalname.get());
  6538. group.setown(queryNamedGroupStore().lookup(grp.str()));
  6539. if (!group)
  6540. throw MakeStringException(-1,"cannot resolve node %s in external file name (%s)",grp.str(),logicalname.get());
  6541. ep = group->queryNode(0).endpoint();
  6542. }
  6543. bool iswin=false;
  6544. bool usedafs;
  6545. switch (getDaliServixOs(ep))
  6546. {
  6547. case DAFS_OSwindows:
  6548. iswin = true;
  6549. // fall through
  6550. case DAFS_OSlinux:
  6551. case DAFS_OSsolaris:
  6552. usedafs = ep.port||!ep.isLocal();
  6553. break;
  6554. default:
  6555. #ifdef _WIN32
  6556. iswin = true;
  6557. #else
  6558. iswin = false;
  6559. #endif
  6560. usedafs = false;
  6561. break;
  6562. }
  6563. //rest is local path
  6564. Owned<IFileDescriptor> fileDesc = createFileDescriptor();
  6565. StringBuffer dir;
  6566. StringBuffer tail;
  6567. IException *e=NULL;
  6568. if (!logicalname.getExternalPath(dir,tail,iswin,&e)) {
  6569. if (e)
  6570. throw e;
  6571. return NULL;
  6572. }
  6573. fileDesc->setDefaultDir(dir.str());
  6574. unsigned n = group.get()?group->ordinality():1;
  6575. StringBuffer partname;
  6576. CDateTime moddt;
  6577. bool moddtset = false;
  6578. for (unsigned i=0;i<n;i++) {
  6579. if (group.get())
  6580. ep = group->queryNode(i).endpoint();
  6581. partname.clear();
  6582. partname.append(dir);
  6583. const char *s = tail.str();
  6584. bool isspecial = (*s=='>');
  6585. if (isspecial)
  6586. partname.append(s);
  6587. else {
  6588. while (*s) {
  6589. if (memicmp(s,"$P$",3)==0) {
  6590. partname.append(i+1);
  6591. s += 3;
  6592. }
  6593. else if (memicmp(s,"$N$",3)==0) {
  6594. partname.append(n);
  6595. s += 3;
  6596. }
  6597. else
  6598. partname.append(*(s++));
  6599. }
  6600. }
  6601. if (!ep.port&&usedafs)
  6602. ep.port = getDaliServixPort();
  6603. RemoteFilename rfn;
  6604. rfn.setPath(ep,partname.str());
  6605. if (!isspecial&&(memcmp(partname.str(),"/$/",3)!=0)&&(memcmp(partname.str(),"\\$\\",3)!=0)) { // don't get date on external data
  6606. try {
  6607. Owned<IFile> file = createIFile(rfn);
  6608. CDateTime dt;
  6609. if (file&&file->getTime(NULL,&dt,NULL)) {
  6610. if (!moddtset||(dt.compareDate(moddt)>0)) {
  6611. moddt.set(dt);
  6612. moddtset = true;
  6613. }
  6614. }
  6615. }
  6616. catch (IException *e) {
  6617. EXCLOG(e,"CDistributedFileDirectory::createExternal");
  6618. e->Release();
  6619. }
  6620. }
  6621. fileDesc->setPart(i,rfn);
  6622. }
  6623. fileDesc->queryPartDiskMapping(0).defaultCopies = DFD_NoCopies;
  6624. IDistributedFile * ret = createNew(fileDesc,logicalname.get(),true); // set modified
  6625. if (ret&&moddtset) {
  6626. ret->setModificationTime(moddt);
  6627. }
  6628. return ret;
  6629. }
  6630. IDistributedFile *CDistributedFileDirectory::lookup(const char *_logicalname, IUserDescriptor *user, bool writeattr, bool hold, IDistributedFileTransaction *transaction, unsigned timeout)
  6631. {
  6632. CDfsLogicalFileName logicalname;
  6633. logicalname.set(_logicalname);
  6634. return lookup(logicalname, user, writeattr, hold, transaction, timeout);
  6635. }
  6636. IDistributedFile *CDistributedFileDirectory::dolookup(CDfsLogicalFileName &_logicalname, IUserDescriptor *user, bool writeattr, bool hold, IDistributedFileTransaction *transaction, unsigned timeout)
  6637. {
  6638. CDfsLogicalFileName *logicalname = &_logicalname;
  6639. if (logicalname->isMulti())
  6640. // don't bother checking because the sub file creation will
  6641. return new CDistributedSuperFile(this,*logicalname,user,transaction); // temp superfile
  6642. Owned<IDfsLogicalFileNameIterator> redmatch;
  6643. loop {
  6644. checkLogicalName(*logicalname,user,true,writeattr,true,NULL);
  6645. if (logicalname->isExternal())
  6646. return createExternal(*logicalname); // external always works?
  6647. if (logicalname->isForeign()) {
  6648. IDistributedFile * ret = getFile(logicalname->get(),user,NULL);
  6649. if (ret)
  6650. return ret;
  6651. }
  6652. else {
  6653. unsigned start = 0;
  6654. loop {
  6655. CFileConnectLock fcl;
  6656. DfsXmlBranchKind bkind;
  6657. if (!fcl.initany("CDistributedFileDirectory::lookup", *logicalname, bkind, false, true, hold, timeout))
  6658. break;
  6659. if (bkind == DXB_File)
  6660. {
  6661. StringBuffer cname;
  6662. if (logicalname->getCluster(cname).length())
  6663. {
  6664. IPropertyTree *froot=fcl.queryRoot();
  6665. if (froot)
  6666. {
  6667. StringBuffer query;
  6668. query.appendf("Cluster[@name=\"%s\"]",cname.str());
  6669. if (!froot->hasProp(query.str()))
  6670. break;
  6671. }
  6672. }
  6673. return new CDistributedFile(this,fcl.detach(),*logicalname,user); // found
  6674. }
  6675. // now super file
  6676. if (bkind != DXB_SuperFile)
  6677. break;
  6678. if (start==0)
  6679. start = msTick();
  6680. unsigned elapsed;
  6681. try {
  6682. return new CDistributedSuperFile(this,fcl.detach(),*logicalname,user,transaction,SDS_SUB_LOCK_TIMEOUT);
  6683. }
  6684. catch (IDFS_Exception *e) {
  6685. elapsed = msTick()-start;
  6686. if ((e->errorCode()!=DFSERR_LookupConnectionTimout)||(elapsed>((timeout==INFINITE)?SDS_CONNECT_TIMEOUT:timeout)))
  6687. throw;
  6688. EXCLOG(e,"Superfile lookup");
  6689. e->Release();
  6690. }
  6691. PROGLOG("CDistributedSuperFile connect timeout (%dms) pausing",elapsed);
  6692. Sleep(SDS_TRANSACTION_RETRY/2+(getRandom()%SDS_TRANSACTION_RETRY));
  6693. }
  6694. }
  6695. if (redmatch.get()) {
  6696. if (!redmatch->next())
  6697. break;
  6698. }
  6699. else {
  6700. redmatch.setown(queryRedirection().getMatch(logicalname->get()));
  6701. if (!redmatch.get())
  6702. break;
  6703. if (!redmatch->first())
  6704. break;
  6705. }
  6706. logicalname = &redmatch->query();
  6707. }
  6708. return NULL;
  6709. }
  6710. IDistributedFile *CDistributedFileDirectory::lookup(CDfsLogicalFileName &logicalname, IUserDescriptor *user, bool writeattr, bool hold, IDistributedFileTransaction *transaction, unsigned timeout)
  6711. {
  6712. return dolookup(logicalname, user, writeattr, hold, transaction, timeout);
  6713. }
  6714. IDistributedSuperFile *CDistributedFileDirectory::lookupSuperFile(const char *_logicalname,IUserDescriptor *user,IDistributedFileTransaction *transaction, unsigned timeout)
  6715. {
  6716. CDfsLogicalFileName logicalname;
  6717. logicalname.set(_logicalname);
  6718. IDistributedFile *file = dolookup(logicalname, user, false, false, transaction, timeout);
  6719. if (file) {
  6720. IDistributedSuperFile *sf = file->querySuperFile();
  6721. if (sf)
  6722. return sf;
  6723. file->Release();
  6724. }
  6725. return NULL;
  6726. }
  6727. bool CDistributedFileDirectory::isSuperFile( const char *logicalname,
  6728. IUserDescriptor *user,
  6729. INode *foreigndali,
  6730. unsigned timeout)
  6731. {
  6732. Owned<IPropertyTree> tree = getFileTree(logicalname, user, foreigndali,timeout, false);
  6733. return tree.get()&&(strcmp(tree->queryName(),queryDfsXmlBranchName(DXB_SuperFile))==0);
  6734. }
  6735. bool CDistributedFileDirectory::exists(const char *_logicalname,IUserDescriptor *user,bool notsuper,bool superonly)
  6736. {
  6737. // (currently) no check on scope permissions for exists
  6738. bool external;
  6739. bool foreign;
  6740. CDfsLogicalFileName dlfn;
  6741. dlfn.set(_logicalname);
  6742. const char *logicalname = dlfn.get();
  6743. external = dlfn.isExternal();
  6744. foreign = dlfn.isForeign();
  6745. if (foreign) {
  6746. Owned<IDistributedFile> file = lookup(_logicalname, user, false, false, NULL, defaultTimeout);
  6747. if (file.get()==NULL)
  6748. return false;
  6749. if (file->querySuperFile()) {
  6750. if (notsuper)
  6751. return false;
  6752. }
  6753. else
  6754. if (superonly)
  6755. return false;
  6756. }
  6757. else if (external) {
  6758. if (!existsPhysical(_logicalname,user))
  6759. return false;
  6760. }
  6761. else {
  6762. StringBuffer str;
  6763. if (!superonly) {
  6764. dlfn.makeFullnameQuery(str,DXB_File,true);
  6765. CConnectLock connlockfile("CDistributedFileDirectory::exists",str.str(),false,false,false,defaultTimeout);
  6766. if (connlockfile.conn.get())
  6767. return true;
  6768. }
  6769. if (notsuper)
  6770. return false;
  6771. dlfn.makeFullnameQuery(str.clear(),DXB_SuperFile,true);
  6772. CConnectLock connlocksuper("CDistributedFileDirectory::exists",str.str(),false,false,false,defaultTimeout);
  6773. if (!connlocksuper.conn.get())
  6774. return false;
  6775. }
  6776. return true;
  6777. }
  6778. bool CDistributedFileDirectory::existsPhysical(const char *_logicalname, IUserDescriptor *user)
  6779. {
  6780. Owned<IDistributedFile> file = lookup(_logicalname, user, false, false, NULL, defaultTimeout);
  6781. if (!file)
  6782. return false;
  6783. return file->existsPhysicalPartFiles(0);
  6784. }
  6785. IDistributedFile *CDistributedFileDirectory::createNew(IFileDescriptor *fdesc,const char *lname, bool includeports)
  6786. {
  6787. CDistributedFile *file = new CDistributedFile(this, fdesc, includeports);
  6788. if (file&&lname&&*lname&&file->isAnon())
  6789. file->setLogicalName(lname);
  6790. return file;
  6791. }
  6792. ////////////////////////////////////
  6793. class DistributedFilePropertyLockFree
  6794. {
  6795. unsigned lockedCount;
  6796. CDistributedFile *file;
  6797. CDistributedSuperFile *sfile;
  6798. public:
  6799. DistributedFilePropertyLockFree(IDistributedFile *_file)
  6800. {
  6801. file = dynamic_cast<CDistributedFile *>(_file);
  6802. sfile = NULL;
  6803. if (file)
  6804. lockedCount = file->setPropLockCount(0);
  6805. else
  6806. {
  6807. sfile = dynamic_cast<CDistributedSuperFile *>(_file);
  6808. lockedCount = sfile->setPropLockCount(0);
  6809. }
  6810. }
  6811. ~DistributedFilePropertyLockFree()
  6812. {
  6813. if (file)
  6814. verifyex(0 == file->setPropLockCount(lockedCount));
  6815. else if (sfile)
  6816. verifyex(0 == sfile->setPropLockCount(lockedCount));
  6817. }
  6818. };
  6819. /**
  6820. * Creates a super-file within a transaction.
  6821. */
  6822. class CCreateSuperFileAction: public CDFAction
  6823. {
  6824. CDfsLogicalFileName logicalname;
  6825. CDistributedFileDirectory *parent;
  6826. Linked<IDistributedSuperFile> super;
  6827. IUserDescriptor *user;
  6828. bool interleaved, created;
  6829. public:
  6830. CCreateSuperFileAction(CDistributedFileDirectory *_parent,
  6831. IUserDescriptor *_user,
  6832. const char *_flname,
  6833. bool _interleaved)
  6834. : parent(_parent), user(_user), created(false), interleaved(_interleaved)
  6835. {
  6836. logicalname.set(_flname);
  6837. }
  6838. IDistributedSuperFile *getSuper()
  6839. {
  6840. if (!super)
  6841. {
  6842. Owned<IDistributedSuperFile> _super = transaction->lookupSuperFile(logicalname.get(), SDS_SUB_LOCK_TIMEOUT);
  6843. if (_super)
  6844. super.setown(_super.getClear());
  6845. else
  6846. {
  6847. /* No super, create one if necessary.
  6848. * This really shouldn't have to work this way, looking up super early, or creating super stub now,
  6849. * because other super file transactions are based on
  6850. * TBD: There should be a way to obtain lock independently of actually attaching.
  6851. */
  6852. Owned<IPropertyTree> root = createPTree();
  6853. root->setPropInt("@interleaved",interleaved?2:0); // this is ill placed
  6854. super.setown(new CDistributedSuperFile(parent, root, logicalname, user));
  6855. created = true;
  6856. transaction->addFile(super);
  6857. }
  6858. addFileLock(super);
  6859. }
  6860. return super.getLink();
  6861. }
  6862. bool prepare()
  6863. {
  6864. Owned<IDistributedFile> _super = getSuper();
  6865. // Attach the file to DFS, if wasn't there already
  6866. if (created)
  6867. super->attach(logicalname.get(), user);
  6868. if (lock())
  6869. return true;
  6870. unlock();
  6871. return false;
  6872. }
  6873. void run()
  6874. {
  6875. // Do nothing, file is already created
  6876. }
  6877. void retry()
  6878. {
  6879. // on retry, we need to remove the file so next lock doesn't fail
  6880. if (created)
  6881. super->detach();
  6882. CDFAction::retry();
  6883. }
  6884. void rollback()
  6885. {
  6886. state = TAS_FAILURE;
  6887. if (created)
  6888. super->detach();
  6889. CDFAction::rollback();
  6890. }
  6891. };
  6892. /**
  6893. * Removes a super-file within a transaction.
  6894. */
  6895. class CRemoveSuperFileAction: public CDFAction
  6896. {
  6897. CDfsLogicalFileName logicalname;
  6898. Linked<IDistributedSuperFile> super;
  6899. IUserDescriptor *user;
  6900. bool delSub;
  6901. Owned<IDistributedFileTransactionExt> nestedTransaction;
  6902. class CNestedTransaction : public CDistributedFileTransaction
  6903. {
  6904. IDistributedFileTransactionExt *transaction;
  6905. CIArrayOf<CDFAction> actions;
  6906. public:
  6907. IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
  6908. CNestedTransaction(IDistributedFileTransactionExt *_transaction, IUserDescriptor *user)
  6909. : CDistributedFileTransaction(user), transaction(_transaction)
  6910. {
  6911. if (transaction->active())
  6912. start();
  6913. }
  6914. // wrap rest of calls into parent transaction calls
  6915. virtual IDistributedFile *lookupFile(const char *lfn,unsigned timeout=INFINITE)
  6916. {
  6917. return transaction->lookupFile(lfn, timeout);
  6918. }
  6919. virtual IDistributedSuperFile *lookupSuperFile(const char *slfn,unsigned timeout=INFINITE)
  6920. {
  6921. return transaction->lookupSuperFile(slfn, timeout);
  6922. }
  6923. virtual IUserDescriptor *queryUser() { return transaction->queryUser(); }
  6924. virtual void descend() { transaction->descend(); }
  6925. virtual void ascend() { transaction->ascend(); }
  6926. virtual void addFile(IDistributedFile *file) { transaction->addFile(file); }
  6927. virtual void ensureFile(IDistributedFile *file) { transaction->ensureFile(file); }
  6928. virtual void clearFile(IDistributedFile *file) { transaction->clearFile(file); }
  6929. virtual void noteAddSubFile(IDistributedSuperFile *super, const char *superName, IDistributedFile *sub)
  6930. {
  6931. transaction->noteAddSubFile(super, superName, sub);
  6932. }
  6933. virtual void noteRemoveSubFile(IDistributedSuperFile *super, IDistributedFile *sub)
  6934. {
  6935. transaction->noteRemoveSubFile(super, sub);
  6936. }
  6937. virtual void noteSuperSwap(IDistributedSuperFile *super1, IDistributedSuperFile *super2)
  6938. {
  6939. transaction->noteSuperSwap(super1, super2);
  6940. }
  6941. virtual void clearSubFiles(IDistributedSuperFile *super)
  6942. {
  6943. transaction->clearSubFiles(super);
  6944. }
  6945. virtual void noteRename(IDistributedFile *file, const char *newName)
  6946. {
  6947. transaction->noteRename(file, newName);
  6948. }
  6949. virtual void validateAddSubFile(IDistributedSuperFile *super, IDistributedFile *sub, const char *subName)
  6950. {
  6951. transaction->validateAddSubFile(super, sub, subName);
  6952. }
  6953. virtual bool isSubFile(IDistributedSuperFile *super, const char *subFile, bool sub)
  6954. {
  6955. return transaction->isSubFile(super, subFile, sub);
  6956. }
  6957. virtual bool addDelayedDelete(CDfsLogicalFileName &lfn,unsigned timeoutms=INFINITE)
  6958. {
  6959. return transaction->addDelayedDelete(lfn, timeoutms);
  6960. }
  6961. };
  6962. public:
  6963. CRemoveSuperFileAction(IUserDescriptor *_user,
  6964. const char *_flname,
  6965. bool _delSub)
  6966. : user(_user), delSub(_delSub)
  6967. {
  6968. logicalname.set(_flname);
  6969. }
  6970. bool prepare()
  6971. {
  6972. // We *have* to make sure the file exists here
  6973. super.setown(transaction->lookupSuperFile(logicalname.get(), SDS_SUB_LOCK_TIMEOUT));
  6974. if (!super)
  6975. ThrowStringException(-1, "Super File %s doesn't exist in the file system", logicalname.get());
  6976. addFileLock(super);
  6977. // Adds actions to transactions before this one and gets executed only on commit
  6978. if (delSub)
  6979. {
  6980. // As 'delSub' means additional actions, handle them in their own transaction context
  6981. // Wrap lookups and record of removed/added subs to parent transaction, for common cache purposes
  6982. nestedTransaction.setown(new CNestedTransaction(transaction, user));
  6983. super->removeSubFile(NULL, true, false, nestedTransaction);
  6984. }
  6985. if (lock())
  6986. {
  6987. if (nestedTransaction)
  6988. {
  6989. if (nestedTransaction->prepareActions())
  6990. return true;
  6991. }
  6992. else
  6993. return true;
  6994. }
  6995. unlock();
  6996. super.clear();
  6997. return false;
  6998. }
  6999. void retry()
  7000. {
  7001. if (nestedTransaction)
  7002. nestedTransaction->retryActions();
  7003. CDFAction::retry();
  7004. }
  7005. void run()
  7006. {
  7007. if (nestedTransaction)
  7008. nestedTransaction->runActions();
  7009. super->detach();
  7010. }
  7011. void commit()
  7012. {
  7013. if (nestedTransaction)
  7014. nestedTransaction->commitAndClearup();
  7015. CDFAction::commit();
  7016. }
  7017. };
  7018. /**
  7019. * Renames a file within a transaction.
  7020. */
  7021. class CRenameFileAction: public CDFAction
  7022. {
  7023. CDfsLogicalFileName fromName, toName;
  7024. CDistributedFileDirectory *parent;
  7025. Linked<IDistributedFile> file;
  7026. IUserDescriptor *user;
  7027. bool renamed;
  7028. enum RenameAction { ra_regular, ra_splitfrom, ra_mergeinto } ra;
  7029. public:
  7030. CRenameFileAction(CDistributedFileDirectory *_parent,
  7031. IUserDescriptor *_user,
  7032. const char *_flname,
  7033. const char *_newname)
  7034. : user(_user), parent(_parent)
  7035. {
  7036. fromName.set(_flname);
  7037. // Basic consistency checking
  7038. toName.set(_newname);
  7039. if (toName.isExternal())
  7040. throw MakeStringException(-1,"rename: cannot rename to external file");
  7041. if (toName.isForeign())
  7042. throw MakeStringException(-1,"rename: cannot rename to foreign file");
  7043. // Make sure files are not the same
  7044. if (0 == strcmp(fromName.get(), toName.get()))
  7045. ThrowStringException(-1, "rename: cannot rename file %s to itself", toName.get());
  7046. ra = ra_regular;
  7047. renamed = false;
  7048. }
  7049. bool prepare()
  7050. {
  7051. // We *have* to make sure the source file exists and can be renamed
  7052. file.setown(transaction->lookupFile(fromName.get(), SDS_SUB_LOCK_TIMEOUT));
  7053. if (!file)
  7054. ThrowStringException(-1, "rename: file %s doesn't exist in the file system", fromName.get());
  7055. if (file->querySuperFile())
  7056. ThrowStringException(-1,"rename: cannot rename file %s as is SuperFile", fromName.get()); // Why not
  7057. StringBuffer reason;
  7058. if (!file->canRemove(reason))
  7059. ThrowStringException(-1,"rename: %s",reason.str());
  7060. addFileLock(file);
  7061. renamed = false;
  7062. if (lock())
  7063. {
  7064. StringBuffer oldcluster, newcluster;
  7065. fromName.getCluster(oldcluster);
  7066. toName.getCluster(newcluster);
  7067. Owned<IDistributedFile> newFile = transaction->lookupFile(toName.get(), SDS_SUB_LOCK_TIMEOUT);
  7068. if (newFile)
  7069. {
  7070. if (newcluster.length())
  7071. {
  7072. if (oldcluster.length())
  7073. ThrowStringException(-1,"rename: cannot specify both source and destination clusters on rename");
  7074. if (newFile->findCluster(newcluster.str())!=NotFound)
  7075. ThrowStringException(-1,"rename: cluster %s already part of file %s",newcluster.str(),toName.get());
  7076. if (file->numClusters()!=1)
  7077. ThrowStringException(-1,"rename: source file %s has more than one cluster",fromName.get());
  7078. // check compatible here ** TBD
  7079. ra = ra_mergeinto;
  7080. }
  7081. else
  7082. ThrowStringException(-1, "rename: file %s already exist in the file system", toName.get());
  7083. }
  7084. else if (oldcluster.length())
  7085. {
  7086. if (newcluster.length())
  7087. ThrowStringException(-1,"rename: cannot specify both source and destination clusters on rename");
  7088. if (file->numClusters()==1)
  7089. ThrowStringException(-1,"rename: cannot rename sole cluster %s",oldcluster.str());
  7090. if (file->findCluster(oldcluster.str())==NotFound)
  7091. ThrowStringException(-1,"rename: cannot find cluster %s",oldcluster.str());
  7092. ra = ra_splitfrom;
  7093. }
  7094. else
  7095. {
  7096. // TODO: something should check that file being renamed is not a subfile of a super where both created in transaction
  7097. transaction->noteRename(file, toName.get());
  7098. ra = ra_regular;
  7099. }
  7100. return true;
  7101. }
  7102. unlock();
  7103. file.clear();
  7104. return false;
  7105. }
  7106. void run()
  7107. {
  7108. doRename(fromName, toName, ra);
  7109. renamed = true;
  7110. }
  7111. void rollback()
  7112. {
  7113. // Only roll back if already renamed
  7114. if (renamed)
  7115. {
  7116. switch (ra)
  7117. {
  7118. case ra_regular:
  7119. doRename(toName, fromName, ra_regular);
  7120. break;
  7121. case ra_splitfrom:
  7122. doRename(toName, fromName, ra_mergeinto);
  7123. break;
  7124. case ra_mergeinto:
  7125. doRename(toName, fromName, ra_splitfrom);
  7126. break;
  7127. default:
  7128. throwUnexpected();
  7129. }
  7130. renamed = false;
  7131. }
  7132. CDFAction::rollback();
  7133. }
  7134. private:
  7135. void doRename(CDfsLogicalFileName &from, CDfsLogicalFileName &to, RenameAction ra)
  7136. {
  7137. CriticalBlock block(physicalChange);
  7138. StringBuffer oldcluster, newcluster;
  7139. fromName.getCluster(oldcluster);
  7140. toName.getCluster(newcluster);
  7141. Owned<IDistributedFile> oldfile;
  7142. if (ra_splitfrom == ra)
  7143. {
  7144. oldfile.setown(file.getClear());
  7145. Owned<IFileDescriptor> newdesc = oldfile->getFileDescriptor(oldcluster.str());
  7146. file.setown(parent->createNew(newdesc));
  7147. }
  7148. // Physical Rename
  7149. Owned<IMultiException> exceptions = MakeMultiException();
  7150. if (!file->renamePhysicalPartFiles(to.get(),newcluster,exceptions))
  7151. {
  7152. unlock();
  7153. StringBuffer errors;
  7154. exceptions->errorMessage(errors);
  7155. ThrowStringException(-1, "rename: could not rename logical file %s to %s: %s", fromName.get(), to.get(), errors.str());
  7156. }
  7157. // Logical rename and cleanup
  7158. switch (ra)
  7159. {
  7160. case ra_splitfrom:
  7161. {
  7162. unlock();
  7163. oldfile->removeCluster(oldcluster.str());
  7164. file->attach(to.get(), user);
  7165. lock();
  7166. break;
  7167. }
  7168. case ra_mergeinto:
  7169. {
  7170. Owned<IDistributedFile> newFile = transaction->lookupFile(to.get(), SDS_SUB_LOCK_TIMEOUT);
  7171. ClusterPartDiskMapSpec mspec = file->queryPartDiskMapping(0);
  7172. // Unlock the old file
  7173. unlock();
  7174. CDistributedFile *_file = dynamic_cast<CDistributedFile *>(file.get());
  7175. _file->detachLogical(INFINITE); // don't delete physicals, now used by newFile
  7176. transaction->clearFile(file); // no long used in transaction
  7177. newFile->addCluster(newcluster.str(),mspec);
  7178. parent->fixDates(newFile);
  7179. // need to clear and re-lookup as changed outside of transaction
  7180. // TBD: Allow 'addCluster' 'fixDates' etc. to be delayed/work inside transaction
  7181. transaction->clearFile(newFile);
  7182. newFile.clear();
  7183. file.setown(transaction->lookupFile(to.get(), SDS_SUB_LOCK_TIMEOUT));
  7184. addFileLock(file);
  7185. lock();
  7186. break;
  7187. }
  7188. case ra_regular:
  7189. {
  7190. /* It is not enough to unlock this actions locks on the file being renamed,
  7191. * because other actions, before and after may hold locks to the same file.
  7192. * For now, IDistributeFile::rename, needs to work on a lock free instance.
  7193. * TBD: Allow IDistributedFile::rename to work properly within transaction.
  7194. */
  7195. DistributedFilePropertyLockFree unlock(file);
  7196. file->rename(to.get(), user);
  7197. break;
  7198. }
  7199. default:
  7200. throwUnexpected();
  7201. }
  7202. // MORE: If the logical rename fails, we should roll back the physical renaming
  7203. // What if the physical renaming-back fails?!
  7204. // For now, leaving as it was, since physical renaming is more prone to errors than logical
  7205. // And checks were made earlier to make sure it was safe to rename
  7206. }
  7207. };
  7208. // MORE: This should be implemented in DFSAccess later on
  7209. IDistributedSuperFile *CDistributedFileDirectory::createSuperFile(const char *_logicalname,IUserDescriptor *user, bool _interleaved,bool ifdoesnotexist,IDistributedFileTransaction *transaction)
  7210. {
  7211. CDfsLogicalFileName logicalname;
  7212. logicalname.set(_logicalname);
  7213. checkLogicalName(logicalname,user,true,true,false,"have a superfile with");
  7214. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  7215. Linked<IDistributedFileTransactionExt> localtrans;
  7216. if (transaction)
  7217. {
  7218. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  7219. localtrans.set(_transaction);
  7220. }
  7221. else
  7222. localtrans.setown(new CDistributedFileTransaction(user));
  7223. IDistributedSuperFile *sfile = localtrans->lookupSuperFile(logicalname.get());
  7224. if (sfile)
  7225. {
  7226. if (ifdoesnotexist)
  7227. return sfile;
  7228. else
  7229. throw MakeStringException(-1,"createSuperFile: SuperFile %s already exists",logicalname.get());
  7230. }
  7231. Owned<CCreateSuperFileAction> action = new CCreateSuperFileAction(this,user,_logicalname,_interleaved);
  7232. localtrans->addAction(action.getLink()); // takes ownership
  7233. localtrans->autoCommit();
  7234. return action->getSuper();
  7235. }
  7236. // MORE: This should be implemented in DFSAccess later on
  7237. void CDistributedFileDirectory::removeSuperFile(const char *_logicalname, bool delSubs, IUserDescriptor *user, IDistributedFileTransaction *transaction)
  7238. {
  7239. CDfsLogicalFileName logicalname;
  7240. logicalname.set(_logicalname);
  7241. checkLogicalName(logicalname,user,true,true,false,"have a superfile with");
  7242. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  7243. Linked<IDistributedFileTransactionExt> localtrans;
  7244. if (transaction)
  7245. {
  7246. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  7247. localtrans.set(_transaction);
  7248. }
  7249. else
  7250. localtrans.setown(new CDistributedFileTransaction(user));
  7251. CRemoveSuperFileAction *action = new CRemoveSuperFileAction(user, _logicalname, delSubs);
  7252. localtrans->addAction(action); // takes ownership
  7253. localtrans->autoCommit();
  7254. }
  7255. bool CDistributedFileDirectory::removeEntry(const char *name, IUserDescriptor *user, IDistributedFileTransaction *transaction, unsigned timeoutms, bool throwException)
  7256. {
  7257. CDfsLogicalFileName logicalname;
  7258. logicalname.set(name);
  7259. checkLogicalName(logicalname,user,true,true,false,"delete");
  7260. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  7261. Linked<IDistributedFileTransactionExt> localtrans;
  7262. if (transaction)
  7263. {
  7264. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  7265. localtrans.set(_transaction);
  7266. }
  7267. else
  7268. localtrans.setown(new CDistributedFileTransaction(user));
  7269. // Action will be executed at the end of the transaction (commit)
  7270. localtrans->addDelayedDelete(logicalname, timeoutms);
  7271. try
  7272. {
  7273. localtrans->autoCommit();
  7274. }
  7275. catch (IException *e)
  7276. {
  7277. // TODO: Transform removeEntry into void
  7278. StringBuffer msg;
  7279. e->errorMessage(msg);
  7280. ERRLOG("Error while deleting %s: %s", logicalname.get(), msg.str());
  7281. if (throwException)
  7282. throw;
  7283. e->Release();
  7284. return false;
  7285. }
  7286. return true;
  7287. }
  7288. void CDistributedFileDirectory::removeEmptyScope(const char *scope)
  7289. {
  7290. if (scope&&*scope) {
  7291. StringBuffer fn(scope);
  7292. fn.append("::x");
  7293. CDfsLogicalFileName dlfn;
  7294. dlfn.set(fn.str());
  7295. removeFileEmptyScope(dlfn,defaultTimeout);
  7296. }
  7297. }
  7298. void CDistributedFileDirectory::renamePhysical(const char *oldname,const char *newname,IUserDescriptor *user,IDistributedFileTransaction *transaction)
  7299. {
  7300. if (!user)
  7301. {
  7302. #ifndef _NO_DALIUSER_STACKTRACE
  7303. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp CDistributedFileDirectory::renamePhysical %d",__LINE__);
  7304. //following debug code to be removed
  7305. PrintStackReport();
  7306. #endif
  7307. user = defaultudesc.get();
  7308. }
  7309. CDfsLogicalFileName oldlogicalname;
  7310. oldlogicalname.set(oldname);
  7311. checkLogicalName(oldlogicalname,user,true,true,false,"rename");
  7312. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  7313. Linked<IDistributedFileTransactionExt> localtrans;
  7314. if (transaction)
  7315. {
  7316. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  7317. localtrans.set(_transaction);
  7318. }
  7319. else
  7320. localtrans.setown(new CDistributedFileTransaction(user));
  7321. CRenameFileAction *action = new CRenameFileAction(this, user, oldname, newname);
  7322. localtrans->addAction(action); // takes ownership
  7323. localtrans->autoCommit();
  7324. }
  7325. void CDistributedFileDirectory::fixDates(IDistributedFile *file)
  7326. {
  7327. // should do in parallel
  7328. unsigned width = file->numParts();
  7329. CriticalSection crit;
  7330. class casyncfor: public CAsyncFor
  7331. {
  7332. IDistributedFile *file;
  7333. CriticalSection &crit;
  7334. unsigned width;
  7335. public:
  7336. bool ok;
  7337. casyncfor(IDistributedFile *_file,unsigned _width,CriticalSection &_errcrit)
  7338. : crit(_errcrit)
  7339. {
  7340. file = _file;
  7341. ok = true;
  7342. width = _width;
  7343. ok = true;
  7344. }
  7345. void Do(unsigned i)
  7346. {
  7347. CriticalBlock block(crit);
  7348. Owned<IDistributedFilePart> part = file->getPart(i);
  7349. CDateTime dt;
  7350. if (!part->getModifiedTime(false,false,dt))
  7351. return;
  7352. unsigned nc = part->numCopies();
  7353. for (unsigned copy = 0; copy < nc; copy++) {
  7354. RemoteFilename rfn;
  7355. part->getFilename(rfn,copy);
  7356. Owned<IFile> partfile = createIFile(rfn);
  7357. try {
  7358. CriticalUnblock unblock(crit);
  7359. CDateTime dt2;
  7360. if (partfile->getTime(NULL,&dt2,NULL)) {
  7361. if (!dt.equals(dt2)) {
  7362. partfile->setTime(NULL,&dt,NULL);
  7363. }
  7364. }
  7365. }
  7366. catch (IException *e) {
  7367. CriticalBlock block(crit);
  7368. StringBuffer s("Failed to find file part ");
  7369. s.append(partfile->queryFilename()).append(" on ");
  7370. rfn.queryEndpoint().getUrlStr(s);
  7371. EXCLOG(e, s.str());
  7372. e->Release();
  7373. }
  7374. }
  7375. }
  7376. } afor(file,width,crit);
  7377. afor.For(width,10,false,true);
  7378. }
  7379. void CDistributedFileDirectory::addEntry(CDfsLogicalFileName &dlfn,IPropertyTree *root,bool superfile, bool ignoreexists)
  7380. {
  7381. // add bit awkward
  7382. bool external;
  7383. bool foreign;
  7384. external = dlfn.isExternal();
  7385. foreign = dlfn.isForeign();
  7386. if (external) {
  7387. root->Release();
  7388. return; // ignore attempts to add external
  7389. }
  7390. CScopeConnectLock sconnlock("CDistributedFileDirectory::addEntry", dlfn, true, false, false, defaultTimeout);
  7391. if (!sconnlock.conn()) {// warn?
  7392. root->Release();
  7393. return;
  7394. }
  7395. IPropertyTree* sroot = sconnlock.conn()->queryRoot();
  7396. StringBuffer tail;
  7397. dlfn.getTail(tail);
  7398. IPropertyTree *prev = getNamedPropTree(sroot,superfile?queryDfsXmlBranchName(DXB_SuperFile):queryDfsXmlBranchName(DXB_File),"@name",tail.str(),false);
  7399. if (!prev) // check super/file doesn't exist
  7400. prev = getNamedPropTree(sroot,superfile?queryDfsXmlBranchName(DXB_File):queryDfsXmlBranchName(DXB_SuperFile),"@name",tail.str(),false);
  7401. if (prev!=NULL) {
  7402. prev->Release();
  7403. root->Release();
  7404. if (ignoreexists)
  7405. return;
  7406. IDFS_Exception *e = new CDFS_Exception(DFSERR_LogicalNameAlreadyExists,dlfn.get());
  7407. throw e;
  7408. }
  7409. root->setProp("@name",tail.str());
  7410. root->setProp("OrigName",dlfn.get());
  7411. if (superfile)
  7412. sroot->addPropTree(queryDfsXmlBranchName(DXB_SuperFile), root); // now owns root
  7413. else
  7414. {
  7415. IPropertyTree *file = sroot->addPropTree(queryDfsXmlBranchName(DXB_File), root); // now owns root
  7416. file->setPropTree("ClusterLock", createPTree());
  7417. }
  7418. }
  7419. IDistributedFileIterator *CDistributedFileDirectory::getIterator(const char *wildname, bool includesuper, IUserDescriptor *user)
  7420. {
  7421. return new CDistributedFileIterator(this,wildname,includesuper,user);
  7422. }
  7423. GetFileClusterNamesType CDistributedFileDirectory::getFileClusterNames(const char *_logicalname,StringArray &out)
  7424. {
  7425. CDfsLogicalFileName logicalname;
  7426. logicalname.set(_logicalname);
  7427. if (logicalname.isForeign())
  7428. return GFCN_Foreign;
  7429. if (logicalname.isExternal())
  7430. return GFCN_External;
  7431. CScopeConnectLock sconnlock("CDistributedFileDirectory::getFileClusterList", logicalname, false, false, false, defaultTimeout);
  7432. DfsXmlBranchKind bkind;
  7433. IPropertyTree *froot = sconnlock.queryFileRoot(logicalname,bkind);
  7434. if (froot) {
  7435. if (bkind==DXB_File) {
  7436. getFileGroups(froot,out);
  7437. return GFCN_Normal;
  7438. }
  7439. if (bkind==DXB_SuperFile)
  7440. return GFCN_Super;
  7441. }
  7442. return GFCN_NotFound;
  7443. }
  7444. // --------------------------------------------------------
  7445. static CDistributedFileDirectory *DFdir = NULL;
  7446. static CriticalSection dfdirCrit;
  7447. /**
  7448. * Public method to control DistributedFileDirectory access
  7449. * as a singleton. This is the only way to get directories,
  7450. * files, super-files and logic-files.
  7451. */
  7452. IDistributedFileDirectory &queryDistributedFileDirectory()
  7453. {
  7454. if (!DFdir) {
  7455. CriticalBlock block(dfdirCrit);
  7456. if (!DFdir)
  7457. DFdir = new CDistributedFileDirectory();
  7458. }
  7459. return *DFdir;
  7460. }
  7461. /**
  7462. * Shutdown distributed file system (root directory).
  7463. */
  7464. void closedownDFS() // called by dacoven
  7465. {
  7466. CriticalBlock block(dfdirCrit);
  7467. try {
  7468. delete DFdir;
  7469. }
  7470. catch (IMP_Exception *e) {
  7471. if (e->errorCode()!=MPERR_link_closed)
  7472. throw;
  7473. PrintExceptionLog(e,"closedownDFS");
  7474. e->Release();
  7475. }
  7476. catch (IDaliClient_Exception *e) {
  7477. if (e->errorCode()!=DCERR_server_closed)
  7478. throw;
  7479. e->Release();
  7480. }
  7481. DFdir = NULL;
  7482. CriticalBlock block2(groupsect);
  7483. ::Release(groupStore);
  7484. groupStore = NULL;
  7485. }
  7486. class CDFPartFilter : public CInterface, implements IDFPartFilter
  7487. {
  7488. protected:
  7489. bool *partincluded;
  7490. unsigned max;
  7491. public:
  7492. IMPLEMENT_IINTERFACE;
  7493. CDFPartFilter(const char *filter)
  7494. {
  7495. max = 0;
  7496. partincluded = NULL;
  7497. unsigned pn=0;
  7498. const char *s=filter;
  7499. if (!s)
  7500. return;
  7501. while (*s) {
  7502. if (isdigit(*s)) {
  7503. pn = pn*10+(*s-'0');
  7504. if (pn>max)
  7505. max = pn;
  7506. }
  7507. else
  7508. pn = 0;
  7509. s++;
  7510. }
  7511. if (max==0)
  7512. return;
  7513. partincluded = new bool[max];
  7514. unsigned i;
  7515. for (i=0;i<max;i++)
  7516. partincluded[i] = false;
  7517. pn=0;
  7518. s=filter;
  7519. unsigned start=0;
  7520. loop {
  7521. if ((*s==0)||(*s==',')||isspace(*s)) {
  7522. if (start) {
  7523. for (i=start-1;i<pn;i++)
  7524. partincluded[i] = true;
  7525. start = 0;
  7526. }
  7527. else
  7528. partincluded[pn-1] = true;
  7529. if (*s==0)
  7530. break;
  7531. pn = 0;
  7532. }
  7533. else if (isdigit(*s)) {
  7534. pn = pn*10+(*s-'0');
  7535. if (pn>max)
  7536. max = pn;
  7537. if (s[1]=='-') {
  7538. s++;
  7539. start = pn;
  7540. pn = 0;
  7541. }
  7542. }
  7543. s++;
  7544. }
  7545. }
  7546. ~CDFPartFilter()
  7547. {
  7548. delete [] partincluded;
  7549. }
  7550. bool includePart(unsigned part)
  7551. {
  7552. if (max==0)
  7553. return true;
  7554. if (part>=max)
  7555. return false;
  7556. return partincluded[part];
  7557. };
  7558. };
  7559. IDFPartFilter *createPartFilter(const char *filter)
  7560. {
  7561. return new CDFPartFilter(filter);
  7562. }
  7563. //=====================================================================================
  7564. // Server Side Support
  7565. class CFileMatch : public CInterface
  7566. {
  7567. StringAttr name;
  7568. Linked<IPropertyTree> tree;
  7569. bool isSuper;
  7570. public:
  7571. CFileMatch(const char *_name, IPropertyTree *_tree, bool _isSuper) : name(_name), tree(_tree), isSuper(_isSuper)
  7572. {
  7573. }
  7574. IPropertyTree &queryFileTree() const { return *tree; }
  7575. const char *queryName() const { return name; }
  7576. bool queryIsSuper() const { return isSuper; }
  7577. };
  7578. typedef CIArrayOf<CFileMatch> CFileMatchArray;
  7579. class CScope : public CInterface
  7580. {
  7581. StringAttr name;
  7582. CIArrayOf<CFileMatch> files; // matches
  7583. CIArrayOf<CScope> subScopes;
  7584. public:
  7585. CScope(const char *_name) : name(_name)
  7586. {
  7587. }
  7588. const char *getName() const { return name; }
  7589. void addMatch(const char *name, IPropertyTree &fileTree, bool isSuper)
  7590. {
  7591. files.append(*new CFileMatch(name, &fileTree, isSuper));
  7592. }
  7593. CScope *addScope(const char *scope)
  7594. {
  7595. CScope *subScope = new CScope(scope);
  7596. subScopes.append(*subScope);
  7597. return subScope;
  7598. }
  7599. void popLastScope()
  7600. {
  7601. subScopes.pop();
  7602. }
  7603. CIArrayOf<CScope> &querySubScopes() { return subScopes; }
  7604. CFileMatchArray &queryFiles() { return files; }
  7605. };
  7606. typedef CIArrayOf<CScope> CScopeArray;
  7607. class CFileScanner
  7608. {
  7609. bool recursive;
  7610. bool includesuper;
  7611. StringAttr wildname;
  7612. Owned<CScope> topLevelScope;
  7613. CScope *currentScope;
  7614. bool scopeMatch(const char *name)
  7615. { // name has trailing '::'
  7616. if (!*name)
  7617. return true;
  7618. if (wildname.isEmpty())
  7619. return true;
  7620. const char *s1 = wildname.get();
  7621. const char *s2 = name;
  7622. while (*s2) {
  7623. if (*s1=='*') {
  7624. if (recursive)
  7625. return true;
  7626. if (*s2==':')
  7627. return false;
  7628. // '*' can only come at end of scope in non-recursive
  7629. while (*s1&&(*s1!=':'))
  7630. s1++;
  7631. while (*s2&&(*s2!=':'))
  7632. s2++;
  7633. }
  7634. else if ((*s1==*s2)||(*s1=='?')) {
  7635. s1++;
  7636. s2++;
  7637. }
  7638. else
  7639. return false;
  7640. }
  7641. return true;
  7642. }
  7643. bool processScopes(IPropertyTree &root,StringBuffer &name)
  7644. {
  7645. bool ret = false;
  7646. CScope *parentScope = currentScope;
  7647. if (parentScope)
  7648. currentScope = parentScope->addScope(name);
  7649. else
  7650. { // once only
  7651. topLevelScope.setown(new CScope(""));
  7652. currentScope = topLevelScope;
  7653. }
  7654. size32_t ns = name.length();
  7655. if (ns)
  7656. name.append("::");
  7657. size32_t ns2 = name.length();
  7658. if (scopeMatch(name.str())) {
  7659. Owned<IPropertyTreeIterator> iter = root.getElements(queryDfsXmlBranchName(DXB_Scope));
  7660. if (iter->first()) {
  7661. do {
  7662. IPropertyTree &scope = iter->query();
  7663. if (scope.hasChildren()) {
  7664. name.append(scope.queryProp("@name"));
  7665. ret |= processScopes(scope, name);
  7666. name.setLength(ns2);
  7667. }
  7668. } while (iter->next());
  7669. }
  7670. ret |= processFiles(root,name);
  7671. }
  7672. if (!ret && parentScope)
  7673. parentScope->popLastScope(); // discard scopes where no matches
  7674. currentScope = parentScope;
  7675. name.setLength(ns);
  7676. return ret;
  7677. }
  7678. bool processFiles(IPropertyTree &root,StringBuffer &name)
  7679. {
  7680. bool ret = false;
  7681. const char *s1 = wildname.get();
  7682. size32_t ns = name.length();
  7683. Owned<IPropertyTreeIterator> iter = root.getElements(queryDfsXmlBranchName(DXB_File));
  7684. if (iter->first()) {
  7685. IPropertyTree &scope = iter->query();
  7686. do {
  7687. IPropertyTree &file = iter->query();
  7688. name.append(file.queryProp("@name"));
  7689. if (!s1||WildMatch(name.str(),s1,true)) {
  7690. currentScope->addMatch(name,file,false);
  7691. ret = true;
  7692. }
  7693. name.setLength(ns);
  7694. } while (iter->next());
  7695. }
  7696. if (includesuper) {
  7697. iter.setown(root.getElements(queryDfsXmlBranchName(DXB_SuperFile)));
  7698. if (iter->first()) {
  7699. do {
  7700. IPropertyTree &file = iter->query();
  7701. name.append(file.queryProp("@name"));
  7702. if (!s1||WildMatch(name.str(),s1,true)) {
  7703. currentScope->addMatch(name,file,true);
  7704. ret = true;
  7705. }
  7706. name.setLength(ns);
  7707. } while (iter->next());
  7708. }
  7709. }
  7710. return ret;
  7711. }
  7712. public:
  7713. void scan(IPropertyTree *sroot, const char *_wildname,bool _recursive,bool _includesuper)
  7714. {
  7715. if (_wildname)
  7716. wildname.set(_wildname);
  7717. else
  7718. wildname.clear();
  7719. recursive = _recursive;
  7720. includesuper = _includesuper;
  7721. StringBuffer name;
  7722. topLevelScope.clear();
  7723. currentScope = NULL;
  7724. processScopes(*sroot->queryPropTree(querySdsFilesRoot()),name);
  7725. }
  7726. void _getResults(bool auth, IUserDescriptor *user, CScope &scope, CFileMatchArray &matchingFiles, StringArray &authScopes, unsigned &count)
  7727. {
  7728. if (auth)
  7729. {
  7730. int perm = getScopePermissions(scope.getName(),user,0); // don't audit
  7731. if (!HASREADPERMISSION(perm))
  7732. return;
  7733. authScopes.append(scope.getName());
  7734. }
  7735. CFileMatchArray &files = scope.queryFiles();
  7736. ForEachItemIn(f, files)
  7737. {
  7738. CFileMatch *match = &files.item(f);
  7739. matchingFiles.append(*LINK(match));
  7740. ++count;
  7741. }
  7742. CScopeArray &subScopes = scope.querySubScopes();
  7743. ForEachItemIn(s, subScopes)
  7744. {
  7745. CScope &subScope = subScopes.item(s);
  7746. _getResults(auth, user, subScope, matchingFiles, authScopes, count);
  7747. }
  7748. }
  7749. unsigned getResults(bool auth, IUserDescriptor *user, CFileMatchArray &matchingFiles, StringArray &authScopes)
  7750. {
  7751. unsigned count = 0;
  7752. _getResults(auth, user, *topLevelScope, matchingFiles, authScopes, count);
  7753. return count;
  7754. }
  7755. };
  7756. struct CMachineEntry: public CInterface
  7757. {
  7758. CMachineEntry(const char *_mname,SocketEndpoint _ep)
  7759. : mname(_mname),ep(_ep)
  7760. {
  7761. }
  7762. StringAttr mname;
  7763. SocketEndpoint ep;
  7764. };
  7765. typedef CMachineEntry *CMachineEntryPtr;
  7766. typedef MapStringTo<CMachineEntryPtr> CMachineEntryMap;
  7767. StringBuffer &getClusterGroupName(IPropertyTree &cluster, StringBuffer &groupName)
  7768. {
  7769. const char *name = cluster.queryProp("@name");
  7770. const char *nodeGroupName = cluster.queryProp("@nodeGroup");
  7771. if (nodeGroupName && *nodeGroupName)
  7772. name = nodeGroupName;
  7773. groupName.append(name);
  7774. return groupName.trim().toLowerCase();
  7775. }
  7776. StringBuffer &getClusterSpareGroupName(IPropertyTree &cluster, StringBuffer &groupName)
  7777. {
  7778. return getClusterGroupName(cluster, groupName).append("_spares");
  7779. }
  7780. // JCSMORE - dfs group handling may be clearer if in own module
  7781. class CInitGroups
  7782. {
  7783. CMachineEntryMap machinemap;
  7784. CIArrayOf<CMachineEntry> machinelist;
  7785. CConnectLock groupsconnlock;
  7786. StringArray clusternames;
  7787. unsigned defaultTimeout;
  7788. bool clusterGroupCompare(IPropertyTree *newClusterGroup, IPropertyTree *oldClusterGroup)
  7789. {
  7790. if (!newClusterGroup && oldClusterGroup)
  7791. return false;
  7792. else if (!oldClusterGroup && newClusterGroup)
  7793. return false;
  7794. if (!newClusterGroup) // both null
  7795. return true;
  7796. // see if identical
  7797. const char *oldKind = oldClusterGroup?oldClusterGroup->queryProp("@kind"):NULL;
  7798. const char *oldDir = oldClusterGroup?oldClusterGroup->queryProp("@dir"):NULL;
  7799. const char *newKind = newClusterGroup?newClusterGroup->queryProp("@kind"):NULL;
  7800. const char *newDir = newClusterGroup?newClusterGroup->queryProp("@dir"):NULL;
  7801. if (oldKind) {
  7802. if (newKind) {
  7803. if (!streq(newKind, newKind))
  7804. return false;
  7805. }
  7806. else
  7807. return false;
  7808. }
  7809. else if (newKind)
  7810. return false;
  7811. if (oldDir) {
  7812. if (newDir) {
  7813. if (!streq(newDir,oldDir))
  7814. return false;
  7815. }
  7816. else
  7817. return false;
  7818. }
  7819. else if (NULL!=newDir)
  7820. return false;
  7821. unsigned oldGroupCount = oldClusterGroup->getCount("Node");
  7822. unsigned newGroupCount = newClusterGroup->getCount("Node");
  7823. if (oldGroupCount != newGroupCount)
  7824. return false;
  7825. if (0 == newGroupCount)
  7826. return true;
  7827. Owned<IPropertyTreeIterator> newIter = newClusterGroup->getElements("Node");
  7828. Owned<IPropertyTreeIterator> oldIter = oldClusterGroup->getElements("Node");
  7829. if (newIter->first() && oldIter->first()) {
  7830. loop {
  7831. const char *oldIp = oldIter->query().queryProp("@ip");
  7832. const char *newIp = newIter->query().queryProp("@ip");
  7833. if (!streq(oldIp, newIp))
  7834. return false;
  7835. if (!oldIter->next() || !newIter->next())
  7836. break;
  7837. }
  7838. }
  7839. return true;
  7840. }
  7841. void addClusterGroup(const char *name, IPropertyTree *newClusterGroup, bool realCluster)
  7842. {
  7843. VStringBuffer prop("Group[@name=\"%s\"]", name);
  7844. IPropertyTree *root = groupsconnlock.conn->queryRoot();
  7845. IPropertyTree *old = root->queryPropTree(prop.str());
  7846. if (old) {
  7847. // JCSMORE
  7848. // clone
  7849. // iterate through files and point to clone
  7850. // i) if change is minor, worth swapping to new group anyway?
  7851. // ii) if old group has machines that are no longer in new environment, mark file bad?
  7852. root->removeTree(old);
  7853. }
  7854. if (!newClusterGroup)
  7855. return;
  7856. if (realCluster)
  7857. clusternames.append(name);
  7858. IPropertyTree *grp = root->addPropTree("Group", newClusterGroup);
  7859. grp->setProp("@name", name);
  7860. }
  7861. IGroup *getGroupFromCluster(GroupType groupType, IPropertyTree &cluster)
  7862. {
  7863. SocketEndpointArray eps;
  7864. const char *processName=NULL;
  7865. switch (groupType) {
  7866. case grp_thor:
  7867. processName = "ThorSlaveProcess";
  7868. break;
  7869. case grp_thorspares:
  7870. processName = "ThorSpareProcess";
  7871. break;
  7872. case grp_roxie:
  7873. processName = "RoxieServerProcess";
  7874. break;
  7875. default:
  7876. throwUnexpected();
  7877. }
  7878. SocketEndpoint nullep;
  7879. Owned<IPropertyTreeIterator> nodes = cluster.getElements(processName);
  7880. ForEach(*nodes) {
  7881. IPropertyTree &node = nodes->query();
  7882. SocketEndpoint ep;
  7883. const char *computer = node.queryProp("@computer");
  7884. const char *netAddress = node.queryProp("@netAddress");
  7885. if (computer && *computer)
  7886. {
  7887. CMachineEntryPtr *m = machinemap.getValue(computer);
  7888. if (!m) {
  7889. ERRLOG("Cannot construct %s, computer name %s not found\n", cluster.queryProp("@name"), computer);
  7890. return NULL;
  7891. }
  7892. ep.set((*m)->ep);
  7893. }
  7894. else if (netAddress && *netAddress)
  7895. {
  7896. ep.set(netAddress, 0);
  7897. }
  7898. else
  7899. {
  7900. ERRLOG("Cannot construct %s, missing computer spec on node\n", cluster.queryProp("@name"));
  7901. return NULL;
  7902. }
  7903. switch (groupType) {
  7904. case grp_roxie:
  7905. // Redundant copies are located via the flags.
  7906. // Old environments may contain duplicated sever information for multiple ports
  7907. eps.appendUniq(ep);
  7908. break;
  7909. case grp_thor:
  7910. case grp_thorspares:
  7911. eps.append(ep);
  7912. break;
  7913. default:
  7914. throwUnexpected();
  7915. }
  7916. }
  7917. if (!eps.ordinality())
  7918. return NULL;
  7919. Owned<IGroup> grp;
  7920. unsigned slavesPerNode = 0;
  7921. if (grp_thor == groupType)
  7922. slavesPerNode = cluster.getPropInt("@slavesPerNode");
  7923. if (slavesPerNode)
  7924. {
  7925. SocketEndpointArray msEps;
  7926. for (unsigned s=0; s<slavesPerNode; s++) {
  7927. ForEachItemIn(e, eps)
  7928. msEps.append(eps.item(e));
  7929. }
  7930. grp.setown(createIGroup(msEps));
  7931. }
  7932. else
  7933. grp.setown(createIGroup(eps));
  7934. return grp.getClear();
  7935. }
  7936. bool loadMachineMap()
  7937. {
  7938. Owned<IRemoteConnection> conn = querySDS().connect("/Environment/Hardware", myProcessSession(), RTM_LOCK_READ, SDS_CONNECT_TIMEOUT);
  7939. if (!conn) {
  7940. WARNLOG("Cannot connect to /Environment/Hardware");
  7941. return false;
  7942. }
  7943. IPropertyTree* root = conn->queryRoot();
  7944. Owned<IPropertyTreeIterator> machines= root->getElements("Computer");
  7945. ForEach(*machines) {
  7946. IPropertyTree &machine = machines->query();
  7947. SocketEndpoint ep(machine.queryProp("@netAddress"));
  7948. const char *name = machine.queryProp("@name");
  7949. CMachineEntry *entry = new CMachineEntry(name,ep);
  7950. machinemap.setValue(name, entry);
  7951. machinelist.append(*entry);
  7952. }
  7953. return true;
  7954. }
  7955. IPropertyTree *createClusterGroup(GroupType groupType, IGroup *group, const char *dir, bool realCluster)
  7956. {
  7957. Owned<IPropertyTree> cluster = createPTree("Group");
  7958. if (realCluster)
  7959. cluster->setPropBool("@cluster", true);
  7960. const char *kind=NULL;
  7961. switch (groupType) {
  7962. case grp_thor:
  7963. kind = "Thor";
  7964. break;
  7965. case grp_roxie:
  7966. kind = "Roxie";
  7967. break;
  7968. case grp_hthor:
  7969. kind = "hthor";
  7970. break;
  7971. }
  7972. if (kind)
  7973. cluster->setProp("@kind",kind);
  7974. if (dir)
  7975. cluster->setProp("@dir",dir);
  7976. Owned<INodeIterator> iter = group->getIterator();
  7977. StringBuffer str;
  7978. ForEach(*iter) {
  7979. iter->query().endpoint().getIpText(str.clear());
  7980. IPropertyTree *n = createPTree("Node");
  7981. n->setProp("@ip",str.str());
  7982. cluster->addPropTree("Node", n);
  7983. }
  7984. return cluster.getClear();
  7985. }
  7986. IPropertyTree *createClusterGroupFromEnvCluster(GroupType groupType, IPropertyTree &cluster, const char *dir, bool realCluster)
  7987. {
  7988. Owned<IGroup> group = getGroupFromCluster(groupType, cluster);
  7989. if (!group)
  7990. return NULL;
  7991. return createClusterGroup(groupType, group, dir, realCluster);
  7992. }
  7993. bool constructGroup(IPropertyTree &cluster, const char *altName, IPropertyTree *oldEnvCluster, GroupType groupType, bool force, StringBuffer &messages)
  7994. {
  7995. /* a 'realCluster' is a cluster who's name matches it's nodeGroup
  7996. * if the nodeGroup differs it implies it's sharing the nodeGroup with other thor instance(s).
  7997. */
  7998. bool realCluster = true;
  7999. bool oldRealCluster = true;
  8000. StringBuffer gname, oldGname;
  8001. const char *defDir = NULL;
  8002. switch (groupType)
  8003. {
  8004. case grp_thor:
  8005. getClusterGroupName(cluster, gname);
  8006. if (!streq(cluster.queryProp("@name"), gname.str()))
  8007. realCluster = false;
  8008. if (oldEnvCluster)
  8009. {
  8010. getClusterGroupName(*oldEnvCluster, oldGname);
  8011. if (!streq(oldEnvCluster->queryProp("@name"), oldGname.str()))
  8012. oldRealCluster = false;
  8013. }
  8014. break;
  8015. case grp_thorspares:
  8016. getClusterSpareGroupName(cluster, gname);
  8017. realCluster = false;
  8018. break;
  8019. case grp_roxie:
  8020. gname.append(cluster.queryProp("@name"));
  8021. break;
  8022. default:
  8023. throwUnexpected();
  8024. }
  8025. if (altName)
  8026. gname.clear().append(altName).toLowerCase();
  8027. VStringBuffer xpath("Group[@name=\"%s\"]", gname.str());
  8028. IPropertyTree *existingClusterGroup = groupsconnlock.conn->queryRoot()->queryPropTree(xpath.str()); // 'live' cluster group
  8029. bool matchOldEnv = false;
  8030. Owned<IPropertyTree> newClusterGroup = createClusterGroupFromEnvCluster(groupType, cluster, defDir, realCluster);
  8031. bool matchExisting = clusterGroupCompare(newClusterGroup, existingClusterGroup);
  8032. if (oldEnvCluster)
  8033. {
  8034. // new matches old, only if neither has changed it's name to mismatch it's nodeGroup name
  8035. if (realCluster == oldRealCluster)
  8036. {
  8037. Owned<IPropertyTree> oldClusterGroup = createClusterGroupFromEnvCluster(groupType, *oldEnvCluster, defDir, oldRealCluster);
  8038. matchOldEnv = clusterGroupCompare(newClusterGroup, oldClusterGroup);
  8039. }
  8040. else
  8041. matchOldEnv = false;
  8042. }
  8043. if (force && !matchExisting)
  8044. {
  8045. VStringBuffer msg("Forcing new group layout for %s [ matched active = %s, matched old environment = %s ]", gname.str(), matchExisting?"true":"false", matchOldEnv?"true":"false");
  8046. WARNLOG("%s", msg.str());
  8047. messages.append(msg).newline();
  8048. matchExisting = matchOldEnv = false;
  8049. }
  8050. if (!existingClusterGroup || (!matchExisting && !matchOldEnv))
  8051. {
  8052. VStringBuffer msg("New cluster layout for cluster %s", gname.str());
  8053. WARNLOG("%s", msg.str());
  8054. messages.append(msg).newline();
  8055. addClusterGroup(gname.str(), newClusterGroup.getClear(), realCluster);
  8056. return true;
  8057. }
  8058. return false;
  8059. }
  8060. void constructHThorGroups(IPropertyTree &cluster)
  8061. {
  8062. const char *groupname = cluster.queryProp("@name");
  8063. if (!groupname || !*groupname)
  8064. return;
  8065. unsigned ins = 0;
  8066. Owned<IPropertyTreeIterator> insts = cluster.getElements("Instance");
  8067. ForEach(*insts) {
  8068. const char *na = insts->query().queryProp("@netAddress");
  8069. if (na&&*na) {
  8070. SocketEndpoint ep(na);
  8071. if (!ep.isNull()) {
  8072. ins++;
  8073. VStringBuffer gname("hthor__%s", groupname);
  8074. if (ins>1)
  8075. gname.append('_').append(ins);
  8076. Owned<IGroup> group = createIGroup(1, &ep);
  8077. Owned<IPropertyTree> clusterGroup = createClusterGroup(grp_hthor, group, NULL, true);
  8078. addClusterGroup(gname.str(), clusterGroup.getClear(), true);
  8079. }
  8080. }
  8081. }
  8082. }
  8083. enum CgCmd { cg_null, cg_reset, cg_add, cg_remove };
  8084. public:
  8085. CInitGroups(unsigned _defaultTimeout)
  8086. : groupsconnlock("constructGroup",SDS_GROUPSTORE_ROOT,true,false,false,_defaultTimeout)
  8087. {
  8088. defaultTimeout = _defaultTimeout;
  8089. }
  8090. bool doClusterGroup(CgCmd cmd, const char *_clusterName, const char *type, bool spares, SocketEndpointArray *eps, StringBuffer &messages)
  8091. {
  8092. Owned<IRemoteConnection> conn = querySDS().connect("/Environment/Software", myProcessSession(), RTM_LOCK_READ, SDS_CONNECT_TIMEOUT);
  8093. if (!conn)
  8094. return false;
  8095. if (!_clusterName || !*_clusterName)
  8096. return false;
  8097. StringAttr clusterName = _clusterName;
  8098. clusterName.toLowerCase();
  8099. if (!type || !*type)
  8100. return false;
  8101. bool ret = true;
  8102. IPropertyTree* root = conn->queryRoot();
  8103. Owned<IPropertyTreeIterator> clusters;
  8104. StringBuffer errMsg;
  8105. const char *clusterType = type;
  8106. if (loadMachineMap()) {
  8107. VStringBuffer xpath("%s[@name=\"%s\"]", type, clusterName.get());
  8108. clusters.setown(root->getElements(xpath.str()));
  8109. if (!clusters || !clusters->first()) {
  8110. VStringBuffer errMsg("Could not find type %s, %s cluster", type, clusterName.get());
  8111. WARNLOG("%s", errMsg.str());
  8112. messages.append(errMsg).newline();
  8113. ret = false;
  8114. }
  8115. else {
  8116. if (!streq("ThorCluster", type))
  8117. return false; // currently only Thor supported here.
  8118. IPropertyTree &cluster = clusters->query();
  8119. switch (cmd) {
  8120. case cg_reset:
  8121. {
  8122. if (spares) {
  8123. if (!constructGroup(cluster,NULL,NULL,grp_thorspares,true,messages))
  8124. ret = false;
  8125. }
  8126. else {
  8127. if (!constructGroup(cluster,NULL,NULL,grp_thor,true,messages))
  8128. ret = false;
  8129. }
  8130. break;
  8131. }
  8132. case cg_add:
  8133. {
  8134. assertex(eps);
  8135. StringBuffer groupName;
  8136. getClusterSpareGroupName(cluster, groupName);
  8137. IPropertyTree *root = groupsconnlock.conn->queryRoot();
  8138. VStringBuffer xpath("Group[@name=\"%s\"]",groupName.str());
  8139. IPropertyTree *existing = root->queryPropTree(xpath.str());
  8140. if (existing) {
  8141. Owned<IPropertyTreeIterator> iter = existing->getElements("Node");
  8142. ForEach(*iter) {
  8143. SocketEndpoint ep(iter->query().queryProp("@ip"));
  8144. if (eps->zap(ep)) {
  8145. StringBuffer epStr;
  8146. VStringBuffer errMsg("addSpares: not adding: %s, already in spares", ep.getUrlStr(epStr).str());
  8147. WARNLOG("%s", errMsg.str());
  8148. messages.append(errMsg).newline();
  8149. while (eps->zap(ep)); // delete any other duplicates
  8150. }
  8151. }
  8152. }
  8153. else {
  8154. existing = createPTree();
  8155. existing->setProp("@name", groupName.str());
  8156. existing = root->addPropTree("Group", existing);
  8157. }
  8158. // add remaining
  8159. ForEachItemIn(e, *eps) {
  8160. SocketEndpoint &ep = eps->item(e);
  8161. StringBuffer ipStr;
  8162. ep.getIpText(ipStr);
  8163. IPropertyTree *node = createPTree();
  8164. node->setProp("@ip", ipStr.str());
  8165. existing->addPropTree("Node", node);
  8166. }
  8167. break;
  8168. }
  8169. case cg_remove:
  8170. {
  8171. assertex(eps);
  8172. StringBuffer groupName;
  8173. getClusterSpareGroupName(cluster, groupName);
  8174. IPropertyTree *root = groupsconnlock.conn->queryRoot();
  8175. VStringBuffer xpath("Group[@name=\"%s\"]", groupName.str());
  8176. IPropertyTree *existing = root->queryPropTree(xpath.str());
  8177. if (existing) {
  8178. ForEachItemIn(e, *eps) {
  8179. SocketEndpoint &ep = eps->item(e);
  8180. StringBuffer ipStr;
  8181. ep.getIpText(ipStr);
  8182. VStringBuffer xpath("Node[@ip=\"%s\"]", ipStr.str());
  8183. if (!existing->removeProp(xpath.str())) {
  8184. VStringBuffer errMsg("removeSpares: %s not found in spares", ipStr.str());
  8185. WARNLOG("%s", errMsg.str());
  8186. messages.append(errMsg).newline();
  8187. while (eps->zap(ep)); // delete any other duplicates
  8188. }
  8189. else
  8190. while (existing->removeProp(xpath.str())); // remove any others, shouldn't be any
  8191. }
  8192. }
  8193. break;
  8194. }
  8195. }
  8196. if (clusters->next()) {
  8197. VStringBuffer errMsg("resetThorGroup: more than one cluster named: %s", clusterName.get());
  8198. WARNLOG("%s", errMsg.str());
  8199. messages.append(errMsg).newline();
  8200. ret = false;
  8201. }
  8202. }
  8203. }
  8204. return ret;
  8205. }
  8206. bool resetClusterGroup(const char *clusterName, const char *type, bool spares, StringBuffer &messages)
  8207. {
  8208. return doClusterGroup(cg_reset, clusterName, type, spares, NULL, messages);
  8209. }
  8210. bool addSpares(const char *clusterName, const char *type, SocketEndpointArray &eps, StringBuffer &messages)
  8211. {
  8212. return doClusterGroup(cg_add, clusterName, type, true, &eps, messages);
  8213. }
  8214. bool removeSpares(const char *clusterName, const char *type, SocketEndpointArray &eps, StringBuffer &messages)
  8215. {
  8216. return doClusterGroup(cg_remove, clusterName, type, true, &eps, messages);
  8217. }
  8218. void constructGroups(bool force, StringBuffer &messages, IPropertyTree *oldEnvironment)
  8219. {
  8220. Owned<IRemoteConnection> conn = querySDS().connect("/Environment/Software", myProcessSession(), RTM_LOCK_READ, SDS_CONNECT_TIMEOUT);
  8221. if (!conn)
  8222. return;
  8223. clusternames.kill();
  8224. IPropertyTree* root = conn->queryRoot();
  8225. Owned<IPropertyTreeIterator> clusters;
  8226. if (loadMachineMap()) {
  8227. clusters.setown(root->getElements("ThorCluster"));
  8228. ForEach(*clusters) {
  8229. IPropertyTree &cluster = clusters->query();
  8230. IPropertyTree *oldCluster = NULL;
  8231. if (oldEnvironment) {
  8232. VStringBuffer xpath("Software/ThorCluster[@name=\"%s\"]", cluster.queryProp("@name"));
  8233. oldCluster = oldEnvironment->queryPropTree(xpath.str());
  8234. }
  8235. constructGroup(cluster,NULL,oldCluster,grp_thor,force,messages);
  8236. constructGroup(cluster,NULL,oldCluster,grp_thorspares,force,messages);
  8237. }
  8238. clusters.setown(root->getElements("RoxieCluster"));
  8239. ForEach(*clusters) {
  8240. IPropertyTree &cluster = clusters->query();
  8241. IPropertyTree *oldCluster = NULL;
  8242. if (oldEnvironment) {
  8243. VStringBuffer xpath("Software/RoxieCluster[@name=\"%s\"]", cluster.queryProp("@name"));
  8244. oldCluster = oldEnvironment->queryPropTree(xpath.str());
  8245. }
  8246. constructGroup(cluster,NULL,oldCluster,grp_roxie,force,messages);
  8247. }
  8248. clusters.setown(root->getElements("EclAgentProcess"));
  8249. ForEach(*clusters) {
  8250. IPropertyTree &cluster = clusters->query();
  8251. constructHThorGroups(cluster);
  8252. }
  8253. // correct cluster flags
  8254. // JCSMORE - why was this necessary, may well be legacy..
  8255. Owned<IPropertyTreeIterator> grps = groupsconnlock.conn->queryRoot()->getElements("Group");
  8256. ForEach(*grps) {
  8257. IPropertyTree &grp = grps->query();
  8258. const char *name = grp.queryProp("@name");
  8259. bool iscluster = NotFound != clusternames.find(name);
  8260. if (iscluster!=grp.getPropBool("@cluster"))
  8261. if (iscluster)
  8262. grp.setPropBool("@cluster", true);
  8263. else
  8264. grp.removeProp("@cluster");
  8265. }
  8266. }
  8267. }
  8268. };
  8269. void initClusterGroups(bool force, StringBuffer &response, IPropertyTree *oldEnvironment, unsigned timems)
  8270. {
  8271. CInitGroups init(timems);
  8272. init.constructGroups(force, response, oldEnvironment);
  8273. }
  8274. bool resetClusterGroup(const char *clusterName, const char *type, bool spares, StringBuffer &response, unsigned timems)
  8275. {
  8276. CInitGroups init(timems);
  8277. return init.resetClusterGroup(clusterName, type, spares, response);
  8278. }
  8279. bool addClusterSpares(const char *clusterName, const char *type, SocketEndpointArray &eps, StringBuffer &response, unsigned timems)
  8280. {
  8281. CInitGroups init(timems);
  8282. return init.addSpares(clusterName, type, eps, response);
  8283. }
  8284. bool removeClusterSpares(const char *clusterName, const char *type, SocketEndpointArray &eps, StringBuffer &response, unsigned timems)
  8285. {
  8286. CInitGroups init(timems);
  8287. return init.removeSpares(clusterName, type, eps, response);
  8288. }
  8289. class CDaliDFSServer: public Thread, public CTransactionLogTracker, implements IDaliServer, implements IExceptionHandler
  8290. { // Coven size
  8291. bool stopped;
  8292. unsigned defaultTimeout;
  8293. unsigned numThreads;
  8294. public:
  8295. IMPLEMENT_IINTERFACE;
  8296. CDaliDFSServer(IPropertyTree *config)
  8297. : Thread("CDaliDFSServer"), CTransactionLogTracker(MDFS_MAX)
  8298. {
  8299. stopped = true;
  8300. defaultTimeout = INFINITE; // server uses default
  8301. numThreads = config->getPropInt("DFS/@numThreads", DEFAULT_NUM_DFS_THREADS);
  8302. PROGLOG("DFS Server: numThreads=%d", numThreads);
  8303. }
  8304. ~CDaliDFSServer()
  8305. {
  8306. }
  8307. void start()
  8308. {
  8309. Thread::start();
  8310. }
  8311. void ready()
  8312. {
  8313. }
  8314. void suspend()
  8315. {
  8316. }
  8317. void stop()
  8318. {
  8319. if (!stopped) {
  8320. stopped = true;
  8321. queryCoven().cancel(RANK_ALL,MPTAG_DFS_REQUEST);
  8322. }
  8323. join();
  8324. }
  8325. int run()
  8326. {
  8327. ICoven &coven=queryCoven();
  8328. CMessageHandler<CDaliDFSServer> handler("CDaliDFSServer", this, &CDaliDFSServer::processMessage, this, numThreads, TIMEOUT_ON_CLOSEDOWN, INFINITE);
  8329. CMessageBuffer mb;
  8330. stopped = false;
  8331. while (!stopped)
  8332. {
  8333. try
  8334. {
  8335. mb.clear();
  8336. if (coven.recv(mb,RANK_ALL,MPTAG_DFS_REQUEST,NULL))
  8337. {
  8338. handler.handleMessage(mb);
  8339. mb.clear(); // ^ has copied mb
  8340. }
  8341. else
  8342. stopped = true;
  8343. }
  8344. catch (IException *e)
  8345. {
  8346. EXCLOG(e, "CDaliDFSServer");
  8347. e->Release();
  8348. }
  8349. }
  8350. return 0;
  8351. }
  8352. void iterateFiles(CMessageBuffer &mb,StringBuffer &trc)
  8353. {
  8354. TransactionLog transactionLog(*this, MDFS_ITERATE_FILES, mb.getSender());
  8355. StringAttr wildname;
  8356. bool recursive;
  8357. bool includesuper = false;
  8358. StringAttr attr;
  8359. mb.read(wildname).read(recursive).read(attr);
  8360. trc.appendf("iterateFiles(%s,%s,%s)",wildname.sget(),recursive?"recursive":"",attr.sget());
  8361. if (queryTransactionLogging())
  8362. transactionLog.log("%s", trc.str());
  8363. Owned<IUserDescriptor> udesc;
  8364. if (mb.getPos()<mb.length()) {
  8365. mb.read(includesuper);
  8366. if (mb.getPos()<mb.length()) {
  8367. udesc.setown(createUserDescriptor());
  8368. udesc->deserialize(mb);
  8369. }
  8370. }
  8371. mb.clear();
  8372. unsigned count=0;
  8373. mb.append(count);
  8374. CFileScanner scanner;
  8375. CSDSServerLockBlock sdsLock; // lock sds while scanning
  8376. unsigned start = msTick();
  8377. scanner.scan(sdsLock, wildname.get(),recursive,includesuper);
  8378. unsigned tookMs = msTick()-start;
  8379. if (tookMs>100)
  8380. PROGLOG("TIMING(filescan): %s: took %dms",trc.str(), tookMs);
  8381. sdsLock.unlock(); // unlock to perform authentification
  8382. bool auth = querySessionManager().checkScopeScansLDAP()&&getScopePermissions(NULL,udesc,(unsigned)-1);
  8383. StringArray authScopes;
  8384. CIArrayOf<CFileMatch> matchingFiles;
  8385. start = msTick();
  8386. count = scanner.getResults(auth, udesc, matchingFiles, authScopes);
  8387. tookMs = msTick()-start;
  8388. if (tookMs>100)
  8389. PROGLOG("TIMING(LDAP): %s: took %dms, %d lookups, file matches = %d", trc.str(), tookMs, authScopes.ordinality(), count);
  8390. sdsLock.lock(); // re-lock sds while serializing
  8391. start = msTick();
  8392. ForEachItemIn(m, matchingFiles)
  8393. {
  8394. CFileMatch &fileMatch = matchingFiles.item(m);
  8395. CDFAttributeIterator::serializeFileAttributes(mb, fileMatch.queryFileTree(), fileMatch.queryName(), fileMatch.queryIsSuper());
  8396. }
  8397. tookMs = msTick()-start;
  8398. if (tookMs>100)
  8399. PROGLOG("TIMING(filescan-serialization): %s: took %dms, %d files",trc.str(), tookMs, count);
  8400. mb.writeDirect(0,sizeof(count),&count);
  8401. }
  8402. void iterateRelationships(CMessageBuffer &mb,StringBuffer &trc)
  8403. {
  8404. TransactionLog transactionLog(*this, MDFS_ITERATE_RELATIONSHIPS, mb.getSender());
  8405. StringAttr primary;
  8406. StringAttr secondary;
  8407. StringAttr primflds;
  8408. StringAttr secflds;
  8409. StringAttr kind;
  8410. StringAttr cardinality;
  8411. byte payloadb;
  8412. mb.read(primary).read(secondary).read(primflds).read(secflds).read(kind).read(cardinality).read(payloadb);
  8413. mb.clear();
  8414. bool payload = (payloadb==1);
  8415. trc.appendf("iterateRelationships(%s,%s,%s,%s,%s,%s,%d)",primary.sget(),secondary.sget(),primflds.sget(),secflds.sget(),kind.sget(),cardinality.sget(),(int)payloadb);
  8416. if (queryTransactionLogging())
  8417. transactionLog.log("%s", trc.str());
  8418. unsigned start = msTick();
  8419. unsigned count=0;
  8420. CSDSServerLockBlock sdsLock; // lock sds while scanning
  8421. StringBuffer xpath;
  8422. CDistributedFileDirectory::getFileRelationshipXPath(xpath,primary,secondary,primflds,secflds,kind,cardinality,((payloadb==0)||(payloadb==1))?&payload:NULL);
  8423. IPropertyTree *root = sdsLock->queryPropTree(querySdsRelationshipsRoot());
  8424. Owned<IPropertyTreeIterator> iter = root?root->getElements(xpath.str()):NULL;
  8425. mb.append(count);
  8426. // save as sequence of branches
  8427. if (iter) {
  8428. ForEach(*iter.get()) {
  8429. iter->query().serialize(mb);
  8430. count++;
  8431. }
  8432. }
  8433. if (msTick()-start>100) {
  8434. PROGLOG("TIMING(relationshipscan): %s: took %dms, %d relations",trc.str(),msTick()-start,count);
  8435. }
  8436. mb.writeDirect(0,sizeof(count),&count);
  8437. }
  8438. void setFileAccessed(CMessageBuffer &mb,StringBuffer &trc)
  8439. {
  8440. TransactionLog transactionLog(*this, MDFS_SET_FILE_ACCESSED, mb.getSender());
  8441. StringAttr lname;
  8442. mb.read(lname);
  8443. CDateTime dt;
  8444. dt.deserialize(mb);
  8445. trc.appendf("setFileAccessed(%s)",lname.sget());
  8446. Owned<IUserDescriptor> udesc;
  8447. if (mb.getPos()<mb.length()) {
  8448. udesc.setown(createUserDescriptor());
  8449. udesc->deserialize(mb);
  8450. }
  8451. if (queryTransactionLogging())
  8452. transactionLog.log("%s", trc.str());
  8453. mb.clear();
  8454. StringBuffer tail;
  8455. CDfsLogicalFileName dlfn;
  8456. dlfn.set(lname);
  8457. if (!checkLogicalName(dlfn,udesc,true,false,true,"setFileAccessed on"))
  8458. return;
  8459. CScopeConnectLock sconnlock("setFileAccessed", dlfn, false, false, false, defaultTimeout);
  8460. IPropertyTree* sroot = sconnlock.conn()?sconnlock.conn()->queryRoot():NULL;
  8461. dlfn.getTail(tail);
  8462. Owned<IPropertyTree> tree = getNamedPropTree(sroot,queryDfsXmlBranchName(DXB_File),"@name",tail.str(),false);
  8463. if (tree) {
  8464. StringBuffer str;
  8465. tree->setProp("@accessed",dt.getString(str).str());
  8466. }
  8467. }
  8468. void setFileProtect(CMessageBuffer &mb,StringBuffer &trc)
  8469. {
  8470. TransactionLog transactionLog(*this, MDFS_SET_FILE_PROTECT, mb.getSender());
  8471. StringAttr lname;
  8472. StringAttr owner;
  8473. bool set;
  8474. mb.read(lname).read(owner).read(set);
  8475. trc.appendf("setFileProtect(%s,%s,%s)",lname.sget(),owner.sget(),set?"true":"false");
  8476. if (queryTransactionLogging())
  8477. transactionLog.log("%s", trc.str());
  8478. Owned<IUserDescriptor> udesc;
  8479. if (mb.getPos()<mb.length()) {
  8480. udesc.setown(createUserDescriptor());
  8481. udesc->deserialize(mb);
  8482. }
  8483. mb.clear();
  8484. StringBuffer tail;
  8485. CDfsLogicalFileName dlfn;
  8486. dlfn.set(lname);
  8487. if (!checkLogicalName(dlfn,udesc,true,false,true,"setFileProtect"))
  8488. return;
  8489. CScopeConnectLock sconnlock("setFileProtect", dlfn, false, false, false, defaultTimeout);
  8490. IPropertyTree* sroot = sconnlock.conn()?sconnlock.conn()->queryRoot():NULL;
  8491. dlfn.getTail(tail);
  8492. Owned<IPropertyTree> tree = getNamedPropTree(sroot,queryDfsXmlBranchName(DXB_File),"@name",tail.str(),false);
  8493. if (!tree)
  8494. tree.setown(getNamedPropTree(sroot,queryDfsXmlBranchName(DXB_SuperFile),"@name",tail.str(),false));
  8495. if (tree) {
  8496. IPropertyTree *pt = tree->queryPropTree("Attr");
  8497. if (pt)
  8498. setFileProtectTree(*pt,*owner?owner:owner,set);
  8499. }
  8500. }
  8501. void getFileTree(CMessageBuffer &mb,StringBuffer &trc)
  8502. {
  8503. TransactionLog transactionLog(*this, MDFS_GET_FILE_TREE, mb.getSender());
  8504. StringAttr lname;
  8505. mb.read(lname);
  8506. unsigned ver;
  8507. if (mb.length()<mb.getPos()+sizeof(unsigned))
  8508. ver = 0;
  8509. else {
  8510. mb.read(ver);
  8511. // this is a bit of a mess - for backward compatibility where user descriptor specified
  8512. if (ver>MDFS_GET_FILE_TREE_V2) {
  8513. mb.reset(mb.getPos()-sizeof(unsigned));
  8514. ver = 0;
  8515. }
  8516. }
  8517. trc.appendf("getFileTree(%s,%d)",lname.sget(),ver);
  8518. if (queryTransactionLogging())
  8519. transactionLog.log("%s", trc.str());
  8520. Owned<IUserDescriptor> udesc;
  8521. if (mb.getPos()<mb.length()) {
  8522. udesc.setown(createUserDescriptor());
  8523. udesc->deserialize(mb);
  8524. }
  8525. mb.clear();
  8526. CDfsLogicalFileName dlfn;
  8527. dlfn.set(lname);
  8528. CDfsLogicalFileName *logicalname=&dlfn;
  8529. Owned<IDfsLogicalFileNameIterator> redmatch;
  8530. loop {
  8531. StringBuffer tail;
  8532. checkLogicalName(*logicalname,udesc,true,false,true,"getFileTree on");
  8533. CScopeConnectLock sconnlock("getFileTree", *logicalname, false, false, false, defaultTimeout);
  8534. IPropertyTree* sroot = sconnlock.conn()?sconnlock.conn()->queryRoot():NULL;
  8535. logicalname->getTail(tail);
  8536. Owned<IPropertyTree> tree = getNamedPropTree(sroot,queryDfsXmlBranchName(DXB_File),"@name",tail.str(),false);
  8537. if (tree) {
  8538. if (ver>=MDFS_GET_FILE_TREE_V2) {
  8539. Owned<IFileDescriptor> fdesc = deserializeFileDescriptorTree(tree,&queryNamedGroupStore(),IFDSF_EXCLUDE_CLUSTERNAMES);
  8540. if (fdesc) {
  8541. ver = MDFS_GET_FILE_TREE_V2;
  8542. mb.append((int)-2).append(ver);
  8543. fdesc->serialize(mb);
  8544. StringBuffer dts;
  8545. if (tree->getProp("@modified",dts)) {
  8546. CDateTime dt;
  8547. dt.setString(dts.str());
  8548. dt.serialize(mb);
  8549. }
  8550. }
  8551. else
  8552. ver = 0;
  8553. }
  8554. if (ver==0) {
  8555. tree.setown(createPTreeFromIPT(tree));
  8556. StringBuffer cname;
  8557. logicalname->getCluster(cname);
  8558. expandFileTree(tree,true,cname.str()); // resolve @node values that may not be set
  8559. tree->serialize(mb);
  8560. }
  8561. break;
  8562. }
  8563. else {
  8564. tree.setown(getNamedPropTree(sroot,queryDfsXmlBranchName(DXB_SuperFile),"@name",tail.str(),false));
  8565. if (tree) {
  8566. tree->serialize(mb);
  8567. break;
  8568. }
  8569. }
  8570. if (redmatch.get()) {
  8571. if (!redmatch->next())
  8572. break;
  8573. }
  8574. else {
  8575. redmatch.setown(queryDistributedFileDirectory().queryRedirection().getMatch(logicalname->get()));
  8576. if (!redmatch.get())
  8577. break;
  8578. if (!redmatch->first())
  8579. break;
  8580. }
  8581. logicalname = &redmatch->query();
  8582. }
  8583. }
  8584. void getGroupTree(CMessageBuffer &mb,StringBuffer &trc)
  8585. {
  8586. TransactionLog transactionLog(*this, MDFS_GET_GROUP_TREE, mb.getSender());
  8587. StringAttr gname;
  8588. mb.read(gname);
  8589. mb.clear();
  8590. trc.appendf("getGroupTree(%s)",gname.sget());
  8591. if (queryTransactionLogging())
  8592. transactionLog.log("%s", trc.str());
  8593. byte ok;
  8594. CConnectLock connlock("getGroupTree",SDS_GROUPSTORE_ROOT,false,false,false,defaultTimeout);
  8595. Owned<IPropertyTree> pt = getNamedPropTree(connlock.conn->queryRoot(),"Group","@name",gname.get(),true);
  8596. if (pt) {
  8597. ok = 1;
  8598. mb.append(ok);
  8599. pt->serialize(mb);
  8600. }
  8601. else {
  8602. ok = 0;
  8603. mb.append(ok);
  8604. }
  8605. }
  8606. void processMessage(CMessageBuffer &mb)
  8607. {
  8608. CheckTime block0("CDaliDFSServer::processMessage ");
  8609. ICoven &coven=queryCoven();
  8610. StringBuffer trc;
  8611. int fn;
  8612. mb.read(fn);
  8613. try {
  8614. switch (fn) {
  8615. case MDFS_ITERATE_FILES: {
  8616. iterateFiles(mb,trc);
  8617. }
  8618. break;
  8619. case MDFS_ITERATE_RELATIONSHIPS: {
  8620. iterateRelationships(mb,trc);
  8621. }
  8622. break;
  8623. case MDFS_GET_FILE_TREE: {
  8624. getFileTree(mb,trc);
  8625. }
  8626. break;
  8627. case MDFS_GET_GROUP_TREE: {
  8628. getGroupTree(mb,trc);
  8629. }
  8630. break;
  8631. case MDFS_SET_FILE_ACCESSED: {
  8632. setFileAccessed(mb,trc);
  8633. }
  8634. break;
  8635. case MDFS_SET_FILE_PROTECT: {
  8636. setFileProtect(mb,trc);
  8637. }
  8638. break;
  8639. default: {
  8640. mb.clear();
  8641. }
  8642. break;
  8643. }
  8644. }
  8645. catch (IException *e) {
  8646. int err=-1; // exception marker
  8647. mb.clear().append(err);
  8648. serializeException(e, mb);
  8649. e->Release();
  8650. }
  8651. coven.reply(mb);
  8652. if (block0.slow()) {
  8653. SocketEndpoint ep = mb.getSender();
  8654. ep.getUrlStr(block0.appendMsg(trc).append(" from "));
  8655. }
  8656. }
  8657. void nodeDown(rank_t rank)
  8658. {
  8659. assertex(!"TBD");
  8660. }
  8661. // CTransactionLogTracker
  8662. virtual StringBuffer &getCmdText(unsigned cmd, StringBuffer &ret) const
  8663. {
  8664. switch (cmd)
  8665. {
  8666. case MDFS_ITERATE_FILES:
  8667. return ret.append("MDFS_ITERATE_FILES");
  8668. case MDFS_ITERATE_RELATIONSHIPS:
  8669. return ret.append("MDFS_ITERATE_RELATIONSHIPS");
  8670. case MDFS_GET_FILE_TREE:
  8671. return ret.append("MDFS_GET_FILE_TREE");
  8672. case MDFS_GET_GROUP_TREE:
  8673. return ret.append("MDFS_GET_GROUP_TREE");
  8674. case MDFS_SET_FILE_ACCESSED:
  8675. return ret.append("MDFS_SET_FILE_ACCESSED");
  8676. case MDFS_SET_FILE_PROTECT:
  8677. return ret.append("MDFS_SET_FILE_PROTECT");
  8678. default:
  8679. return ret.append("UNKNOWN");
  8680. }
  8681. }
  8682. // IExceptionHandler impl.
  8683. virtual bool fireException(IException *e)
  8684. {
  8685. EXCLOG(e, "CDaliDFSServer exception");
  8686. return true;
  8687. }
  8688. } *daliDFSServer = NULL;
  8689. IDFAttributesIterator *CDistributedFileDirectory::getDFAttributesIterator(const char *wildname, IUserDescriptor *user, bool recursive, bool includesuper,INode *foreigndali,unsigned foreigndalitimeout)
  8690. {
  8691. if (!wildname||!*wildname||(strcmp(wildname,"*")==0)) {
  8692. recursive = true;
  8693. }
  8694. CMessageBuffer mb;
  8695. mb.append((int)MDFS_ITERATE_FILES).append(wildname).append(recursive).append("").append(includesuper); // "" is legacy
  8696. if (user)
  8697. user->serialize(mb);
  8698. #ifndef _NO_DALIUSER_STACKTRACE
  8699. else
  8700. {
  8701. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp getDFAttributesIterator() line %d",__LINE__);
  8702. PrintStackReport();
  8703. }
  8704. #endif
  8705. if (foreigndali)
  8706. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  8707. else
  8708. queryCoven().sendRecv(mb,RANK_RANDOM,MPTAG_DFS_REQUEST);
  8709. checkDfsReplyException(mb);
  8710. return new CDFAttributeIterator(mb);
  8711. }
  8712. IDFScopeIterator *CDistributedFileDirectory::getScopeIterator(IUserDescriptor *user, const char *basescope, bool recursive,bool includeempty)
  8713. {
  8714. return new CDFScopeIterator(this,basescope,recursive,includeempty,defaultTimeout);
  8715. }
  8716. static bool isValidLFN(const char *lfn)
  8717. { // bit OTT
  8718. if (!lfn||!*lfn||(strcmp(lfn,".")==0))
  8719. return false;
  8720. StringBuffer tmp(".::");
  8721. tmp.append(lfn);
  8722. CDfsLogicalFileName dlfn;
  8723. return dlfn.setValidate(tmp.str());
  8724. }
  8725. bool CDistributedFileDirectory::loadScopeContents(const char *scopelfn,
  8726. StringArray *scopes,
  8727. StringArray *supers,
  8728. StringArray *files,
  8729. bool includeemptyscopes
  8730. )
  8731. {
  8732. StringBuffer baseq;
  8733. if (scopelfn&&*scopelfn) {
  8734. if (memcmp(scopelfn,".::",3)==0) // scopes not in .
  8735. scopelfn += 3;
  8736. StringBuffer tmp(scopelfn);
  8737. if (tmp.trim().length()) {
  8738. tmp.append("::.");
  8739. CDfsLogicalFileName dlfn;
  8740. if (!dlfn.setValidate(tmp.str()))
  8741. return false;
  8742. dlfn.makeScopeQuery(baseq,false);
  8743. }
  8744. }
  8745. CConnectLock connlock("CDistributedFileDirectory::loadScopeContents",querySdsFilesRoot(),false,false,false,defaultTimeout);
  8746. if (!connlock.conn)
  8747. return false;
  8748. IPropertyTree *root = connlock.conn->queryRoot();
  8749. if (!root)
  8750. return false;
  8751. if (baseq.length()) {
  8752. root = root->queryPropTree(baseq.str());
  8753. if (!root)
  8754. return false;
  8755. }
  8756. Owned<IPropertyTreeIterator> iter;
  8757. if (scopes) {
  8758. iter.setown(root->getElements(queryDfsXmlBranchName(DXB_Scope)));
  8759. ForEach(*iter) {
  8760. IPropertyTree &ct = iter->query();
  8761. if (includeemptyscopes||!recursiveCheckEmptyScope(ct)) {
  8762. StringBuffer name;
  8763. if (ct.getProp("@name",name)&&name.trim().length()&&isValidLFN(name.str()))
  8764. scopes->append(name.str());
  8765. }
  8766. }
  8767. }
  8768. if (!supers&&!files)
  8769. return true;
  8770. if (baseq.length()==0) { // bit odd but top level files are in '.'
  8771. CDfsLogicalFileName dlfn;
  8772. dlfn.set(".",".");
  8773. dlfn.makeScopeQuery(baseq,false);
  8774. root = root->queryPropTree(baseq.str());
  8775. if (!root)
  8776. return true;
  8777. }
  8778. if (supers) {
  8779. iter.setown(root->getElements(queryDfsXmlBranchName(DXB_SuperFile)));
  8780. ForEach(*iter) {
  8781. IPropertyTree &ct = iter->query();
  8782. StringBuffer name;
  8783. if (ct.getProp("@name",name)&&name.trim().length()&&isValidLFN(name.str()))
  8784. supers->append(name.str());
  8785. }
  8786. }
  8787. if (files) {
  8788. iter.setown(root->getElements(queryDfsXmlBranchName(DXB_File)));
  8789. ForEach(*iter) {
  8790. StringBuffer name;
  8791. IPropertyTree &ct = iter->query();
  8792. if (ct.getProp("@name",name)&&name.trim().length()&&isValidLFN(name.str()))
  8793. files->append(name.str());
  8794. }
  8795. }
  8796. return true;
  8797. }
  8798. void CDistributedFileDirectory::setFileAccessed(CDfsLogicalFileName &dlfn,IUserDescriptor *user, const CDateTime &dt, const INode *foreigndali,unsigned foreigndalitimeout)
  8799. {
  8800. // this accepts either a foreign dali node or a foreign lfn
  8801. Owned<INode> fnode;
  8802. SocketEndpoint ep;
  8803. const char *lname;
  8804. if (dlfn.isForeign()) {
  8805. if (!dlfn.getEp(ep))
  8806. throw MakeStringException(-1,"cannot resolve dali ip in foreign file name (%s)",dlfn.get());
  8807. fnode.setown(createINode(ep));
  8808. foreigndali = fnode;
  8809. lname = dlfn.get(true);
  8810. }
  8811. else if (dlfn.isExternal())
  8812. return;
  8813. else
  8814. lname = dlfn.get();
  8815. if (isLocalDali(foreigndali))
  8816. foreigndali = NULL;
  8817. CMessageBuffer mb;
  8818. mb.append((int)MDFS_SET_FILE_ACCESSED).append(lname);
  8819. dt.serialize(mb);
  8820. if (user)
  8821. user->serialize(mb);
  8822. #ifndef _NO_DALIUSER_STACKTRACE
  8823. else
  8824. {
  8825. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp setFileAccessed() line %d",__LINE__);
  8826. PrintStackReport();
  8827. }
  8828. #endif
  8829. if (foreigndali)
  8830. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  8831. else
  8832. queryCoven().sendRecv(mb,RANK_RANDOM,MPTAG_DFS_REQUEST);
  8833. checkDfsReplyException(mb);
  8834. }
  8835. void CDistributedFileDirectory::setFileProtect(CDfsLogicalFileName &dlfn,IUserDescriptor *user, const char *owner, bool set, const INode *foreigndali,unsigned foreigndalitimeout)
  8836. {
  8837. // this accepts either a foreign dali node or a foreign lfn
  8838. Owned<INode> fnode;
  8839. SocketEndpoint ep;
  8840. const char *lname;
  8841. if (dlfn.isForeign()) {
  8842. if (!dlfn.getEp(ep))
  8843. throw MakeStringException(-1,"cannot resolve dali ip in foreign file name (%s)",dlfn.get());
  8844. fnode.setown(createINode(ep));
  8845. foreigndali = fnode;
  8846. lname = dlfn.get(true);
  8847. }
  8848. else if (dlfn.isExternal())
  8849. return;
  8850. else
  8851. lname = dlfn.get();
  8852. if (isLocalDali(foreigndali))
  8853. foreigndali = NULL;
  8854. CMessageBuffer mb;
  8855. if (!owner)
  8856. owner = "";
  8857. mb.append((int)MDFS_SET_FILE_PROTECT).append(lname).append(owner).append(set);
  8858. if (user)
  8859. user->serialize(mb);
  8860. #ifndef _NO_DALIUSER_STACKTRACE
  8861. else
  8862. {
  8863. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp setFileProtect() line %d",__LINE__);
  8864. PrintStackReport();
  8865. }
  8866. #endif
  8867. if (foreigndali)
  8868. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  8869. else
  8870. queryCoven().sendRecv(mb,RANK_RANDOM,MPTAG_DFS_REQUEST);
  8871. checkDfsReplyException(mb);
  8872. }
  8873. IPropertyTree *CDistributedFileDirectory::getFileTree(const char *lname, IUserDescriptor *user, const INode *foreigndali,unsigned foreigndalitimeout, bool expandnodes, bool appendForeign)
  8874. {
  8875. // this accepts either a foreign dali node or a foreign lfn
  8876. Owned<INode> fnode;
  8877. CDfsLogicalFileName dlfn;
  8878. SocketEndpoint ep;
  8879. dlfn.set(lname);
  8880. if (dlfn.isForeign()) {
  8881. if (!dlfn.getEp(ep))
  8882. throw MakeStringException(-1,"cannot resolve dali ip in foreign file name (%s)",lname);
  8883. fnode.setown(createINode(ep));
  8884. foreigndali = fnode;
  8885. lname = dlfn.get(true);
  8886. }
  8887. if (isLocalDali(foreigndali))
  8888. foreigndali = NULL;
  8889. CMessageBuffer mb;
  8890. mb.append((int)MDFS_GET_FILE_TREE).append(lname);
  8891. mb.append(MDFS_GET_FILE_TREE_V2);
  8892. if (user)
  8893. user->serialize(mb);
  8894. #ifndef _NO_DALIUSER_STACKTRACE
  8895. else
  8896. {
  8897. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp getFileTree() line %d",__LINE__);
  8898. PrintStackReport();
  8899. }
  8900. #endif
  8901. if (foreigndali)
  8902. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  8903. else
  8904. queryCoven().sendRecv(mb,RANK_RANDOM,MPTAG_DFS_REQUEST);
  8905. checkDfsReplyException(mb);
  8906. if (mb.length()==0)
  8907. return NULL;
  8908. unsigned ver = 0;
  8909. if ((mb.length()>=sizeof(int))&&(*(int *)mb.bufferBase()) == -2) { // version indicator
  8910. int i;
  8911. mb.read(i);
  8912. mb.read(ver);
  8913. }
  8914. Owned<IPropertyTree> ret;
  8915. if (ver==0)
  8916. ret.setown(createPTree(mb));
  8917. else {
  8918. Owned<IFileDescriptor> fdesc;
  8919. CDateTime modified;
  8920. if (ver==MDFS_GET_FILE_TREE_V2) { // no longer in use but support for back compatibility
  8921. fdesc.setown(deserializeFileDescriptor(mb));
  8922. if (mb.remaining()>0)
  8923. modified.deserialize(mb);
  8924. }
  8925. else
  8926. throw MakeStringException(-1,"Unknown GetFileTree serialization version %d",ver);
  8927. ret.setown(createPTree(queryDfsXmlBranchName(DXB_File)));
  8928. fdesc->serializeTree(*ret,expandnodes?0:CPDMSF_packParts);
  8929. if (!modified.isNull()) {
  8930. StringBuffer dts;
  8931. ret->setProp("@modified",modified.getString(dts).str());
  8932. }
  8933. }
  8934. if (expandnodes) {
  8935. StringBuffer cname;
  8936. dlfn.getCluster(cname);
  8937. expandFileTree(ret,true,cname.str());
  8938. CDfsLogicalFileName dlfn2;
  8939. dlfn2.set(dlfn);
  8940. if (foreigndali)
  8941. dlfn2.setForeign(foreigndali->endpoint(),false);
  8942. ret->setProp("OrigName",dlfn.get());
  8943. }
  8944. if (foreigndali && appendForeign)
  8945. resolveForeignFiles(ret,foreigndali);
  8946. return ret.getClear();
  8947. }
  8948. IFileDescriptor *CDistributedFileDirectory::getFileDescriptor(const char *lname,IUserDescriptor *user,const INode *foreigndali,unsigned foreigndalitimeout)
  8949. {
  8950. Owned<IPropertyTree> tree = getFileTree(lname,user,foreigndali,foreigndalitimeout,false);
  8951. if (!tree)
  8952. return NULL;
  8953. if (strcmp(tree->queryName(),queryDfsXmlBranchName(DXB_SuperFile))==0) {
  8954. CDfsLogicalFileName dlfn;
  8955. dlfn.set(lname);
  8956. Owned<CDistributedSuperFile> sfile = new CDistributedSuperFile(this,tree, dlfn, user);
  8957. return sfile->getFileDescriptor(NULL);
  8958. }
  8959. if (strcmp(tree->queryName(),queryDfsXmlBranchName(DXB_File))!=0)
  8960. return NULL; // what is it?
  8961. IFileDescriptor * fdesc = deserializeFileDescriptorTree(tree,&queryNamedGroupStore(),0);
  8962. if (fdesc)
  8963. fdesc->setTraceName(lname);
  8964. return fdesc;
  8965. }
  8966. IDistributedFile *CDistributedFileDirectory::getFile(const char *lname,IUserDescriptor *user,const INode *foreigndali,unsigned foreigndalitimeout)
  8967. {
  8968. Owned<IPropertyTree> tree = getFileTree(lname,user,foreigndali,foreigndalitimeout,false);
  8969. if (!tree)
  8970. return NULL;
  8971. if (strcmp(tree->queryName(),queryDfsXmlBranchName(DXB_SuperFile))==0) {
  8972. CDfsLogicalFileName dlfn;
  8973. dlfn.set(lname);
  8974. return new CDistributedSuperFile(this,tree, dlfn, user);
  8975. }
  8976. if (strcmp(tree->queryName(),queryDfsXmlBranchName(DXB_File))!=0)
  8977. return NULL; // what is it?
  8978. Owned<IFileDescriptor> fdesc = deserializeFileDescriptorTree(tree,&queryNamedGroupStore(),IFDSF_FOREIGN_GROUP);
  8979. if (!fdesc)
  8980. return NULL;
  8981. fdesc->setTraceName(lname);
  8982. IDistributedFile *ret = createNew(fdesc,lname,true);
  8983. const char *date = tree->queryProp("@modified");
  8984. if (ret) {
  8985. CDateTime dt;
  8986. if (date&&*date)
  8987. dt.setString(date);
  8988. ret->setModificationTime(dt);
  8989. }
  8990. return ret;
  8991. }
  8992. static void addForeignName(IPropertyTree &t,const INode *foreigndali,const char *attr)
  8993. {
  8994. StringBuffer sb;
  8995. const char *name = t.queryProp(attr);
  8996. if (!name||!*name)
  8997. return;
  8998. CDfsLogicalFileName logicalname;
  8999. logicalname.set(name);
  9000. if (logicalname.isExternal()||logicalname.isQuery())
  9001. return; // how did that get in here?
  9002. if (logicalname.isForeign()) {
  9003. SocketEndpoint ep;
  9004. Owned<INode> fd = createINode(ep);
  9005. if (logicalname.getEp(ep)&&isLocalDali(fd)) { // see if pointing back at self
  9006. logicalname.clearForeign();
  9007. t.setProp(attr,logicalname.get());
  9008. }
  9009. }
  9010. else if (foreigndali) {
  9011. logicalname.setForeign(foreigndali->endpoint(),false);
  9012. t.setProp(attr,logicalname.get());
  9013. }
  9014. }
  9015. void CDistributedFileDirectory::resolveForeignFiles(IPropertyTree *tree,const INode *foreigndali)
  9016. {
  9017. if (!tree||!foreigndali)
  9018. return;
  9019. // now add to all sub files
  9020. Owned<IPropertyTreeIterator> pe = tree->getElements("SubFile");
  9021. ForEach(*pe)
  9022. addForeignName(pe->query(),foreigndali,"@name");
  9023. pe.setown(tree->getElements("SuperOwner"));
  9024. ForEach(*pe)
  9025. addForeignName(pe->query(),foreigndali,"@name");
  9026. // do origname?
  9027. }
  9028. int CDistributedFileDirectory::getFilePermissions(const char *lname,IUserDescriptor *user,unsigned auditflags)
  9029. {
  9030. CDfsLogicalFileName dlfn;
  9031. dlfn.set(lname);
  9032. StringBuffer scopes;
  9033. dlfn.getScopes(scopes);
  9034. return getScopePermissions(scopes.str(),user,auditflags);
  9035. }
  9036. int CDistributedFileDirectory::getNodePermissions(const IpAddress &ip,IUserDescriptor *user,unsigned auditflags)
  9037. {
  9038. if (ip.isNull())
  9039. return 0;
  9040. CDfsLogicalFileName dlfn;
  9041. SocketEndpoint ep(0,ip);
  9042. dlfn.setExternal(ep,"/x");
  9043. StringBuffer scopes;
  9044. dlfn.getScopes(scopes,true);
  9045. return getScopePermissions(scopes.str(),user,auditflags);
  9046. }
  9047. int CDistributedFileDirectory::getFDescPermissions(IFileDescriptor *fdesc,IUserDescriptor *user,unsigned auditflags)
  9048. {
  9049. // this checks have access to the nodes in the file descriptor
  9050. int ret = 255;
  9051. unsigned np = fdesc->numParts();
  9052. for (unsigned i=0;i<np;i++) {
  9053. INode *node = fdesc->queryNode(i);
  9054. if (node) {
  9055. bool multi = false;
  9056. RemoteMultiFilename mfn;
  9057. unsigned n = 1;
  9058. if (fdesc->isMulti()) {
  9059. fdesc->getMultiFilename(i,0,mfn);
  9060. multi = true;
  9061. n = mfn.ordinality();
  9062. }
  9063. for (unsigned j = 0;j<n;j++) {
  9064. RemoteFilename rfn;
  9065. if (multi) {
  9066. rfn.set(mfn.item(j));
  9067. }
  9068. else
  9069. fdesc->getFilename(i,0,rfn);
  9070. StringBuffer localpath;
  9071. rfn.getLocalPath(localpath);
  9072. // translate wild cards
  9073. for (unsigned k=0;k<localpath.length();k++)
  9074. if ((localpath.charAt(k)=='?')||(localpath.charAt(k)=='*'))
  9075. localpath.setCharAt(k,'_');
  9076. CDfsLogicalFileName dlfn;
  9077. dlfn.setExternal(rfn.queryEndpoint(),localpath.str());
  9078. StringBuffer scopes;
  9079. dlfn.getScopes(scopes);
  9080. int p = getScopePermissions(scopes.str(),user,auditflags);
  9081. if (p<ret) {
  9082. ret = p;
  9083. if (ret==0)
  9084. return 0;
  9085. }
  9086. }
  9087. }
  9088. }
  9089. return ret;
  9090. }
  9091. void CDistributedFileDirectory::setDefaultUser(IUserDescriptor *user)
  9092. {
  9093. if (user)
  9094. defaultudesc.set(user);
  9095. else
  9096. defaultudesc.setown(createUserDescriptor());
  9097. }
  9098. IUserDescriptor* CDistributedFileDirectory::queryDefaultUser()
  9099. {
  9100. return defaultudesc.get();
  9101. }
  9102. void CDistributedFileDirectory::setDefaultPreferredClusters(const char *clusters)
  9103. {
  9104. defprefclusters.set(clusters);
  9105. }
  9106. bool removePhysicalFiles(IGroup *grp,const char *_filemask,unsigned short port,ClusterPartDiskMapSpec &mspec,IMultiException *mexcept)
  9107. {
  9108. // TBD this won't remove repeated parts
  9109. PROGLOG("removePhysicalFiles(%s)",_filemask);
  9110. if (!isAbsolutePath(_filemask))
  9111. throw MakeStringException(-1,"removePhysicalFiles: Filename %s must be complete path",_filemask);
  9112. size32_t l = strlen(_filemask);
  9113. while (l&&isdigit(_filemask[l-1]))
  9114. l--;
  9115. unsigned width=0;
  9116. if (l&&(_filemask[l-1]=='_'))
  9117. width = atoi(_filemask+l);
  9118. if (!width)
  9119. width = grp->ordinality();
  9120. CriticalSection errcrit;
  9121. class casyncfor: public CAsyncFor
  9122. {
  9123. unsigned short port;
  9124. CriticalSection &errcrit;
  9125. IMultiException *mexcept;
  9126. unsigned width;
  9127. StringAttr filemask;
  9128. IGroup *grp;
  9129. ClusterPartDiskMapSpec &mspec;
  9130. public:
  9131. bool ok;
  9132. casyncfor(IGroup *_grp,const char *_filemask,unsigned _width,unsigned short _port,ClusterPartDiskMapSpec &_mspec,IMultiException *_mexcept,CriticalSection &_errcrit)
  9133. : mspec(_mspec),filemask(_filemask),errcrit(_errcrit)
  9134. {
  9135. grp = _grp;
  9136. port = _port;
  9137. ok = true;
  9138. mexcept = _mexcept;
  9139. width = _width;
  9140. }
  9141. void Do(unsigned i)
  9142. {
  9143. for (unsigned copy = 0; copy < 2; copy++) // ** TBD
  9144. {
  9145. RemoteFilename rfn;
  9146. constructPartFilename(grp,i+1,width,NULL,filemask,"",copy>0,mspec,rfn);
  9147. if (port)
  9148. rfn.setPort(port); // if daliservix
  9149. Owned<IFile> partfile = createIFile(rfn);
  9150. StringBuffer eps;
  9151. try
  9152. {
  9153. unsigned start = msTick();
  9154. #if 1
  9155. if (partfile->remove()) {
  9156. PROGLOG("Removed '%s'",partfile->queryFilename());
  9157. unsigned t = msTick()-start;
  9158. if (t>5*1000)
  9159. LOG(MCwarning, unknownJob, "Removing %s from %s took %ds", partfile->queryFilename(), rfn.queryEndpoint().getUrlStr(eps).str(), t/1000);
  9160. }
  9161. else
  9162. LOG(MCwarning, unknownJob, "Failed to remove file part %s from %s", partfile->queryFilename(),rfn.queryEndpoint().getUrlStr(eps).str());
  9163. #else
  9164. if (partfile->exists())
  9165. PROGLOG("Would remove '%s'",partfile->queryFilename());
  9166. #endif
  9167. }
  9168. catch (IException *e)
  9169. {
  9170. CriticalBlock block(errcrit);
  9171. if (mexcept)
  9172. mexcept->append(*e);
  9173. else {
  9174. StringBuffer s("Failed to remove file part ");
  9175. s.append(partfile->queryFilename()).append(" from ");
  9176. rfn.queryEndpoint().getUrlStr(s);
  9177. EXCLOG(e, s.str());
  9178. e->Release();
  9179. }
  9180. ok = false;
  9181. }
  9182. }
  9183. }
  9184. } afor(grp,_filemask,width,port,mspec,mexcept,errcrit);
  9185. afor.For(width,10,false,true);
  9186. return afor.ok;
  9187. }
  9188. IDaliServer *createDaliDFSServer(IPropertyTree *config)
  9189. {
  9190. assertex(!daliDFSServer); // initialization problem
  9191. daliDFSServer = new CDaliDFSServer(config);
  9192. return daliDFSServer;
  9193. }
  9194. IDistributedFileTransaction *createDistributedFileTransaction(IUserDescriptor *user)
  9195. {
  9196. return new CDistributedFileTransaction(user);
  9197. }
  9198. static void encodeCompareResult(DistributedFileCompareResult &ret,bool differs,CDateTime &newestdt1,CDateTime &newestdt2)
  9199. {
  9200. if (ret!=DFS_COMPARE_RESULT_FAILURE) {
  9201. int cmp = 0;
  9202. if (!newestdt1.isNull()) {
  9203. if (!newestdt2.isNull()) {
  9204. int cmp = newestdt1.compare(newestdt2,false);
  9205. if (cmp>=0)
  9206. ret = DFS_COMPARE_RESULT_SAME_NEWER;
  9207. else
  9208. ret = DFS_COMPARE_RESULT_SAME_OLDER;
  9209. }
  9210. else
  9211. ret = DFS_COMPARE_RESULT_SAME_NEWER;
  9212. }
  9213. else if (!newestdt2.isNull())
  9214. ret = DFS_COMPARE_RESULT_SAME_OLDER;
  9215. if (differs) {
  9216. if (ret==DFS_COMPARE_RESULT_SAME_OLDER) // ok they could be same but seems rather unlikely!
  9217. ret = DFS_COMPARE_RESULT_DIFFER_OLDER;
  9218. else
  9219. ret = DFS_COMPARE_RESULT_DIFFER_NEWER;
  9220. }
  9221. }
  9222. }
  9223. DistributedFileCompareResult CDistributedFileDirectory::fileCompare(const char *lfn1,const char *lfn2,DistributedFileCompareMode mode,StringBuffer &errstr,IUserDescriptor *user)
  9224. {
  9225. DistributedFileCompareResult ret = DFS_COMPARE_RESULT_SAME;
  9226. StringBuffer msg;
  9227. try
  9228. {
  9229. Owned<IDistributedFile> file1 = lookup(lfn1, user, false, false, NULL, defaultTimeout);
  9230. Owned<IDistributedFile> file2 = lookup(lfn2, user, false, false, NULL, defaultTimeout);
  9231. if (!file1)
  9232. {
  9233. errstr.appendf("File %s not found",lfn1);
  9234. ret = DFS_COMPARE_RESULT_FAILURE;
  9235. }
  9236. else if (!file2)
  9237. {
  9238. errstr.appendf("File %s not found",lfn2);
  9239. ret = DFS_COMPARE_RESULT_FAILURE;
  9240. }
  9241. else
  9242. {
  9243. unsigned np = file1->numParts();
  9244. if (np!=file2->numParts())
  9245. {
  9246. errstr.appendf("Files %s and %s have differing number of parts",lfn1,lfn2);
  9247. ret = DFS_COMPARE_RESULT_FAILURE;
  9248. }
  9249. else
  9250. {
  9251. CDateTime newestdt1;
  9252. CDateTime newestdt2;
  9253. bool differs = false;
  9254. class casyncfor: public CAsyncFor
  9255. {
  9256. CriticalSection crit;
  9257. DistributedFileCompareResult &ret;
  9258. IDistributedFile *file1;
  9259. IDistributedFile *file2;
  9260. const char *lfn1;
  9261. const char *lfn2;
  9262. StringBuffer &errstr;
  9263. DistributedFileCompareMode mode;
  9264. bool physdatesize;
  9265. CDateTime &newestdt1;
  9266. CDateTime &newestdt2;
  9267. bool &differs;
  9268. public:
  9269. casyncfor(const char *_lfn1,const char *_lfn2,IDistributedFile *_file1,IDistributedFile *_file2,DistributedFileCompareMode _mode,DistributedFileCompareResult &_ret,StringBuffer &_errstr,
  9270. CDateTime &_newestdt1,CDateTime &_newestdt2,bool &_differs)
  9271. : ret(_ret), errstr(_errstr),newestdt1(_newestdt1),newestdt2(_newestdt2),differs(_differs)
  9272. {
  9273. lfn1 = _lfn1;
  9274. lfn2 = _lfn2;
  9275. file1 = _file1;
  9276. file2 = _file2;
  9277. mode = _mode;
  9278. physdatesize = (mode==DFS_COMPARE_FILES_PHYSICAL)||(mode==DFS_COMPARE_FILES_PHYSICAL_CRCS);
  9279. }
  9280. void Do(unsigned p)
  9281. {
  9282. CriticalBlock block (crit);
  9283. StringBuffer msg;
  9284. Owned<IDistributedFilePart> part1 = file1->getPart(p);
  9285. Owned<IDistributedFilePart> part2 = file2->getPart(p);
  9286. CDateTime dt1;
  9287. RemoteFilename rfn;
  9288. bool ok;
  9289. {
  9290. CriticalUnblock unblock(crit);
  9291. ok = part1->getModifiedTime(true,physdatesize,dt1);
  9292. }
  9293. if (!ok) {
  9294. if (errstr.length()==0) {
  9295. errstr.append("Could not find ");
  9296. part1->getFilename(rfn);
  9297. rfn.getPath(errstr);
  9298. }
  9299. ret = DFS_COMPARE_RESULT_FAILURE;
  9300. }
  9301. CDateTime dt2;
  9302. {
  9303. CriticalUnblock unblock(crit);
  9304. ok = part2->getModifiedTime(true,physdatesize,dt2);
  9305. }
  9306. if (!ok) {
  9307. if (errstr.length()==0) {
  9308. errstr.append("Could not find ");
  9309. part2->getFilename(rfn);
  9310. rfn.getPath(errstr);
  9311. }
  9312. ret = DFS_COMPARE_RESULT_FAILURE;
  9313. }
  9314. if (ret!=DFS_COMPARE_RESULT_FAILURE) {
  9315. int cmp = dt1.compare(dt2,false);
  9316. if (cmp>0) {
  9317. if (newestdt1.isNull()||(dt1.compare(newestdt1,false)>0))
  9318. newestdt1.set(dt1);
  9319. }
  9320. else if (cmp<0) {
  9321. if (newestdt2.isNull()||(dt2.compare(newestdt2,false)>0))
  9322. newestdt2.set(dt2);
  9323. }
  9324. }
  9325. if ((ret!=DFS_COMPARE_RESULT_FAILURE)&&!differs) {
  9326. offset_t sz1;
  9327. offset_t sz2;
  9328. {
  9329. CriticalUnblock unblock(crit);
  9330. sz1 = part1->getFileSize(true,physdatesize);
  9331. sz2 = part2->getFileSize(true,physdatesize);
  9332. }
  9333. if (sz1!=sz2)
  9334. differs = true;
  9335. }
  9336. if ((ret!=DFS_COMPARE_RESULT_FAILURE)&&!differs) {
  9337. unsigned crc1;
  9338. unsigned crc2;
  9339. if (mode==DFS_COMPARE_FILES_PHYSICAL_CRCS) {
  9340. {
  9341. CriticalUnblock unblock(crit);
  9342. crc1 = part1->getPhysicalCrc();
  9343. crc2 = part2->getPhysicalCrc();
  9344. }
  9345. }
  9346. else {
  9347. if (!part1->getCrc(crc1))
  9348. return;
  9349. if (!part2->getCrc(crc2))
  9350. return;
  9351. }
  9352. if (crc1!=crc2)
  9353. differs = true;
  9354. }
  9355. }
  9356. } afor(lfn1,lfn2,file1,file2,mode,ret,errstr,newestdt1,newestdt2,differs);
  9357. afor.For(np,20,false,false);
  9358. encodeCompareResult(ret,differs,newestdt1,newestdt2);
  9359. }
  9360. }
  9361. }
  9362. catch (IException *e) {
  9363. if (errstr.length()==0)
  9364. e->errorMessage(errstr);
  9365. else
  9366. EXCLOG(e,"CDistributedFileDirectory::fileCompare");
  9367. e->Release();
  9368. ret = DFS_COMPARE_RESULT_FAILURE;
  9369. }
  9370. return ret;
  9371. }
  9372. bool CDistributedFileDirectory::filePhysicalVerify(const char *lfn, IUserDescriptor *user, bool includecrc, StringBuffer &errstr)
  9373. {
  9374. bool differs = false;
  9375. Owned<IDistributedFile> file = lookup(lfn, user, false, false, NULL, defaultTimeout);
  9376. if (!file)
  9377. {
  9378. errstr.appendf("Could not find file: %s",lfn);
  9379. return false;
  9380. }
  9381. try
  9382. {
  9383. unsigned np = file->numParts();
  9384. class casyncfor: public CAsyncFor
  9385. {
  9386. CriticalSection crit;
  9387. IDistributedFile *file;
  9388. const char *lfn;
  9389. StringBuffer &errstr;
  9390. bool includecrc;
  9391. bool &differs;
  9392. unsigned defaultTimeout;
  9393. public:
  9394. casyncfor(const char *_lfn,IDistributedFile *_file,StringBuffer &_errstr, bool _includecrc,
  9395. bool &_differs, unsigned _defaultTimeout)
  9396. : errstr(_errstr), differs(_differs)
  9397. {
  9398. lfn = _lfn;
  9399. file = _file;
  9400. includecrc = _includecrc;
  9401. defaultTimeout = _defaultTimeout;
  9402. }
  9403. void Do(unsigned p)
  9404. {
  9405. CriticalBlock block (crit);
  9406. StringBuffer msg;
  9407. Owned<IDistributedFilePart> part = file->getPart(p);
  9408. CDateTime dt1; // logical
  9409. CDateTime dt2; // physical
  9410. RemoteFilename rfn;
  9411. bool ok;
  9412. bool nological = !part->getModifiedTime(false,false,dt1);
  9413. {
  9414. CriticalUnblock unblock(crit);
  9415. ok = part->getModifiedTime(true,true,dt2);
  9416. }
  9417. if (!ok) {
  9418. if (errstr.length()==0) {
  9419. errstr.append("Could not find part file: ");
  9420. part->getFilename(rfn);
  9421. rfn.getPath(errstr);
  9422. }
  9423. differs = true;
  9424. }
  9425. if (!differs&&!includecrc) {
  9426. if (nological) {
  9427. StringBuffer str;
  9428. // TODO: Create DistributedFilePropertyLock for parts
  9429. part->lockProperties(defaultTimeout);
  9430. part->queryAttributes().setProp("@modified",dt2.getString(str).str());
  9431. part->unlockProperties();
  9432. }
  9433. else {
  9434. if (dt1.compare(dt2,false)!=0) {
  9435. if (errstr.length()==0) {
  9436. errstr.append("Modified time differs for: ");
  9437. part->getFilename(rfn);
  9438. rfn.getPath(errstr);
  9439. }
  9440. differs = true;
  9441. }
  9442. }
  9443. }
  9444. if (!differs) {
  9445. offset_t sz1;
  9446. offset_t sz2;
  9447. {
  9448. CriticalUnblock unblock(crit);
  9449. sz1 = part->getFileSize(false,false);
  9450. sz2 = part->getFileSize(true,true);
  9451. }
  9452. if (sz1!=sz2) {
  9453. if (sz1==(offset_t)-1) {
  9454. // TODO: Create DistributedFilePropertyLock for parts
  9455. part->lockProperties(defaultTimeout);
  9456. part->queryAttributes().setPropInt64("@size",sz2);
  9457. part->unlockProperties();
  9458. }
  9459. else if (sz2!=(offset_t)-1) {
  9460. if (errstr.length()==0) {
  9461. errstr.append("File size differs for: ");
  9462. part->getFilename(rfn);
  9463. rfn.getPath(errstr);
  9464. }
  9465. differs = true;
  9466. }
  9467. }
  9468. }
  9469. if (!differs&&includecrc) {
  9470. unsigned crc1;
  9471. unsigned crc2;
  9472. {
  9473. CriticalUnblock unblock(crit);
  9474. crc2 = part->getPhysicalCrc();
  9475. }
  9476. if (!part->getCrc(crc1)) {
  9477. // TODO: Create DistributedFilePropertyLock for parts
  9478. part->lockProperties(defaultTimeout);
  9479. part->queryAttributes().setPropInt64("@fileCrc",(unsigned)crc2);
  9480. part->unlockProperties();
  9481. }
  9482. else if (crc1!=crc2) {
  9483. if (errstr.length()==0) {
  9484. errstr.append("File CRC differs for: ");
  9485. part->getFilename(rfn);
  9486. rfn.getPath(errstr);
  9487. }
  9488. differs = true;
  9489. }
  9490. }
  9491. }
  9492. } afor(lfn,file,errstr,includecrc,differs,defaultTimeout);
  9493. afor.For(np,10,false,false);
  9494. }
  9495. catch (IException *e) {
  9496. if (errstr.length()==0)
  9497. e->errorMessage(errstr);
  9498. else
  9499. EXCLOG(e,"CDistributedFileDirectory::fileCompare");
  9500. e->Release();
  9501. differs = true;
  9502. }
  9503. return !differs;
  9504. }
  9505. typedef MapStringTo<bool> SubfileSet;
  9506. class CFilterAttrIterator: public CInterface, implements IDFAttributesIterator
  9507. {
  9508. Owned<IDFAttributesIterator> iter;
  9509. Linked<IUserDescriptor> user;
  9510. SubfileSet sfset;
  9511. bool includesub;
  9512. public:
  9513. IMPLEMENT_IINTERFACE;
  9514. CFilterAttrIterator(IDFAttributesIterator *_iter,IUserDescriptor* _user,bool _includesub,unsigned timeoutms)
  9515. : iter(_iter), user(_user)
  9516. {
  9517. includesub = _includesub;
  9518. CDfsLogicalFileName lfn;
  9519. StringBuffer query;
  9520. Owned<IDFScopeIterator> siter = queryDistributedFileDirectory().getScopeIterator(user,NULL,true,false);
  9521. ForEach(*siter) {
  9522. lfn.set(siter->query(),"X");
  9523. lfn.makeScopeQuery(query.clear());
  9524. Owned<IRemoteConnection> conn = querySDS().connect(query.str(),myProcessSession(),0, timeoutms);
  9525. if (conn) {
  9526. IPropertyTree *t = conn->queryRoot();
  9527. Owned<IPropertyTreeIterator> iter = t->getElements("SuperFile/SubFile");
  9528. ForEach(*iter) {
  9529. const char *name = iter->query().queryProp("@name");
  9530. if (!sfset.getValue(name))
  9531. sfset.setValue(name, true);
  9532. }
  9533. }
  9534. }
  9535. }
  9536. inline bool match()
  9537. {
  9538. const char *name = iter->query().queryProp("@name");
  9539. return ((sfset.getValue(name)!=NULL)==includesub);
  9540. }
  9541. bool first()
  9542. {
  9543. if (!iter->first())
  9544. return false;
  9545. while (!match())
  9546. if (!iter->next())
  9547. return false;
  9548. return true;
  9549. }
  9550. bool next()
  9551. {
  9552. do {
  9553. if (!iter->next())
  9554. return false;
  9555. } while (!match());
  9556. return true;
  9557. }
  9558. bool isValid() { return iter->isValid(); }
  9559. IPropertyTree & query() { return iter->query(); }
  9560. };
  9561. IDFAttributesIterator *createSubFileFilter(IDFAttributesIterator *_iter,IUserDescriptor* _user, bool includesub, unsigned timeoutms)
  9562. {
  9563. return new CFilterAttrIterator(_iter,_user,includesub,timeoutms);
  9564. }
  9565. bool decodeChildGroupName(const char *gname,StringBuffer &parentname, StringBuffer &range)
  9566. {
  9567. if (!gname||!*gname)
  9568. return false;
  9569. size32_t l = strlen(gname);
  9570. if (gname[l-1]!=']')
  9571. return false;
  9572. const char *ss = strchr(gname,'[');
  9573. if (!ss||(ss==gname))
  9574. return false;
  9575. range.append(l-(ss-gname)-2,ss+1);
  9576. range.trim();
  9577. if (!range.length())
  9578. return false;
  9579. parentname.append(ss-gname,gname);
  9580. return true;
  9581. }
  9582. class CLightWeightSuperFileConn: public CInterface, implements ISimpleSuperFileEnquiry
  9583. {
  9584. CFileConnectLock lock;
  9585. bool readonly;
  9586. IArrayOf<IRemoteConnection> children;
  9587. unsigned defaultTimeout;
  9588. Owned<IUserDescriptor> udesc;
  9589. static StringBuffer &getSubPath(StringBuffer &path,unsigned idx)
  9590. {
  9591. return path.append("SubFile[@num=\"").append(idx+1).append("\"]");
  9592. }
  9593. void migrateProp(const char *name, unsigned num,IPropertyTree *from,IPropertyTree *to,IPropertyTree *newt, bool allowunchanged)
  9594. {
  9595. StringBuffer aname("Attr/");
  9596. aname.append(name);
  9597. StringBuffer s;
  9598. StringBuffer o;
  9599. if (from->getProp(aname.str(),s))
  9600. if ((num==1)||(allowunchanged&&to->getProp(aname.str(),o)&&(strcmp(s.str(),o.str())==0)))
  9601. newt->setProp(name,s.str());
  9602. }
  9603. void migrateAttr(IPropertyTree *from,IPropertyTree *to)
  9604. {
  9605. // this tries hard to set what it knows but avoids sibling traversal
  9606. if (!to)
  9607. return;
  9608. const char *desc = to->queryProp("Attr/@description");
  9609. IPropertyTree* newt = getEmptyAttr();
  9610. if (desc)
  9611. newt->setProp("@description",desc);
  9612. if (from) {
  9613. unsigned num=to->getPropInt("@numsubfiles");
  9614. migrateProp("@size",num,from,to,newt,false);
  9615. migrateProp("@checkSum",num,from,to,newt,true);
  9616. migrateProp("@formatCrc",num,from,to,newt,true);
  9617. migrateProp("@recordSize",num,from,to,newt,true);
  9618. MemoryBuffer mb;
  9619. MemoryBuffer mbo;
  9620. const char *aname = "Attr/_record_layout";
  9621. if (from->getPropBin(aname,mb))
  9622. if ((num==1)||(to->getPropBin(aname,mbo)&&
  9623. (mb.length()==mbo.length())&&
  9624. (memcmp(mb.bufferBase(),mbo.bufferBase(),mb.length())==0)))
  9625. newt->setPropBin("_record_layout", mb.length(), mb.bufferBase());
  9626. }
  9627. to->setPropTree("Attr",newt);
  9628. }
  9629. void migrateSuperOwnersAttr(IPropertyTree *from)
  9630. {
  9631. if (!from)
  9632. return;
  9633. Owned<IPropertyTreeIterator> iter = from->getElements("SuperOwner");
  9634. StringBuffer pname;
  9635. StringBuffer query;
  9636. ForEach(*iter) {
  9637. if (iter->query().getProp("@name",pname.clear())) {
  9638. CDfsLogicalFileName lfn;
  9639. lfn.set(pname.str());
  9640. lfn.makeFullnameQuery(query.clear(),DXB_SuperFile,true);
  9641. Owned<IRemoteConnection> conn;
  9642. try {
  9643. conn.setown(querySDS().connect(query.str(),myProcessSession(),RTM_LOCK_WRITE,1000*60*5));
  9644. }
  9645. catch (ISDSException *e) {
  9646. if (SDSExcpt_LockTimeout != e->errorCode())
  9647. throw;
  9648. e->Release();
  9649. WARNLOG("migrateSuperOwnersAttr: Could not lock parent %s",query.str());
  9650. conn.setown(querySDS().connect(query.str(),myProcessSession(),0,defaultTimeout));
  9651. }
  9652. if (conn) {
  9653. migrateAttr(from,conn->queryRoot());
  9654. migrateSuperOwnersAttr(conn->queryRoot());
  9655. }
  9656. else
  9657. WARNLOG("migrateSuperOwnersAttr could not connect to parent superfile %s",lfn.get());
  9658. }
  9659. }
  9660. }
  9661. public:
  9662. IMPLEMENT_IINTERFACE;
  9663. CLightWeightSuperFileConn(unsigned _defaultTimeout, IUserDescriptor *_udesc)
  9664. {
  9665. defaultTimeout = _defaultTimeout;
  9666. readonly = false;
  9667. udesc.set(_udesc);
  9668. }
  9669. bool connect(CDistributedFileDirectory *parent,const char *title, const char *name, bool _readonly, bool *autocreate, unsigned timeout)
  9670. {
  9671. if (autocreate)
  9672. *autocreate = false;
  9673. readonly = _readonly;
  9674. disconnect(false);
  9675. CDfsLogicalFileName lfn;
  9676. if (!lfn.setValidate(name))
  9677. throw MakeStringException(-1,"%s: Invalid superfile name '%s'",title,name);
  9678. if (lfn.isMulti()||lfn.isExternal()||lfn.isForeign())
  9679. return false;
  9680. if (!lock.init(title, lfn, DXB_SuperFile, !readonly, true, false, timeout))
  9681. {
  9682. if (!autocreate) // NB not !*autocreate here !
  9683. return false;
  9684. IPropertyTree *root = createPTree();
  9685. root->setPropInt("@interleaved",2);
  9686. root->setPropInt("@numsubfiles",0);
  9687. root->setPropTree("Attr",getEmptyAttr());
  9688. parent->addEntry(lfn,root,true,false);
  9689. if (!lock.init(title, lfn, DXB_SuperFile, true, true, false, timeout))
  9690. throw MakeStringException(-1,"%s: Cannot create superfile '%s'",title,name);
  9691. if (autocreate)
  9692. *autocreate = true;
  9693. }
  9694. StringBuffer reason;
  9695. if (!readonly&&checkProtectAttr(name,lock.queryRoot(),reason))
  9696. throw MakeStringException(-1,"CDistributedSuperFile::%s %s",title,reason.str());
  9697. return true;
  9698. }
  9699. void disconnect(bool commit)
  9700. {
  9701. if (lock.conn()&&!readonly) {
  9702. if (commit) {
  9703. migrateSuperOwnersAttr(lock.queryRoot());
  9704. CDateTime dt;
  9705. dt.setNow();
  9706. StringBuffer s;
  9707. lock.queryRoot()->setProp("@modified",dt.getString(s).str());
  9708. }
  9709. else {
  9710. ForEachItemIn(i,children)
  9711. children.item(i).rollback();
  9712. lock.conn()->rollback();
  9713. }
  9714. }
  9715. lock.kill();
  9716. children.kill();
  9717. }
  9718. unsigned numSubFiles() const
  9719. {
  9720. return (unsigned)lock.queryRoot()->getPropInt("@numsubfiles");
  9721. }
  9722. bool getSubFileName(unsigned num,StringBuffer &name) const
  9723. {
  9724. if ((unsigned)lock.queryRoot()->getPropInt("@numsubfiles")<=num)
  9725. return false;
  9726. StringBuffer xpath;
  9727. getSubPath(xpath,num);
  9728. IPropertyTree *sub = lock.queryRoot()->queryPropTree(xpath.str());
  9729. if (!sub)
  9730. return false;
  9731. name.append(sub->queryProp("@name"));
  9732. return true;
  9733. }
  9734. unsigned findSubName(const char *subname) const
  9735. {
  9736. unsigned n = findSubFileOrd(subname);
  9737. if (n!=NotFound)
  9738. return n;
  9739. StringBuffer lfn;
  9740. normalizeLFN(subname,lfn);
  9741. Owned<IPropertyTreeIterator> iter = lock.queryRoot()->getElements("SubFile");
  9742. ForEach(*iter) {
  9743. if (stricmp(iter->query().queryProp("@name"),lfn.str())==0) {
  9744. unsigned ret=iter->query().getPropInt("@num");
  9745. if (ret&&((unsigned)lock.queryRoot()->getPropInt("@numsubfiles")>=ret))
  9746. return ret-1;
  9747. }
  9748. }
  9749. return NotFound;
  9750. }
  9751. unsigned getContents(StringArray &contents) const
  9752. {
  9753. // slightly inefficient
  9754. unsigned n = lock.queryRoot()->getPropInt("@numsubfiles");
  9755. StringBuffer xpath;
  9756. for (unsigned sni=0;sni<n;sni++) {
  9757. getSubPath(xpath.clear(),sni);
  9758. IPropertyTree *sub = lock.queryRoot()->queryPropTree(xpath.str());
  9759. if (!sub)
  9760. break;
  9761. contents.append(sub->queryProp("@name"));
  9762. }
  9763. return contents.ordinality();
  9764. }
  9765. };
  9766. // Contention never expected for this function!
  9767. #define PROMOTE_CONN_TIMEOUT (60*1000) // how long to wait for a single superfile
  9768. #define PROMOTE_DELAY (30*1000)
  9769. // Check files don't share subfiles (MORE - make this part of swap files action?)
  9770. static int hasCommonSubChildren(IDistributedSuperFile *orig, IDistributedSuperFile *dest)
  9771. {
  9772. unsigned origSubs = orig->numSubFiles();
  9773. unsigned destSubs = dest->numSubFiles();
  9774. if (origSubs == 0)
  9775. return NotFound;
  9776. for (unsigned j=0; j<origSubs; j++) {
  9777. for (unsigned k=0; k<destSubs; k++) {
  9778. if (strcmp(orig->querySubFile(j).queryLogicalName(), dest->querySubFile(k).queryLogicalName())==0)
  9779. return j;
  9780. }
  9781. }
  9782. return NotFound;
  9783. }
  9784. // MORE - use string arrays, rather than char* arrays or comma-separated strings
  9785. void CDistributedFileDirectory::promoteSuperFiles(unsigned numsf,const char **sfnames,const char *addsubnames,bool delsub,bool createonlyonesuperfile,IUserDescriptor *user,unsigned timeout,StringArray &outunlinked)
  9786. {
  9787. if (!numsf)
  9788. return;
  9789. // Create a local transaction that will be destroyed
  9790. Owned<IDistributedFileTransactionExt> transaction = new CDistributedFileTransaction(user);
  9791. transaction->start();
  9792. // Lookup all files (keep them in transaction's cache)
  9793. bool created = false;
  9794. unsigned files = numsf;
  9795. for (unsigned i=0; i<numsf; i++) {
  9796. Owned<IDistributedSuperFile> super = transaction->lookupSuperFile(sfnames[i]);
  9797. if (!super.get()) {
  9798. if (created && createonlyonesuperfile) {
  9799. files = i;
  9800. break;
  9801. }
  9802. Owned<IDistributedSuperFile> sfile = createSuperFile(sfnames[i],user,false,false,transaction);
  9803. created = true;
  9804. }
  9805. }
  9806. // If last file had sub-files, clean and fill outlinked
  9807. Owned<IDistributedSuperFile> last = transaction->lookupSuperFile(sfnames[files-1]);
  9808. assertex(last.get());
  9809. unsigned lastSubs = last->numSubFiles();
  9810. if (files == numsf && lastSubs > 0) {
  9811. for (unsigned i=0; i<lastSubs; i++) {
  9812. outunlinked.append(last->querySubFile(i).queryLogicalName());
  9813. }
  9814. last->removeSubFile(NULL,false,false,transaction);
  9815. }
  9816. last.clear();
  9817. // Move up, starting from last
  9818. for (unsigned i=files-1; i; i--) {
  9819. Owned<IDistributedSuperFile> orig = transaction->lookupSuperFile(sfnames[i-1]);
  9820. Owned<IDistributedSuperFile> dest = transaction->lookupSuperFile(sfnames[i]);
  9821. assertex(orig.get());
  9822. assertex(dest.get());
  9823. int common = hasCommonSubChildren(orig, dest);
  9824. if (common != NotFound) {
  9825. throw MakeStringException(-1,"promoteSuperFiles: superfiles %s and %s share same subfile %s",
  9826. orig->queryLogicalName(), dest->queryLogicalName(), orig->querySubFile(common).queryLogicalName());
  9827. }
  9828. orig->swapSuperFile(dest, transaction);
  9829. }
  9830. // Move new subs to first super, if any
  9831. Owned<IDistributedSuperFile> first = transaction->lookupSuperFile(sfnames[0]);
  9832. assertex(first.get());
  9833. StringArray toadd;
  9834. toadd.appendListUniq(addsubnames, ",");
  9835. ForEachItemIn(i,toadd) {
  9836. CDfsLogicalFileName lfn;
  9837. if (!lfn.setValidate(toadd.item(i)))
  9838. throw MakeStringException(-1,"promoteSuperFiles: invalid logical name to add: %s",toadd.item(i));
  9839. first->addSubFile(toadd.item(i),false,NULL,false,transaction);
  9840. }
  9841. first.clear();
  9842. transaction->commit();
  9843. // MORE - once deletion of logic files are also in transaction we can move this up (and allow promote within transactions)
  9844. if (delsub) {
  9845. ForEachItemIn(j,outunlinked)
  9846. removeEntry(outunlinked.item(j),user,transaction,timeout);
  9847. }
  9848. }
  9849. ISimpleSuperFileEnquiry * CDistributedFileDirectory::getSimpleSuperFileEnquiry(const char *logicalname,const char *title,IUserDescriptor *udesc,unsigned timeout)
  9850. {
  9851. Owned<CLightWeightSuperFileConn> ret = new CLightWeightSuperFileConn(defaultTimeout,udesc);
  9852. if (ret->connect(this,title,logicalname,true,NULL,timeout))
  9853. return ret.getClear();
  9854. return NULL;
  9855. }
  9856. bool CDistributedFileDirectory::getFileSuperOwners(const char *logicalname, StringArray &owners)
  9857. {
  9858. CFileConnectLock lock;
  9859. CDfsLogicalFileName lfn;
  9860. if (!lfn.setValidate(logicalname))
  9861. throw MakeStringException(-1,"CDistributedFileDirectory::getFileSuperOwners: Invalid file name '%s'",logicalname);
  9862. if (lfn.isMulti()||lfn.isExternal()||lfn.isForeign())
  9863. return false;
  9864. DfsXmlBranchKind bkind;
  9865. if (!lock.initany("CDistributedFileDirectory::getFileSuperOwners", lfn, bkind, false, false, false, defaultTimeout))
  9866. return false;
  9867. Owned<IPropertyTreeIterator> iter = lock.queryRoot()->getElements("SuperOwner");
  9868. StringBuffer pname;
  9869. ForEach(*iter) {
  9870. iter->query().getProp("@name",pname.clear());
  9871. if (pname.length())
  9872. owners.append(pname.str());
  9873. }
  9874. return true;
  9875. }
  9876. class CFileRelationship: public CInterface, implements IFileRelationship
  9877. {
  9878. Linked<IPropertyTree> pt;
  9879. const char *queryProp(const char *name)
  9880. {
  9881. if (pt.get()) {
  9882. const char *ret = pt->queryProp(name);
  9883. if (ret)
  9884. return ret;
  9885. }
  9886. return "";
  9887. }
  9888. public:
  9889. IMPLEMENT_IINTERFACE;
  9890. CFileRelationship(IPropertyTree *_pt)
  9891. : pt(_pt)
  9892. {
  9893. }
  9894. virtual const char *queryKind() { return queryProp("@kind"); }
  9895. virtual const char *queryPrimaryFilename() { return queryProp("@primary"); }
  9896. virtual const char *querySecondaryFilename() { return queryProp("@secondary"); }
  9897. virtual const char *queryPrimaryFields() { return queryProp("@primflds"); }
  9898. virtual const char *querySecondaryFields() { return queryProp("@secflds"); }
  9899. virtual const char *queryCardinality() { return queryProp("@cardinality"); }
  9900. virtual bool isPayload() { return pt->getPropBool("@payload"); }
  9901. virtual const char *queryDescription() { return queryProp("Description"); }
  9902. virtual IPropertyTree *queryTree() { return pt.get(); }
  9903. };
  9904. class CFileRelationshipIterator: public CInterface, implements IFileRelationshipIterator
  9905. {
  9906. unsigned num;
  9907. unsigned idx;
  9908. CMessageBuffer mb;
  9909. Owned<CFileRelationship> r;
  9910. Owned<IPropertyTree> pt;
  9911. Linked<INode> foreigndali;
  9912. unsigned defaultTimeout;
  9913. bool setPT()
  9914. {
  9915. if (idx<num) {
  9916. pt.setown(createPTree(mb));
  9917. addForeignName(*pt,foreigndali,"@primary");
  9918. addForeignName(*pt,foreigndali,"@secondary");
  9919. }
  9920. return pt.get()!=NULL;
  9921. }
  9922. public:
  9923. IMPLEMENT_IINTERFACE;
  9924. CFileRelationshipIterator(unsigned timems)
  9925. {
  9926. num = 0;
  9927. idx = 0;
  9928. mb.append(num);
  9929. defaultTimeout = timems;
  9930. }
  9931. void init(
  9932. INode *_foreigndali,
  9933. unsigned foreigndalitimeout,
  9934. const char *primary,
  9935. const char *secondary,
  9936. const char *primflds,
  9937. const char *secflds,
  9938. const char *kind,
  9939. const char *cardinality,
  9940. const bool *payload )
  9941. {
  9942. foreigndali.set(_foreigndali);
  9943. if (isLocalDali(foreigndali)) {
  9944. CConnectLock connlock("lookupFileRelationships",querySdsRelationshipsRoot(),false,false,false,defaultTimeout);
  9945. StringBuffer xpath;
  9946. CDistributedFileDirectory::getFileRelationshipXPath(xpath,primary,secondary,primflds,secflds,kind,cardinality,payload);
  9947. Owned<IPropertyTreeIterator> iter = connlock.conn?connlock.conn->getElements(xpath.str()):NULL;
  9948. mb.clear();
  9949. unsigned count = 0;
  9950. mb.append(count);
  9951. // save as sequence of branches
  9952. if (iter) {
  9953. ForEach(*iter.get()) {
  9954. iter->query().serialize(mb);
  9955. count++;
  9956. }
  9957. mb.writeDirect(0,sizeof(count),&count);
  9958. }
  9959. }
  9960. else {
  9961. byte payloadb = 255;
  9962. if (payload)
  9963. payloadb = *payload?1:0;
  9964. mb.clear().append((int)MDFS_ITERATE_RELATIONSHIPS).append(primary).append(secondary).append(primflds).append(secflds).append(kind).append(cardinality).append(payloadb);
  9965. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  9966. checkDfsReplyException(mb);
  9967. if (mb.length()<sizeof(unsigned))
  9968. mb.clear().append((unsigned)0);
  9969. }
  9970. }
  9971. void initall(const char *filename)
  9972. {
  9973. StringBuffer xpath;
  9974. Owned<IPropertyTreeIterator> iter;
  9975. mb.clear();
  9976. unsigned count = 0;
  9977. mb.append(count);
  9978. {
  9979. CConnectLock connlock("lookupFileRelationships",querySdsRelationshipsRoot(),false,false,false,defaultTimeout);
  9980. CDistributedFileDirectory::getFileRelationshipXPath(xpath,filename,NULL,NULL,NULL,NULL,NULL,NULL);
  9981. // save as sequence of branches
  9982. iter.setown(connlock.conn?connlock.conn->getElements(xpath.str()):NULL);
  9983. if (iter) {
  9984. ForEach(*iter.get()) {
  9985. iter->query().serialize(mb);
  9986. count++;
  9987. }
  9988. }
  9989. }
  9990. { // Kludge - seems to be a bug in getElements without second conn lock
  9991. CConnectLock connlock("lookupFileRelationships",querySdsRelationshipsRoot(),false,false,false,defaultTimeout);
  9992. xpath.clear();
  9993. CDistributedFileDirectory::getFileRelationshipXPath(xpath,NULL,filename,NULL,NULL,NULL,NULL,NULL);
  9994. iter.clear();
  9995. iter.setown(connlock.conn?connlock.conn->getElements(xpath.str()):NULL);
  9996. if (iter) {
  9997. ForEach(*iter.get()) {
  9998. IPropertyTree &it = iter->query();
  9999. const char *fn1 = it.queryProp("@primary");
  10000. if (!fn1||(strcmp(fn1,filename)!=0)) { // see if already done
  10001. it.serialize(mb);
  10002. count++;
  10003. }
  10004. }
  10005. }
  10006. }
  10007. mb.writeDirect(0,sizeof(count),&count);
  10008. }
  10009. bool first()
  10010. {
  10011. r.clear();
  10012. pt.clear();
  10013. idx = 0;
  10014. mb.reset().read(num);
  10015. return setPT();
  10016. }
  10017. bool next()
  10018. {
  10019. r.clear();
  10020. pt.clear();
  10021. idx++;
  10022. return setPT();
  10023. }
  10024. bool isValid()
  10025. {
  10026. return pt.get()!=NULL;
  10027. }
  10028. IFileRelationship & query()
  10029. {
  10030. if (!r)
  10031. r.setown(new CFileRelationship(pt));
  10032. return *r;
  10033. }
  10034. };
  10035. static bool isWild(const char *path,bool emptydefault=false)
  10036. {
  10037. if (!path||!*path)
  10038. return emptydefault;
  10039. return ((strchr(path,'?')||strchr(path,'*')));
  10040. }
  10041. static void addRelationCondition(StringBuffer &xpath,const char *fld,const char *mask)
  10042. {
  10043. if (!mask||!*mask||((*mask=='*')&&(!mask[1])))
  10044. return;
  10045. xpath.append('[').append(fld).append('=');
  10046. if (isWild(mask))
  10047. xpath.append('~');
  10048. xpath.append('"').append(mask).append("\"]");
  10049. }
  10050. static void addRelationBoolCondition(StringBuffer &xpath,const char *fld,const bool *mask)
  10051. {
  10052. if (!mask)
  10053. return;
  10054. xpath.append('[').append(fld).append("=\"");
  10055. if (*mask)
  10056. xpath.append("1\"]");
  10057. else
  10058. xpath.append("0\"]");
  10059. }
  10060. static const char *normLFN(const char *name,CDfsLogicalFileName &logicalname,const char *title)
  10061. {
  10062. if (isWild(name,true))
  10063. return name;
  10064. if (!logicalname.setValidate(name))
  10065. throw MakeStringException(-1,"%s: invalid logical file name '%s'",title,name);
  10066. if (logicalname.isForeign()) {
  10067. SocketEndpoint ep;
  10068. Owned<INode> fd = createINode(ep);
  10069. if (logicalname.getEp(ep)&&isLocalDali(fd)) // see if pointing back at self
  10070. logicalname.clearForeign();
  10071. }
  10072. return logicalname.get();
  10073. }
  10074. StringBuffer &CDistributedFileDirectory::getFileRelationshipXPath(
  10075. StringBuffer &xpath,
  10076. const char *primary,
  10077. const char *secondary,
  10078. const char *primflds,
  10079. const char *secflds,
  10080. const char *kind,
  10081. const char *cardinality,
  10082. const bool *payload
  10083. )
  10084. {
  10085. xpath.append("Relationship");
  10086. CDfsLogicalFileName lfn;
  10087. addRelationCondition(xpath,"@kind",kind);
  10088. addRelationCondition(xpath,"@primary",normLFN(primary,lfn,"findFileRelationship(primary)"));
  10089. addRelationCondition(xpath,"@secondary",normLFN(secondary,lfn,"findFileRelationship(secondary)"));
  10090. addRelationCondition(xpath,"@primflds",primflds);
  10091. addRelationCondition(xpath,"@secflds",secflds);
  10092. addRelationCondition(xpath,"@cardinality",cardinality);
  10093. addRelationBoolCondition(xpath,"@payload",payload);
  10094. return xpath;
  10095. }
  10096. void CDistributedFileDirectory::doRemoveFileRelationship(
  10097. IRemoteConnection *conn,
  10098. const char *primary,
  10099. const char *secondary,
  10100. const char *primflds,
  10101. const char *secflds,
  10102. const char *kind
  10103. )
  10104. {
  10105. if (!conn)
  10106. return;
  10107. StringBuffer xpath;
  10108. CDistributedFileDirectory::getFileRelationshipXPath(xpath,primary,secondary,primflds,secflds,kind,NULL,NULL);
  10109. Owned<IPropertyTreeIterator> iter = conn->getElements(xpath.str());
  10110. IArrayOf<IPropertyTree> toremove;
  10111. ForEach(*iter) {
  10112. IPropertyTree &t = iter->query();
  10113. toremove.append(*LINK(&t));
  10114. }
  10115. ForEachItemIn(i, toremove) {
  10116. conn->queryRoot()->removeTree(&toremove.item(i));
  10117. }
  10118. }
  10119. void CDistributedFileDirectory::addFileRelationship(
  10120. const char *primary,
  10121. const char *secondary,
  10122. const char *primflds,
  10123. const char *secflds,
  10124. const char *kind,
  10125. const char *cardinality,
  10126. bool payload,
  10127. IUserDescriptor *user,
  10128. const char *description=NULL
  10129. )
  10130. {
  10131. if (!kind||!*kind)
  10132. kind = S_LINK_RELATIONSHIP_KIND;
  10133. Owned<IPropertyTree> pt = createPTree("Relationship");
  10134. if (isWild(primary,true)||isWild(secondary,true)||isWild(primflds,false)||isWild(secflds,false)||isWild(cardinality,false))
  10135. throw MakeStringException(-1,"Wildcard not allowed in addFileRelation");
  10136. CDfsLogicalFileName pfn;
  10137. if (!pfn.setValidate(primary))
  10138. throw MakeStringException(-1,"addFileRelationship invalid primary name '%s'",primary);
  10139. if (pfn.isExternal()||pfn.isForeign()||pfn.isQuery())
  10140. throw MakeStringException(-1,"addFileRelationship primary %s not allowed",pfn.get());
  10141. primary = pfn.get();
  10142. if (!exists(primary,user))
  10143. throw MakeStringException(-1,"addFileRelationship primary %s does not exist",primary);
  10144. CDfsLogicalFileName sfn;
  10145. if (!sfn.setValidate(secondary))
  10146. throw MakeStringException(-1,"addFileRelationship invalid secondary name '%s'",secondary);
  10147. if (sfn.isExternal()||sfn.isForeign()||sfn.isQuery())
  10148. throw MakeStringException(-1,"addFileRelationship secondary %s not allowed",sfn.get());
  10149. secondary = sfn.get();
  10150. if (!exists(secondary,user))
  10151. throw MakeStringException(-1,"addFileRelationship secondary %s does not exist",secondary);
  10152. if (cardinality&&*cardinality&&!strchr(cardinality,':'))
  10153. throw MakeStringException(-1,"addFileRelationship cardinality %s invalid",cardinality);
  10154. pt->setProp("@kind",kind);
  10155. pt->setProp("@primary",primary);
  10156. pt->setProp("@secondary",secondary);
  10157. pt->setProp("@cardinality",cardinality);
  10158. pt->setProp("@primflds",primflds);
  10159. pt->setProp("@secflds",secflds);
  10160. pt->setPropBool("@payload",payload);
  10161. if (description&&*description)
  10162. pt->setProp("Description",description);
  10163. StringBuffer xpath(querySdsFilesRoot());
  10164. for (unsigned i=0;i<2;i++) {
  10165. CConnectLock connlock("addFileRelation",querySdsRelationshipsRoot(),true,false,false,defaultTimeout);
  10166. if (!connlock.conn) {
  10167. CConnectLock connlock2("addFileRelation.2",querySdsFilesRoot(),true,false,false,defaultTimeout);
  10168. if (!connlock2.conn)
  10169. return;
  10170. Owned<IPropertyTree> ptr = createPTree("Relationships");
  10171. connlock2.conn->queryRoot()->addPropTree("Relationships",ptr.getClear());
  10172. continue;
  10173. }
  10174. StringBuffer query;
  10175. doRemoveFileRelationship(connlock.conn,primary,secondary,primflds,secflds,kind);
  10176. connlock.conn->queryRoot()->addPropTree("Relationship",pt.getClear());
  10177. break;
  10178. }
  10179. }
  10180. void CDistributedFileDirectory::removeFileRelationships(
  10181. const char *primary,
  10182. const char *secondary,
  10183. const char *primflds,
  10184. const char *secflds,
  10185. const char *kind
  10186. )
  10187. {
  10188. if ((!primary||!*primary||(strcmp(primary,"*")==0))&&
  10189. (!secondary||!*secondary||(strcmp(secondary,"*")==0)))
  10190. throw MakeStringException(-1,"removeFileRelationships primary and secondary cannot both be wild");
  10191. CConnectLock connlock("removeFileRelation",querySdsRelationshipsRoot(),true,false,false,defaultTimeout);
  10192. doRemoveFileRelationship(connlock.conn,primary,secondary,primflds,secflds,kind);
  10193. }
  10194. IFileRelationshipIterator *CDistributedFileDirectory::lookupFileRelationships(
  10195. const char *primary,
  10196. const char *secondary,
  10197. const char *primflds,
  10198. const char *secflds,
  10199. const char *kind,
  10200. const char *cardinality,
  10201. const bool *payload,
  10202. const char *foreigndali,
  10203. unsigned foreigndalitimeout
  10204. )
  10205. {
  10206. Owned<INode> foreign;
  10207. if (foreigndali&&*foreigndali) {
  10208. SocketEndpoint ep(foreigndali);
  10209. if (ep.isNull())
  10210. throw MakeStringException(-1,"lookupFileRelationships::Cannot resolve foreign dali %s",foreigndali);
  10211. foreign.setown(createINode(ep));
  10212. }
  10213. Owned<CFileRelationshipIterator> ret = new CFileRelationshipIterator(defaultTimeout);
  10214. ret->init(foreign,foreigndalitimeout,primary,secondary,primflds,secflds,kind,cardinality,payload);
  10215. return ret.getClear();
  10216. }
  10217. void CDistributedFileDirectory::removeAllFileRelationships(const char *filename)
  10218. {
  10219. if (!filename||!*filename||(strcmp(filename,"*")==0))
  10220. throw MakeStringException(-1,"removeAllFileRelationships filename cannot be wild");
  10221. {
  10222. CConnectLock connlock("removeFileRelation",querySdsRelationshipsRoot(),true,false,false,defaultTimeout);
  10223. doRemoveFileRelationship(connlock.conn,filename,NULL,NULL,NULL,NULL);
  10224. }
  10225. { // kludge bug in getElements if connection used twice
  10226. CConnectLock connlock("removeFileRelation",querySdsRelationshipsRoot(),true,false,false,defaultTimeout);
  10227. doRemoveFileRelationship(connlock.conn,NULL,filename,NULL,NULL,NULL);
  10228. }
  10229. }
  10230. IFileRelationshipIterator *CDistributedFileDirectory::lookupAllFileRelationships(
  10231. const char *filename)
  10232. {
  10233. if (isWild(filename,true))
  10234. throw MakeStringException(-1,"Wildcard filename not allowed in lookupAllFileRelationships");
  10235. CDfsLogicalFileName lfn;
  10236. normLFN(filename,lfn,"lookupAllFileRelationships");
  10237. Owned<CFileRelationshipIterator> ret = new CFileRelationshipIterator(defaultTimeout);
  10238. ret->initall(lfn.get());
  10239. return ret.getClear();
  10240. }
  10241. void CDistributedFileDirectory::renameFileRelationships(const char *oldname,const char *newname,IFileRelationshipIterator *reliter,IUserDescriptor*user)
  10242. {
  10243. CDfsLogicalFileName oldlfn;
  10244. normLFN(oldname,oldlfn,"renameFileRelationships(old name)");
  10245. CDfsLogicalFileName newlfn;
  10246. normLFN(newname,newlfn,"renameFileRelationships(new name)");
  10247. ForEach(*reliter) {
  10248. try {
  10249. IFileRelationship &r = reliter->query();
  10250. bool adj = false;
  10251. const char *pf = r.queryPrimaryFilename();
  10252. if (!pf)
  10253. continue;
  10254. if (strcmp(pf,oldlfn.get())==0) {
  10255. adj = true;
  10256. pf = newlfn.get();
  10257. }
  10258. const char *sf = r.querySecondaryFilename();
  10259. if (!sf)
  10260. continue;
  10261. if (strcmp(sf,oldlfn.get())==0) {
  10262. adj = true;
  10263. sf = newlfn.get();
  10264. }
  10265. if (adj)
  10266. addFileRelationship(pf,sf,r.queryPrimaryFields(),r.querySecondaryFields(),r.queryKind(),r.queryCardinality(),r.isPayload(),user,r.queryDescription());
  10267. }
  10268. catch (IException *e)
  10269. {
  10270. EXCLOG(e,"renameFileRelationships");
  10271. e->Release();
  10272. }
  10273. }
  10274. }
  10275. // JCSMORE what was this for, not called by anything afaics
  10276. bool CDistributedFileDirectory::publishMetaFileXML(const CDfsLogicalFileName &logicalname,IUserDescriptor *user)
  10277. {
  10278. if (logicalname.isExternal()||logicalname.isForeign()||logicalname.isQuery())
  10279. return false;
  10280. Owned<IPropertyTree> file = getFileTree(logicalname.get(),user,NULL,FOREIGN_DALI_TIMEOUT,true);
  10281. if (!file.get())
  10282. return false;
  10283. if (strcmp(file->queryName(),queryDfsXmlBranchName(DXB_SuperFile))==0)
  10284. return false;
  10285. unsigned max = file->getPropInt("@numparts");
  10286. SocketEndpointArray ips;
  10287. StringBuffer xpath;
  10288. StringBuffer ipstr;
  10289. for (unsigned i=0;i<max;i++) { // probably could be done better
  10290. xpath.clear().append("Part[@num=\"").append(i+1).append("\"]");
  10291. Owned<IPropertyTree> child = file->getPropTree(xpath.str());
  10292. SocketEndpoint ep;
  10293. if (child.get()&&child->getProp("@node",ipstr.clear()))
  10294. ep.ipset(ipstr.str());
  10295. ips.append(ep);
  10296. }
  10297. Owned<IException> exc;
  10298. CriticalSection errcrit;
  10299. class casyncfor: public CAsyncFor
  10300. {
  10301. IPropertyTree* file;
  10302. CriticalSection &errcrit;
  10303. Owned<IException> &exc;
  10304. SocketEndpointArray &ips;
  10305. public:
  10306. casyncfor(IPropertyTree* _file,SocketEndpointArray &_ips,Owned<IException> &_exc,CriticalSection &_errcrit)
  10307. : ips(_ips), exc(_exc), errcrit(_errcrit)
  10308. {
  10309. file = _file;
  10310. }
  10311. void Do(unsigned i)
  10312. {
  10313. UnsignedArray parts;
  10314. SocketEndpoint &ep = ips.item(i);
  10315. if (ep.isNull())
  10316. return;
  10317. ForEachItemIn(j,ips) {
  10318. if (j==i)
  10319. parts.append(i);
  10320. else if (ep.ipequals(ips.item(j))) {
  10321. if (j<i)
  10322. return; // already done
  10323. parts.append(j);
  10324. }
  10325. }
  10326. try {
  10327. StringBuffer path;
  10328. StringBuffer mask;
  10329. if (file->getProp("@directory",path)&&file->getProp("@partmask",mask)) {
  10330. addPathSepChar(path).append(mask);
  10331. StringBuffer outpath;
  10332. StringBuffer tail("META__");
  10333. splitFilename(path.str(), &outpath, &outpath, &tail, NULL);
  10334. outpath.append(tail).append(".xml");
  10335. Owned<IPropertyTree> pt = createPTreeFromIPT(file);
  10336. filterParts(pt,parts);
  10337. StringBuffer str;
  10338. toXML(pt, str);
  10339. RemoteFilename rfn;
  10340. rfn.setPath(ep,outpath.str());
  10341. Owned<IFile> out = createIFile(rfn);
  10342. Owned<IFileIO> outio = out->open(IFOcreate);
  10343. if (outio)
  10344. outio->write(0,str.length(),str.str());
  10345. }
  10346. }
  10347. catch(IException *e)
  10348. {
  10349. CriticalBlock block(errcrit);
  10350. EXCLOG(e,"publishMetaFileXML");
  10351. if (!exc.get())
  10352. exc.setown(e);
  10353. else
  10354. e->Release();
  10355. }
  10356. }
  10357. } afor(file,ips,exc,errcrit);
  10358. afor.For(max,20);
  10359. if (exc)
  10360. throw exc.getClear();
  10361. return true;
  10362. }
  10363. IFileDescriptor *CDistributedFileDirectory::createDescriptorFromMetaFile(const CDfsLogicalFileName &logicalname,IUserDescriptor *user)
  10364. {
  10365. return NULL; // TBD
  10366. }
  10367. // Overwrite protection
  10368. bool CDistributedFileDirectory::isProtectedFile(const CDfsLogicalFileName &logicalname, unsigned timeout)
  10369. {
  10370. DfsXmlBranchKind bkind;
  10371. CFileConnectLock fconnattrlock(true);
  10372. if (!fconnattrlock.initany("CDistributedFileDirectory::isProtectedFile", logicalname, bkind, true, false, false, timeout?timeout:INFINITE))
  10373. return false; // timeout will raise exception
  10374. Owned<IPropertyTreeIterator> wpiter = fconnattrlock.queryRoot()->getElements("Protect");
  10375. bool prot = false;
  10376. ForEach(*wpiter) {
  10377. IPropertyTree &t = wpiter->query();
  10378. if (t.getPropInt("@count")) {
  10379. prot = true;
  10380. break;
  10381. }
  10382. }
  10383. // timeout retry TBD
  10384. return prot;
  10385. }
  10386. unsigned CDistributedFileDirectory::queryProtectedCount(const CDfsLogicalFileName &logicalname, const char *owner)
  10387. {
  10388. DfsXmlBranchKind bkind;
  10389. CFileConnectLock fconnattrlock(true);
  10390. if (!fconnattrlock.initany("CDistributedFileDirectory::isProtectedFile", logicalname, bkind, true, false, false, defaultTimeout))
  10391. return 0; // timeout will raise exception
  10392. Owned<IPropertyTreeIterator> wpiter = fconnattrlock.queryRoot()->getElements("Protect");
  10393. unsigned count = 0;
  10394. ForEach(*wpiter) {
  10395. IPropertyTree &t = wpiter->query();
  10396. const char *name = t.queryProp("@name");
  10397. if (!owner||!*owner||(name&&(strcmp(owner,name)==0)))
  10398. count += t.getPropInt("@count");
  10399. }
  10400. return count;
  10401. }
  10402. bool CDistributedFileDirectory::getProtectedInfo(const CDfsLogicalFileName &logicalname, StringArray &names, UnsignedArray &counts)
  10403. {
  10404. DfsXmlBranchKind bkind;
  10405. CFileConnectLock fconnattrlock(true);
  10406. if (!fconnattrlock.initany("CDistributedFileDirectory::isProtectedFile", logicalname, bkind, true, false, false, defaultTimeout))
  10407. return false; // timeout will raise exception
  10408. Owned<IPropertyTreeIterator> wpiter = fconnattrlock.queryRoot()->getElements("Protect");
  10409. bool prot = false;
  10410. ForEach(*wpiter) {
  10411. IPropertyTree &t = wpiter->query();
  10412. const char *name = t.queryProp("@name");
  10413. names.append(name?name:"<Unknown>");
  10414. unsigned c = t.getPropInt("@count");
  10415. if (c)
  10416. prot = true;
  10417. counts.append(c);
  10418. }
  10419. return prot;
  10420. }
  10421. IDFProtectedIterator *CDistributedFileDirectory::lookupProtectedFiles(const char *owner,bool notsuper,bool superonly)
  10422. {
  10423. return new CDFProtectedIterator(owner,notsuper,superonly,defaultTimeout);
  10424. }
  10425. #ifdef _USE_CPPUNIT
  10426. /*
  10427. * This method removes files only logically. removeEntry() used to do that, but the only
  10428. * external use for logical-files only is this test-suite, so I'd rather hack the test
  10429. * suite than expose the behaviour to more viewers.
  10430. */
  10431. extern da_decl void removeLogical(const char *fname, IUserDescriptor *user) {
  10432. if (queryDistributedFileDirectory().exists(fname, user)) {
  10433. Owned<IDistributedFile> file = queryDistributedFileDirectory().lookup(fname, user, true);
  10434. CDistributedFile *f = QUERYINTERFACE(file.get(),CDistributedFile);
  10435. assert(f);
  10436. f->detachLogical();
  10437. }
  10438. }
  10439. #endif // _USE_CPPUNIT