dadfs.cpp 414 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001
  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_ITERATE_FILTEREDFILES,
  64. MDFS_MAX
  65. };
  66. // Mutex for physical operations (remove/rename)
  67. static CriticalSection physicalChange;
  68. #define MDFS_GET_FILE_TREE_V2 ((unsigned)1)
  69. static int strcompare(const void * left, const void * right)
  70. {
  71. const char * l = (const char *)left;
  72. const char * r = (const char *)right;
  73. return stricmp(l,r);
  74. }
  75. inline unsigned ipGroupDistance(const IpAddress &ip,const IGroup *grp)
  76. {
  77. if (!grp)
  78. return (unsigned)-1;
  79. return grp->distance(ip);
  80. }
  81. inline unsigned groupDistance(IGroup *grp1,IGroup *grp2)
  82. {
  83. if (grp1==grp2)
  84. return 0;
  85. if (!grp1||!grp2)
  86. return (unsigned)-1;
  87. return grp1->distance(grp2);
  88. }
  89. static StringBuffer &normalizeFormat(StringBuffer &in)
  90. {
  91. in.toLowerCase();
  92. for (unsigned i = 0;i<in.length();)
  93. {
  94. switch (in.charAt(i)) {
  95. case '-':
  96. case '_':
  97. case ' ':
  98. in.remove(i,1);
  99. break;
  100. default:
  101. i++;
  102. break;
  103. }
  104. }
  105. return in;
  106. }
  107. static StringBuffer &getAttrQueryStr(StringBuffer &str,const char *sub,const char *key,const char *name)
  108. {
  109. assertex(key[0]=='@');
  110. str.appendf("%s[%s=\"%s\"]",sub,key,name);
  111. return str;
  112. }
  113. static IPropertyTree *getNamedPropTree(IPropertyTree *parent,const char *sub,const char *key,const char *name,bool preload)
  114. { // no create
  115. if (!parent)
  116. return NULL;
  117. StringBuffer query;
  118. getAttrQueryStr(query,sub,key,name);
  119. if (preload)
  120. return parent->getBranch(query.str());
  121. return parent->getPropTree(query.str());
  122. }
  123. static IPropertyTree *addNamedPropTree(IPropertyTree *parent,const char *sub,const char *key,const char *name, IPropertyTree* init=NULL)
  124. {
  125. IPropertyTree* ret = init?createPTreeFromIPT(init):createPTree(sub);
  126. assertex(key[0]=='@');
  127. ret->setProp(key,name);
  128. ret = parent->addPropTree(sub,ret);
  129. return LINK(ret);
  130. }
  131. const char *normalizeLFN(const char *s,StringBuffer &tmp)
  132. {
  133. CDfsLogicalFileName dlfn;
  134. dlfn.set(s);
  135. return dlfn.get(tmp).str();
  136. }
  137. static IPropertyTree *getEmptyAttr()
  138. {
  139. return createPTree("Attr");
  140. }
  141. RemoteFilename &constructPartFilename(IGroup *grp,unsigned partno,unsigned partmax,const char *name,const char *partmask,const char *partdir,unsigned copy,ClusterPartDiskMapSpec &mspec,RemoteFilename &rfn)
  142. {
  143. partno--;
  144. StringBuffer tmp;
  145. if (!name||!*name) {
  146. if (!partmask||!*partmask) {
  147. partmask = "!ERROR!._$P$_of_$N$"; // could use logical tail name if I had it
  148. ERRLOG("No partmask for constructPartFilename");
  149. }
  150. name = expandMask(tmp,partmask,partno,partmax).str();
  151. }
  152. StringBuffer fullname;
  153. if (findPathSepChar(name)==NULL)
  154. addPathSepChar(fullname.append(partdir));
  155. fullname.append(name);
  156. unsigned n;
  157. unsigned d;
  158. mspec.calcPartLocation(partno,partmax,copy,grp?grp->ordinality():partmax,n,d);
  159. setReplicateFilename(fullname,d);
  160. SocketEndpoint ep;
  161. if (grp)
  162. ep=grp->queryNode(n).endpoint();
  163. rfn.setPath(ep,fullname.toLowerCase().str());
  164. return rfn;
  165. }
  166. inline void LOGPTREE(const char *title,IPropertyTree *pt)
  167. {
  168. StringBuffer buf;
  169. if (pt) {
  170. toXML(pt,buf);
  171. PROGLOG("%s:\n%s\n",title,buf.str());
  172. }
  173. else
  174. PROGLOG("%s : NULL",title);
  175. }
  176. inline void LOGFDESC(const char *title,IFileDescriptor *fdesc)
  177. {
  178. if (fdesc) {
  179. Owned<IPropertyTree> pt = fdesc->getFileTree();
  180. LOGPTREE(title,pt);
  181. }
  182. else
  183. PROGLOG("%s : NULL",title);
  184. }
  185. class CDFS_Exception: public CInterface, implements IDFS_Exception
  186. {
  187. StringAttr errstr;
  188. int errcode;
  189. public:
  190. CDFS_Exception(int _errcode, const char *_errstr)
  191. : errstr(_errstr)
  192. {
  193. errcode = _errcode;
  194. }
  195. int errorCode() const { return errcode; }
  196. StringBuffer & errorMessage(StringBuffer &str) const
  197. {
  198. if (errcode==DFSERR_ok)
  199. return str;
  200. str.append("DFS Exception: ").append(errcode);
  201. switch(errcode) {
  202. case DFSERR_LogicalNameAlreadyExists:
  203. return str.append(": logical name ").append(errstr).append(" already exists");
  204. case DFSERR_CannotFindPartFileSize:
  205. return str.append(": Cannot find physical file size for ").append(errstr);
  206. case DFSERR_CannotFindPartFileCrc:
  207. return str.append(": Cannot find physical file crc for ").append(errstr);
  208. case DFSERR_LookupAccessDenied:
  209. return str.append(" Lookup access denied for scope ").append(errstr);
  210. case DFSERR_CreateAccessDenied:
  211. return str.append(" Create access denied for scope ").append(errstr);
  212. case DFSERR_PhysicalPartAlreadyExists:
  213. return str.append(": physical part ").append(errstr).append(" already exists");
  214. case DFSERR_PhysicalPartDoesntExist:
  215. return str.append(": physical part ").append(errstr).append(" doesnt exist");
  216. case DFSERR_ForeignDaliTimeout:
  217. return str.append(": Timeout connecting to Dali Server on ").append(errstr);
  218. case DFSERR_ClusterNotFound:
  219. return str.append(": Cluster not found: ").append(errstr);
  220. case DFSERR_ClusterAlreadyExists:
  221. return str.append(": Cluster already exists: ").append(errstr);
  222. case DFSERR_LookupConnectionTimout:
  223. return str.append(": Lookup connection timeout: ").append(errstr);
  224. }
  225. return str.append("Unknown DFS Exception");
  226. }
  227. MessageAudience errorAudience() const { return MSGAUD_user; }
  228. IMPLEMENT_IINTERFACE;
  229. };
  230. class CConnectLock
  231. {
  232. public:
  233. Owned<IRemoteConnection> conn;
  234. CConnectLock(const char *caller, const char *name, bool write, bool preload, bool hold, unsigned timeout)
  235. {
  236. unsigned start = msTick();
  237. bool first = true;
  238. loop
  239. {
  240. try
  241. {
  242. unsigned mode = write ? RTM_LOCK_WRITE : RTM_LOCK_READ;
  243. if (preload) mode |= RTM_SUB;
  244. if (hold) mode |= RTM_LOCK_HOLD;
  245. conn.setown(querySDS().connect(name, queryCoven().inCoven() ? 0 : myProcessSession(), mode, (timeout==INFINITE)?1000*60*5:timeout));
  246. #ifdef TRACE_LOCKS
  247. PROGLOG("%s: LOCKGOT(%x) %s %s",caller,(unsigned)(memsize_t)conn.get(),name,write?"WRITE":"");
  248. LogRemoteConn(conn);
  249. PrintStackReport();
  250. #endif
  251. break;
  252. }
  253. catch (ISDSException *e)
  254. {
  255. if (SDSExcpt_LockTimeout == e->errorCode())
  256. {
  257. #ifdef TRACE_LOCKS
  258. PROGLOG("%s: LOCKFAIL %s %s",caller,name,write?"WRITE":"");
  259. LogRemoteConn(conn);
  260. #endif
  261. unsigned tt = msTick()-start;
  262. if (timeout!=INFINITE) {
  263. StringBuffer tmp;
  264. e->errorMessage(tmp);
  265. CDFS_Exception *dfse = new CDFS_Exception(DFSERR_LookupConnectionTimout,tmp.str());
  266. e->Release();
  267. throw dfse;
  268. }
  269. WARNLOG("CConnectLock on %s waiting for %ds",name,tt/1000);
  270. if (first) {
  271. PrintStackReport();
  272. first = false;
  273. }
  274. if (tt>SDS_CONNECT_TIMEOUT)
  275. throw;
  276. e->Release();
  277. }
  278. else
  279. throw;
  280. }
  281. catch (IException *e) {
  282. StringBuffer tmp("CConnectLock ");
  283. tmp.append(caller).append(' ').append(name);
  284. EXCLOG(e, tmp.str());
  285. throw;
  286. }
  287. }
  288. }
  289. IRemoteConnection *detach()
  290. {
  291. #ifdef TRACE_LOCKS
  292. if (conn.get()) {
  293. PROGLOG("LOCKDETACH(%x)",(unsigned)(memsize_t)conn.get());
  294. LogRemoteConn(conn);
  295. }
  296. #endif
  297. return conn.getClear();
  298. }
  299. #ifdef TRACE_LOCKS
  300. ~CConnectLock()
  301. {
  302. if (conn.get()) {
  303. PROGLOG("LOCKDELETE(%x)",(unsigned)(memsize_t)conn.get());
  304. LogRemoteConn(conn);
  305. }
  306. }
  307. #endif
  308. };
  309. void ensureFileScope(const CDfsLogicalFileName &dlfn,unsigned timeout)
  310. {
  311. CConnectLock connlock("ensureFileScope",querySdsFilesRoot(),true,false,false,timeout);
  312. StringBuffer query;
  313. IPropertyTree *r = connlock.conn->getRoot();
  314. StringBuffer scopes;
  315. const char *s=dlfn.getScopes(scopes,true).str();
  316. loop {
  317. IPropertyTree *nr;
  318. const char *e = strstr(s,"::");
  319. query.clear();
  320. if (e)
  321. query.append(e-s,s);
  322. else
  323. query.append(s);
  324. nr = getNamedPropTree(r,queryDfsXmlBranchName(DXB_Scope),"@name",query.trim().toLowerCase().str(),false);
  325. if (!nr)
  326. nr = addNamedPropTree(r,queryDfsXmlBranchName(DXB_Scope),"@name",query.str());
  327. r->Release();
  328. if (!e) {
  329. ::Release(nr);
  330. break;
  331. }
  332. r = nr;
  333. s = e+2;
  334. }
  335. }
  336. void removeFileEmptyScope(const CDfsLogicalFileName &dlfn,unsigned timeout)
  337. {
  338. CConnectLock connlock("removeFileEmptyScope",querySdsFilesRoot(),true,false,false,timeout); //*1
  339. IPropertyTree *root = connlock.conn.get()?connlock.conn->queryRoot():NULL;
  340. if (!root)
  341. return;
  342. StringBuffer query;
  343. dlfn.makeScopeQuery(query.clear(),false);
  344. StringBuffer head;
  345. loop {
  346. if (query.length()) {
  347. const char *tail = splitXPath(query.str(),head.clear());
  348. if (!tail||!*tail)
  349. break;
  350. IPropertyTree *pt;
  351. if (head.length()) {
  352. query.set(head);
  353. pt = root->queryPropTree(query.str());
  354. }
  355. else
  356. pt = root;
  357. IPropertyTree *t = pt?pt->queryPropTree(tail):NULL;
  358. if (t) {
  359. if (t->hasChildren())
  360. break;
  361. pt->removeTree(t);
  362. if (root==pt)
  363. break;
  364. }
  365. else
  366. break;
  367. }
  368. else
  369. break;
  370. }
  371. }
  372. class CFileLockBase
  373. {
  374. IRemoteConnection *conn;
  375. protected:
  376. Owned<IRemoteConnection> lock;
  377. bool init(const char *lockPath, unsigned mode, IRemoteConnection *_conn, unsigned timeout, const char *msg)
  378. {
  379. conn = NULL;
  380. lock.clear();
  381. CTimeMon tm(timeout);
  382. loop
  383. {
  384. try
  385. {
  386. lock.setown(querySDS().connect(lockPath, myProcessSession(), mode, timeout>60000 ? 60000 : timeout));
  387. if (lock.get())
  388. {
  389. conn = _conn;
  390. return true;
  391. }
  392. return false;
  393. }
  394. catch (ISDSException *e)
  395. {
  396. if (SDSExcpt_LockTimeout != e->errorCode() || tm.timedout())
  397. throw;
  398. WARNLOG("CFileAttrLockBase(%s) blocked for %ds", msg, tm.elapsed()/1000);
  399. e->Release();
  400. }
  401. }
  402. }
  403. public:
  404. CFileLockBase()
  405. {
  406. conn = NULL;
  407. }
  408. ~CFileLockBase()
  409. {
  410. // if conn provided, 'lock' was just a surrogate for the owner connection, commit now to conn if write lock
  411. if (conn && lock)
  412. conn->commit();
  413. }
  414. IRemoteConnection *detach()
  415. {
  416. return lock.getClear();
  417. }
  418. void clear()
  419. {
  420. lock.clear();
  421. conn = NULL;
  422. }
  423. IPropertyTree *queryRoot() const
  424. {
  425. return lock.get() ? lock->queryRoot() : NULL;
  426. }
  427. };
  428. class CFileLock : protected CFileLockBase
  429. {
  430. protected:
  431. DfsXmlBranchKind kind;
  432. public:
  433. CFileLock()
  434. {
  435. kind = DXB_Internal;
  436. }
  437. bool init(const CDfsLogicalFileName &logicalName, DfsXmlBranchKind bkind, unsigned mode, unsigned timeout, const char *msg)
  438. {
  439. StringBuffer lockPath;
  440. logicalName.makeFullnameQuery(lockPath, bkind, true);
  441. if (CFileLockBase::init(lockPath, mode, NULL, timeout, msg))
  442. {
  443. kind = bkind;
  444. return true;
  445. }
  446. kind = DXB_Internal;
  447. return false;
  448. }
  449. bool init(const CDfsLogicalFileName &logicalName, unsigned mode, unsigned timeout, const char *msg)
  450. {
  451. StringBuffer lockPath;
  452. logicalName.makeFullnameQuery(lockPath, DXB_File, true);
  453. if (CFileLockBase::init(lockPath, mode, NULL, timeout, msg))
  454. {
  455. kind = DXB_File;
  456. return true;
  457. }
  458. // try super
  459. logicalName.makeFullnameQuery(lockPath.clear(), DXB_SuperFile, true);
  460. if (CFileLockBase::init(lockPath, mode, NULL, timeout, msg))
  461. {
  462. kind = DXB_SuperFile;
  463. return true;
  464. }
  465. kind = DXB_Internal;
  466. return false;
  467. }
  468. IRemoteConnection *detach() { return CFileLockBase::detach(); }
  469. IPropertyTree *queryRoot() const { return CFileLockBase::queryRoot(); }
  470. IRemoteConnection *queryConnection() const
  471. {
  472. return lock;
  473. }
  474. void clear()
  475. {
  476. CFileLockBase::clear();
  477. kind = DXB_Internal;
  478. }
  479. DfsXmlBranchKind getKind() const { return kind; }
  480. };
  481. class CFileSubLock : protected CFileLockBase
  482. {
  483. public:
  484. bool init(const CDfsLogicalFileName &logicalName, DfsXmlBranchKind bkind, unsigned mode, const char *subLock, IRemoteConnection *conn, unsigned timeout, const char *msg)
  485. {
  486. StringBuffer lockPath;
  487. logicalName.makeFullnameQuery(lockPath, bkind, true);
  488. lockPath.appendf("/%s", subLock);
  489. return CFileLockBase::init(lockPath, mode, conn, timeout, msg);
  490. }
  491. bool init(const CDfsLogicalFileName &logicalName, unsigned mode, const char *subLock, IRemoteConnection *conn, unsigned timeout, const char *msg)
  492. {
  493. StringBuffer lockPath;
  494. logicalName.makeFullnameQuery(lockPath, DXB_File, true);
  495. lockPath.appendf("/%s", subLock);
  496. if (CFileLockBase::init(lockPath, mode, conn, timeout, msg))
  497. return true;
  498. // try super
  499. logicalName.makeFullnameQuery(lockPath.clear(), DXB_SuperFile, true);
  500. return CFileLockBase::init(lockPath, mode, conn, timeout, msg);
  501. }
  502. };
  503. class CFileAttrLock : protected CFileSubLock
  504. {
  505. public:
  506. bool init(const CDfsLogicalFileName &logicalName, DfsXmlBranchKind bkind, unsigned mode, IRemoteConnection *conn, unsigned timeout, const char *msg)
  507. {
  508. return CFileSubLock::init(logicalName, bkind, mode, "Attr", conn, timeout, msg);
  509. }
  510. bool init(const CDfsLogicalFileName &logicalName, unsigned mode, IRemoteConnection *conn, unsigned timeout, const char *msg)
  511. {
  512. return CFileSubLock::init(logicalName, mode, "Attr", conn, timeout, msg);
  513. }
  514. IPropertyTree *queryRoot() const { return CFileSubLock::queryRoot(); }
  515. };
  516. class CFileLockCompound : protected CFileLockBase
  517. {
  518. public:
  519. bool init(const CDfsLogicalFileName &logicalName, unsigned mode, IRemoteConnection *conn, const char *subLock, unsigned timeout, const char *msg)
  520. {
  521. StringBuffer lockPath;
  522. if (subLock)
  523. lockPath.appendf("/_Locks/%s/", subLock);
  524. logicalName.makeXPathLName(lockPath);
  525. return CFileLockBase::init(lockPath, mode, conn, timeout, msg);
  526. }
  527. };
  528. class CFileSuperOwnerLock : protected CFileLockCompound
  529. {
  530. public:
  531. bool init(const CDfsLogicalFileName &logicalName, IRemoteConnection *conn, unsigned timeout, const char *msg)
  532. {
  533. return CFileLockCompound::init(logicalName, RTM_CREATE_QUERY | RTM_LOCK_WRITE | RTM_DELETE_ON_DISCONNECT, conn, "SuperOwnerLock", timeout, msg);
  534. }
  535. IRemoteConnection *detach()
  536. {
  537. return CFileLockCompound::detach();
  538. }
  539. };
  540. class CScopeConnectLock
  541. {
  542. CConnectLock *lock;
  543. public:
  544. CScopeConnectLock()
  545. {
  546. lock = NULL;
  547. }
  548. CScopeConnectLock(const char *caller, const CDfsLogicalFileName &lname, bool write, bool preload, bool hold, unsigned timeout)
  549. {
  550. lock = NULL;
  551. init(caller, lname, write, preload, hold, timeout);
  552. }
  553. ~CScopeConnectLock()
  554. {
  555. delete lock;
  556. }
  557. bool init(const char *caller, const CDfsLogicalFileName &lname, bool write, bool preload, bool hold, unsigned timeout)
  558. {
  559. delete lock;
  560. StringBuffer query;
  561. lname.makeScopeQuery(query,true);
  562. lock = new CConnectLock(caller, query.str(), write, preload,hold, timeout);
  563. if (lock->conn.get()==NULL)
  564. {
  565. delete lock;
  566. lock = NULL;
  567. ensureFileScope(lname);
  568. lock = new CConnectLock(caller, query.str(), write, preload, hold, timeout);
  569. }
  570. return lock->conn.get()!=NULL;
  571. }
  572. IRemoteConnection *detach()
  573. {
  574. return lock?lock->detach():NULL;
  575. }
  576. IRemoteConnection *conn()
  577. {
  578. return lock?lock->conn:NULL;
  579. }
  580. IPropertyTree *queryRoot()
  581. {
  582. return (lock&&lock->conn.get())?lock->conn->queryRoot():NULL;
  583. }
  584. void remove()
  585. {
  586. if (lock&&lock->conn.get())
  587. lock->conn->close(true);
  588. }
  589. IPropertyTree *queryFileRoot(const CDfsLogicalFileName &dlfn,DfsXmlBranchKind &bkind)
  590. {
  591. bool external;
  592. bool foreign;
  593. external = dlfn.isExternal();
  594. foreign = dlfn.isForeign();
  595. if (external||foreign)
  596. return NULL;
  597. IPropertyTree *sroot = queryRoot();
  598. if (!sroot)
  599. return NULL;
  600. StringBuffer tail;
  601. dlfn.getTail(tail);
  602. StringBuffer query;
  603. getAttrQueryStr(query,queryDfsXmlBranchName(DXB_File),"@name",tail.str());
  604. IPropertyTree *froot = sroot->queryPropTree(query.str());
  605. bkind = DXB_File;
  606. if (!froot) {
  607. // check for super file
  608. getAttrQueryStr(query.clear(),queryDfsXmlBranchName(DXB_SuperFile),"@name",tail.str());
  609. froot = sroot->queryPropTree(query.str());
  610. if (froot)
  611. bkind = DXB_SuperFile;
  612. }
  613. return froot;
  614. }
  615. };
  616. class CClustersLockedSection
  617. {
  618. Owned<IRemoteConnection> conn;
  619. public:
  620. CClustersLockedSection(CDfsLogicalFileName &dlfn)
  621. {
  622. StringBuffer xpath;
  623. dlfn.makeFullnameQuery(xpath,DXB_File,true).append("/ClusterLock");
  624. conn.setown(querySDS().connect(xpath.str(), myProcessSession(), RTM_CREATE | RTM_LOCK_WRITE | RTM_DELETE_ON_DISCONNECT, SDS_CONNECT_TIMEOUT));
  625. }
  626. ~CClustersLockedSection()
  627. {
  628. }
  629. };
  630. static void checkDfsReplyException(MemoryBuffer &mb)
  631. {
  632. if (mb.length()<=sizeof(int))
  633. return;
  634. if ((*(int *)mb.bufferBase()) == -1) { // exception indicator
  635. int i;
  636. mb.read(i);
  637. throw deserializeException(mb);
  638. }
  639. }
  640. static void foreignDaliSendRecv(const INode *foreigndali,CMessageBuffer &mb, unsigned foreigndalitimeout)
  641. {
  642. SocketEndpoint ep = foreigndali->endpoint();
  643. if (ep.port==0)
  644. ep.port = DALI_SERVER_PORT;
  645. Owned<IGroup> grp = createIGroup(1,&ep);
  646. Owned<ICommunicator> comm = createCommunicator(grp,true);
  647. if (!comm->verifyConnection(0,foreigndalitimeout)) {
  648. StringBuffer tmp;
  649. IDFS_Exception *e = new CDFS_Exception(DFSERR_ForeignDaliTimeout, foreigndali->endpoint().getUrlStr(tmp).str());
  650. throw e;
  651. }
  652. comm->sendRecv(mb,0,MPTAG_DFS_REQUEST);
  653. }
  654. static bool isLocalDali(const INode *foreigndali)
  655. {
  656. if (!foreigndali)
  657. return true;
  658. Owned<INode> node;
  659. SocketEndpoint ep = foreigndali->endpoint();
  660. if (ep.port==0) {
  661. ep.port = DALI_SERVER_PORT;
  662. node.setown(createINode(ep));
  663. foreigndali = node.get();
  664. }
  665. return queryCoven().inCoven((INode *)foreigndali);
  666. }
  667. class FileClusterInfoArray: public IArrayOf<IClusterInfo>
  668. {
  669. ClusterPartDiskMapSpec defaultmapping;
  670. bool singleclusteroverride;
  671. public:
  672. FileClusterInfoArray()
  673. {
  674. singleclusteroverride = false;
  675. }
  676. void clear()
  677. {
  678. IArrayOf<IClusterInfo>::kill();
  679. }
  680. unsigned getNames(StringArray &clusternames)
  681. {
  682. StringBuffer name;
  683. ForEachItem(i) {
  684. clusternames.append(item(i).getClusterLabel(name.clear()).str());
  685. if (singleclusteroverride)
  686. break;
  687. }
  688. return clusternames.ordinality();
  689. }
  690. unsigned find(const char *_clusterName)
  691. {
  692. StringAttr clusterName = _clusterName;
  693. clusterName.toLowerCase();
  694. StringBuffer name;
  695. ForEachItem(i) {
  696. if (strcmp(item(i).getClusterLabel(name.clear()).str(),clusterName)==0)
  697. return i;
  698. if (singleclusteroverride)
  699. break;
  700. }
  701. return NotFound;
  702. }
  703. IGroup *queryGroup(unsigned clusternum)
  704. {
  705. if (clusternum>=ordinality())
  706. return NULL;
  707. if (singleclusteroverride&&clusternum)
  708. return NULL;
  709. return item(clusternum).queryGroup();
  710. }
  711. IGroup *getGroup(unsigned clusternum)
  712. {
  713. IGroup *ret = queryGroup(clusternum);
  714. return LINK(ret);
  715. }
  716. unsigned copyNum(unsigned part,unsigned copy,unsigned maxparts, unsigned *replicate)
  717. {
  718. ForEachItem(i) {
  719. IGroup *g = queryGroup(i);
  720. unsigned cw = g?g->ordinality():1;
  721. unsigned mc = item(i).queryPartDiskMapping().numCopies(part,cw,maxparts);
  722. if (copy<mc) {
  723. if (replicate)
  724. *replicate = copy;
  725. return i;
  726. }
  727. copy -= mc;
  728. if (singleclusteroverride)
  729. break;
  730. }
  731. return NotFound;
  732. }
  733. ClusterPartDiskMapSpec &queryPartDiskMapping(unsigned clusternum)
  734. {
  735. if (clusternum>=ordinality()||(singleclusteroverride&&clusternum))
  736. return defaultmapping;
  737. return item(clusternum).queryPartDiskMapping();
  738. }
  739. void updatePartDiskMapping(unsigned clusternum,const ClusterPartDiskMapSpec &spec)
  740. {
  741. if (clusternum<ordinality())
  742. item(clusternum).queryPartDiskMapping() = spec;
  743. }
  744. StringBuffer &getName(unsigned clusternum,StringBuffer &name)
  745. {
  746. if (clusternum<ordinality())
  747. item(clusternum).getClusterLabel(name);
  748. return name;
  749. }
  750. void setPreferred(const char *clusters,CDfsLogicalFileName &lfname)
  751. {
  752. unsigned nc = ordinality();
  753. if (nc<=1)
  754. return;
  755. StringBuffer cname;
  756. StringArray clustlist;
  757. if (lfname.getCluster(cname).length())
  758. clustlist.append(cname.str());
  759. unsigned i;
  760. if (clusters) {
  761. loop {
  762. const char *s = clusters;
  763. while (*s&&(*s!=','))
  764. s++;
  765. if (s!=clusters) {
  766. cname.clear().append(s-clusters,clusters);
  767. for (i=0;i<clustlist.ordinality();i++)
  768. if (strcmp(clustlist.item(i),cname.str())==0)
  769. break;
  770. if (i==clustlist.ordinality())
  771. clustlist.append(cname.str());
  772. }
  773. if (!*s)
  774. break;
  775. clusters = s+1;
  776. }
  777. }
  778. if (clustlist.ordinality()==0) {
  779. // sort by closest to this node
  780. const IpAddress &myip = queryMyNode()->endpoint();
  781. unsigned *d=new unsigned[nc];
  782. for (i=0;i<nc;i++)
  783. d[i] = ipGroupDistance(myip,item(i).queryGroup());
  784. // bubble sort it - only a few
  785. for (i=0;i+1<nc;i++)
  786. for (unsigned j=0;j+i+1<nc;j++)
  787. if (d[j+1]<d[j]) {
  788. unsigned bd = d[j+1];
  789. d[j+1] = d[j];
  790. d[j] = bd;
  791. swap(j,j+1);
  792. }
  793. delete [] d;
  794. return;
  795. }
  796. Owned<IGroup> firstgrp;
  797. unsigned done = 0;
  798. StringBuffer name;
  799. StringBuffer name2;
  800. ForEachItemIn(ci,clustlist) {
  801. const char *cls = clustlist.item(ci);
  802. Owned<IGroup> grp = queryNamedGroupStore().lookup(cls);
  803. if (!grp) {
  804. ERRLOG("IDistributedFile::setPreferred - cannot find cluster %s",cls);
  805. return;
  806. }
  807. if (!firstgrp.get())
  808. firstgrp.set(grp);
  809. for (i=done;i<nc;i++) {
  810. IClusterInfo &info=item(i);
  811. if (stricmp(info.getClusterLabel(name2.clear()).str(),name.str())==0)
  812. break;
  813. IGroup *grp2 = info.queryGroup();
  814. if (grp2&&(grp->compare(grp2)!=GRdisjoint))
  815. break;
  816. }
  817. if (i<nc) {
  818. if (i) {
  819. Linked<IClusterInfo> tmp = &item(i);
  820. remove(i);
  821. add(*tmp.getClear(),done);
  822. }
  823. done++;
  824. if (done+1>=nc)
  825. break;
  826. }
  827. }
  828. if (done+1<nc) { // sort remaining by nearest to first group
  829. unsigned *d=new unsigned[nc]; // only use done to nc
  830. for (i=done;i<nc;i++)
  831. d[i] = groupDistance(firstgrp,item(i).queryGroup());
  832. // bubble sort it - only a few
  833. for (i=done;i+1<nc;i++)
  834. for (unsigned j=done;j+i+1<nc;j++)
  835. if (d[j+1]<d[j]) {
  836. unsigned bd = d[j+1];
  837. d[j+1] = d[j];
  838. d[j] = bd;
  839. swap(j,j+1);
  840. }
  841. delete [] d;
  842. }
  843. }
  844. void setSingleClusterOnly(bool set=true)
  845. {
  846. singleclusteroverride = set;
  847. }
  848. unsigned numCopies(unsigned part,unsigned maxparts)
  849. {
  850. unsigned ret = 0;
  851. ForEachItem(i) {
  852. IGroup *g = queryGroup(i);
  853. unsigned cw = g?g->ordinality():1;
  854. ret += item(i).queryPartDiskMapping().numCopies(part,cw,maxparts);
  855. if (singleclusteroverride)
  856. break;
  857. }
  858. return ret;
  859. }
  860. };
  861. // Internal extension of transaction interface, used to manipulate and track transaction
  862. interface IDistributedFileTransactionExt : extends IDistributedFileTransaction
  863. {
  864. virtual IUserDescriptor *queryUser()=0;
  865. virtual void descend()=0; // descend into a recursive call (can't autoCommit if depth is not zero)
  866. virtual void ascend()=0; // ascend back from the deep, one step at a time
  867. virtual void autoCommit()=0; // if transaction not active, commit straight away
  868. virtual void addAction(CDFAction *action)=0;
  869. virtual void addFile(IDistributedFile *file)=0;
  870. virtual void ensureFile(IDistributedFile *file)=0;
  871. virtual void clearFile(IDistributedFile *file)=0;
  872. virtual void clearFiles()=0;
  873. virtual void noteAddSubFile(IDistributedSuperFile *super, const char *superName, IDistributedFile *sub) = 0;
  874. virtual void noteRemoveSubFile(IDistributedSuperFile *super, IDistributedFile *sub) = 0;
  875. virtual void noteSuperSwap(IDistributedSuperFile *super1, IDistributedSuperFile *super2) = 0;
  876. virtual void clearSubFiles(IDistributedSuperFile *super) = 0;
  877. virtual void noteRename(IDistributedFile *file, const char *newName) = 0;
  878. virtual void validateAddSubFile(IDistributedSuperFile *super, IDistributedFile *sub, const char *subName) = 0;
  879. virtual bool isSubFile(IDistributedSuperFile *super, const char *subFile, bool sub) = 0;
  880. virtual bool addDelayedDelete(CDfsLogicalFileName &lfn,unsigned timeoutms=INFINITE)=0; // used internally to delay deletes until commit
  881. virtual bool prepareActions()=0;
  882. virtual void retryActions()=0;
  883. virtual void runActions()=0;
  884. virtual void commitAndClearup()=0;
  885. };
  886. class CDistributedFileDirectory: public CInterface, implements IDistributedFileDirectory
  887. {
  888. Owned<IUserDescriptor> defaultudesc;
  889. Owned<IDFSredirection> redirection;
  890. void resolveForeignFiles(IPropertyTree *tree,const INode *foreigndali);
  891. protected: friend class CDistributedFile;
  892. StringAttr defprefclusters;
  893. unsigned defaultTimeout;
  894. public:
  895. IMPLEMENT_IINTERFACE;
  896. CDistributedFileDirectory()
  897. {
  898. defaultTimeout = INFINITE;
  899. defaultudesc.setown(createUserDescriptor());
  900. redirection.setown(createDFSredirection());
  901. }
  902. IDistributedFile *dolookup(CDfsLogicalFileName &logicalname, IUserDescriptor *user, bool writeattr, bool hold, bool lockSuperOwner, IDistributedFileTransaction *transaction, unsigned timeout);
  903. IDistributedFile *lookup(const char *_logicalname, IUserDescriptor *user, bool writeattr, bool hold, bool lockSuperOwner, IDistributedFileTransaction *transaction, unsigned timeout);
  904. IDistributedFile *lookup(CDfsLogicalFileName &logicalname, IUserDescriptor *user, bool writeattr, bool hold, bool lockSuperOwner, IDistributedFileTransaction *transaction, unsigned timeout);
  905. /* createNew always creates an unnamed unattached distributed file
  906. * The caller must associated it with a name and credentials when it is attached (attach())
  907. */
  908. IDistributedFile *createNew(IFileDescriptor * fdesc, bool includeports=false);
  909. IDistributedSuperFile *createSuperFile(const char *logicalname,IUserDescriptor *user,bool interleaved,bool ifdoesnotexist,IDistributedFileTransaction *transaction=NULL);
  910. void removeSuperFile(const char *_logicalname, bool delSubs, IUserDescriptor *user, IDistributedFileTransaction *transaction);
  911. IDistributedFileIterator *getIterator(const char *wildname, bool includesuper,IUserDescriptor *user);
  912. IDFAttributesIterator *getDFAttributesIterator(const char *wildname, IUserDescriptor *user, bool recursive, bool includesuper,INode *foreigndali,unsigned foreigndalitimeout);
  913. IPropertyTreeIterator *getDFAttributesTreeIterator(const char *filters, DFUQResultField* localFilters, const char *localFilterBuf,
  914. IUserDescriptor *user, INode *foreigndali,unsigned foreigndalitimeout);
  915. IDFAttributesIterator *getForeignDFAttributesIterator(const char *wildname, IUserDescriptor *user, bool recursive=true, bool includesuper=false, const char *foreigndali="", unsigned foreigndalitimeout=FOREIGN_DALI_TIMEOUT)
  916. {
  917. Owned<INode> foreign;
  918. if (foreigndali&&*foreigndali) {
  919. SocketEndpoint ep(foreigndali);
  920. foreign.setown(createINode(ep));
  921. }
  922. return getDFAttributesIterator(wildname, user, recursive, includesuper,foreign,foreigndalitimeout);
  923. }
  924. IDFScopeIterator *getScopeIterator(IUserDescriptor *user, const char *subscope,bool recursive,bool includeempty);
  925. bool loadScopeContents(const char *scopelfn,StringArray *scopes, StringArray *supers,StringArray *files, bool includeemptyscopes);
  926. IPropertyTree *getFileTree(const char *lname,IUserDescriptor *user,const INode *foreigndali,unsigned foreigndalitimeout,bool expandnodes=false, bool appendForeign=true);
  927. void setFileAccessed(CDfsLogicalFileName &dlfn, IUserDescriptor *user,const CDateTime &dt,const INode *foreigndali=NULL,unsigned foreigndalitimeout=FOREIGN_DALI_TIMEOUT);
  928. IFileDescriptor *getFileDescriptor(const char *lname,IUserDescriptor *user,const INode *foreigndali=NULL,unsigned foreigndalitimeout=FOREIGN_DALI_TIMEOUT);
  929. IDistributedFile *getFile(const char *lname,IUserDescriptor *user,const INode *foreigndali=NULL,unsigned foreigndalitimeout=FOREIGN_DALI_TIMEOUT);
  930. bool exists(const char *_logicalname,IUserDescriptor *user,bool notsuper=false,bool superonly=false);
  931. bool existsPhysical(const char *_logicalname,IUserDescriptor *user);
  932. void addEntry(CDfsLogicalFileName &lfn,IPropertyTree *root,bool superfile, bool ignoreexists);
  933. bool removeEntry(const char *name, IUserDescriptor *user, IDistributedFileTransaction *transaction=NULL, unsigned timeoutms=INFINITE, bool throwException=false);
  934. void renamePhysical(const char *oldname,const char *newname,IUserDescriptor *user,IDistributedFileTransaction *transaction);
  935. void removeEmptyScope(const char *name);
  936. IDistributedSuperFile *lookupSuperFile(const char *logicalname,IUserDescriptor *user,IDistributedFileTransaction *transaction,unsigned timeout=INFINITE);
  937. int getFilePermissions(const char *lname,IUserDescriptor *user,unsigned auditflags);
  938. int getNodePermissions(const IpAddress &ip,IUserDescriptor *user,unsigned auditflags);
  939. int getFDescPermissions(IFileDescriptor *,IUserDescriptor *user,unsigned auditflags=0);
  940. void setDefaultUser(IUserDescriptor *user);
  941. IUserDescriptor* queryDefaultUser();
  942. DistributedFileCompareResult fileCompare(const char *lfn1,const char *lfn2,DistributedFileCompareMode mode,StringBuffer &errstr,IUserDescriptor *user);
  943. bool filePhysicalVerify(const char *lfn1,IUserDescriptor *user,bool includecrc,StringBuffer &errstr);
  944. void setDefaultPreferredClusters(const char *clusters);
  945. void fixDates(IDistributedFile *fil);
  946. GetFileClusterNamesType getFileClusterNames(const char *logicalname,StringArray &out); // returns 0 for normal file, 1 for
  947. bool isSuperFile( const char *logicalname, IUserDescriptor *user, INode *foreigndali, unsigned timeout);
  948. void promoteSuperFiles(unsigned numsf,const char **sfnames,const char *addsubnames,bool delsub,bool createonlyonesuperfile,IUserDescriptor *user, unsigned timeout, StringArray &outunlinked);
  949. ISimpleSuperFileEnquiry * getSimpleSuperFileEnquiry(const char *logicalname,const char *title,IUserDescriptor *udesc,unsigned timeout);
  950. bool getFileSuperOwners(const char *logicalname, StringArray &owners);
  951. IDFSredirection & queryRedirection() { return *redirection; }
  952. static StringBuffer &getFileRelationshipXPath(StringBuffer &xpath, const char *primary, const char *secondary,const char *primflds,const char *secflds,
  953. const char *kind, const char *cardinality, const bool *payload
  954. );
  955. void doRemoveFileRelationship( IRemoteConnection *conn, const char *primary,const char *secondary,const char *primflds,const char *secflds, const char *kind);
  956. void removeFileRelationships(const char *primary,const char *secondary, const char *primflds, const char *secflds, const char *kind);
  957. 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);
  958. IFileRelationshipIterator *lookupFileRelationships(const char *primary,const char *secondary,const char *primflds,const char *secflds,
  959. const char *kind,const char *cardinality,const bool *payload,
  960. const char *foreigndali,unsigned foreigndalitimeout);
  961. void removeAllFileRelationships(const char *filename);
  962. IFileRelationshipIterator *lookupAllFileRelationships(const char *filenames);
  963. void renameFileRelationships(const char *oldname,const char *newname,IFileRelationshipIterator *reliter, IUserDescriptor *user);
  964. bool publishMetaFileXML(const CDfsLogicalFileName &logicalname,IUserDescriptor *user);
  965. IFileDescriptor *createDescriptorFromMetaFile(const CDfsLogicalFileName &logicalname,IUserDescriptor *user);
  966. bool isProtectedFile(const CDfsLogicalFileName &logicalname, unsigned timeout) ;
  967. unsigned queryProtectedCount(const CDfsLogicalFileName &logicalname, const char *owner);
  968. bool getProtectedInfo(const CDfsLogicalFileName &logicalname, StringArray &names, UnsignedArray &counts);
  969. IDFProtectedIterator *lookupProtectedFiles(const char *owner=NULL,bool notsuper=false,bool superonly=false);
  970. IDFAttributesIterator* getLogicalFilesSorted(IUserDescriptor* udesc, DFUQResultField *sortOrder, const void *filterBuf, DFUQResultField *specialFilters,
  971. const void *specialFilterBuf, unsigned startOffset, unsigned maxNum, __int64 *cacheHint, unsigned *total);
  972. void setFileProtect(CDfsLogicalFileName &dlfn,IUserDescriptor *user, const char *owner, bool set, const INode *foreigndali=NULL,unsigned foreigndalitimeout=FOREIGN_DALI_TIMEOUT);
  973. unsigned setDefaultTimeout(unsigned timems)
  974. {
  975. unsigned ret = defaultTimeout;
  976. defaultTimeout = timems;
  977. return ret;
  978. }
  979. };
  980. // === Transactions
  981. class CDFAction: public CInterface
  982. {
  983. unsigned locked;
  984. protected:
  985. IDistributedFileTransactionExt *transaction;
  986. IArrayOf<IDistributedFile> lockedFiles;
  987. DFTransactionState state;
  988. void addFileLock(IDistributedFile *file)
  989. {
  990. // derived's prepare must call this before locking
  991. lockedFiles.append(*LINK(file));
  992. }
  993. bool lock()
  994. {
  995. // Files most have been acquired already by derived's class prepare
  996. ForEachItemIn(i,lockedFiles)
  997. {
  998. try
  999. {
  1000. lockedFiles.item(i).lockProperties(0);
  1001. }
  1002. catch (ISDSException *e)
  1003. {
  1004. if (SDSExcpt_LockTimeout != e->errorCode())
  1005. throw;
  1006. e->Release();
  1007. PROGLOG("CDFAction lock timed out on %s",lockedFiles.item(i).queryLogicalName());
  1008. return false;
  1009. }
  1010. locked++;
  1011. }
  1012. return true;
  1013. }
  1014. void unlock()
  1015. {
  1016. for(unsigned i=0; i<locked; i++)
  1017. lockedFiles.item(i).unlockProperties(state);
  1018. locked = 0;
  1019. lockedFiles.kill();
  1020. }
  1021. public:
  1022. CDFAction() : locked(0), state(TAS_NONE)
  1023. {
  1024. transaction = NULL;
  1025. }
  1026. // Clear all locked files (when re-using transaction on auto-commit mode)
  1027. virtual ~CDFAction()
  1028. {
  1029. if (transaction)
  1030. unlock();
  1031. }
  1032. void setTransaction(IDistributedFileTransactionExt *_transaction)
  1033. {
  1034. assertex(_transaction);
  1035. assertex(!transaction);
  1036. transaction = _transaction;
  1037. }
  1038. virtual bool prepare()=0; // should call lock
  1039. virtual void run()=0; // must override this
  1040. // If some lock fails, call this
  1041. virtual void retry()
  1042. {
  1043. state = TAS_RETRY;
  1044. unlock();
  1045. }
  1046. // MORE: In the rare event of a commit failure, not all actions can be rolled back.
  1047. // Since all actions today occur during "run", and since commit phases does very little,
  1048. // this chance is minimal and will probably be caused by corrupted file descriptors.
  1049. // The problem is that the state of the sub removals and the order in which they occur might not
  1050. // be trivial on such a low level error, and there's no way to atomically do operations in SDS
  1051. // at present time. We need more thought about this.
  1052. virtual void commit()
  1053. {
  1054. state = TAS_SUCCESS;
  1055. unlock();
  1056. }
  1057. virtual void rollback()
  1058. {
  1059. state = TAS_FAILURE;
  1060. unlock();
  1061. }
  1062. };
  1063. static void setUserDescriptor(Linked<IUserDescriptor> &udesc,IUserDescriptor *user)
  1064. {
  1065. if (!user)
  1066. {
  1067. #ifdef NULL_DALIUSER_STACKTRACE
  1068. StringBuffer sb;
  1069. if (user)
  1070. user->getUserName(sb);
  1071. if (sb.length()==0)
  1072. {
  1073. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp setUserDescriptor() %d",__LINE__);
  1074. //following debug code to be removed
  1075. PrintStackReport();
  1076. }
  1077. #endif
  1078. user = queryDistributedFileDirectory().queryDefaultUser();
  1079. }
  1080. udesc.set(user);
  1081. }
  1082. static int getScopePermissions(const char *scopename,IUserDescriptor *user,unsigned auditflags)
  1083. { // scope must be normalized already
  1084. static bool permissionsavail=true;
  1085. if (auditflags==(unsigned)-1)
  1086. return permissionsavail?1:0;
  1087. int ret = 255;
  1088. if (permissionsavail&&scopename&&*scopename&&((*scopename!='.')||scopename[1])) {
  1089. if (!user)
  1090. {
  1091. #ifdef NULL_DALIUSER_STACKTRACE
  1092. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp getScopePermissions() line %d",__LINE__);
  1093. //following debug code to be removed
  1094. PrintStackReport();
  1095. #endif
  1096. user = queryDistributedFileDirectory().queryDefaultUser();
  1097. }
  1098. ret = querySessionManager().getPermissionsLDAP(queryDfsXmlBranchName(DXB_Scope),scopename,user,auditflags);
  1099. if (ret<0) {
  1100. if (ret==-1) {
  1101. permissionsavail=false;
  1102. ret = 255;
  1103. }
  1104. else
  1105. ret = 0;
  1106. }
  1107. }
  1108. return ret;
  1109. }
  1110. static void checkLogicalScope(const char *scopename,IUserDescriptor *user,bool readreq,bool createreq)
  1111. {
  1112. // scope must be normalized already
  1113. if (!readreq&&!createreq)
  1114. return;
  1115. unsigned auditflags = 0;
  1116. if (readreq)
  1117. auditflags |= (DALI_LDAP_AUDIT_REPORT|DALI_LDAP_READ_WANTED);
  1118. if (createreq)
  1119. auditflags |= (DALI_LDAP_AUDIT_REPORT|DALI_LDAP_WRITE_WANTED);
  1120. #ifdef NULL_DALIUSER_STACKTRACE
  1121. if (!user)
  1122. {
  1123. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp checkLogicalScope() line %d",__LINE__);
  1124. PrintStackReport();
  1125. }
  1126. #endif
  1127. int perm = getScopePermissions(scopename,user,auditflags);
  1128. IDFS_Exception *e = NULL;
  1129. if (readreq&&!HASREADPERMISSION(perm))
  1130. e = new CDFS_Exception(DFSERR_LookupAccessDenied,scopename);
  1131. else if (createreq&&!HASWRITEPERMISSION(perm))
  1132. e = new CDFS_Exception(DFSERR_CreateAccessDenied,scopename);
  1133. if (e)
  1134. throw e;
  1135. }
  1136. static bool checkLogicalName(CDfsLogicalFileName &dlfn,IUserDescriptor *user,bool readreq,bool createreq,bool allowquery,const char *specialnotallowedmsg)
  1137. {
  1138. bool ret = true;
  1139. if (dlfn.isMulti()) { //is temporary superFile?
  1140. if (specialnotallowedmsg)
  1141. throw MakeStringException(-1,"cannot %s a multi file name (%s)",specialnotallowedmsg,dlfn.get());
  1142. if (!dlfn.isExpanded())
  1143. dlfn.expand(user);//expand wildcards
  1144. unsigned i = dlfn.multiOrdinality();
  1145. while (--i)//continue looping even when ret is false, in order to check for illegal elements (foreigns/externals), and to check each scope permission
  1146. ret = checkLogicalName((CDfsLogicalFileName &)dlfn.multiItem(i),user,readreq,createreq,allowquery,specialnotallowedmsg)&&ret;
  1147. }
  1148. else {
  1149. if (specialnotallowedmsg) {
  1150. if (dlfn.isExternal()) {
  1151. if (dlfn.isQuery()&&allowquery)
  1152. ret = false;
  1153. else
  1154. throw MakeStringException(-1,"cannot %s an external file name (%s)",specialnotallowedmsg,dlfn.get());
  1155. }
  1156. if (dlfn.isForeign()) {
  1157. throw MakeStringException(-1,"cannot %s a foreign file name (%s)",specialnotallowedmsg,dlfn.get());
  1158. }
  1159. }
  1160. StringBuffer scopes;
  1161. dlfn.getScopes(scopes);
  1162. checkLogicalScope(scopes.str(),user,readreq,createreq);
  1163. }
  1164. return ret;
  1165. }
  1166. /*
  1167. * This class removes all files marked for deletion during transactions.
  1168. *
  1169. * TODO: the doDelete method re-acquires the lock to remove the files, and
  1170. * that creates a window (between end of commit and deletion) where other
  1171. * processes can acquire locks and blow things up. To fix this, you'd have
  1172. * to be selective on what files you unlock during commit, so that you
  1173. * can still keep an unified cache AND release the deletions later on.
  1174. */
  1175. class CDelayedDelete: public CInterface
  1176. {
  1177. CDfsLogicalFileName lfn;
  1178. Linked<IUserDescriptor> user;
  1179. unsigned timeoutms;
  1180. public:
  1181. CDelayedDelete(CDfsLogicalFileName &_lfn,IUserDescriptor *_user,unsigned _timeoutms)
  1182. : user(_user), timeoutms(_timeoutms)
  1183. {
  1184. lfn.set(_lfn);
  1185. }
  1186. void doDelete() // Throw on error!
  1187. {
  1188. const char *logicalname = lfn.get();
  1189. if (!lfn.isExternal() && checkLogicalName(lfn,user,true,true,true,"remove"))
  1190. ThrowStringException(-1, "Logical Name fails for removal on %s", lfn.get());
  1191. // Transaction files have already been unlocked at this point, delete all remaining files
  1192. Owned<IDistributedFile> file = queryDistributedFileDirectory().lookup(lfn, user, true, false, true, NULL, SDS_SUB_LOCK_TIMEOUT);
  1193. if (!file.get())
  1194. return;
  1195. StringBuffer reason;
  1196. if (!file->canRemove(reason, false))
  1197. ThrowStringException(-1, "Can't remove %s: %s", lfn.get(), reason.str());
  1198. // This will do the right thing for either super-files and logical-files.
  1199. file->detach();
  1200. }
  1201. };
  1202. class CDistributedFileTransaction: public CInterface, implements IDistributedFileTransactionExt
  1203. {
  1204. class CTransactionFile : public CSimpleInterface
  1205. {
  1206. class HTMapping : public CInterface
  1207. {
  1208. IDistributedFile *file;
  1209. StringAttr name;
  1210. public:
  1211. HTMapping(const char *_name, IDistributedFile *_file) : name(_name), file(_file) { }
  1212. IDistributedFile &query() { return *file; }
  1213. const char *queryFindString() const { return name; }
  1214. const void *queryFindParam() const { return &file; }
  1215. };
  1216. class CSubFileIter : protected SuperHashIteratorOf<HTMapping>, implements IDistributedFileIterator
  1217. {
  1218. typedef SuperHashIteratorOf<HTMapping> PARENT;
  1219. public:
  1220. IMPLEMENT_IINTERFACE_USING(PARENT);
  1221. CSubFileIter(OwningStringSuperHashTableOf<HTMapping> &table) : PARENT(table)
  1222. {
  1223. }
  1224. // IDistributedFileIterator impl.
  1225. virtual IDistributedFile &query()
  1226. {
  1227. HTMapping &map = PARENT::query();
  1228. return map.query();
  1229. }
  1230. virtual bool first() { return PARENT::first(); }
  1231. virtual bool isValid() { return PARENT::isValid(); }
  1232. virtual bool next() { return PARENT::next(); }
  1233. virtual StringBuffer &getName(StringBuffer &name)
  1234. {
  1235. HTMapping &map = PARENT::query();
  1236. return name.append(map.queryFindString());
  1237. }
  1238. };
  1239. CDistributedFileTransaction &owner;
  1240. OwningStringSuperHashTableOf<HTMapping> subFilesByName;
  1241. StringAttr name;
  1242. Linked<IDistributedFile> file;
  1243. public:
  1244. CTransactionFile(CDistributedFileTransaction &_owner, const char *_name, IDistributedFile *_file) : owner(_owner), name(_name), file(_file)
  1245. {
  1246. }
  1247. const char *queryName() const { return name; }
  1248. IDistributedFile *queryFile() { return file; }
  1249. IDistributedFileIterator *getSubFiles()
  1250. {
  1251. IDistributedSuperFile *super = file->querySuperFile();
  1252. if (!super)
  1253. return NULL;
  1254. return new CSubFileIter(subFilesByName);
  1255. }
  1256. void clearSubs()
  1257. {
  1258. subFilesByName.kill();
  1259. }
  1260. unsigned numSubFiles() const { return subFilesByName.count(); }
  1261. void noteAddSubFile(IDistributedFile *sub)
  1262. {
  1263. if (NULL == subFilesByName.find(sub->queryLogicalName()))
  1264. {
  1265. Owned<HTMapping> map = new HTMapping(sub->queryLogicalName(), sub);
  1266. subFilesByName.replace(*map.getLink());
  1267. }
  1268. }
  1269. void noteRemoveSubFile(IDistributedFile *sub)
  1270. {
  1271. HTMapping *map = subFilesByName.find(sub->queryLogicalName());
  1272. if (map)
  1273. verifyex(subFilesByName.removeExact(map));
  1274. }
  1275. bool find(const char *subFile, bool sub)
  1276. {
  1277. HTMapping *match = subFilesByName.find(subFile);
  1278. if (match)
  1279. return &match->query();
  1280. else if (sub)
  1281. {
  1282. SuperHashIteratorOf<HTMapping> iter(subFilesByName);
  1283. ForEach(iter)
  1284. {
  1285. HTMapping &map = iter.query();
  1286. IDistributedFile &file = map.query();
  1287. IDistributedSuperFile *super = file.querySuperFile();
  1288. if (super)
  1289. {
  1290. if (owner.isSubFile(super, subFile, sub))
  1291. return true;
  1292. }
  1293. }
  1294. }
  1295. return false;
  1296. }
  1297. const void *queryFindParam() const { return &file; }
  1298. const char *queryFindString() const { return name; }
  1299. };
  1300. CIArrayOf<CDFAction> actions;
  1301. OwningSimpleHashTableOf<CTransactionFile, IDistributedFile *> trackedFiles;
  1302. OwningStringSuperHashTableOf<CTransactionFile> trackedFilesByName;
  1303. bool isactive;
  1304. Linked<IUserDescriptor> udesc;
  1305. CIArrayOf<CDelayedDelete> delayeddelete;
  1306. // auto-commit only works at depth zero (for recursive calls)
  1307. // MORE: Maybe this needs a context object (descend on c-tor, ascend on d-tor)
  1308. // But we need all actions within transactions first to find out if there is
  1309. // any exception to the rule used by addSubFile / removeSubFile
  1310. unsigned depth;
  1311. unsigned prepared;
  1312. /* 'owner' is set if, transaction object is implicitly created, because none provided
  1313. * The owner cannot be release or unlocked. The transaction can still retry if other files are locked,
  1314. * so need to ensure 'owner' remains in tracked file cache.
  1315. */
  1316. IDistributedSuperFile *owner;
  1317. void validateAddSubFile(IDistributedSuperFile *super, IDistributedFile *sub, const char *subName);
  1318. CTransactionFile *queryCreate(const char *name, IDistributedFile *file, bool recreate=false)
  1319. {
  1320. Owned<CTransactionFile> trackedFile;
  1321. if (!recreate)
  1322. trackedFile.set(trackedFiles.find(file));
  1323. if (!trackedFile)
  1324. {
  1325. StringBuffer tmp;
  1326. name = normalizeLFN(name, tmp);
  1327. trackedFile.setown(new CTransactionFile(*this, tmp.str(), file));
  1328. trackedFiles.replace(*trackedFile.getLink());
  1329. trackedFilesByName.replace(*trackedFile.getLink());
  1330. }
  1331. return trackedFile;
  1332. }
  1333. CTransactionFile *lookupTrackedFile(IDistributedFile *file)
  1334. {
  1335. return trackedFiles.find(file);
  1336. }
  1337. public:
  1338. IMPLEMENT_IINTERFACE;
  1339. CDistributedFileTransaction(IUserDescriptor *user, IDistributedSuperFile *_owner=NULL)
  1340. : isactive(false), depth(0), prepared(0), owner(_owner)
  1341. {
  1342. setUserDescriptor(udesc,user);
  1343. }
  1344. ~CDistributedFileTransaction()
  1345. {
  1346. // New files should be removed automatically if not committed
  1347. // MORE - refactor cCreateSuperFileAction to avoid this
  1348. if (isactive)
  1349. rollback();
  1350. assert(depth == 0);
  1351. }
  1352. void ensureFile(IDistributedFile *file)
  1353. {
  1354. if (!trackedFiles.find(file))
  1355. addFile(file);
  1356. }
  1357. void addFile(IDistributedFile *file)
  1358. {
  1359. CTransactionFile *trackedFile = queryCreate(file->queryLogicalName(), file, false);
  1360. // Also add subfiles to cache
  1361. IDistributedSuperFile *sfile = file->querySuperFile();
  1362. if (sfile)
  1363. {
  1364. Owned<IDistributedFileIterator> iter = sfile->getSubFileIterator();
  1365. ForEach(*iter)
  1366. {
  1367. IDistributedFile *f = &iter->query();
  1368. trackedFile->noteAddSubFile(f);
  1369. addFile(f);
  1370. }
  1371. }
  1372. }
  1373. void noteAddSubFile(IDistributedSuperFile *super, const char *superName, IDistributedFile *sub)
  1374. {
  1375. CTransactionFile *trackedSuper = queryCreate(superName, super);
  1376. trackedSuper->noteAddSubFile(sub);
  1377. }
  1378. void noteRemoveSubFile(IDistributedSuperFile *super, IDistributedFile *sub)
  1379. {
  1380. CTransactionFile *trackedSuper = lookupTrackedFile(super);
  1381. if (trackedSuper)
  1382. trackedSuper->noteRemoveSubFile(sub);
  1383. }
  1384. virtual void clearSubFiles(IDistributedSuperFile *super)
  1385. {
  1386. CTransactionFile *trackedSuper = lookupTrackedFile(super);
  1387. if (trackedSuper)
  1388. trackedSuper->clearSubs();
  1389. }
  1390. virtual void noteSuperSwap(IDistributedSuperFile *super1, IDistributedSuperFile *super2)
  1391. {
  1392. CTransactionFile *trackedSuper1 = lookupTrackedFile(super1);
  1393. CTransactionFile *trackedSuper2 = lookupTrackedFile(super2);
  1394. assertex(trackedSuper1 && trackedSuper2);
  1395. ICopyArrayOf<IDistributedFile> super1Subs, super2Subs;
  1396. Owned<IDistributedFileIterator> iter = trackedSuper1->getSubFiles();
  1397. ForEach(*iter)
  1398. super1Subs.append(iter->query());
  1399. trackedSuper1->clearSubs();
  1400. iter.setown(trackedSuper2->getSubFiles());
  1401. ForEach(*iter)
  1402. super2Subs.append(iter->query());
  1403. trackedSuper2->clearSubs();
  1404. ForEachItemIn(s, super2Subs)
  1405. trackedSuper1->noteAddSubFile(&super2Subs.item(s));
  1406. ForEachItemIn(s2, super1Subs)
  1407. trackedSuper2->noteAddSubFile(&super1Subs.item(s2));
  1408. }
  1409. void noteRename(IDistributedFile *file, const char *newName)
  1410. {
  1411. CTransactionFile *trackedFile = lookupTrackedFile(file);
  1412. if (trackedFile)
  1413. {
  1414. trackedFiles.removeExact(trackedFile);
  1415. trackedFilesByName.removeExact(trackedFile);
  1416. trackedFile = queryCreate(newName, file);
  1417. }
  1418. }
  1419. void addAction(CDFAction *action)
  1420. {
  1421. actions.append(*action); // takes ownership
  1422. action->setTransaction(this);
  1423. }
  1424. void start()
  1425. {
  1426. if (isactive)
  1427. throw MakeStringException(-1,"Transaction already started");
  1428. clearFiles();
  1429. actions.kill();
  1430. isactive = true;
  1431. prepared = 0;
  1432. assertex(actions.ordinality()==0);
  1433. }
  1434. bool prepareActions()
  1435. {
  1436. prepared = 0;
  1437. unsigned toPrepare = actions.ordinality();
  1438. ForEachItemIn(i0,actions)
  1439. {
  1440. if (actions.item(i0).prepare())
  1441. ++prepared;
  1442. else
  1443. break;
  1444. }
  1445. return prepared == toPrepare;
  1446. }
  1447. void retryActions()
  1448. {
  1449. clearFiles(); // clear all previously tracked pending file changes, e.g. renames, super file additions/removals
  1450. while (prepared) // unlock for retry
  1451. actions.item(--prepared).retry();
  1452. }
  1453. void runActions()
  1454. {
  1455. ForEachItemIn(i,actions)
  1456. actions.item(i).run();
  1457. }
  1458. void commitActions()
  1459. {
  1460. while (actions.ordinality()) // if we get here everything should work!
  1461. {
  1462. Owned<CDFAction> action = &actions.popGet();
  1463. action->commit();
  1464. }
  1465. }
  1466. void commit()
  1467. {
  1468. if (!isactive)
  1469. return;
  1470. IException *rete=NULL;
  1471. // =============== PREPARE AND RETRY UNTIL READY
  1472. try
  1473. {
  1474. loop
  1475. {
  1476. if (prepareActions())
  1477. break;
  1478. else
  1479. retryActions();
  1480. PROGLOG("CDistributedFileTransaction: Transaction pausing");
  1481. Sleep(SDS_TRANSACTION_RETRY/2+(getRandom()%SDS_TRANSACTION_RETRY));
  1482. }
  1483. runActions();
  1484. commitAndClearup();
  1485. return;
  1486. }
  1487. catch (IException *e)
  1488. {
  1489. rete = e;
  1490. }
  1491. rollback();
  1492. throw rete;
  1493. }
  1494. void commitAndClearup()
  1495. {
  1496. // =============== COMMIT and CLEANUP
  1497. commitActions();
  1498. clearFiles();
  1499. isactive = false;
  1500. actions.kill();
  1501. deleteFiles();
  1502. }
  1503. void rollback()
  1504. {
  1505. // =============== ROLLBACK AND CLEANUP
  1506. while (actions.ordinality())
  1507. {
  1508. try
  1509. {
  1510. // we don't want to unlock what hasn't been locked
  1511. // if an exception was thrown while locking, but we
  1512. // do want to pop them all
  1513. Owned<CDFAction> action = &actions.popGet();
  1514. if (actions.ordinality()<prepared)
  1515. action->rollback();
  1516. }
  1517. catch (IException *e)
  1518. {
  1519. e->Release();
  1520. }
  1521. }
  1522. actions.kill(); // should be empty
  1523. clearFiles(); // release locks
  1524. if (!isactive)
  1525. return;
  1526. isactive = false;
  1527. // this we only want to do if active
  1528. delayeddelete.kill();
  1529. }
  1530. void autoCommit()
  1531. {
  1532. // Recursive calls to transaction will not commit until
  1533. // all calls have finished (gone back to zero depth)
  1534. if (!depth && !isactive) {
  1535. try {
  1536. isactive = true;
  1537. commit();
  1538. }
  1539. catch (IException *) {
  1540. rollback();
  1541. throw;
  1542. }
  1543. }
  1544. }
  1545. // Call this when you're recurring
  1546. void descend()
  1547. {
  1548. depth++;
  1549. }
  1550. // Call this at the end of the block that started recursion
  1551. void ascend()
  1552. {
  1553. assertex(depth);
  1554. depth--;
  1555. }
  1556. IDistributedFile *findFile(const char *name)
  1557. {
  1558. StringBuffer tmp;
  1559. name = normalizeLFN(name, tmp);
  1560. CTransactionFile *trackedFile = trackedFilesByName.find(tmp.str());
  1561. if (!trackedFile)
  1562. return NULL;
  1563. return trackedFile->queryFile();
  1564. }
  1565. IDistributedFile *lookupFile(const char *name,unsigned timeout)
  1566. {
  1567. IDistributedFile *ret = findFile(name);
  1568. if (ret)
  1569. return LINK(ret);
  1570. else
  1571. {
  1572. ret = queryDistributedFileDirectory().lookup(name, udesc, false, false, false, this, timeout);
  1573. if (ret)
  1574. queryCreate(name, ret, true);
  1575. return ret;
  1576. }
  1577. }
  1578. IDistributedSuperFile *lookupSuperFile(const char *name, unsigned timeout)
  1579. {
  1580. IDistributedFile *f = findFile(name);
  1581. if (f)
  1582. return LINK(f->querySuperFile());
  1583. else
  1584. {
  1585. IDistributedSuperFile *ret = queryDistributedFileDirectory().lookupSuperFile(name,udesc,this,timeout);
  1586. if (ret)
  1587. addFile(ret);
  1588. return ret;
  1589. }
  1590. }
  1591. virtual bool isSubFile(IDistributedSuperFile *super, const char *subFile, bool sub)
  1592. {
  1593. CTransactionFile *trackedSuper = lookupTrackedFile(super);
  1594. if (!trackedSuper)
  1595. return false;
  1596. return trackedSuper->find(subFile, sub);
  1597. }
  1598. public:
  1599. bool active()
  1600. {
  1601. return isactive;
  1602. }
  1603. void clearFiles()
  1604. {
  1605. trackedFiles.kill();
  1606. trackedFilesByName.kill();
  1607. if (owner)
  1608. addFile(owner); // ensure remains tracked
  1609. }
  1610. void clearFile(IDistributedFile *file)
  1611. {
  1612. CTransactionFile *trackedFile = lookupTrackedFile(file);
  1613. IDistributedSuperFile *sfile = file->querySuperFile();
  1614. if (trackedFile)
  1615. {
  1616. Owned<IDistributedFileIterator> iter = trackedFile->getSubFiles();
  1617. if (iter)
  1618. {
  1619. ForEach(*iter)
  1620. clearFile(&iter->query());
  1621. }
  1622. trackedFiles.removeExact(trackedFile);
  1623. trackedFilesByName.removeExact(trackedFile);
  1624. }
  1625. }
  1626. IUserDescriptor *queryUser()
  1627. {
  1628. return udesc;
  1629. }
  1630. bool addDelayedDelete(CDfsLogicalFileName &lfn,unsigned timeoutms)
  1631. {
  1632. delayeddelete.append(*new CDelayedDelete(lfn,udesc,timeoutms));
  1633. return true;
  1634. }
  1635. void deleteFiles() // no rollback at this point
  1636. {
  1637. Owned<IMultiException> me = MakeMultiException("Transaction");
  1638. ForEachItemIn(i,delayeddelete) {
  1639. try {
  1640. delayeddelete.item(i).doDelete();
  1641. } catch (IException *e) {
  1642. me->append(*e);
  1643. }
  1644. }
  1645. delayeddelete.kill();
  1646. if (me->ordinality())
  1647. throw me.getClear();
  1648. }
  1649. };
  1650. static bool recursiveCheckEmptyScope(IPropertyTree &ct)
  1651. {
  1652. Owned<IPropertyTreeIterator> iter = ct.getElements("*");
  1653. ForEach(*iter) {
  1654. IPropertyTree &item = iter->query();
  1655. const char *n = item.queryName();
  1656. if (!n||(strcmp(n,queryDfsXmlBranchName(DXB_Scope))!=0))
  1657. return false;
  1658. if (!recursiveCheckEmptyScope(item))
  1659. return false;
  1660. }
  1661. return true;
  1662. }
  1663. class CDFScopeIterator: public CInterface, implements IDFScopeIterator
  1664. {
  1665. PointerArray scopes;
  1666. unsigned index;
  1667. IDistributedFileDirectory *dir;
  1668. bool includeempty;
  1669. void add(IPropertyTree &t, bool recursive, StringBuffer &name)
  1670. {
  1671. name.trim();
  1672. size32_t nl = name.length();
  1673. size32_t l=nl;
  1674. if (nl) {
  1675. name.append("::");
  1676. l+=2;
  1677. }
  1678. Owned<IPropertyTreeIterator> iter = t.getElements(queryDfsXmlBranchName(DXB_Scope));
  1679. ForEach(*iter) {
  1680. IPropertyTree &ct = iter->query();
  1681. if (includeempty||!recursiveCheckEmptyScope(ct)) {
  1682. name.append(ct.queryProp("@name"));
  1683. scopes.append(strdup(name.str()));
  1684. if (recursive)
  1685. add(ct,recursive,name);
  1686. name.setLength(l);
  1687. }
  1688. }
  1689. name.setLength(nl);
  1690. }
  1691. public:
  1692. IMPLEMENT_IINTERFACE;
  1693. CDFScopeIterator(IDistributedFileDirectory *_dir,const char *base,bool recursive, bool _includeempty,unsigned timeout) // attrib not yet implemented
  1694. {
  1695. includeempty = _includeempty;
  1696. dir = _dir;
  1697. StringBuffer baseq;
  1698. StringBuffer tmp;
  1699. if (base&&*base) {
  1700. CDfsLogicalFileName dlfn;
  1701. dlfn.set(base,".");
  1702. dlfn.makeScopeQuery(baseq,false);
  1703. }
  1704. {
  1705. CConnectLock connlock("CDFScopeIterator",querySdsFilesRoot(),false,false,false,timeout);
  1706. // could use CScopeConnectLock here probably
  1707. StringBuffer name;
  1708. IPropertyTree *root = connlock.conn->queryRoot();
  1709. if (baseq.length())
  1710. root = root->queryPropTree(baseq.str());
  1711. if (root)
  1712. add(*root,recursive,name);
  1713. }
  1714. if (scopes.ordinality()>1)
  1715. qsortvec(scopes.getArray(),scopes.ordinality(),strcompare);
  1716. index = 0;
  1717. }
  1718. ~CDFScopeIterator()
  1719. {
  1720. ForEachItemIn(i,scopes) {
  1721. free(scopes.item(i));
  1722. }
  1723. }
  1724. bool first()
  1725. {
  1726. index = 0;
  1727. return isValid();
  1728. }
  1729. bool next()
  1730. {
  1731. index++;
  1732. return isValid();
  1733. }
  1734. bool isValid()
  1735. {
  1736. return (index<scopes.ordinality());
  1737. }
  1738. const char *query()
  1739. {
  1740. return (const char *)scopes.item(index);
  1741. }
  1742. };
  1743. class CDFAttributeIterator: public CInterface, implements IDFAttributesIterator
  1744. {
  1745. IArrayOf<IPropertyTree> attrs;
  1746. unsigned index;
  1747. public:
  1748. IMPLEMENT_IINTERFACE;
  1749. static MemoryBuffer &serializeFileAttributes(MemoryBuffer &mb, IPropertyTree &root, const char *name, bool issuper)
  1750. {
  1751. StringBuffer buf;
  1752. mb.append(name);
  1753. if (issuper) {
  1754. mb.append("!SF");
  1755. mb.append(root.getPropInt("@numsubfiles",0));
  1756. mb.append("");
  1757. }
  1758. else {
  1759. mb.append(root.queryProp("@directory"));
  1760. mb.append(root.getPropInt("@numparts",0));
  1761. mb.append(root.queryProp("@partmask"));
  1762. }
  1763. mb.append(root.queryProp("@modified"));
  1764. Owned<IPropertyTree> attrs = root.getPropTree("Attr");;
  1765. Owned<IAttributeIterator> attriter;
  1766. if (attrs)
  1767. attriter.setown(attrs->getAttributes());
  1768. unsigned count=0;
  1769. size32_t countpos = mb.length();
  1770. mb.append(count);
  1771. if (attriter.get()&&attriter->first()) {
  1772. do {
  1773. mb.append(attriter->queryName());
  1774. mb.append(attriter->queryValue());
  1775. count++;
  1776. } while (attriter->next());
  1777. }
  1778. const char *ps = root.queryProp("@group");
  1779. if (ps&&*ps) {
  1780. count++;
  1781. mb.append("@group");
  1782. mb.append(ps);
  1783. }
  1784. // add protected
  1785. if (attrs) {
  1786. Owned<IPropertyTreeIterator> piter = attrs->getElements("Protect");
  1787. StringBuffer plist;
  1788. ForEach(*piter) {
  1789. const char *name = piter->get().queryProp("@name");
  1790. if (name&&*name) {
  1791. unsigned count = piter->get().getPropInt("@count");
  1792. if (count) {
  1793. if (plist.length())
  1794. plist.append(',');
  1795. plist.append(name);
  1796. if (count>1)
  1797. plist.append(':').append(count);
  1798. }
  1799. }
  1800. }
  1801. if (plist.length()) {
  1802. count++;
  1803. mb.append("@protect");
  1804. mb.append(plist.str());
  1805. }
  1806. }
  1807. mb.writeDirect(countpos,sizeof(count),&count);
  1808. return mb;
  1809. }
  1810. CDFAttributeIterator(MemoryBuffer &mb) // attrib not yet implemented
  1811. {
  1812. unsigned numfiles;
  1813. mb.read(numfiles);
  1814. while (numfiles--) {
  1815. IPropertyTree *attr = getEmptyAttr();
  1816. StringAttr val;
  1817. unsigned n;
  1818. mb.read(val);
  1819. attr->setProp("@name",val.get());
  1820. mb.read(val);
  1821. if (stricmp(val,"!SF")==0) {
  1822. mb.read(n);
  1823. attr->setPropInt("@numsubfiles",n);
  1824. mb.read(val); // not used currently
  1825. }
  1826. else {
  1827. attr->setProp("@directory",val.get());
  1828. mb.read(n);
  1829. attr->setPropInt("@numparts",n);
  1830. mb.read(val);
  1831. attr->setProp("@partmask",val.get());
  1832. }
  1833. mb.read(val);
  1834. attr->setProp("@modified",val.get());
  1835. unsigned count;
  1836. mb.read(count);
  1837. StringAttr at;
  1838. while (count--) {
  1839. mb.read(at);
  1840. mb.read(val);
  1841. attr->setProp(at.get(),val.get());
  1842. }
  1843. attrs.append(*attr);
  1844. }
  1845. index = 0;
  1846. }
  1847. CDFAttributeIterator(IArrayOf<IPropertyTree>& trees)
  1848. {
  1849. ForEachItemIn(t, trees)
  1850. attrs.append(*LINK(&trees.item(t)));
  1851. index = 0;
  1852. }
  1853. ~CDFAttributeIterator()
  1854. {
  1855. attrs.kill();
  1856. }
  1857. bool first()
  1858. {
  1859. index = 0;
  1860. return (attrs.ordinality()!=0);
  1861. }
  1862. bool next()
  1863. {
  1864. index++;
  1865. return (index<attrs.ordinality());
  1866. }
  1867. bool isValid()
  1868. {
  1869. return (index<attrs.ordinality());
  1870. }
  1871. IPropertyTree & query()
  1872. {
  1873. return attrs.item(index);
  1874. }
  1875. };
  1876. class CDFProtectedIterator: public CInterface, implements IDFProtectedIterator
  1877. {
  1878. StringAttr owner;
  1879. StringAttr fn;
  1880. unsigned count;
  1881. bool issuper;
  1882. Owned<IRemoteConnection> conn;
  1883. Owned<IPropertyTreeIterator> fiter;
  1884. Owned<IPropertyTreeIterator> piter;
  1885. unsigned defaultTimeout;
  1886. bool notsuper;
  1887. bool superonly;
  1888. void fill()
  1889. {
  1890. IPropertyTree &t = fiter->query();
  1891. fn.set(t.queryProp("OrigName"));
  1892. IPropertyTree &pt = piter->query();
  1893. owner.set(pt.queryProp("@name"));
  1894. count = pt.getPropInt("@count");
  1895. }
  1896. void clear()
  1897. {
  1898. piter.clear();
  1899. fiter.clear();
  1900. conn.clear();
  1901. issuper = false;
  1902. }
  1903. public:
  1904. IMPLEMENT_IINTERFACE;
  1905. CDFProtectedIterator(const char *_owner,bool _notsuper,bool _superonly,unsigned _defaultTimeout)
  1906. : owner(_owner)
  1907. {
  1908. count = 0;
  1909. issuper = false;
  1910. notsuper=_notsuper;
  1911. superonly=_superonly;
  1912. defaultTimeout = _defaultTimeout;
  1913. }
  1914. ~CDFProtectedIterator()
  1915. {
  1916. clear();
  1917. }
  1918. bool first()
  1919. {
  1920. clear();
  1921. conn.setown(querySDS().connect("Files",myProcessSession(),0, defaultTimeout));
  1922. if (!conn)
  1923. return false;
  1924. IPropertyTree *t = conn->queryRoot();
  1925. if (!superonly) {
  1926. fiter.setown(t->getElements("//File[Attr/Protect]", iptiter_remote));
  1927. if (fiter->first()) {
  1928. piter.setown(fiter->query().getElements("Attr/Protect"));
  1929. if (piter->first()) {
  1930. fill();
  1931. return true;
  1932. }
  1933. }
  1934. }
  1935. if (!notsuper) {
  1936. issuper = true;
  1937. fiter.clear();
  1938. fiter.setown(t->getElements("//SuperFile[Attr/Protect]", iptiter_remote));
  1939. if (fiter->first()) {
  1940. piter.setown(fiter->query().getElements("Attr/Protect"));
  1941. if (piter->first()) {
  1942. fill();
  1943. return true;
  1944. }
  1945. }
  1946. }
  1947. clear();
  1948. return false;
  1949. }
  1950. bool next()
  1951. {
  1952. if (!fiter.get())
  1953. return false;
  1954. if (piter->next()) {
  1955. fill();
  1956. return true;
  1957. }
  1958. loop {
  1959. if (fiter->next()) {
  1960. piter.setown(fiter->query().getElements("Attr/Protect"));
  1961. if (piter->first()) {
  1962. fill();
  1963. return true;
  1964. }
  1965. }
  1966. else if (!notsuper&&!issuper) {
  1967. issuper = true;
  1968. fiter.clear();
  1969. fiter.setown(conn->queryRoot()->getElements("//SuperFile[Attr/Protect]", iptiter_remote));
  1970. if (fiter->first()) {
  1971. piter.setown(fiter->query().getElements("Attr/Protect"));
  1972. if (piter->first()) {
  1973. fill();
  1974. return true;
  1975. }
  1976. }
  1977. else
  1978. break;
  1979. }
  1980. else
  1981. break;
  1982. }
  1983. clear();
  1984. return false;
  1985. }
  1986. bool isValid()
  1987. {
  1988. return fiter.get()!=NULL;
  1989. }
  1990. const char *queryFilename()
  1991. {
  1992. return fn;
  1993. }
  1994. const char *queryOwner()
  1995. {
  1996. return owner;
  1997. }
  1998. unsigned getCount()
  1999. {
  2000. return count;
  2001. }
  2002. bool isSuper()
  2003. {
  2004. return issuper;
  2005. }
  2006. };
  2007. // --------------------------------------------------------
  2008. class CDistributedFilePart: public CInterface, implements IDistributedFilePart
  2009. {
  2010. unsigned partIndex;
  2011. CDistributedFile &parent;
  2012. Owned<IPropertyTree> attr;
  2013. CriticalSection sect;
  2014. StringAttr overridename; // may or not be relative to directory
  2015. bool dirty; // whether needs updating in tree
  2016. offset_t getSize(bool checkCompressed);
  2017. public:
  2018. virtual void Link(void) const;
  2019. virtual bool Release(void) const;
  2020. void set(IPropertyTree *pt,FileClusterInfoArray &clusters,unsigned maxcluster);
  2021. RemoteFilename &getFilename(RemoteFilename &ret,unsigned copy);
  2022. void renameFile(IFile *file);
  2023. IPropertyTree &queryAttributes();
  2024. bool lockProperties(unsigned timems);
  2025. void unlockProperties(DFTransactionState state);
  2026. bool isHost(unsigned copy);
  2027. offset_t getFileSize(bool allowphysical,bool forcephysical);
  2028. offset_t getDiskSize(bool allowphysical,bool forcephysical);
  2029. bool getModifiedTime(bool allowphysical,bool forcephysical,CDateTime &dt);
  2030. bool getCrc(unsigned &crc);
  2031. unsigned getPhysicalCrc();
  2032. IPartDescriptor *getPartDescriptor();
  2033. unsigned numCopies();
  2034. INode *queryNode(unsigned copy);
  2035. unsigned queryDrive(unsigned copy);
  2036. StringBuffer &getPartName(StringBuffer &name);
  2037. StringBuffer &getPartDirectory(StringBuffer &name,unsigned copy);
  2038. const char *queryOverrideName() { return overridename; }
  2039. void clearOverrideName()
  2040. {
  2041. if (overridename.get()&&overridename.length()) {
  2042. dirty = true;
  2043. overridename.clear();
  2044. }
  2045. }
  2046. unsigned bestCopyNum(const IpAddress &ip,unsigned rel=0);
  2047. unsigned copyClusterNum(unsigned copy,unsigned *replicate=NULL);
  2048. void childLink(void) { CInterface::Link(); }
  2049. bool childRelease(void) { return CInterface::Release(); }
  2050. CDistributedFilePart(CDistributedFile &_parent,unsigned _part,IPartDescriptor *pd);
  2051. unsigned getPartIndex()
  2052. {
  2053. return partIndex;
  2054. }
  2055. INode *getNode(unsigned copy)
  2056. {
  2057. INode *ret = queryNode(copy);
  2058. if (ret)
  2059. return LINK(ret);
  2060. return NULL;
  2061. }
  2062. void setAttr(IPropertyTree &pt)
  2063. {
  2064. attr.setown(createPTreeFromIPT(&pt)); // take a copy
  2065. dirty = false;
  2066. }
  2067. IPropertyTree *queryAttr()
  2068. {
  2069. return attr;
  2070. }
  2071. inline CDistributedFile &queryParent()
  2072. {
  2073. return parent;
  2074. }
  2075. inline bool isDirty()
  2076. {
  2077. return dirty;
  2078. }
  2079. inline bool clearDirty()
  2080. {
  2081. bool ret=dirty;
  2082. dirty = false;
  2083. return ret;
  2084. }
  2085. };
  2086. // --------------------------------------------------------
  2087. class CDistributedFilePartArray: public CIArrayOf<CDistributedFilePart>
  2088. {
  2089. public:
  2090. virtual ~CDistributedFilePartArray() // this shouldn't be needed - points to problem in CIArrayOf?
  2091. {
  2092. kill();
  2093. }
  2094. void kill(bool nodel = false)
  2095. {
  2096. if (nodel)
  2097. CIArrayOf<CDistributedFilePart>::kill(true);
  2098. else {
  2099. while (ordinality()) {
  2100. CDistributedFilePart &part = popGet();
  2101. part.Release();
  2102. }
  2103. }
  2104. }
  2105. };
  2106. // --------------------------------------------------------
  2107. /**
  2108. * Base Iterator class for all iterator types. Implements basic iteration
  2109. * logic and forces all iterators to behave similarly. This will simplify
  2110. * future compatibility with STL containers/algorithms.
  2111. *
  2112. * INTERFACE needs to be extended from IIteratorOf<>
  2113. * ARRAYTY need to be extended from IArrayOf<>
  2114. */
  2115. template <class INTERFACE, class ARRAYTY>
  2116. class CDistributedFileIteratorBase: public CInterface, implements INTERFACE
  2117. {
  2118. protected:
  2119. unsigned index;
  2120. ARRAYTY list;
  2121. virtual bool set() { return isValid(); }
  2122. public:
  2123. IMPLEMENT_IINTERFACE;
  2124. CDistributedFileIteratorBase()
  2125. : index(0)
  2126. {
  2127. }
  2128. virtual ~CDistributedFileIteratorBase()
  2129. {
  2130. list.kill();
  2131. }
  2132. bool first()
  2133. {
  2134. if (list.ordinality() == 0)
  2135. return false;
  2136. index = 0;
  2137. return set();
  2138. }
  2139. bool next()
  2140. {
  2141. index++;
  2142. set();
  2143. return isValid();
  2144. }
  2145. bool isValid()
  2146. {
  2147. return (index < list.ordinality());
  2148. }
  2149. };
  2150. /**
  2151. * FilePart Iterator, used by files to manipulate its parts.
  2152. */
  2153. class CDistributedFilePartIterator: public CDistributedFileIteratorBase<IDistributedFilePartIterator, CDistributedFilePartArray>
  2154. {
  2155. public:
  2156. CDistributedFilePartIterator(CDistributedFilePartArray &parts, IDFPartFilter *filter)
  2157. {
  2158. ForEachItemIn(i,parts) {
  2159. if (!filter||filter->includePart(i))
  2160. list.append(*LINK(&parts.item(i)));
  2161. }
  2162. }
  2163. CDistributedFilePartIterator()
  2164. {
  2165. }
  2166. IDistributedFilePart & query()
  2167. {
  2168. return list.item(index);
  2169. }
  2170. CDistributedFilePartArray &queryParts()
  2171. {
  2172. return list;
  2173. }
  2174. };
  2175. /**
  2176. * File Iterator, used by directory to list file search results.
  2177. */
  2178. class CDistributedFileIterator: public CDistributedFileIteratorBase<IDistributedFileIterator, PointerArray>
  2179. {
  2180. Owned<IDistributedFile> cur;
  2181. IDistributedFileDirectory *parent;
  2182. Linked<IUserDescriptor> udesc;
  2183. Linked<IDistributedFileTransaction> transaction;
  2184. bool set()
  2185. {
  2186. while (isValid()) {
  2187. cur.setown(parent->lookup(queryName(),udesc,false,NULL));
  2188. if (cur)
  2189. return true;
  2190. index++;
  2191. }
  2192. return false;
  2193. }
  2194. public:
  2195. CDistributedFileIterator(IDistributedFileDirectory *_dir,const char *wildname,bool includesuper,IUserDescriptor *user,IDistributedFileTransaction *_transaction=NULL)
  2196. : transaction(_transaction)
  2197. {
  2198. setUserDescriptor(udesc,user);
  2199. if (!wildname||!*wildname)
  2200. wildname = "*";
  2201. parent = _dir;
  2202. bool recursive = (stricmp(wildname,"*")==0);
  2203. Owned<IDFAttributesIterator> attriter = parent->getDFAttributesIterator(wildname,user,recursive,includesuper,NULL);
  2204. ForEach(*attriter) {
  2205. IPropertyTree &pt = attriter->query();
  2206. list.append(strdup(pt.queryProp("@name")));
  2207. }
  2208. index = 0;
  2209. if (list.ordinality()>1)
  2210. qsortvec(list.getArray(),list.ordinality(),strcompare);
  2211. }
  2212. const char *queryName()
  2213. {
  2214. return (const char *)list.item(index);
  2215. }
  2216. StringBuffer & getName(StringBuffer &name)
  2217. {
  2218. return name.append(queryName());
  2219. }
  2220. IDistributedFile & query()
  2221. {
  2222. return *cur;
  2223. }
  2224. };
  2225. /**
  2226. * SuperFile Iterator, used by CDistributedFile to list all its super-owners by name.
  2227. */
  2228. class CDistributedSuperFileIterator: public CDistributedFileIteratorBase<IDistributedSuperFileIterator, StringAttrArray>
  2229. {
  2230. CDistributedFileDirectory *parent;
  2231. Linked<IUserDescriptor> udesc;
  2232. Linked<IDistributedFileTransaction> transaction;
  2233. Owned<IDistributedSuperFile> cur;
  2234. Linked<IDistributedFile> owner;
  2235. public:
  2236. CDistributedSuperFileIterator(IDistributedFile *_owner, CDistributedFileDirectory *_parent,IPropertyTree *root,IUserDescriptor *user, IDistributedFileTransaction *_transaction)
  2237. : owner(_owner), transaction(_transaction)
  2238. {
  2239. setUserDescriptor(udesc,user);
  2240. parent = _parent;
  2241. if (root)
  2242. {
  2243. Owned<IPropertyTreeIterator> iter = root->getElements("SuperOwner");
  2244. StringBuffer pname;
  2245. ForEach(*iter)
  2246. {
  2247. iter->query().getProp("@name",pname.clear());
  2248. if (pname.length())
  2249. list.append(* new StringAttrItem(pname.str()));
  2250. }
  2251. }
  2252. }
  2253. IDistributedSuperFile & query()
  2254. {
  2255. // NOTE: This used to include a do/while (!cur.get()&&next()) loop
  2256. // this should never be needed but match previous semantics
  2257. // throwing an exception now, to catch the error early on
  2258. if (transaction.get())
  2259. cur.setown(transaction->lookupSuperFile(queryName()));
  2260. else
  2261. cur.setown(parent->lookupSuperFile(queryName(),udesc,NULL));
  2262. if (!cur.get())
  2263. throw MakeStringException(-1,"superFileIter: invalid super-file on query at %s", queryName());
  2264. return *cur;
  2265. }
  2266. virtual const char *queryName()
  2267. {
  2268. if (isValid())
  2269. return list.item(index).text.get();
  2270. return NULL;
  2271. }
  2272. };
  2273. //-----------------------------------------------------------------------------
  2274. inline void dfCheckRoot(const char *trc,Owned<IPropertyTree> &root,IRemoteConnection *conn)
  2275. {
  2276. if (root.get()!=conn->queryRoot()) {
  2277. WARNLOG("%s - root changed",trc);
  2278. #ifdef _DEBUG
  2279. PrintStackReport();
  2280. #endif
  2281. root.setown(conn->getRoot());
  2282. }
  2283. }
  2284. static bool setFileProtectTree(IPropertyTree &p,const char *owner, bool protect)
  2285. {
  2286. bool ret = false;
  2287. CDateTime dt;
  2288. dt.setNow();
  2289. if (owner&&*owner) {
  2290. Owned<IPropertyTree> t = getNamedPropTree(&p,"Protect","@name",owner,false);
  2291. if (t) {
  2292. unsigned c = t->getPropInt("@count");
  2293. if (protect)
  2294. c++;
  2295. else {
  2296. if (c>=1) {
  2297. p.removeTree(t);
  2298. c = 0;
  2299. }
  2300. else
  2301. c--;
  2302. }
  2303. if (c) {
  2304. t->setPropInt("@count",c);
  2305. StringBuffer str;
  2306. t->setProp("@modified",dt.getString(str).str());
  2307. }
  2308. }
  2309. else if (protect) {
  2310. t.setown(addNamedPropTree(&p,"Protect","@name",owner));
  2311. t->setPropInt("@count",1);
  2312. StringBuffer str;
  2313. t->setProp("@modified",dt.getString(str).str());
  2314. }
  2315. ret = true;
  2316. }
  2317. else if (!protect) {
  2318. unsigned n=0;
  2319. IPropertyTree *pt;
  2320. while ((pt=p.queryPropTree("Protect[1]"))!=NULL) {
  2321. p.removeTree(pt);
  2322. n++;
  2323. }
  2324. if (n)
  2325. ret = true;
  2326. }
  2327. return ret;
  2328. }
  2329. static bool checkProtectAttr(const char *logicalname,IPropertyTree *froot,StringBuffer &reason)
  2330. {
  2331. Owned<IPropertyTreeIterator> wpiter = froot->getElements("Attr/Protect");
  2332. bool prot = false;
  2333. ForEach(*wpiter) {
  2334. IPropertyTree &t = wpiter->query();
  2335. if (t.getPropInt("@count")) {
  2336. const char *wpname = t.queryProp("@name");
  2337. if (!wpname||!*wpname)
  2338. wpname = "<Unknown>";
  2339. if (prot)
  2340. reason.appendf(", %s",wpname);
  2341. else {
  2342. reason.appendf("file %s protected by %s",logicalname,wpname);
  2343. prot = true;
  2344. }
  2345. }
  2346. }
  2347. return prot;
  2348. }
  2349. /**
  2350. * A template class which implements the common methods of an IDistributedFile interface.
  2351. * The actual interface (extended from IDistributedFile) is provided as a template argument.
  2352. */
  2353. template <class INTERFACE>
  2354. class CDistributedFileBase : public CInterface, implements INTERFACE
  2355. {
  2356. protected:
  2357. Owned<IPropertyTree> root;
  2358. Owned<IRemoteConnection> conn; // kept connected during lifetime for attributes
  2359. CDfsLogicalFileName logicalName;
  2360. CriticalSection sect;
  2361. CDistributedFileDirectory *parent;
  2362. unsigned proplockcount;
  2363. unsigned transactionnest;
  2364. Linked<IUserDescriptor> udesc;
  2365. unsigned defaultTimeout;
  2366. bool dirty;
  2367. Owned<IRemoteConnection> superOwnerLock;
  2368. public:
  2369. IPropertyTree *queryRoot() { return root; }
  2370. CDistributedFileBase<INTERFACE>()
  2371. {
  2372. parent = NULL;
  2373. proplockcount = 0;
  2374. transactionnest = 0;
  2375. defaultTimeout = INFINITE;
  2376. dirty = false;
  2377. }
  2378. ~CDistributedFileBase<INTERFACE>()
  2379. {
  2380. root.clear();
  2381. }
  2382. void setSuperOwnerLock(IRemoteConnection *_superOwnerLock)
  2383. {
  2384. superOwnerLock.setown(_superOwnerLock);
  2385. }
  2386. unsigned setPropLockCount(unsigned _propLockCount)
  2387. {
  2388. unsigned prevPropLockCount = proplockcount;
  2389. proplockcount = _propLockCount;
  2390. return prevPropLockCount;
  2391. }
  2392. bool isCompressed(bool *blocked)
  2393. {
  2394. return ::isCompressed(queryAttributes(),blocked);
  2395. }
  2396. StringBuffer &getLogicalName(StringBuffer &lname)
  2397. {
  2398. lname.append(logicalName.get());
  2399. return lname;
  2400. }
  2401. void setLogicalName(const char *lname)
  2402. {
  2403. logicalName.set(lname);
  2404. }
  2405. const char *queryLogicalName()
  2406. {
  2407. return logicalName.get();
  2408. }
  2409. IPropertyTree &queryAttributes()
  2410. {
  2411. IPropertyTree *t = root->queryPropTree("Attr");
  2412. if (!t)
  2413. t = root->setPropTree("Attr",createPTree("Attr")); // takes ownership
  2414. return *t;
  2415. }
  2416. protected:
  2417. class CFileChangeWriteLock
  2418. {
  2419. IRemoteConnection *conn;
  2420. unsigned timeoutMs, prevMode;
  2421. public:
  2422. CFileChangeWriteLock(IRemoteConnection *_conn, unsigned _timeoutMs)
  2423. : conn(_conn), timeoutMs(_timeoutMs)
  2424. {
  2425. if (conn)
  2426. {
  2427. prevMode = conn->queryMode();
  2428. unsigned newMode = (prevMode & ~RTM_LOCKBASIC_MASK) | RTM_LOCK_WRITE;
  2429. conn->changeMode(RTM_LOCK_WRITE, timeoutMs);
  2430. }
  2431. else
  2432. prevMode = RTM_NONE;
  2433. }
  2434. ~CFileChangeWriteLock()
  2435. {
  2436. if (conn)
  2437. conn->changeMode(prevMode, timeoutMs);
  2438. }
  2439. void clear() { conn = NULL; }
  2440. };
  2441. IPropertyTree *closeConnection(bool removeFile)
  2442. {
  2443. Owned<IPropertyTree> detachedRoot = createPTreeFromIPT(root);
  2444. root.clear();
  2445. if (conn)
  2446. {
  2447. conn->close(removeFile);
  2448. conn.clear();
  2449. }
  2450. return detachedRoot.getClear();
  2451. }
  2452. IPropertyTree *resetFileAttr(IPropertyTree *prop=NULL)
  2453. {
  2454. if (prop)
  2455. return root->setPropTree("Attr", prop);
  2456. root->removeProp("Attr");
  2457. return NULL;
  2458. }
  2459. void updateFS(const CDfsLogicalFileName &lfn, unsigned timeoutMs)
  2460. {
  2461. // Update the file system
  2462. removeFileEmptyScope(lfn, timeoutMs);
  2463. // MORE: We shouldn't have to update all relationships if we had done a better job making sure
  2464. // that all correct relationships were properly cleaned up
  2465. queryDistributedFileDirectory().removeAllFileRelationships(lfn.get());
  2466. }
  2467. public:
  2468. bool isAnon()
  2469. {
  2470. return !logicalName.isSet();
  2471. }
  2472. /*
  2473. * Change connection to write-mode, allowing multiple writers only on the same instance.
  2474. * Returns true if the lock was lost at least once before succeeding, hinting that some
  2475. * resources might need reload (like sub-files list, etc).
  2476. *
  2477. * WARN: This is not thread-safe
  2478. *
  2479. * @deprecated : use DistributedFilePropertyLock instead, when possible
  2480. */
  2481. bool lockProperties(unsigned timeoutms)
  2482. {
  2483. bool reload = false;
  2484. if (timeoutms==INFINITE)
  2485. timeoutms = defaultTimeout;
  2486. if (proplockcount++==0)
  2487. {
  2488. if (conn)
  2489. {
  2490. conn->rollback(); // changes chouldn't be done outside lock properties
  2491. #ifdef TRACE_LOCKS
  2492. PROGLOG("lockProperties: pre safeChangeModeWrite(%x)",(unsigned)(memsize_t)conn.get());
  2493. #endif
  2494. try
  2495. {
  2496. if (0 == timeoutms)
  2497. conn->changeMode(RTM_LOCK_WRITE, 0, true); // 0 timeout, test and fail immediately if contention
  2498. else
  2499. safeChangeModeWrite(conn,queryLogicalName(),reload,timeoutms);
  2500. }
  2501. catch(IException *)
  2502. {
  2503. proplockcount--;
  2504. dfCheckRoot("lockProperties",root,conn);
  2505. if (reload)
  2506. dirty = true; // safeChangeModeWrite unlocked, and reload will be need if retried
  2507. throw;
  2508. }
  2509. if (dirty) // a previous attempt unlocked and did not reload
  2510. {
  2511. dirty = false;
  2512. if (!reload) // if reload=true, safeChangeModeWrite has just reloaded, so no need to again here
  2513. {
  2514. conn->reload();
  2515. reload = true;
  2516. }
  2517. }
  2518. #ifdef TRACE_LOCKS
  2519. PROGLOG("lockProperties: done safeChangeModeWrite(%x)",(unsigned)(memsize_t)conn.get());
  2520. LogRemoteConn(conn);
  2521. #endif
  2522. dfCheckRoot("lockProperties",root,conn);
  2523. }
  2524. }
  2525. return reload;
  2526. }
  2527. /*
  2528. * Change connection back to read mode on the last unlock. There should never be
  2529. * an uneven number of locks/unlocks, since that will leave the connection with
  2530. * the DFS locked until the instance's destruction.
  2531. *
  2532. * WARN: This is not thread-safe
  2533. *
  2534. * @deprecated : use DistributedFilePropertyLock instead, when possible
  2535. */
  2536. void unlockProperties(DFTransactionState state=TAS_NONE)
  2537. {
  2538. savePartsAttr();
  2539. if (--proplockcount==0) {
  2540. if (conn) {
  2541. // Transactional logic, if any
  2542. switch(state) {
  2543. case TAS_SUCCESS:
  2544. conn->commit();
  2545. break;
  2546. case TAS_FAILURE:
  2547. conn->rollback();
  2548. break;
  2549. case TAS_RETRY:
  2550. conn->changeMode(RTM_NONE,defaultTimeout,true);
  2551. return;
  2552. // TAS_NONE, do nothing
  2553. }
  2554. #ifdef TRACE_LOCKS
  2555. PROGLOG("unlockProperties: pre changeMode(%x)",(unsigned)(memsize_t)conn.get());
  2556. #endif
  2557. conn->changeMode(RTM_LOCK_READ,defaultTimeout,true);
  2558. #ifdef TRACE_LOCKS
  2559. PROGLOG("unlockProperties: post changeMode(%x)",(unsigned)(memsize_t)conn.get());
  2560. LogRemoteConn(conn);
  2561. #endif
  2562. dfCheckRoot("unlockProperties",root,conn);
  2563. }
  2564. }
  2565. }
  2566. bool getModificationTime(CDateTime &dt)
  2567. {
  2568. StringBuffer str;
  2569. if (!root->getProp("@modified",str))
  2570. return false;
  2571. dt.setString(str.str());
  2572. return true;
  2573. }
  2574. void setModificationTime(const CDateTime &dt)
  2575. {
  2576. DistributedFilePropertyLock lock(this);
  2577. if (dt.isNull())
  2578. root->removeProp("@modified");
  2579. else {
  2580. StringBuffer str;
  2581. root->setProp("@modified",dt.getString(str).str());
  2582. }
  2583. root->removeProp("@verified");
  2584. }
  2585. void setModified()
  2586. {
  2587. CDateTime dt;
  2588. dt.setNow();
  2589. setModificationTime(dt);
  2590. }
  2591. virtual StringBuffer &getECL(StringBuffer &buf)
  2592. {
  2593. MemoryBuffer mb;
  2594. if (queryAttributes().getPropBin("ECLbin",mb))
  2595. buf.deserialize(mb);
  2596. else
  2597. queryAttributes().getProp("ECL",buf);
  2598. return buf;
  2599. }
  2600. virtual void setECL(const char *ecl)
  2601. {
  2602. DistributedFilePropertyLock lock(this);
  2603. IPropertyTree &p = queryAttributes();
  2604. #ifdef PACK_ECL
  2605. p.removeProp("ECL");
  2606. if (!ecl||!*ecl)
  2607. p.removeProp("ECLbin");
  2608. else {
  2609. MemoryBuffer mb; // could be better
  2610. StringBuffer buf(ecl);
  2611. buf.serialize(mb);
  2612. root->setPropBin("ECLbin",mb.length(),mb.toByteArray());
  2613. }
  2614. #else
  2615. p.setProp("ECL",ecl);
  2616. #endif
  2617. }
  2618. void setProtect(const char *owner, bool protect, unsigned timems)
  2619. {
  2620. if (logicalName.isForeign()) {
  2621. parent->setFileProtect(logicalName,udesc,owner,protect);
  2622. }
  2623. else {
  2624. bool ret=false;
  2625. if (conn) {
  2626. DistributedFilePropertyLock lock(this);
  2627. IPropertyTree &p = queryAttributes();
  2628. CDateTime dt;
  2629. dt.setNow();
  2630. if (setFileProtectTree(p,owner,protect))
  2631. conn->commit();
  2632. dfCheckRoot("setProtect.1",root,conn);
  2633. }
  2634. else
  2635. ERRLOG("setProtect - cannot protect %s (no connection in file)",owner?owner:"");
  2636. }
  2637. }
  2638. virtual IDistributedSuperFileIterator *getOwningSuperFiles(IDistributedFileTransaction *_transaction)
  2639. {
  2640. CriticalBlock block(sect);
  2641. return new CDistributedSuperFileIterator(this,parent,root,udesc,_transaction);
  2642. }
  2643. virtual void checkFormatAttr(IDistributedFile *sub, const char* exprefix="")
  2644. {
  2645. // check file has same (or similar) format
  2646. IPropertyTree &superProp = queryAttributes();
  2647. IPropertyTree &subProp = sub->queryAttributes();
  2648. if (!exprefix)
  2649. exprefix = "CheckFormatAttr";
  2650. bool superBlocked = false;
  2651. bool superComp = ::isCompressed(superProp,&superBlocked);
  2652. bool subBlocked = false;
  2653. bool subComp = ::isCompressed(subProp,&subBlocked);
  2654. // FIXME: this may fail if an empty superfile added to a compressed superfile
  2655. if (superComp != subComp)
  2656. throw MakeStringException(-1,"%s: %s's compression setting (%s) is different than %s's (%s)",
  2657. exprefix, sub->queryLogicalName(), (subComp?"compressed":"uncompressed"),
  2658. queryLogicalName(), (superComp?"compressed":"uncompressed"));
  2659. if (superBlocked != subBlocked)
  2660. throw MakeStringException(-1,"%s: %s's blocked setting (%s) is different than %s's (%s)",
  2661. exprefix, sub->queryLogicalName(), (subBlocked?"blocked":"unblocked"),
  2662. queryLogicalName(), (superBlocked?"blocked":"unblocked"));
  2663. #ifdef SUBFILE_COMPATIBILITY_CHECKING
  2664. bool subSoft = subProp.hasProp("_record_layout");
  2665. bool superSoft = superProp.hasProp("_record_layout");
  2666. if (superSoft != subSoft)
  2667. throw MakeStringException(-1,"%s: %s's record layout (%s) is different than %s's (%s)",
  2668. exprefix, sub->queryLogicalName(), (subSoft?"dynamic":"fixed"),
  2669. queryLogicalName(), (superSoft?"dynamic":"fixed"));
  2670. // If they don't, they must have the same size
  2671. if (!superSoft) {
  2672. unsigned superSize = superProp.getPropInt("@recordSize",0);
  2673. unsigned subSize = subProp.getPropInt("@recordSize",0);
  2674. // Variable length files (CSV, etc) have zero record size
  2675. if (superSize && subSize && (superSize != subSize))
  2676. throw MakeStringException(-1,"%s: %s's record size (%d) is different than %s's (%d)",
  2677. exprefix, sub->queryLogicalName(), subSize, queryLogicalName(), superSize);
  2678. }
  2679. StringBuffer superFmt;
  2680. bool superHasFmt = superProp.getProp("@format",superFmt);
  2681. StringBuffer subFmt;
  2682. bool subHasFmt = subProp.getProp("@format",subFmt);
  2683. if (subHasFmt && superHasFmt)
  2684. if (strcmp(normalizeFormat(superFmt).str(),normalizeFormat(subFmt).str()) != 0)
  2685. throw MakeStringException(-1,"%s: %s's format (%s) is different than %s's (%s)",
  2686. exprefix, sub->queryLogicalName(), superFmt.str(),
  2687. queryLogicalName(), subFmt.str());
  2688. #endif
  2689. bool superLocal = superProp.getPropBool("@local",false);
  2690. bool subLocal = subProp.getPropBool("@local",false);
  2691. if (subLocal != superLocal)
  2692. throw MakeStringException(-1,"%s: %s's local setting (%s) is different than %s's (%s)",
  2693. exprefix, sub->queryLogicalName(), (subLocal?"local":"global"),
  2694. queryLogicalName(), (superLocal?"local":"global"));
  2695. int superRepO = superProp.getPropInt("@replicateOffset",1);
  2696. int subRepO = subProp.getPropInt("@replicateOffset",1);
  2697. if (subRepO != superRepO)
  2698. throw MakeStringException(-1,"%s: %s's replication offset (%d) is different than %s's (%d)",
  2699. exprefix, sub->queryLogicalName(), subRepO,
  2700. queryLogicalName(), superRepO);
  2701. }
  2702. virtual void getSuperOwners(StringArray &owners)
  2703. {
  2704. if (root)
  2705. {
  2706. StringBuffer owner;
  2707. Owned<IPropertyTreeIterator> iter = root->getElements("SuperOwner");
  2708. ForEach (*iter)
  2709. {
  2710. iter->query().getProp("@name", owner.clear());
  2711. if (owner.length())
  2712. {
  2713. if (NotFound == owners.find(owner))
  2714. owners.append(owner);
  2715. }
  2716. }
  2717. }
  2718. }
  2719. void linkSuperOwner(const char *superfile,bool link)
  2720. {
  2721. if (!superfile||!*superfile)
  2722. return;
  2723. if (conn)
  2724. {
  2725. CFileSuperOwnerLock attrLock;
  2726. if (0 == proplockcount)
  2727. verifyex(attrLock.init(logicalName, conn, defaultTimeout, "CDistributedFile::linkSuperOwner"));
  2728. Owned<IPropertyTree> t = getNamedPropTree(root,"SuperOwner","@name",superfile,false);
  2729. if (t && !link)
  2730. root->removeTree(t);
  2731. else if (!t && link)
  2732. t.setown(addNamedPropTree(root,"SuperOwner","@name",superfile));
  2733. }
  2734. else
  2735. ERRLOG("linkSuperOwner - cannot link to %s (no connection in file)",superfile);
  2736. }
  2737. void setAccessed()
  2738. {
  2739. CDateTime dt;
  2740. dt.setNow();
  2741. setAccessedTime(dt);
  2742. }
  2743. virtual StringBuffer &getColumnMapping(StringBuffer &mapping)
  2744. {
  2745. queryAttributes().getProp("@columnMapping",mapping);
  2746. return mapping;
  2747. }
  2748. virtual void setColumnMapping(const char *mapping)
  2749. {
  2750. DistributedFilePropertyLock lock(this);
  2751. if (!mapping||!*mapping)
  2752. queryAttributes().removeProp("@columnMapping");
  2753. else
  2754. queryAttributes().setProp("@columnMapping",mapping);
  2755. }
  2756. unsigned setDefaultTimeout(unsigned timems)
  2757. {
  2758. unsigned ret = defaultTimeout;
  2759. defaultTimeout = timems;
  2760. return ret;
  2761. }
  2762. // MORE - simplify this, after removing CLightWeightSuperFileConn
  2763. bool canModify(StringBuffer &reason)
  2764. {
  2765. return !checkProtectAttr(logicalName.get(),root,reason);
  2766. }
  2767. bool canRemove(StringBuffer &reason,bool ignoresub=false)
  2768. {
  2769. CriticalBlock block(sect);
  2770. if (!canModify(reason))
  2771. return false;
  2772. const char *logicalname = logicalName.get();
  2773. if (!logicalname||!*logicalname) {
  2774. reason.appendf("empty filename");
  2775. return false;
  2776. }
  2777. if (logicalName.isQuery()) {
  2778. reason.appendf("%s is query",logicalname);
  2779. return false;
  2780. }
  2781. if (logicalName.isForeign()) {
  2782. reason.appendf("%s is foreign",logicalname);
  2783. return false;
  2784. }
  2785. if (logicalName.isMulti()) {
  2786. reason.appendf("%s is multi",logicalname);
  2787. return false;
  2788. }
  2789. if (!ignoresub) {
  2790. // And has super owners
  2791. Owned<IPropertyTreeIterator> iter = root->getElements("SuperOwner");
  2792. if (iter->first()) {
  2793. reason.append("Cannot remove file ").append(logicalname).append(" as owned by SuperFile(s): ");
  2794. loop {
  2795. reason.append(iter->query().queryProp("@name"));
  2796. if (!iter->next())
  2797. break;
  2798. reason.append(", ");
  2799. }
  2800. return false;
  2801. }
  2802. }
  2803. return true;
  2804. }
  2805. virtual const char *queryDefaultDir() = 0;
  2806. virtual unsigned numParts() = 0;
  2807. virtual IDistributedFilePart &queryPart(unsigned idx) = 0;
  2808. virtual IDistributedFilePart* getPart(unsigned idx) = 0;
  2809. virtual void savePartsAttr(bool force=false) = 0;
  2810. virtual IDistributedFilePartIterator *getIterator(IDFPartFilter *filter=NULL) = 0;
  2811. virtual IDistributedSuperFile *querySuperFile() = 0;
  2812. virtual ClusterPartDiskMapSpec &queryPartDiskMapping(unsigned clusternum)=0;
  2813. virtual void updatePartDiskMapping(const char *clustername,const ClusterPartDiskMapSpec &spec)=0;
  2814. virtual void enqueueReplicate()=0;
  2815. virtual bool getAccessedTime(CDateTime &dt) = 0; // get date and time last accessed (returns false if not set)
  2816. virtual void setAccessedTime(const CDateTime &dt) = 0; // set date and time last accessed
  2817. };
  2818. class CDistributedFile: public CDistributedFileBase<IDistributedFile>
  2819. {
  2820. protected:
  2821. CDistributedFilePartArray parts; // use queryParts to access
  2822. CriticalSection sect;
  2823. StringAttr directory;
  2824. StringAttr partmask;
  2825. FileClusterInfoArray clusters;
  2826. void savePartsAttr(bool force)
  2827. {
  2828. CriticalBlock block (sect);
  2829. IPropertyTree *pt;
  2830. if (parts.ordinality()==1) { // single part saved as part
  2831. if (parts.item(0).clearDirty()||force) {
  2832. CDistributedFilePart &part = parts.item(0);
  2833. while ((pt=root->queryPropTree("Part[1]"))!=NULL)
  2834. root->removeTree(pt);
  2835. pt = createPTreeFromIPT(part.queryAttr());
  2836. pt->setPropInt("@num",1);
  2837. const char *grp = root->queryProp("@group");
  2838. if (!grp||!*grp) {
  2839. StringBuffer eps;
  2840. pt->addProp("@node",part.queryNode(0)->endpoint().getUrlStr(eps).str()); // legacy
  2841. }
  2842. const char *override = part.queryOverrideName();
  2843. if (override&&*override)
  2844. pt->setProp("@name",override);
  2845. else {
  2846. pt->removeProp("@name");
  2847. const char *mask=queryPartMask();
  2848. if (mask&&*mask) {
  2849. StringBuffer tmp;
  2850. expandMask(tmp,mask,0,1);
  2851. pt->setProp("@name",tmp.str());
  2852. }
  2853. }
  2854. root->setPropTree("Part",pt);
  2855. }
  2856. }
  2857. else {
  2858. unsigned n = parts.ordinality();
  2859. unsigned i1;
  2860. for (i1=0;i1<n;i1++) {
  2861. if (parts.item(i1).clearDirty()||force) {
  2862. MemoryBuffer mb;
  2863. CriticalBlock block (sect);
  2864. ForEachItemIn(i2,parts)
  2865. serializePartAttr(mb,parts.item(i2).queryAttr());
  2866. root->setPropBin("Parts",mb.length(),mb.toByteArray());
  2867. while ((pt=root->queryPropTree("Part[1]"))!=NULL)
  2868. root->removeTree(pt);
  2869. break;
  2870. }
  2871. }
  2872. while (i1<n)
  2873. parts.item(i1++).clearDirty();
  2874. }
  2875. }
  2876. void detach(unsigned timeoutMs=INFINITE, bool removePhysicals=true)
  2877. {
  2878. // Removes either a cluster in case of multi cluster file or the whole File entry from DFS
  2879. assert(proplockcount == 0 && "CDistributedFile detach: Some properties are still locked");
  2880. assertex(!isAnon()); // not attached!
  2881. if (removePhysicals)
  2882. {
  2883. // Avoid removing physically when there is no physical representation
  2884. if (logicalName.isMulti())
  2885. removePhysicals = false;
  2886. }
  2887. StringBuffer clusterName;
  2888. Owned<IFileDescriptor> fileDescCopy;
  2889. #ifdef EXTRA_LOGGING
  2890. PROGLOG("CDistributedFile::detach(%s)",logicalName.get());
  2891. LOGPTREE("CDistributedFile::detach root.1",root);
  2892. #endif
  2893. {
  2894. CriticalBlock block(sect); // JCSMORE - not convinced this is still necessary
  2895. CFileChangeWriteLock writeLock(conn, timeoutMs);
  2896. logicalName.getCluster(clusterName);
  2897. // copy file descriptor before altered, used by physical file removal routines
  2898. if (removePhysicals)
  2899. {
  2900. MemoryBuffer mb;
  2901. Owned<IFileDescriptor> fdesc = getFileDescriptor(clusterName);
  2902. fdesc->serialize(mb);
  2903. fileDescCopy.setown(deserializeFileDescriptor(mb));
  2904. }
  2905. bool removeFile=true;
  2906. if (clusterName.length())
  2907. {
  2908. // Remove just cluster specified, unless it's the last, in which case detach below will remove File entry.
  2909. if (clusters.ordinality()>1)
  2910. {
  2911. if (removeCluster(clusterName.str()))
  2912. removeFile=false;
  2913. else
  2914. ThrowStringException(-1, "Cluster %s not present in file %s", clusterName.str(), logicalName.get());
  2915. }
  2916. }
  2917. if (removeFile)
  2918. {
  2919. // check can remove, e.g. cannot if this is a subfile of a super
  2920. StringBuffer reason;
  2921. if (!canRemove(reason))
  2922. throw MakeStringException(-1,"detach: %s", reason.str());
  2923. }
  2924. // detach this IDistributeFile
  2925. /* JCSMORE - In 'removeFile=true' case, this should really delete before release exclusive lock.
  2926. */
  2927. writeLock.clear();
  2928. root.setown(closeConnection(removeFile));
  2929. // NB: The file is now unlocked
  2930. if (removeFile && !logicalName.isExternal())
  2931. updateFS(logicalName, timeoutMs);
  2932. logicalName.clear();
  2933. }
  2934. // NB: beyond unlock
  2935. if (removePhysicals)
  2936. {
  2937. CriticalBlock block(physicalChange);
  2938. Owned<IMultiException> exceptions = MakeMultiException("CDistributedFile::detach");
  2939. removePhysicalPartFiles(fileDescCopy, exceptions);
  2940. if (exceptions->ordinality())
  2941. throw exceptions.getClear();
  2942. }
  2943. }
  2944. bool removePhysicalPartFiles(IFileDescriptor *fileDesc, IMultiException *mexcept)
  2945. {
  2946. if (logicalName.isExternal())
  2947. {
  2948. if (logicalName.isQuery())
  2949. return false;
  2950. }
  2951. if (logicalName.isForeign())
  2952. throw MakeStringException(-1,"cannot remove a foreign file (%s)",logicalName.get());
  2953. class casyncfor: public CAsyncFor
  2954. {
  2955. IFileDescriptor *fileDesc;
  2956. CriticalSection errcrit;
  2957. IMultiException *mexcept;
  2958. public:
  2959. bool ok;
  2960. bool islazy;
  2961. casyncfor(IFileDescriptor *_fileDesc, IMultiException *_mexcept)
  2962. {
  2963. fileDesc = _fileDesc;
  2964. ok = true;
  2965. islazy = false;
  2966. mexcept = _mexcept;
  2967. }
  2968. void Do(unsigned i)
  2969. {
  2970. IPartDescriptor *part = fileDesc->queryPart(i);
  2971. unsigned nc = part->numCopies();
  2972. for (unsigned copy = 0; copy < nc; copy++)
  2973. {
  2974. RemoteFilename rfn;
  2975. part->getFilename(copy, rfn);
  2976. Owned<IFile> partfile = createIFile(rfn);
  2977. StringBuffer eps;
  2978. try
  2979. {
  2980. unsigned start = msTick();
  2981. if (!partfile->remove()&&(copy==0)&&!islazy) // only warn about missing primary files
  2982. LOG(MCwarning, unknownJob, "Failed to remove file part %s from %s", partfile->queryFilename(),rfn.queryEndpoint().getUrlStr(eps).str());
  2983. else
  2984. {
  2985. unsigned t = msTick()-start;
  2986. if (t>5*1000)
  2987. LOG(MCwarning, unknownJob, "Removing %s from %s took %ds", partfile->queryFilename(), rfn.queryEndpoint().getUrlStr(eps).str(), t/1000);
  2988. }
  2989. }
  2990. catch (IException *e)
  2991. {
  2992. CriticalBlock block(errcrit);
  2993. if (mexcept)
  2994. mexcept->append(*e);
  2995. else
  2996. {
  2997. StringBuffer s("Failed to remove file part ");
  2998. s.append(partfile->queryFilename()).append(" from ");
  2999. rfn.queryEndpoint().getUrlStr(s);
  3000. EXCLOG(e, s.str());
  3001. e->Release();
  3002. }
  3003. ok = false;
  3004. }
  3005. }
  3006. }
  3007. } afor(fileDesc, mexcept);
  3008. afor.islazy = fileDesc->queryProperties().getPropBool("@lazy");
  3009. afor.For(fileDesc->numParts(),10,false,true);
  3010. return afor.ok;
  3011. }
  3012. protected: friend class CDistributedFilePart;
  3013. CDistributedFilePartArray &queryParts()
  3014. {
  3015. return parts;
  3016. }
  3017. public:
  3018. IMPLEMENT_IINTERFACE;
  3019. CDistributedFile(CDistributedFileDirectory *_parent, IRemoteConnection *_conn,const CDfsLogicalFileName &lname,IUserDescriptor *user) // takes ownership of conn
  3020. {
  3021. setUserDescriptor(udesc,user);
  3022. logicalName.set(lname);
  3023. parent = _parent;
  3024. conn.setown(_conn);
  3025. CClustersLockedSection sect(logicalName);
  3026. root.setown(conn->getRoot());
  3027. root->queryBranch("."); // load branch
  3028. #ifdef EXTRA_LOGGING
  3029. LOGPTREE("CDistributedFile.a root",root);
  3030. #endif
  3031. Owned<IFileDescriptor> fdesc = deserializeFileDescriptorTree(root,&queryNamedGroupStore(),0);
  3032. #ifdef EXTRA_LOGGING
  3033. LOGFDESC("CDistributedFile.a fdesc",fdesc);
  3034. #endif
  3035. setFileAttrs(fdesc,false);
  3036. setClusters(fdesc);
  3037. setPreferredClusters(_parent->defprefclusters);
  3038. setParts(fdesc,false);
  3039. //shrinkFileTree(root); // enable when safe!
  3040. }
  3041. CDistributedFile(CDistributedFileDirectory *_parent, IFileDescriptor *fdesc, IUserDescriptor *user, bool includeports)
  3042. {
  3043. #ifdef EXTRA_LOGGING
  3044. LOGFDESC("CDistributedFile.b fdesc",fdesc);
  3045. #endif
  3046. parent = _parent;
  3047. root.setown(createPTree(queryDfsXmlBranchName(DXB_File)));
  3048. // fdesc->serializeTree(*root,IFDSF_EXCLUDE_NODES);
  3049. setFileAttrs(fdesc,true);
  3050. setClusters(fdesc);
  3051. setPreferredClusters(_parent->defprefclusters);
  3052. saveClusters();
  3053. setParts(fdesc,true);
  3054. udesc.set(user);
  3055. #ifdef EXTRA_LOGGING
  3056. LOGPTREE("CDistributedFile.b root.1",root);
  3057. #endif
  3058. offset_t totalsize=0;
  3059. unsigned checkSum = ~0;
  3060. bool useableCheckSum = true;
  3061. MemoryBuffer pmb;
  3062. unsigned n = fdesc->numParts();
  3063. for (unsigned i=0;i<n;i++) {
  3064. IPropertyTree *partattr = &fdesc->queryPart(i)->queryProperties();
  3065. if (!partattr)
  3066. {
  3067. totalsize = (unsigned)-1;
  3068. useableCheckSum = false;
  3069. }
  3070. else
  3071. {
  3072. offset_t psz;
  3073. if (totalsize!=(offset_t)-1) {
  3074. psz = (offset_t)partattr->getPropInt64("@size", -1);
  3075. if (psz==(offset_t)-1)
  3076. totalsize = psz;
  3077. else
  3078. totalsize += psz;
  3079. }
  3080. if (useableCheckSum) {
  3081. unsigned crc;
  3082. if (fdesc->queryPart(i)->getCrc(crc))
  3083. checkSum ^= crc;
  3084. else
  3085. useableCheckSum = false;
  3086. }
  3087. }
  3088. }
  3089. shrinkFileTree(root);
  3090. if (totalsize!=(offset_t)-1)
  3091. queryAttributes().setPropInt64("@size", totalsize);
  3092. if (useableCheckSum)
  3093. queryAttributes().setPropInt64("@checkSum", checkSum);
  3094. setModified();
  3095. #ifdef EXTRA_LOGGING
  3096. LOGPTREE("CDistributedFile.b root.2",root);
  3097. #endif
  3098. }
  3099. void killParts()
  3100. {
  3101. ForEachItemIn(i,parts)
  3102. parts.item(i).childRelease();
  3103. parts.kill(true);
  3104. }
  3105. ~CDistributedFile()
  3106. {
  3107. assert(proplockcount == 0 && "CDistributedFile destructor: Some properties are still locked");
  3108. if (conn)
  3109. conn->rollback(); // changes should always be done in locked properties
  3110. killParts();
  3111. clusters.kill();
  3112. }
  3113. IFileDescriptor *getFileDescriptor(const char *_clusterName)
  3114. {
  3115. CriticalBlock block (sect);
  3116. Owned<IFileDescriptor> fdesc = deserializeFileDescriptorTree(root,&queryNamedGroupStore(),0);
  3117. fdesc->setTraceName(logicalName.get());
  3118. StringArray cnames;
  3119. if (_clusterName&&*_clusterName)
  3120. {
  3121. StringAttr clusterName = _clusterName;
  3122. clusterName.toLowerCase();
  3123. cnames.append(clusterName);
  3124. }
  3125. else
  3126. getClusterNames(cnames);
  3127. fdesc->setClusterOrder(cnames,_clusterName&&*_clusterName);
  3128. return fdesc.getClear();
  3129. }
  3130. void setFileAttrs(IFileDescriptor *fdesc,bool save)
  3131. {
  3132. directory.set(fdesc->queryDefaultDir());
  3133. partmask.set(fdesc->queryPartMask());
  3134. const char *lfn = logicalName.get();
  3135. if (lfn&&*lfn) {
  3136. if (partmask.isEmpty()) {
  3137. StringBuffer mask;
  3138. getPartMask(mask,lfn,0);
  3139. partmask.set(mask);
  3140. }
  3141. }
  3142. if (!save)
  3143. return;
  3144. if (directory.isEmpty())
  3145. root->removeProp("@directory");
  3146. else
  3147. root->setProp("@directory",directory);
  3148. if (partmask.isEmpty())
  3149. root->removeProp("@partmask");
  3150. else
  3151. root->setProp("@partmask",partmask);
  3152. IPropertyTree *t = &fdesc->queryProperties();
  3153. if (isEmptyPTree(t))
  3154. resetFileAttr();
  3155. else
  3156. resetFileAttr(createPTreeFromIPT(t));
  3157. }
  3158. void setClusters(IFileDescriptor *fdesc)
  3159. {
  3160. clusters.clear();
  3161. unsigned nc = fdesc->numClusters();
  3162. if (nc) {
  3163. for (unsigned i=0;i<nc;i++) {
  3164. StringBuffer cname;
  3165. StringBuffer clabel;
  3166. IClusterInfo &cluster = *createClusterInfo(
  3167. fdesc->getClusterGroupName(i,cname,NULL).str(),
  3168. fdesc->queryClusterGroup(i),
  3169. fdesc->queryPartDiskMapping(i),
  3170. &queryNamedGroupStore()
  3171. );
  3172. #ifdef EXTRA_LOGGING
  3173. PROGLOG("setClusters(%d,%s)",i,cname.str());
  3174. #endif
  3175. if (!cluster.queryGroup(&queryNamedGroupStore())) {
  3176. ERRLOG("IDistributedFileDescriptor cannot set cluster for %s",logicalName.get());
  3177. }
  3178. clusters.append(cluster);
  3179. }
  3180. }
  3181. else
  3182. ERRLOG("No cluster specified for %s",logicalName.get());
  3183. }
  3184. unsigned numClusters()
  3185. {
  3186. return clusters.ordinality();
  3187. }
  3188. unsigned findCluster(const char *clustername)
  3189. {
  3190. return clusters.find(clustername);
  3191. }
  3192. unsigned getClusterNames(StringArray &clusternames)
  3193. {
  3194. return clusters.getNames(clusternames);
  3195. }
  3196. void reloadClusters()
  3197. {
  3198. // called from CClustersLockedSection
  3199. if (!CDistributedFileBase<IDistributedFile>::conn)
  3200. return;
  3201. assertex(CDistributedFileBase<IDistributedFile>::proplockcount==0); // cannot reload clusters if properties locked
  3202. CDistributedFileBase<IDistributedFile>::conn->reload(); // should only be cluster changes but a bit dangerous
  3203. IPropertyTree *t = CDistributedFileBase<IDistributedFile>::conn->queryRoot(); // NB not CDistributedFileBase<IDistributedFile>::queryRoot();
  3204. if (!t)
  3205. return;
  3206. clusters.clear();
  3207. getClusterInfo(*t,&queryNamedGroupStore(),0,clusters);
  3208. }
  3209. void saveClusters()
  3210. {
  3211. // called from CClustersLockedSection
  3212. IPropertyTree *t;
  3213. if (CDistributedFileBase<IDistributedFile>::conn)
  3214. t = CDistributedFileBase<IDistributedFile>::conn->queryRoot();
  3215. else
  3216. t = CDistributedFileBase<IDistributedFile>::queryRoot(); //cache
  3217. if (!t)
  3218. return;
  3219. IPropertyTree *pt;
  3220. IPropertyTree *tc = CDistributedFileBase<IDistributedFile>::queryRoot(); //cache
  3221. IPropertyTree *t0 = t;
  3222. StringBuffer grplist;
  3223. // the following is complicated by fact there is a cache of the file branch
  3224. loop {
  3225. while ((pt=t->queryPropTree("Cluster[1]"))!=NULL)
  3226. t->removeTree(pt);
  3227. ForEachItemIn(i,clusters) {
  3228. IPropertyTree *pt = createPTree("Cluster");
  3229. clusters.item(i).serializeTree(pt,IFDSF_EXCLUDE_GROUPS);
  3230. if (!isEmptyPTree(pt)) {
  3231. t->addPropTree("Cluster",pt);
  3232. if (t==t0) {
  3233. StringBuffer clabel;
  3234. clusters.item(i).getClusterLabel(clabel);
  3235. if (clabel.length()) {
  3236. if (grplist.length())
  3237. grplist.append(',');
  3238. grplist.append(clabel);
  3239. }
  3240. }
  3241. }
  3242. else
  3243. WARNLOG("CFileClusterOwner::saveClusters - empty cluster");
  3244. }
  3245. if (grplist.length())
  3246. t->setProp("@group",grplist.str());
  3247. else
  3248. t->removeProp("@group");
  3249. t->setPropInt("@numclusters",clusters.ordinality());
  3250. t->setProp("@directory", directory);
  3251. if (t==tc)
  3252. break;
  3253. t = tc; // now fix cache
  3254. }
  3255. if (CDistributedFileBase<IDistributedFile>::conn)
  3256. CDistributedFileBase<IDistributedFile>::conn->commit(); // should only be cluster changes but a bit dangerous
  3257. }
  3258. void addCluster(const char *clustername,const ClusterPartDiskMapSpec &mspec)
  3259. {
  3260. if (!clustername&&!*clustername)
  3261. return;
  3262. CClustersLockedSection cls(CDistributedFileBase<IDistributedFile>::logicalName);
  3263. reloadClusters();
  3264. if (findCluster(clustername)!=NotFound) {
  3265. IDFS_Exception *e = new CDFS_Exception(DFSERR_ClusterAlreadyExists,clustername);
  3266. throw e;
  3267. }
  3268. Owned<IClusterInfo> cluster = createClusterInfo(clustername,NULL,mspec,&queryNamedGroupStore());
  3269. if (cluster->queryGroup(&queryNamedGroupStore())) {
  3270. clusters.append(*cluster.getClear());
  3271. }
  3272. else {
  3273. IDFS_Exception *e = new CDFS_Exception(DFSERR_ClusterNotFound,clustername);
  3274. throw e;
  3275. }
  3276. saveClusters();
  3277. }
  3278. bool removeCluster(const char *clustername)
  3279. {
  3280. CClustersLockedSection cls(CDistributedFileBase<IDistributedFile>::logicalName);
  3281. reloadClusters();
  3282. unsigned i = findCluster(clustername);
  3283. if (i!=NotFound) {
  3284. if (clusters.ordinality()==1)
  3285. throw MakeStringException(-1,"CFileClusterOwner::removeCluster cannot remove sole cluster %s",clustername);
  3286. // If the cluster is the 'default' one we need to update the directory too
  3287. StringBuffer oldBaseDir;
  3288. char pathSepChar = getPathSepChar(directory.get());
  3289. DFD_OS os = SepCharBaseOs(pathSepChar);
  3290. clusters.item(i).getBaseDir(oldBaseDir, os);
  3291. unsigned oldLen = oldBaseDir.length();
  3292. clusters.remove(i);
  3293. if (oldLen && strncmp(directory, oldBaseDir, oldLen)==0 && (directory[oldLen]==pathSepChar || directory[oldLen]=='\0'))
  3294. {
  3295. StringBuffer newBaseDir;
  3296. clusters.item(0).getBaseDir(newBaseDir, os);
  3297. newBaseDir.append(directory.get() + oldBaseDir.length());
  3298. directory.set(newBaseDir);
  3299. }
  3300. saveClusters();
  3301. return true;
  3302. }
  3303. return false;
  3304. }
  3305. void setPreferredClusters(const char *clusterlist)
  3306. {
  3307. clusters.setPreferred(clusterlist,CDistributedFileBase<IDistributedFile>::logicalName);
  3308. }
  3309. INode *queryNode(unsigned idx,unsigned copy)
  3310. {
  3311. unsigned rep;
  3312. unsigned cluster = copyClusterNum(idx,copy,&rep);
  3313. if (cluster==NotFound)
  3314. return queryNullNode();
  3315. unsigned nn;
  3316. unsigned dn;
  3317. IGroup *grp = clusters.queryGroup(cluster);
  3318. if (!grp)
  3319. return queryNullNode();
  3320. if (!clusters.item(cluster).queryPartDiskMapping().calcPartLocation (idx, numParts(),rep, grp->ordinality(), nn, dn))
  3321. return queryNullNode();
  3322. return &grp->queryNode(nn);
  3323. }
  3324. unsigned queryDrive(unsigned idx,unsigned copy,const char *dir)
  3325. {
  3326. // this is odd routine
  3327. unsigned dn = dir?getPathDrive(dir):0;
  3328. if (dn)
  3329. return dn;
  3330. unsigned rep;
  3331. unsigned cluster = copyClusterNum(idx,copy,&rep);
  3332. if (cluster==NotFound)
  3333. return 0;
  3334. unsigned nn;
  3335. IGroup *grp = clusters.queryGroup(cluster);
  3336. if (!grp)
  3337. return 0;
  3338. if (!clusters.item(cluster).queryPartDiskMapping().calcPartLocation (idx, numParts(),rep, grp->ordinality(), nn, dn))
  3339. return 0;
  3340. return dn;
  3341. }
  3342. StringBuffer &getClusterName(unsigned clusternum,StringBuffer &name)
  3343. {
  3344. return clusters.getName(clusternum,name);
  3345. }
  3346. unsigned copyClusterNum(unsigned part, unsigned copy,unsigned *replicate)
  3347. {
  3348. return clusters.copyNum(part,copy, numParts(),replicate);
  3349. }
  3350. ClusterPartDiskMapSpec &queryPartDiskMapping(unsigned clusternum)
  3351. {
  3352. assertex(clusternum<clusters.ordinality());
  3353. return clusters.queryPartDiskMapping(clusternum);
  3354. }
  3355. void updatePartDiskMapping(const char *clustername,const ClusterPartDiskMapSpec &spec)
  3356. {
  3357. CClustersLockedSection cls(CDistributedFileBase<IDistributedFile>::logicalName);
  3358. reloadClusters();
  3359. unsigned i = findCluster(clustername);
  3360. if (i!=NotFound) {
  3361. clusters.updatePartDiskMapping(i,spec);
  3362. saveClusters();
  3363. }
  3364. }
  3365. IGroup *queryClusterGroup(unsigned clusternum)
  3366. {
  3367. return clusters.queryGroup(clusternum);
  3368. }
  3369. virtual unsigned numCopies(unsigned partno)
  3370. {
  3371. return clusters.numCopies(partno,numParts());
  3372. }
  3373. void setSingleClusterOnly()
  3374. {
  3375. clusters.setSingleClusterOnly();
  3376. }
  3377. unsigned numClusterCopies(unsigned cnum,unsigned partnum)
  3378. {
  3379. IClusterInfo &cluster = clusters.item(cnum);
  3380. IGroup *grp = cluster.queryGroup();
  3381. return cluster.queryPartDiskMapping().numCopies(partnum,grp?grp->ordinality():1,numParts());
  3382. }
  3383. void adjustClusterDir(unsigned partno,unsigned copy, StringBuffer &path)
  3384. {
  3385. // this corrects the directory for a copy
  3386. // assumes default dir matches one of clusters
  3387. unsigned rep=0;
  3388. unsigned cluster = NotFound;
  3389. const char *ds = path.str();
  3390. unsigned nc = clusters.ordinality();
  3391. if (nc>1) {
  3392. StringAttr matched;
  3393. StringAttr toadd;
  3394. unsigned i=0;
  3395. bool c = 0;
  3396. int cp = (int)copy;
  3397. while (i<nc) {
  3398. StringBuffer dcmp;
  3399. clusters.item(i).getBaseDir(dcmp,SepCharBaseOs(getPathSepChar(ds))); // no trailing sep
  3400. const char *t = dcmp.str();
  3401. const char *d = ds;
  3402. while (*d&&(*t==*d)) {
  3403. d++;
  3404. t++;
  3405. }
  3406. if (!*t&&(!*d||isPathSepChar(*d))&&(dcmp.length()>matched.length()))
  3407. matched.set(dcmp);
  3408. unsigned mc = numClusterCopies(i,partno);
  3409. if ((cp>=0)&&(cp<(int)mc)) {
  3410. toadd.set(dcmp);
  3411. rep = (unsigned)cp;
  3412. cluster = i;
  3413. }
  3414. cp -= mc;
  3415. i++;
  3416. }
  3417. if (!matched.isEmpty()&&!toadd.isEmpty()&&(strcmp(matched,toadd)!=0)) {
  3418. StringBuffer tmp(toadd);
  3419. tmp.append(ds+matched.length());
  3420. path.swapWith(tmp);
  3421. }
  3422. }
  3423. else {
  3424. rep = copy;
  3425. cluster = 0;
  3426. }
  3427. // now set replicate
  3428. if (cluster!=NotFound) {
  3429. unsigned n;
  3430. unsigned d;
  3431. ClusterPartDiskMapSpec& mspec = clusters.item(cluster).queryPartDiskMapping();
  3432. mspec.calcPartLocation(partno,numParts(),rep,clusters.queryGroup(cluster)?clusters.queryGroup(cluster)->ordinality():numParts(),n,d);
  3433. if ((d==1) && (mspec.flags&CPDMSF_overloadedConfig) && mspec.defaultReplicateDir.length())
  3434. path.set(mspec.defaultReplicateDir.get());
  3435. else
  3436. setReplicateFilename(path,d);
  3437. }
  3438. }
  3439. void setParts(IFileDescriptor *fdesc,bool save)
  3440. {
  3441. unsigned np = fdesc->numParts();
  3442. for (unsigned i = 0;i<np;i++) {
  3443. CDistributedFilePart &part = *new CDistributedFilePart(*this,i,fdesc->queryPart(i));
  3444. parts.append(part);
  3445. }
  3446. if (save) {
  3447. root->setPropInt("@numparts",parts.ordinality());
  3448. savePartsAttr(true);
  3449. }
  3450. }
  3451. unsigned numParts()
  3452. {
  3453. return parts.ordinality();
  3454. }
  3455. IDistributedFilePart &queryPart(unsigned idx)
  3456. {
  3457. if (idx<parts.ordinality())
  3458. return queryParts().item(idx);
  3459. return *(IDistributedFilePart *)NULL;
  3460. }
  3461. IDistributedFilePart* getPart(unsigned idx)
  3462. {
  3463. if (idx>=parts.ordinality())
  3464. return NULL;
  3465. IDistributedFilePart *ret = &queryParts().item(idx);
  3466. return LINK(ret);
  3467. }
  3468. IDistributedFilePartIterator *getIterator(IDFPartFilter *filter=NULL)
  3469. {
  3470. return new CDistributedFilePartIterator(queryParts(),filter);
  3471. }
  3472. void rename(const char *_logicalname,IUserDescriptor *user)
  3473. {
  3474. StringBuffer prevname;
  3475. Owned<IFileRelationshipIterator> reliter;
  3476. // set prevname
  3477. if (!isAnon()) {
  3478. getLogicalName(prevname);
  3479. try {
  3480. IFileRelationshipIterator *iter = parent->lookupAllFileRelationships(prevname.str());
  3481. reliter.setown(iter);
  3482. }
  3483. catch (IException *e) {
  3484. EXCLOG(e,"CDistributedFile::rename");
  3485. e->Release();
  3486. }
  3487. detachLogical();
  3488. }
  3489. attach(_logicalname,user);
  3490. if (prevname.length()) {
  3491. DistributedFilePropertyLock lock(this);
  3492. IPropertyTree &pt = queryAttributes();
  3493. StringBuffer list;
  3494. if (pt.getProp("@renamedFrom",list)&&list.length())
  3495. list.append(',');
  3496. pt.setProp("@renamedFrom",list.append(prevname).str());
  3497. }
  3498. if (reliter.get()) {
  3499. // add back any relationships with new name
  3500. parent->renameFileRelationships(prevname.str(),_logicalname,reliter,user);
  3501. }
  3502. }
  3503. const char *queryDefaultDir()
  3504. {
  3505. CriticalBlock block (sect);
  3506. return directory.get();
  3507. }
  3508. const char *queryPartMask()
  3509. {
  3510. CriticalBlock block (sect);
  3511. if (partmask.isEmpty()) {
  3512. assertex(root);
  3513. partmask.set(root->queryProp("@partmask"));
  3514. }
  3515. return partmask.get();
  3516. }
  3517. bool isAnon()
  3518. {
  3519. return (!logicalName.isSet());
  3520. }
  3521. void attach(const char *_logicalname,IUserDescriptor *user)
  3522. {
  3523. CriticalBlock block (sect);
  3524. assertex(isAnon()); // already attached!
  3525. logicalName.set(_logicalname);
  3526. if (!checkLogicalName(logicalName,user,true,true,true,"attach"))
  3527. return; // query
  3528. #ifdef EXTRA_LOGGING
  3529. PROGLOG("CDistributedFile::attach(%s)",_logicalname);
  3530. LOGPTREE("CDistributedFile::attach root.1",root);
  3531. #endif
  3532. parent->addEntry(logicalName,root.getClear(),false,false);
  3533. killParts();
  3534. clusters.kill();
  3535. CFileLock fcl;
  3536. verifyex(fcl.init(logicalName, DXB_File, RTM_LOCK_READ, defaultTimeout, "CDistributedFile::attach"));
  3537. conn.setown(fcl.detach());
  3538. root.setown(conn->getRoot());
  3539. root->queryBranch("."); // load branch
  3540. Owned<IFileDescriptor> fdesc = deserializeFileDescriptorTree(root,&queryNamedGroupStore(),0);
  3541. setFileAttrs(fdesc,false);
  3542. setClusters(fdesc);
  3543. setParts(fdesc,false);
  3544. setUserDescriptor(udesc, user);
  3545. #ifdef EXTRA_LOGGING
  3546. LOGFDESC("CDistributedFile::attach fdesc",fdesc);
  3547. LOGPTREE("CDistributedFile::attach root.2",root);
  3548. #endif
  3549. }
  3550. /*
  3551. * Internal method (not in IDistributedFile interface) that is used
  3552. * when renaming files (so don't delete the physical representation).
  3553. *
  3554. * This is also used during CPPUINT tests, so we need to make them public
  3555. * only when tests are enabled (ie. non-production mode).
  3556. *
  3557. * See removeLogical()
  3558. */
  3559. public:
  3560. void detachLogical(unsigned timeoutms=INFINITE)
  3561. {
  3562. detach(timeoutms, false);
  3563. }
  3564. public:
  3565. virtual void detach(unsigned timeoutMs=INFINITE)
  3566. {
  3567. detach(timeoutMs, true);
  3568. }
  3569. bool existsPhysicalPartFiles(unsigned short port)
  3570. {
  3571. unsigned width = numParts();
  3572. CriticalSection errcrit;
  3573. class casyncfor: public CAsyncFor
  3574. {
  3575. IDistributedFile *file;
  3576. unsigned short port;
  3577. CriticalSection &errcrit;
  3578. unsigned width;
  3579. public:
  3580. bool ok;
  3581. casyncfor(IDistributedFile *_file,unsigned _width,unsigned short _port,CriticalSection &_errcrit)
  3582. : errcrit(_errcrit)
  3583. {
  3584. file = _file;
  3585. port = _port;
  3586. ok = true;
  3587. width = _width;
  3588. ok = true;
  3589. }
  3590. void Do(unsigned i)
  3591. {
  3592. {
  3593. CriticalBlock block(errcrit);
  3594. if (!ok)
  3595. return;
  3596. }
  3597. Owned<IDistributedFilePart> part = file->getPart(i);
  3598. unsigned nc = part->numCopies();
  3599. for (unsigned copy = 0; copy < nc; copy++)
  3600. {
  3601. RemoteFilename rfn;
  3602. part->getFilename(rfn,copy);
  3603. if (port)
  3604. rfn.setPort(port); // if daliservix
  3605. Owned<IFile> partfile = createIFile(rfn);
  3606. try
  3607. {
  3608. if (partfile->exists())
  3609. return;
  3610. }
  3611. catch (IException *e)
  3612. {
  3613. CriticalBlock block(errcrit);
  3614. StringBuffer s("Failed to find file part ");
  3615. s.append(partfile->queryFilename()).append(" on ");
  3616. rfn.queryEndpoint().getUrlStr(s);
  3617. EXCLOG(e, s.str());
  3618. e->Release();
  3619. }
  3620. }
  3621. CriticalBlock block(errcrit);
  3622. ok = false;
  3623. }
  3624. } afor(this,width,port,errcrit);
  3625. afor.For(width,10,false,true);
  3626. return afor.ok;
  3627. }
  3628. // This method takes an existing physical directory path for a logical file
  3629. // and a constructed path to the same logical file created in this context
  3630. // and deduces the original base path e.g. /var/lib/HPCCSystems/hpcc-data/thor
  3631. // This is necessary, because there is no not enough context to directly fetch the
  3632. // original base path to construct new paths for the rename
  3633. bool getBase(const char *oldPath, const char *thisPath, StringBuffer &baseDir)
  3634. {
  3635. const char *oldEnd = oldPath+strlen(oldPath)-1;
  3636. const char *thisEnd = thisPath+strlen(thisPath)-1;
  3637. if (isPathSepChar(*oldEnd))
  3638. oldEnd--;
  3639. if (isPathSepChar(*thisEnd))
  3640. thisEnd--;
  3641. const char *oldP = oldEnd, *thisP = thisEnd;
  3642. loop {
  3643. if (oldP==oldPath || thisP==thisPath)
  3644. break;
  3645. if (*oldP != *thisP) {
  3646. // unless last was separator, continue until find one
  3647. if (isPathSepChar(*(oldP+1)))
  3648. oldP++;
  3649. else {
  3650. while (oldP != oldPath && (!isPathSepChar(*oldP)))
  3651. oldP--;
  3652. }
  3653. baseDir.append(oldP-oldPath, oldPath);
  3654. return true;
  3655. }
  3656. --oldP;
  3657. --thisP;
  3658. }
  3659. return false;
  3660. }
  3661. bool renamePhysicalPartFiles(const char *newname,
  3662. const char *cluster,
  3663. IMultiException *mexcept,
  3664. const char *newbasedir)
  3665. {
  3666. // cluster TBD
  3667. unsigned width = numParts();
  3668. StringBuffer newdir;
  3669. StringBuffer newmask;
  3670. const char *diroverride = NULL;
  3671. char psc = getPathSepChar(directory.get());
  3672. DFD_OS os = SepCharBaseOs(psc);
  3673. StringBuffer basedir;
  3674. if (newbasedir)
  3675. diroverride = newbasedir;
  3676. const char *myBase = queryBaseDirectory(grp_unknown, 0, os);
  3677. StringBuffer baseDir, newPath;
  3678. makePhysicalPartName(logicalName.get(), 0, 0, newPath, false, os, diroverride);
  3679. if (!getBase(directory, newPath, baseDir))
  3680. baseDir.append(myBase); // getBase returns false, if directory==newPath, so have common base
  3681. getPartMask(newmask,newname,width);
  3682. if (newmask.length()==0)
  3683. return false;
  3684. makePhysicalPartName(newname, 0, 0, newPath.clear(), false, os, diroverride);
  3685. if (newPath.length()==0)
  3686. return false;
  3687. if (isPathSepChar(newPath.charAt(newPath.length()-1)))
  3688. newPath.setLength(newPath.length()-1);
  3689. newPath.remove(0, strlen(myBase));
  3690. newdir.append(baseDir).append(newPath);
  3691. StringBuffer fullname;
  3692. CIArrayOf<CIStringArray> newNames;
  3693. unsigned i;
  3694. for (i=0;i<width;i++) {
  3695. newNames.append(*new CIStringArray);
  3696. CDistributedFilePart &part = parts.item(i);
  3697. for (unsigned copy=0; copy<part.numCopies(); copy++) {
  3698. makePhysicalPartName(newname, i+1, width, newPath.clear(), false, os, myBase);
  3699. newPath.remove(0, strlen(myBase));
  3700. StringBuffer copyDir(baseDir);
  3701. adjustClusterDir(i, copy, copyDir);
  3702. fullname.clear().append(copyDir).append(newPath);
  3703. PROGLOG("fullname = %s", fullname.str());
  3704. newNames.item(i).append(fullname);
  3705. }
  3706. }
  3707. // NB: the code below, specifically deals with 1 primary + 1 replicate
  3708. // it will need refactoring if it's to deal with multiple clusters/copies
  3709. // first check file doestn't exist for any new part
  3710. CriticalSection crit;
  3711. class casyncforbase: public CAsyncFor
  3712. {
  3713. protected:
  3714. CriticalSection &crit;
  3715. CIArrayOf<CIStringArray> &newNames;
  3716. IDistributedFile *file;
  3717. unsigned width;
  3718. IMultiException *mexcept;
  3719. bool *ignoreprim;
  3720. bool *ignorerep;
  3721. public:
  3722. bool ok;
  3723. bool * doneprim;
  3724. bool * donerep;
  3725. IException *except;
  3726. casyncforbase(IDistributedFile *_file,CIArrayOf<CIStringArray> &_newNames,unsigned _width,IMultiException *_mexcept,CriticalSection &_crit,bool *_ignoreprim,bool *_ignorerep)
  3727. : newNames(_newNames),crit(_crit)
  3728. {
  3729. width = _width;
  3730. file = _file;
  3731. ok = true;
  3732. mexcept = _mexcept;
  3733. doneprim = (bool *)calloc(sizeof(bool),width);
  3734. donerep = (bool *)calloc(sizeof(bool),width);
  3735. except = NULL;
  3736. ignoreprim = _ignoreprim;
  3737. ignorerep = _ignorerep;
  3738. }
  3739. ~casyncforbase()
  3740. {
  3741. free(doneprim);
  3742. free(donerep);
  3743. }
  3744. virtual bool doPart(IDistributedFilePart *,bool,RemoteFilename &,RemoteFilename &, bool &)
  3745. #ifdef _WIN32
  3746. {
  3747. assertex(!"doPart"); // stupid microsoft error
  3748. return false;
  3749. }
  3750. #else
  3751. = 0;
  3752. #endif
  3753. void Do(unsigned idx)
  3754. {
  3755. {
  3756. CriticalBlock block(crit);
  3757. if (!ok)
  3758. return;
  3759. }
  3760. Owned<IDistributedFilePart> part = file->getPart(idx);
  3761. unsigned copies = part->numCopies();
  3762. for (int copy = copies-1; copy>=0; copy--)
  3763. {
  3764. if ((copy==0)&&ignoreprim&&ignoreprim[idx])
  3765. continue;
  3766. if ((copy!=0)&&ignorerep&&ignorerep[idx])
  3767. continue;
  3768. bool pok=false;
  3769. IException *ex = NULL;
  3770. RemoteFilename oldrfn;
  3771. part->getFilename(oldrfn,(unsigned)copy);
  3772. const char *newfn = newNames.item(idx).item(copy);
  3773. if (!newfn||!*newfn)
  3774. continue;
  3775. RemoteFilename newrfn;
  3776. newrfn.setPath(part->queryNode(copy)->endpoint(),newfn);
  3777. try {
  3778. pok = doPart(part,copy!=0,oldrfn,newrfn,(copy==0)?doneprim[idx]:donerep[idx]);
  3779. }
  3780. catch (IException *e) {
  3781. EXCLOG(e, NULL);
  3782. ex = e;
  3783. }
  3784. CriticalBlock block(crit);
  3785. if (!pok||ex) {
  3786. ok = false;
  3787. if (ex) {
  3788. StringBuffer s("renamePhysicalPartFiles ");
  3789. s.append(file->queryLogicalName()).append(" part ").append(newfn);
  3790. EXCLOG(ex, s.str());
  3791. if (mexcept)
  3792. mexcept->append(*ex);
  3793. else {
  3794. if (except)
  3795. ex->Release();
  3796. else
  3797. except = ex;
  3798. }
  3799. }
  3800. }
  3801. }
  3802. }
  3803. };
  3804. class casyncfor1: public casyncforbase
  3805. {
  3806. public:
  3807. casyncfor1(IDistributedFile *_file,CIArrayOf<CIStringArray> &_newNames,unsigned _width,IMultiException *_mexcept,CriticalSection &_crit,bool *_ignoreprim,bool *_ignorerep)
  3808. : casyncforbase(_file,_newNames,_width,_mexcept,_crit,_ignoreprim,_ignorerep)
  3809. {
  3810. }
  3811. bool doPart(IDistributedFilePart *part,bool isrep,RemoteFilename &oldrfn,RemoteFilename &newrfn, bool &done)
  3812. {
  3813. done = false;
  3814. Owned<IFile> src = createIFile(oldrfn);
  3815. if (src->exists())
  3816. done = true;
  3817. else {
  3818. StringBuffer s;
  3819. oldrfn.getRemotePath(s);
  3820. WARNLOG("renamePhysicalPartFiles: %s doesn't exist",s.str());
  3821. return true;
  3822. }
  3823. Owned<IFile> dest = createIFile(newrfn);
  3824. StringBuffer newname;
  3825. newrfn.getRemotePath(newname);
  3826. if (dest->exists()) {
  3827. IDFS_Exception *e = new CDFS_Exception(DFSERR_PhysicalPartAlreadyExists,newname.str());
  3828. throw e;
  3829. }
  3830. // check destination directory exists
  3831. StringBuffer newdir;
  3832. splitDirTail(newname.str(),newdir);
  3833. Owned<IFile> destdir = createIFile(newdir.str());
  3834. destdir->createDirectory();
  3835. return true;
  3836. }
  3837. } afor1 (this,newNames,width,mexcept,crit,NULL,NULL);
  3838. afor1.For(width,10,false,true);
  3839. if (afor1.except)
  3840. throw afor1.except; // no recovery needed
  3841. if (!afor1.ok)
  3842. return false; // no recovery needed
  3843. MemoryAttr ignorebuf;
  3844. bool *ignoreprim = (bool *)ignorebuf.allocate(width*sizeof(bool)*2);
  3845. bool *ignorerep = ignoreprim+width;
  3846. for (i=0;i<width;i++) {
  3847. if (afor1.donerep[i]) {
  3848. ignorerep[i] = false;
  3849. ignoreprim[i] = !afor1.doneprim[i];
  3850. }
  3851. else if (afor1.doneprim[i]) {
  3852. ignorerep[i] = true;
  3853. ignoreprim[i] = false;
  3854. }
  3855. else {
  3856. StringBuffer s(queryLogicalName());
  3857. s.append(" Part ").append(i+1);
  3858. IDFS_Exception *e = new CDFS_Exception(DFSERR_PhysicalPartDoesntExist,s.str());
  3859. throw e;
  3860. }
  3861. }
  3862. // now do the rename
  3863. class casyncfor2: public casyncforbase
  3864. {
  3865. public:
  3866. casyncfor2(IDistributedFile *_file,CIArrayOf<CIStringArray> &_newNames,unsigned _width,IMultiException *_mexcept,CriticalSection &_crit,bool *_ignoreprim,bool *_ignorerep)
  3867. : casyncforbase(_file,_newNames,_width,_mexcept,_crit,_ignoreprim,_ignorerep)
  3868. {
  3869. }
  3870. bool doPart(IDistributedFilePart *part,bool isrep,RemoteFilename &oldrfn,RemoteFilename &newrfn, bool &done)
  3871. {
  3872. done = false;
  3873. StringBuffer oldfn;
  3874. oldrfn.getRemotePath(oldfn);
  3875. StringBuffer newfn;
  3876. newrfn.getRemotePath(newfn);
  3877. Owned<IFile> f = createIFile(oldrfn);
  3878. if (!isrep||f->exists()) { // ignore non-existant replicates
  3879. f->move(newfn.str());
  3880. PROGLOG("Succeeded rename %s to %s",oldfn.str(),newfn.str());
  3881. }
  3882. done = true;
  3883. return true;;
  3884. }
  3885. } afor2 (this,newNames,width,mexcept,crit,ignoreprim,ignorerep);
  3886. afor2.For(width,10,false,true);
  3887. if (afor2.ok) {
  3888. // now rename directory and partmask
  3889. DistributedFilePropertyLock lock(this);
  3890. root->setProp("@directory",newdir.str());
  3891. root->setProp("@partmask",newmask.str());
  3892. partmask.set(newmask.str());
  3893. directory.set(newdir.str());
  3894. StringBuffer mask;
  3895. for (unsigned i=0;i<width;i++) {
  3896. mask.appendf("Part[%d]/@name",i+1);
  3897. parts.item(i).clearOverrideName();
  3898. }
  3899. savePartsAttr(false);
  3900. }
  3901. else {
  3902. // attempt recovery
  3903. // do this synchronously to maximize chance of success (I don't expect many to have been done)
  3904. for (i=0;i<width;i++) {
  3905. Owned<IDistributedFilePart> part = getPart(i);
  3906. unsigned copies = part->numCopies();
  3907. for (int copy = copies-1; copy>=0; copy--) {
  3908. bool done = (copy==0)?afor2.doneprim[i]:afor2.donerep[i];
  3909. if (done) {
  3910. RemoteFilename oldrfn;
  3911. part->getFilename(oldrfn,(unsigned)copy);
  3912. const char *newfn = newNames.item(i).item(copy);
  3913. if (!newfn||!*newfn)
  3914. continue;
  3915. RemoteFilename newrfn;
  3916. newrfn.setPath(part->queryNode(copy)->endpoint(),newfn);
  3917. for (unsigned t=1;t<3;t++) { // 3 goes
  3918. try {
  3919. StringBuffer oldfn;
  3920. oldrfn.getRemotePath(oldfn);
  3921. StringBuffer newfn;
  3922. newrfn.getRemotePath(newfn);
  3923. Owned<IFile> f = createIFile(newrfn);
  3924. f->move(oldfn.str());
  3925. PROGLOG("Succeeded rename %s back to %s",newfn.str(),oldfn.str());
  3926. break;
  3927. }
  3928. catch (IException *e) {
  3929. if (!afor2.except)
  3930. afor2.except = e;
  3931. else
  3932. e->Release();
  3933. }
  3934. }
  3935. }
  3936. }
  3937. }
  3938. }
  3939. if (afor2.except)
  3940. throw afor2.except;
  3941. return afor2.ok;
  3942. }
  3943. IPropertyTree *queryRoot() { return root; }
  3944. __int64 getFileSize(bool allowphysical,bool forcephysical)
  3945. {
  3946. __int64 ret = (__int64)(forcephysical?-1:queryAttributes().getPropInt64("@size",-1));
  3947. if (ret==-1)
  3948. {
  3949. ret = 0;
  3950. unsigned n = numParts();
  3951. for (unsigned i=0;i<n;i++)
  3952. {
  3953. Owned<IDistributedFilePart> part = getPart(i);
  3954. __int64 ps = part->getFileSize(allowphysical,forcephysical);
  3955. if (ps == -1)
  3956. {
  3957. ret = ps;
  3958. break;
  3959. }
  3960. ret += ps;
  3961. }
  3962. }
  3963. return ret;
  3964. }
  3965. __int64 getDiskSize(bool allowphysical,bool forcephysical)
  3966. {
  3967. if (!isCompressed(NULL))
  3968. return getFileSize(allowphysical, forcephysical);
  3969. __int64 ret = (__int64)(forcephysical?-1:queryAttributes().getPropInt64("@compressedSize",-1));
  3970. if (ret==-1)
  3971. {
  3972. ret = 0;
  3973. unsigned n = numParts();
  3974. for (unsigned i=0;i<n;i++)
  3975. {
  3976. Owned<IDistributedFilePart> part = getPart(i);
  3977. __int64 ps = part->getDiskSize(allowphysical,forcephysical);
  3978. if (ps == -1)
  3979. {
  3980. ret = ps;
  3981. break;
  3982. }
  3983. ret += ps;
  3984. }
  3985. }
  3986. return ret;
  3987. }
  3988. bool getFileCheckSum(unsigned &checkSum)
  3989. {
  3990. if (queryAttributes().hasProp("@checkSum"))
  3991. checkSum = (unsigned)queryAttributes().getPropInt64("@checkSum");
  3992. else
  3993. {
  3994. checkSum = ~0;
  3995. unsigned n = numParts();
  3996. for (unsigned i=0;i<n;i++) {
  3997. Owned<IDistributedFilePart> part = getPart(i);
  3998. unsigned crc;
  3999. if (!part->getCrc(crc))
  4000. return false;
  4001. checkSum ^= crc;
  4002. }
  4003. }
  4004. return true;
  4005. }
  4006. virtual bool getFormatCrc(unsigned &crc)
  4007. {
  4008. if (queryAttributes().hasProp("@formatCrc")) {
  4009. // NB pre record_layout CRCs are not valid
  4010. crc = (unsigned)queryAttributes().getPropInt("@formatCrc");
  4011. return true;
  4012. }
  4013. return false;
  4014. }
  4015. virtual bool getRecordLayout(MemoryBuffer &layout)
  4016. {
  4017. return queryAttributes().getPropBin("_record_layout",layout);
  4018. }
  4019. virtual bool getRecordSize(size32_t &rsz)
  4020. {
  4021. if (queryAttributes().hasProp("@recordSize")) {
  4022. rsz = (size32_t)queryAttributes().getPropInt("@recordSize");
  4023. return true;
  4024. }
  4025. return false;
  4026. }
  4027. virtual unsigned getPositionPart(offset_t pos, offset_t &base)
  4028. {
  4029. unsigned n = numParts();
  4030. base = 0;
  4031. for (unsigned i=0;i<n;i++) {
  4032. Owned<IDistributedFilePart> part = getPart(i);
  4033. offset_t ps = part->getFileSize(true,false);
  4034. if (ps==(offset_t)-1)
  4035. break;
  4036. if (ps>pos)
  4037. return i;
  4038. pos -= ps;
  4039. base += ps;
  4040. }
  4041. return NotFound;
  4042. }
  4043. IDistributedSuperFile *querySuperFile()
  4044. {
  4045. return NULL; // i.e. this isn't super file
  4046. }
  4047. virtual bool checkClusterCompatible(IFileDescriptor &fdesc, StringBuffer &err)
  4048. {
  4049. unsigned n = numParts();
  4050. if (fdesc.numParts()!=n) {
  4051. err.appendf("Different cluster width (%d/%d)",n,fdesc.numParts());
  4052. return false;
  4053. }
  4054. if (fdesc.numClusters()!=1) {
  4055. err.append("Cannot merge more than one cluster");
  4056. return false;
  4057. }
  4058. StringBuffer cname;
  4059. fdesc.getClusterLabel(0,cname);
  4060. if (cname.length()&&(findCluster(cname.str())!=NotFound)) {
  4061. err.append("File already contains cluster");
  4062. err.append(cname.str());
  4063. return false;
  4064. }
  4065. StringBuffer pname;
  4066. StringBuffer fdtail;
  4067. for (unsigned pn=0;pn<n;pn++) {
  4068. IDistributedFilePart &part = queryPart(pn);
  4069. part.getPartName(pname.clear());
  4070. fdesc.queryPart(pn)->getTail(fdtail.clear());
  4071. if (strcmp(pname.str(),fdtail.str())!=0) {
  4072. err.appendf("Part name mismatch (%s,%s)",pname.str(),fdtail.str());
  4073. return false;
  4074. }
  4075. RemoteFilename fdrfn;
  4076. fdesc.getFilename(pn,0,fdrfn);
  4077. unsigned nc = numCopies(pn);
  4078. for (unsigned c = 0;c<nc;c++) {
  4079. RemoteFilename rfn;
  4080. part.getFilename(rfn,c);
  4081. if (rfn.equals(fdrfn)) {
  4082. err.appendf("Parts overlap %s and %s",pname.str(),fdtail.str());
  4083. return false;
  4084. }
  4085. }
  4086. }
  4087. return true;
  4088. }
  4089. void enqueueReplicate()
  4090. {
  4091. MemoryBuffer mb;
  4092. mb.append((byte)DRQ_REPLICATE).append(queryLogicalName());
  4093. udesc->serialize(mb);
  4094. CDateTime filedt;
  4095. getModificationTime(filedt);
  4096. filedt.serialize(mb);
  4097. Owned<INamedQueueConnection> qconn = createNamedQueueConnection(0);
  4098. Owned<IQueueChannel> qchannel = qconn->open(DFS_REPLICATE_QUEUE);
  4099. qchannel->put(mb);
  4100. }
  4101. bool getAccessedTime(CDateTime &dt)
  4102. {
  4103. StringBuffer str;
  4104. if (!root->getProp("@accessed",str))
  4105. return false;
  4106. dt.setString(str.str());
  4107. return true;
  4108. }
  4109. virtual void setAccessedTime(const CDateTime &dt)
  4110. {
  4111. if (logicalName.isForeign())
  4112. parent->setFileAccessed(logicalName,udesc,dt);
  4113. else
  4114. {
  4115. CFileAttrLock attrLock;
  4116. if (0 == proplockcount && conn)
  4117. verifyex(attrLock.init(logicalName, DXB_File, RTM_LOCK_WRITE, conn, defaultTimeout, "CDistributedFile::setAccessedTime"));
  4118. if (dt.isNull())
  4119. queryAttributes().removeProp("@accessed");
  4120. else
  4121. {
  4122. StringBuffer str;
  4123. queryAttributes().setProp("@accessed",dt.getString(str).str());
  4124. }
  4125. }
  4126. }
  4127. void setAccessed()
  4128. {
  4129. CDateTime dt;
  4130. dt.setNow();
  4131. setAccessedTime(dt);
  4132. }
  4133. };
  4134. static unsigned findSubFileOrd(const char *name)
  4135. {
  4136. if (*name=='#') {
  4137. const char *n = name+1;
  4138. if (*n) {
  4139. do { n++; } while (*n&&isdigit(*n));
  4140. if (!*n)
  4141. return atoi(name+1)-1;
  4142. }
  4143. }
  4144. return NotFound;
  4145. }
  4146. class CDistributedSuperFile: public CDistributedFileBase<IDistributedSuperFile>
  4147. {
  4148. void checkNotForeign()
  4149. {
  4150. if (!conn)
  4151. throw MakeStringException(-1,"Operation not allowed on foreign file");
  4152. }
  4153. CDistributedFilePartArray partscache;
  4154. FileClusterInfoArray clusterscache;
  4155. /**
  4156. * Adds a sub-file to a super-file within a transaction.
  4157. */
  4158. class cAddSubFileAction: public CDFAction
  4159. {
  4160. StringAttr parentlname;
  4161. Owned<IDistributedSuperFile> parent;
  4162. Owned<IDistributedFile> sub;
  4163. StringAttr subfile;
  4164. bool before;
  4165. StringAttr other;
  4166. public:
  4167. cAddSubFileAction(const char *_parentlname,const char *_subfile,bool _before,const char *_other)
  4168. : parentlname(_parentlname), subfile(_subfile), before(_before), other(_other)
  4169. {
  4170. }
  4171. virtual bool prepare()
  4172. {
  4173. parent.setown(transaction->lookupSuperFile(parentlname));
  4174. if (!parent)
  4175. throw MakeStringException(-1,"addSubFile: SuperFile %s cannot be found",parentlname.get());
  4176. if (!subfile.isEmpty())
  4177. {
  4178. try
  4179. {
  4180. sub.setown(transaction->lookupFile(subfile,SDS_SUB_LOCK_TIMEOUT));
  4181. if (!sub)
  4182. throw MakeStringException(-1,"cAddSubFileAction: sub file %s not found", subfile.sget());
  4183. // Must validate before locking for update below, to check sub is not already in parent (and therefore locked already)
  4184. transaction->validateAddSubFile(parent, sub, subfile);
  4185. }
  4186. catch (IDFS_Exception *e)
  4187. {
  4188. if (e->errorCode()!=DFSERR_LookupConnectionTimout)
  4189. throw;
  4190. e->Release();
  4191. return false;
  4192. }
  4193. if (!sub.get())
  4194. throw MakeStringException(-1,"addSubFile: File %s cannot be found to add",subfile.get());
  4195. }
  4196. // Try to lock all files
  4197. addFileLock(parent);
  4198. if (lock())
  4199. {
  4200. transaction->noteAddSubFile(parent, parentlname, sub);
  4201. return true;
  4202. }
  4203. unlock();
  4204. parent.clear();
  4205. sub.clear();
  4206. return false;
  4207. }
  4208. virtual void run()
  4209. {
  4210. if (!sub)
  4211. throw MakeStringException(-1,"addSubFile(2): File %s cannot be found to add",subfile.get());
  4212. CDistributedSuperFile *sf = QUERYINTERFACE(parent.get(),CDistributedSuperFile);
  4213. if (sf)
  4214. sf->doAddSubFile(LINK(sub),before,other,transaction);
  4215. }
  4216. virtual void commit()
  4217. {
  4218. CDistributedSuperFile *sf = QUERYINTERFACE(parent.get(),CDistributedSuperFile);
  4219. if (sf)
  4220. sf->updateParentFileAttrs(transaction);
  4221. CDFAction::commit();
  4222. }
  4223. virtual void retry()
  4224. {
  4225. parent.clear();
  4226. sub.clear();
  4227. CDFAction::retry();
  4228. }
  4229. };
  4230. /**
  4231. * Removes a sub-file of a super-file within a transaction.
  4232. */
  4233. class cRemoveSubFileAction: public CDFAction
  4234. {
  4235. StringAttr parentlname;
  4236. Owned<IDistributedSuperFile> parent;
  4237. Owned<IDistributedFile> sub;
  4238. StringAttr subfile;
  4239. bool remsub;
  4240. public:
  4241. cRemoveSubFileAction(const char *_parentlname,const char *_subfile,bool _remsub=false)
  4242. : parentlname(_parentlname), subfile(_subfile), remsub(_remsub)
  4243. {
  4244. }
  4245. virtual bool prepare()
  4246. {
  4247. parent.setown(transaction->lookupSuperFile(parentlname));
  4248. if (!parent)
  4249. throw MakeStringException(-1,"removeSubFile: SuperFile %s cannot be found",parentlname.get());
  4250. if (!subfile.isEmpty())
  4251. {
  4252. try
  4253. {
  4254. sub.setown(transaction->lookupFile(subfile,SDS_SUB_LOCK_TIMEOUT));
  4255. }
  4256. catch (IDFS_Exception *e)
  4257. {
  4258. if (e->errorCode()!=DFSERR_LookupConnectionTimout)
  4259. throw;
  4260. e->Release();
  4261. return false;
  4262. }
  4263. if (!transaction->isSubFile(parent, subfile, true))
  4264. WARNLOG("addSubFile: File %s is not a subfile of %s", subfile.get(), parent->queryLogicalName());
  4265. }
  4266. // Try to lock all files
  4267. addFileLock(parent);
  4268. if (sub && remsub) // NB: I only need to lock (for exclusivity, if going to delete
  4269. addFileLock(sub);
  4270. if (lock())
  4271. {
  4272. if (sub)
  4273. transaction->noteRemoveSubFile(parent, sub);
  4274. else
  4275. transaction->clearSubFiles(parent);
  4276. return true;
  4277. }
  4278. unlock();
  4279. parent.clear();
  4280. sub.clear();
  4281. return false;
  4282. }
  4283. virtual void run()
  4284. {
  4285. CDistributedSuperFile *sf = QUERYINTERFACE(parent.get(),CDistributedSuperFile);
  4286. if (sf) {
  4287. // Delay the deletion of the subs until commit
  4288. if (remsub) {
  4289. if (subfile) {
  4290. CDfsLogicalFileName lname;
  4291. lname.set(subfile.get());
  4292. transaction->addDelayedDelete(lname, SDS_SUB_LOCK_TIMEOUT);
  4293. } else { // Remove all subfiles
  4294. Owned<IDistributedFileIterator> iter = parent->getSubFileIterator(false);
  4295. ForEach (*iter) {
  4296. CDfsLogicalFileName lname;
  4297. IDistributedFile *f = &iter->query();
  4298. lname.set(f->queryLogicalName());
  4299. transaction->addDelayedDelete(lname, SDS_SUB_LOCK_TIMEOUT);
  4300. }
  4301. }
  4302. }
  4303. // Now we clean the subs
  4304. if (subfile.get())
  4305. sf->doRemoveSubFile(subfile.get(), transaction);
  4306. else
  4307. sf->doRemoveSubFiles(transaction);
  4308. }
  4309. }
  4310. virtual void retry()
  4311. {
  4312. parent.clear();
  4313. sub.clear();
  4314. CDFAction::retry();
  4315. }
  4316. };
  4317. /**
  4318. * Removes all subfiles exclusively owned by named superfile within a transaction.
  4319. */
  4320. class cRemoveOwnedSubFilesAction: public CDFAction
  4321. {
  4322. StringAttr parentlname;
  4323. Owned<IDistributedSuperFile> parent;
  4324. bool remsub;
  4325. public:
  4326. cRemoveOwnedSubFilesAction(IDistributedFileTransaction *_transaction, const char *_parentlname,bool _remsub=false)
  4327. : parentlname(_parentlname), remsub(_remsub)
  4328. {
  4329. }
  4330. virtual bool prepare()
  4331. {
  4332. parent.setown(transaction->lookupSuperFile(parentlname));
  4333. if (!parent)
  4334. throw MakeStringException(-1,"removeOwnedSubFiles: SuperFile %s cannot be found", parentlname.get());
  4335. // Try to lock all files
  4336. addFileLock(parent);
  4337. if (lock())
  4338. return true;
  4339. unlock();
  4340. parent.clear();
  4341. return false;
  4342. }
  4343. virtual void run()
  4344. {
  4345. CDistributedSuperFile *sf = QUERYINTERFACE(parent.get(),CDistributedSuperFile);
  4346. if (sf)
  4347. {
  4348. StringArray toRemove;
  4349. Owned<IDistributedFileIterator> iter = parent->getSubFileIterator(false);
  4350. ForEach (*iter)
  4351. {
  4352. IDistributedFile *file = &iter->query();
  4353. CDistributedFile *_file = QUERYINTERFACE(file, CDistributedFile);
  4354. StringArray owners;
  4355. _file->getSuperOwners(owners);
  4356. if (NotFound == owners.find(parentlname))
  4357. ThrowStringException(-1, "removeOwnedSubFiles: SuperFile %s, subfile %s - subfile not owned by superfile", parentlname.get(), file->queryLogicalName());
  4358. if (1 == owners.ordinality()) // just me
  4359. {
  4360. const char *logicalName = file->queryLogicalName();
  4361. toRemove.append(logicalName);
  4362. // Delay the deletion of the subs until commit
  4363. if (remsub)
  4364. {
  4365. CDfsLogicalFileName lname;
  4366. lname.set(logicalName);
  4367. transaction->addDelayedDelete(lname, SDS_SUB_LOCK_TIMEOUT);
  4368. }
  4369. }
  4370. }
  4371. // Now we clean the subs
  4372. if (sf->numSubFiles(false) == toRemove.ordinality())
  4373. sf->doRemoveSubFiles(transaction); // remove all
  4374. else
  4375. {
  4376. ForEachItemIn(r, toRemove)
  4377. sf->doRemoveSubFile(toRemove.item(r), transaction);
  4378. }
  4379. }
  4380. }
  4381. virtual void retry()
  4382. {
  4383. parent.clear();
  4384. CDFAction::retry();
  4385. }
  4386. };
  4387. /**
  4388. * Swaps sub-files between two super-files within a transaction.
  4389. */
  4390. class cSwapFileAction: public CDFAction
  4391. {
  4392. Linked<IDistributedSuperFile> super1, super2;
  4393. StringAttr super1Name, super2Name;
  4394. public:
  4395. cSwapFileAction(const char *_super1Name, const char *_super2Name)
  4396. : super1Name(_super1Name), super2Name(_super2Name)
  4397. {
  4398. }
  4399. virtual bool prepare()
  4400. {
  4401. super1.setown(transaction->lookupSuperFile(super1Name));
  4402. if (!super1)
  4403. throw MakeStringException(-1,"swapSuperFile: SuperFile %s cannot be found", super1Name.get());
  4404. super2.setown(transaction->lookupSuperFile(super2Name));
  4405. if (!super2)
  4406. {
  4407. super1.clear();
  4408. throw MakeStringException(-1,"swapSuperFile: SuperFile %s cannot be found", super2Name.get());
  4409. }
  4410. // Try to lock all files
  4411. addFileLock(super1);
  4412. for (unsigned i=0; i<super1->numSubFiles(); i++)
  4413. addFileLock(&super1->querySubFile(i));
  4414. addFileLock(super2);
  4415. for (unsigned i=0; i<super2->numSubFiles(); i++)
  4416. addFileLock(&super2->querySubFile(i));
  4417. if (lock())
  4418. {
  4419. transaction->noteSuperSwap(super1, super2);
  4420. return true;
  4421. }
  4422. unlock();
  4423. super1.clear();
  4424. super2.clear();
  4425. return false;
  4426. }
  4427. virtual void run()
  4428. {
  4429. CDistributedSuperFile *sf = QUERYINTERFACE(super1.get(),CDistributedSuperFile);
  4430. if (sf)
  4431. sf->doSwapSuperFile(super2,transaction);
  4432. }
  4433. virtual void retry()
  4434. {
  4435. super1.clear();
  4436. super2.clear();
  4437. CDFAction::retry();
  4438. }
  4439. };
  4440. /**
  4441. * SubFile Iterator, used only to list sub-files of a super-file.
  4442. */
  4443. class cSubFileIterator: public CDistributedFileIteratorBase< IDistributedFileIterator, IArrayOf<IDistributedFile> >
  4444. {
  4445. public:
  4446. cSubFileIterator(IArrayOf<IDistributedFile> &_subfiles, bool supersub)
  4447. {
  4448. ForEachItemIn(i,_subfiles) {
  4449. IDistributedSuperFile* super = supersub?_subfiles.item(i).querySuperFile():NULL;
  4450. if (super) {
  4451. Owned<IDistributedFileIterator> iter = super->getSubFileIterator(true);
  4452. ForEach(*iter)
  4453. list.append(iter->get());
  4454. }
  4455. else
  4456. list.append(*LINK(&_subfiles.item(i)));
  4457. }
  4458. }
  4459. StringBuffer & getName(StringBuffer &name)
  4460. {
  4461. return list.item(index).getLogicalName(name);
  4462. }
  4463. IDistributedFile & query()
  4464. {
  4465. return list.item(index);
  4466. }
  4467. };
  4468. void checkModify(const char *title)
  4469. {
  4470. StringBuffer reason;
  4471. if (!canModify(reason)) {
  4472. #ifdef EXTRA_LOGGING
  4473. PROGLOG("CDistributedSuperFile::%s(canModify) %s",title,reason.str());
  4474. #endif
  4475. if (reason.length())
  4476. throw MakeStringException(-1,"CDistributedSuperFile::%s %s",title,reason.str());
  4477. }
  4478. }
  4479. protected:
  4480. int interleaved; // 0 not interleaved, 1 interleaved old, 2 interleaved new
  4481. IArrayOf<IDistributedFile> subfiles;
  4482. void clearSuperOwners(unsigned timeoutMs)
  4483. {
  4484. /* JCSMORE - Why on earth is this doing this way?
  4485. * We are in a super file, we already have [read] locks to sub files (in 'subfiles' array)
  4486. * This should iterate through those and call unlinkSubFile I think.
  4487. */
  4488. Owned<IPropertyTreeIterator> iter = root->getElements("SubFile");
  4489. StringBuffer oquery;
  4490. oquery.append("SuperOwner[@name=\"").append(logicalName.get()).append("\"]");
  4491. Owned<IMultiException> exceptions = MakeMultiException("CDelayedDelete::doRemoveEntry::SuperOwners");
  4492. ForEach(*iter)
  4493. {
  4494. const char *name = iter->query().queryProp("@name");
  4495. if (name&&*name)
  4496. {
  4497. CDfsLogicalFileName subfn;
  4498. subfn.set(name);
  4499. CFileLock fconnlockSub;
  4500. // JCSMORE - this is really not right, but consistent with previous version
  4501. // MORE: Use CDistributedSuperFile::linkSuperOwner(false) - ie. unlink
  4502. if (fconnlockSub.init(subfn, RTM_LOCK_READ, timeoutMs, "CDistributedFile::doRemoveEntry"))
  4503. {
  4504. IPropertyTree *subfroot = fconnlockSub.queryRoot();
  4505. if (subfroot)
  4506. {
  4507. if (!subfroot->removeProp(oquery.str()))
  4508. exceptions->append(*MakeStringException(-1, "CDelayedDelete::removeEntry: SubFile %s of %s not found for removal",name?name:"(NULL)", logicalName.get()));
  4509. }
  4510. }
  4511. }
  4512. }
  4513. if (exceptions->ordinality())
  4514. throw exceptions.getClear();
  4515. }
  4516. virtual void getSuperOwners(StringArray &owners)
  4517. {
  4518. ForEachItemIn(i, subfiles)
  4519. {
  4520. IDistributedFile *file = &subfiles.item(i);
  4521. IDistributedSuperFile *super = file->querySuperFile();
  4522. if (super)
  4523. {
  4524. CDistributedSuperFile *_super = QUERYINTERFACE(super, CDistributedSuperFile);
  4525. if (_super)
  4526. _super->getSuperOwners(owners);
  4527. }
  4528. else
  4529. {
  4530. CDistributedFile *_file = QUERYINTERFACE(file, CDistributedFile);
  4531. if (_file)
  4532. _file->getSuperOwners(owners);
  4533. }
  4534. }
  4535. }
  4536. static StringBuffer &getSubPath(StringBuffer &path,unsigned idx)
  4537. {
  4538. return path.append("SubFile[@num=\"").append(idx+1).append("\"]");
  4539. }
  4540. void loadSubFiles(IDistributedFileTransaction *transaction, unsigned timeout)
  4541. {
  4542. partscache.kill();
  4543. StringBuffer path;
  4544. StringBuffer subname;
  4545. subfiles.kill();
  4546. unsigned n = root->getPropInt("@numsubfiles");
  4547. if (n == 0)
  4548. return;
  4549. try
  4550. {
  4551. // Find all reported indexes and bail on bad range (before we lock any file)
  4552. Owned<IPropertyTreeIterator> subit = root->getElements("SubFile");
  4553. // Adding a sub 'before' another get the list out of order (but still valid)
  4554. OwnedMalloc<IPropertyTree *> orderedSubFiles(n, true);
  4555. ForEach (*subit)
  4556. {
  4557. IPropertyTree &sub = subit->query();
  4558. unsigned sn = sub.getPropInt("@num",0);
  4559. if (sn == 0)
  4560. ThrowStringException(-1, "CDistributedSuperFile: SuperFile %s: bad subfile part number %d of %d", logicalName.get(), sn, n);
  4561. if (sn > n)
  4562. ThrowStringException(-1, "CDistributedSuperFile: SuperFile %s: out-of-range subfile part number %d of %d", logicalName.get(), sn, n);
  4563. if (orderedSubFiles[sn-1])
  4564. ThrowStringException(-1, "CDistributedSuperFile: SuperFile %s: duplicated subfile part number %d of %d", logicalName.get(), sn, n);
  4565. orderedSubFiles[sn-1] = &sub;
  4566. }
  4567. for (unsigned i=0; i<n; i++)
  4568. {
  4569. if (!orderedSubFiles[i])
  4570. ThrowStringException(-1, "CDistributedSuperFile: SuperFile %s: missing subfile part number %d of %d", logicalName.get(), i+1, n);
  4571. }
  4572. // Now try to resolve them all (file/superfile)
  4573. for (unsigned f=0; f<n; f++)
  4574. {
  4575. IPropertyTree &sub = *(orderedSubFiles[f]);
  4576. sub.getProp("@name",subname.clear());
  4577. Owned<IDistributedFile> subfile;
  4578. subfile.setown(transaction?transaction->lookupFile(subname.str(),timeout):parent->lookup(subname.str(), udesc, false, false, false, transaction, timeout));
  4579. if (!subfile.get())
  4580. subfile.setown(transaction?transaction->lookupSuperFile(subname.str(),timeout):parent->lookupSuperFile(subname.str(),udesc,transaction,timeout));
  4581. // Some files are ok not to exist
  4582. if (!subfile.get())
  4583. {
  4584. CDfsLogicalFileName cdfsl;
  4585. cdfsl.set(subname);
  4586. if (cdfsl.isForeign())
  4587. {
  4588. // MORE - This foreign treatment seems flaky at best
  4589. WARNLOG("CDistributedSuperFile: SuperFile %s's sub-file file '%s' is foreign, removing it from super", logicalName.get(), subname.str());
  4590. root->removeTree(&sub);
  4591. continue;
  4592. }
  4593. else
  4594. ThrowStringException(-1, "CDistributedSuperFile: SuperFile %s: corrupt subfile file '%s' cannot be found", logicalName.get(), subname.str());
  4595. }
  4596. subfiles.append(*subfile.getClear());
  4597. }
  4598. // This is *only* due to foreign files
  4599. if (subfiles.ordinality() != n)
  4600. {
  4601. WARNLOG("CDistributedSuperFile: SuperFile %s's number of sub-files updated to %d", logicalName.get(), subfiles.ordinality());
  4602. root->setPropInt("@numsubfiles", subfiles.ordinality());
  4603. }
  4604. }
  4605. catch (IException *)
  4606. {
  4607. partscache.kill();
  4608. subfiles.kill(); // one out, all out
  4609. throw;
  4610. }
  4611. }
  4612. void addItem(unsigned pos,IDistributedFile *_file)
  4613. {
  4614. Owned<IDistributedFile> file = _file;
  4615. partscache.kill();
  4616. // first renumber all above
  4617. StringBuffer path;
  4618. IPropertyTree *sub;
  4619. for (unsigned i=subfiles.ordinality();i>pos;i--) {
  4620. sub = root->queryPropTree(getSubPath(path.clear(),i-1).str());
  4621. if (!sub)
  4622. throw MakeStringException(-1,"C(2): Corrupt subfile file part %d cannot be found",i);
  4623. sub->setPropInt("@num",i+1);
  4624. }
  4625. sub = createPTree();
  4626. sub->setPropInt("@num",pos+1);
  4627. sub->setProp("@name",file->queryLogicalName());
  4628. if (pos==0) {
  4629. resetFileAttr(createPTreeFromIPT(&file->queryAttributes()));
  4630. }
  4631. root->addPropTree("SubFile",sub);
  4632. subfiles.add(*file.getClear(),pos);
  4633. root->setPropInt("@numsubfiles",subfiles.ordinality());
  4634. }
  4635. void removeItem(unsigned pos)
  4636. {
  4637. partscache.kill();
  4638. StringBuffer path;
  4639. IPropertyTree* sub = root->queryPropTree(getSubPath(path,pos).str());
  4640. if (!sub)
  4641. throw MakeStringException(-1,"CDistributedSuperFile(3): Corrupt subfile file part %d cannot be found",pos+1);
  4642. root->removeTree(sub);
  4643. // now renumber all above
  4644. for (unsigned i=pos+1; i<subfiles.ordinality(); i++) {
  4645. sub = root->queryPropTree(getSubPath(path.clear(),i).str());
  4646. if (!sub)
  4647. throw MakeStringException(-1,"CDistributedSuperFile(2): Corrupt subfile file part %d cannot be found",i+1);
  4648. sub->setPropInt("@num",i);
  4649. }
  4650. subfiles.remove(pos);
  4651. if (pos==0) {
  4652. if (subfiles.ordinality())
  4653. resetFileAttr(createPTreeFromIPT(&subfiles.item(0).queryAttributes()));
  4654. else
  4655. resetFileAttr(getEmptyAttr());
  4656. }
  4657. root->setPropInt("@numsubfiles",subfiles.ordinality());
  4658. }
  4659. void loadParts(CDistributedFilePartArray &partsret, IDFPartFilter *filter)
  4660. {
  4661. unsigned p = 0;
  4662. if (interleaved) { // a bit convoluted but should work
  4663. IArrayOf<IDistributedFile> allsubfiles;
  4664. ForEachItemIn(i,subfiles) {
  4665. // if old format keep original interleaving
  4666. IDistributedSuperFile* super = (interleaved==1)?NULL:subfiles.item(i).querySuperFile();
  4667. if (super) {
  4668. Owned<IDistributedFileIterator> iter = super->getSubFileIterator(true);
  4669. ForEach(*iter)
  4670. allsubfiles.append(iter->get());
  4671. }
  4672. else
  4673. allsubfiles.append(*LINK(&subfiles.item(i)));
  4674. }
  4675. unsigned *pn = new unsigned[allsubfiles.ordinality()];
  4676. ForEachItemIn(j,allsubfiles)
  4677. pn[j] = allsubfiles.item(j).numParts();
  4678. unsigned f=0;
  4679. bool found=false;
  4680. loop {
  4681. if (f==allsubfiles.ordinality()) {
  4682. if (!found)
  4683. break; // no more
  4684. found = false;
  4685. f = 0;
  4686. }
  4687. if (pn[f]) {
  4688. found = true;
  4689. if (!filter||filter->includePart(p)) {
  4690. IDistributedFile &subfile = allsubfiles.item(f);
  4691. IDistributedFilePart *part = subfile.getPart(subfile.numParts()-pn[f]);
  4692. partsret.append(*QUERYINTERFACE(part,CDistributedFilePart)); // bit kludgy
  4693. }
  4694. p++;
  4695. pn[f]--;
  4696. }
  4697. f++;
  4698. }
  4699. delete [] pn;
  4700. }
  4701. else { // sequential
  4702. ForEachItemIn(i,subfiles) { // not wonderfully quick
  4703. IDistributedFile &subfile = subfiles.item(i);
  4704. unsigned n = subfile.numParts();
  4705. unsigned j = 0;
  4706. while (n--) {
  4707. if (!filter||filter->includePart(p)) {
  4708. IDistributedFilePart *part = subfile.getPart(j++);
  4709. partsret.append(*QUERYINTERFACE(part,CDistributedFilePart)); // bit kludgy
  4710. }
  4711. p++;
  4712. }
  4713. }
  4714. }
  4715. }
  4716. void linkSubFile(unsigned pos, bool link=true)
  4717. {
  4718. IDistributedFile *subfile = &subfiles.item(pos);
  4719. IDistributedSuperFile *ssub = subfile->querySuperFile();
  4720. if (ssub) {
  4721. CDistributedSuperFile *cdsuper = QUERYINTERFACE(ssub,CDistributedSuperFile);
  4722. cdsuper->linkSuperOwner(queryLogicalName(),link);
  4723. }
  4724. else {
  4725. CDistributedFile *cdfile = QUERYINTERFACE(subfile,CDistributedFile);
  4726. cdfile->linkSuperOwner(queryLogicalName(),link);
  4727. }
  4728. }
  4729. void unlinkSubFile(unsigned pos)
  4730. {
  4731. linkSubFile(pos, false);
  4732. }
  4733. void checkSubFormatAttr(IDistributedFile *sub, const char* exprefix="")
  4734. {
  4735. // empty super files now pass
  4736. ForEachItemIn(i,subfiles) {
  4737. IDistributedSuperFile* super = subfiles.item(i).querySuperFile();
  4738. if (super) {
  4739. CDistributedSuperFile *cdsuper = QUERYINTERFACE(super,CDistributedSuperFile);
  4740. if (cdsuper)
  4741. cdsuper->checkSubFormatAttr(sub,exprefix);
  4742. return;
  4743. }
  4744. CDistributedFile *cdfile = QUERYINTERFACE(&subfiles.item(0),CDistributedFile);
  4745. if (cdfile)
  4746. cdfile->checkFormatAttr(sub,exprefix); // any file will do
  4747. }
  4748. }
  4749. public:
  4750. void checkFormatAttr(IDistributedFile *sub, const char* exprefix="")
  4751. {
  4752. // only check sub files not siblings, which is excessive (format checking is really only debug aid)
  4753. checkSubFormatAttr(sub,exprefix);
  4754. }
  4755. unsigned findSubFile(const char *name)
  4756. {
  4757. StringBuffer lfn;
  4758. normalizeLFN(name,lfn);
  4759. ForEachItemIn(i,subfiles)
  4760. if (stricmp(subfiles.item(i).queryLogicalName(),lfn.str())==0)
  4761. return i;
  4762. return NotFound;
  4763. }
  4764. IMPLEMENT_IINTERFACE;
  4765. void init(CDistributedFileDirectory *_parent, IPropertyTree *_root, const CDfsLogicalFileName &_name, IUserDescriptor* user, IDistributedFileTransaction *transaction, unsigned timeout=INFINITE)
  4766. {
  4767. assertex(_name.isSet());
  4768. setUserDescriptor(udesc,user);
  4769. logicalName.set(_name);
  4770. parent = _parent;
  4771. root.set(_root);
  4772. const char *val = root->queryProp("@interleaved");
  4773. if (val&&isdigit(*val))
  4774. interleaved = atoi(val);
  4775. else
  4776. interleaved = strToBool(val)?1:0;
  4777. loadSubFiles(transaction,timeout);
  4778. }
  4779. CDistributedSuperFile(CDistributedFileDirectory *_parent, IPropertyTree *_root,const CDfsLogicalFileName &_name,IUserDescriptor* user)
  4780. {
  4781. init(_parent,_root,_name,user,NULL);
  4782. }
  4783. CDistributedSuperFile(CDistributedFileDirectory *_parent, IRemoteConnection *_conn,const CDfsLogicalFileName &_name,IUserDescriptor* user, IDistributedFileTransaction *transaction,unsigned timeout)
  4784. {
  4785. conn.setown(_conn);
  4786. init(_parent,conn->queryRoot(),_name,user,transaction,timeout);
  4787. }
  4788. CDistributedSuperFile(CDistributedFileDirectory *_parent, CDfsLogicalFileName &_name, IUserDescriptor* user, IDistributedFileTransaction *transaction)
  4789. {
  4790. // temp super file
  4791. assertex(_name.isMulti());
  4792. if (!_name.isExpanded())
  4793. _name.expand(user);//expand wildcards
  4794. Owned<IPropertyTree> tree = _name.createSuperTree();
  4795. init(_parent,tree,_name,user,transaction);
  4796. }
  4797. ~CDistributedSuperFile()
  4798. {
  4799. partscache.kill();
  4800. subfiles.kill();
  4801. }
  4802. StringBuffer &getClusterName(unsigned clusternum,StringBuffer &name)
  4803. {
  4804. // returns the cluster name if all the same
  4805. CriticalBlock block (sect);
  4806. if (subfiles.ordinality()==1)
  4807. return subfiles.item(0).getClusterName(clusternum,name);
  4808. size32_t rl = name.length();
  4809. StringBuffer test;
  4810. ForEachItemIn(i,subfiles) {
  4811. if (i) {
  4812. subfiles.item(i).getClusterName(clusternum,test.clear());
  4813. if (strcmp(name.str(),test.str())!=0) {
  4814. name.setLength(rl);
  4815. break;
  4816. }
  4817. }
  4818. else
  4819. subfiles.item(i).getClusterName(clusternum,name);
  4820. }
  4821. return name;
  4822. }
  4823. IFileDescriptor *getFileDescriptor(const char *clustername)
  4824. {
  4825. CriticalBlock block (sect);
  4826. if (subfiles.ordinality()==1)
  4827. return subfiles.item(0).getFileDescriptor(clustername);
  4828. // superfiles assume consistant replication & compression
  4829. UnsignedArray subcounts;
  4830. bool mixedwidth = false;
  4831. unsigned width = 0;
  4832. bool first = true;
  4833. Owned<IPropertyTree> at = getEmptyAttr();
  4834. Owned<IDistributedFileIterator> fiter = getSubFileIterator(true);
  4835. ForEach(*fiter)
  4836. {
  4837. IDistributedFile &file = fiter->query();
  4838. if (first)
  4839. {
  4840. first = false;
  4841. Owned<IAttributeIterator> ait = file.queryAttributes().getAttributes();
  4842. ForEach(*ait)
  4843. {
  4844. const char *name = ait->queryName();
  4845. if ((stricmp(name,"@size")!=0)&&(stricmp(name,"@recordCount")!=0))
  4846. {
  4847. const char *v = ait->queryValue();
  4848. if (!v)
  4849. continue;
  4850. bool ok = true;
  4851. // add attributes that are common
  4852. for (unsigned i=1;i<subfiles.ordinality();i++)
  4853. {
  4854. IDistributedFile &file = subfiles.item(i);
  4855. IDistributedSuperFile *sFile = file.querySuperFile();
  4856. if (!sFile || sFile->numSubFiles(true)) // skip empty super files
  4857. {
  4858. const char *p = file.queryAttributes().queryProp(name);
  4859. if (!p||(strcmp(p,v)!=0))
  4860. {
  4861. ok = false;
  4862. break;
  4863. }
  4864. }
  4865. }
  4866. if (ok)
  4867. at->setProp(name,v);
  4868. }
  4869. }
  4870. }
  4871. unsigned np = file.numParts();
  4872. if (0 == width)
  4873. width = np;
  4874. else if (np!=width)
  4875. mixedwidth = true;
  4876. subcounts.append(np);
  4877. }
  4878. // need common attributes
  4879. Owned<ISuperFileDescriptor> fdesc=createSuperFileDescriptor(at.getClear());
  4880. if (interleaved&&(interleaved!=2))
  4881. WARNLOG("getFileDescriptor: Unsupported interleave value (1)");
  4882. fdesc->setSubMapping(subcounts,interleaved!=0);
  4883. fdesc->setTraceName(logicalName.get());
  4884. Owned<IDistributedFilePartIterator> iter = getIterator(NULL);
  4885. unsigned n = 0;
  4886. SocketEndpointArray reps;
  4887. ForEach(*iter) {
  4888. IDistributedFilePart &part = iter->query();
  4889. CDistributedFilePart *cpart = (clustername&&*clustername)?QUERYINTERFACE(&part,CDistributedFilePart):NULL;
  4890. unsigned copy = 0;
  4891. if (cpart) {
  4892. IDistributedFile &f = cpart->queryParent();
  4893. unsigned cn = f.findCluster(clustername);
  4894. if (cn!=NotFound) {
  4895. for (unsigned i = 0;i<cpart->numCopies();i++)
  4896. if (cpart->copyClusterNum(i,NULL)==cn) {
  4897. copy = i;
  4898. break;
  4899. }
  4900. }
  4901. }
  4902. if (mixedwidth) {
  4903. SocketEndpoint rep;
  4904. if (copy+1<part.numCopies())
  4905. rep = part.queryNode(copy+1)->endpoint();
  4906. reps.append(rep);
  4907. }
  4908. RemoteFilename rfn;
  4909. fdesc->setPart(n,part.getFilename(rfn,copy),&part.queryAttributes());
  4910. n++;
  4911. }
  4912. ClusterPartDiskMapSpec mspec;
  4913. if (subfiles.ordinality()) {
  4914. mspec = subfiles.item(0).queryPartDiskMapping(0);
  4915. }
  4916. mspec.interleave = numSubFiles(true);
  4917. fdesc->endCluster(mspec);
  4918. if (mixedwidth) { // bleah - have to add replicate node numbers
  4919. Owned<IGroup> group = fdesc->getGroup();
  4920. unsigned gw = group->ordinality();
  4921. for (unsigned pn=0;pn<reps.ordinality();pn++) {
  4922. const SocketEndpoint &ep=reps.item(pn);
  4923. if (!ep.isNull()) {
  4924. unsigned gn = pn;
  4925. if (gn<gw) {
  4926. do {
  4927. gn++;
  4928. if (gn==gw)
  4929. gn = 0;
  4930. if (ep.equals(group->queryNode((rank_t)gn).endpoint())) {
  4931. IPartDescriptor *part = fdesc->queryPart(pn);
  4932. if (part)
  4933. part->queryProperties().setPropInt("@rn",(unsigned)gn);
  4934. break;
  4935. }
  4936. } while (gn!=pn);
  4937. }
  4938. }
  4939. }
  4940. }
  4941. return fdesc.getClear();
  4942. }
  4943. unsigned numParts()
  4944. {
  4945. CriticalBlock block(sect);
  4946. unsigned ret=0;
  4947. ForEachItemIn(i,subfiles)
  4948. ret += subfiles.item(i).numParts();
  4949. return ret;
  4950. }
  4951. IDistributedFilePart &queryPart(unsigned idx)
  4952. {
  4953. CriticalBlock block(sect);
  4954. if (subfiles.ordinality()==1)
  4955. return subfiles.item(0).queryPart(idx);
  4956. if (partscache.ordinality()==0)
  4957. loadParts(partscache,NULL);
  4958. if (idx>=partscache.ordinality())
  4959. return *(IDistributedFilePart *)NULL;
  4960. return partscache.item(idx);
  4961. }
  4962. IDistributedFilePart* getPart(unsigned idx)
  4963. {
  4964. IDistributedFilePart* ret = &queryPart(idx);
  4965. return LINK(ret);
  4966. }
  4967. IDistributedFilePartIterator *getIterator(IDFPartFilter *filter=NULL)
  4968. {
  4969. CriticalBlock block(sect);
  4970. if (subfiles.ordinality()==1)
  4971. return subfiles.item(0).getIterator(filter);
  4972. CDistributedFilePartIterator *ret = new CDistributedFilePartIterator();
  4973. loadParts(ret->queryParts(),filter);
  4974. return ret;
  4975. }
  4976. void rename(const char *_logicalname,IUserDescriptor *user)
  4977. {
  4978. StringBuffer prevname;
  4979. Owned<IFileRelationshipIterator> reliter;
  4980. // set prevname
  4981. if (!isAnon()) {
  4982. getLogicalName(prevname);
  4983. try {
  4984. IFileRelationshipIterator *iter = parent->lookupAllFileRelationships(prevname.str());
  4985. reliter.setown(iter);
  4986. }
  4987. catch (IException *e) {
  4988. EXCLOG(e,"CDistributedFileDirectory::rename");
  4989. e->Release();
  4990. }
  4991. detach();
  4992. }
  4993. attach(_logicalname,user);
  4994. if (reliter.get()) {
  4995. // add back any relationships with new name
  4996. parent->renameFileRelationships(prevname.str(),_logicalname,reliter,user);
  4997. }
  4998. }
  4999. const char *queryDefaultDir()
  5000. {
  5001. // returns the directory if all the same
  5002. const char *ret = NULL;
  5003. CriticalBlock block (sect);
  5004. ForEachItemIn(i,subfiles) {
  5005. if (subfiles.item(i).numParts())
  5006. {
  5007. const char *s = subfiles.item(i).queryDefaultDir();
  5008. if (!s)
  5009. return NULL;
  5010. if (!ret)
  5011. ret = s;
  5012. else if (strcmp(ret,s)!=0)
  5013. return NULL;
  5014. }
  5015. }
  5016. return ret;
  5017. }
  5018. const char *queryPartMask()
  5019. {
  5020. // returns the part mask if all the same
  5021. const char *ret = NULL;
  5022. CriticalBlock block (sect);
  5023. ForEachItemIn(i,subfiles) {
  5024. const char *s = subfiles.item(i).queryPartMask();
  5025. if (!s)
  5026. return NULL;
  5027. if (!ret)
  5028. ret = s;
  5029. else if (stricmp(ret,s)!=0)
  5030. return NULL;
  5031. }
  5032. return ret;
  5033. }
  5034. void attach(const char *_logicalname,IUserDescriptor *user)
  5035. {
  5036. assertex(!conn.get()); // already attached
  5037. CriticalBlock block (sect);
  5038. StringBuffer tail;
  5039. StringBuffer lfn;
  5040. logicalName.set(_logicalname);
  5041. checkLogicalName(logicalName,user,true,true,false,"attach");
  5042. parent->addEntry(logicalName,root.getClear(),true,false);
  5043. conn.clear();
  5044. CFileLock fcl;
  5045. verifyex(fcl.init(logicalName, DXB_SuperFile, RTM_LOCK_READ, defaultTimeout, "CDistributedSuperFile::attach"));
  5046. conn.setown(fcl.detach());
  5047. assertex(conn.get()); // must have been attached
  5048. root.setown(conn->getRoot());
  5049. }
  5050. void detach(unsigned timeoutMs=INFINITE)
  5051. {
  5052. assertex(conn.get()); // must be attached
  5053. CriticalBlock block(sect);
  5054. checkModify("CDistributedSuperFile::detach");
  5055. subfiles.kill();
  5056. // Remove from SDS
  5057. /* JCSMORE - this looks very kludgy...
  5058. * We have readlock, this code is doing
  5059. * 1) change to write lock (not using lockProperties or DistributedFilePropertyLock to do so) [using CFileChangeWriteLock]
  5060. * CFileChangeWriteLock doesn't preserve lock mode quite right.. (see 'newMode')
  5061. * 2) manually deleting SuperOwner from subfiles (in clearSuperOwners)
  5062. * 3) Using the connection to delete the SuperFile from Dali (clones to 'root' in process)
  5063. * 4) ~CFileChangeWriteLock() [writeLock.clear()], restores read lock from write to read
  5064. * 5) updateFS (housekeeping of empty scopes, relationships) - ok
  5065. */
  5066. CFileChangeWriteLock writeLock(conn, timeoutMs);
  5067. clearSuperOwners(timeoutMs);
  5068. writeLock.clear();
  5069. root.setown(closeConnection(true));
  5070. updateFS(logicalName, timeoutMs);
  5071. logicalName.clear();
  5072. }
  5073. bool existsPhysicalPartFiles(unsigned short port)
  5074. {
  5075. CriticalBlock block (sect);
  5076. ForEachItemIn(i,subfiles) {
  5077. IDistributedFile &f=subfiles.item(i);
  5078. if (!f.existsPhysicalPartFiles(port))
  5079. return false;
  5080. }
  5081. return true;
  5082. }
  5083. bool renamePhysicalPartFiles(const char *newlfn,const char *cluster,IMultiException *mexcept,const char *newbasedir)
  5084. {
  5085. throw MakeStringException(-1,"renamePhysicalPartFiles not supported for SuperFiles");
  5086. return false;
  5087. }
  5088. void serialize(MemoryBuffer &mb)
  5089. {
  5090. UNIMPLEMENTED; // not yet needed
  5091. }
  5092. virtual unsigned numCopies(unsigned partno)
  5093. {
  5094. unsigned ret = (unsigned)-1;
  5095. CriticalBlock block (sect);
  5096. ForEachItemIn(i,subfiles) {
  5097. IDistributedFile &f=subfiles.item(i);
  5098. unsigned fnc = f.numCopies(partno);
  5099. if (fnc<ret)
  5100. ret = fnc;
  5101. }
  5102. return (ret==(unsigned)-1)?1:ret;
  5103. }
  5104. __int64 getFileSize(bool allowphysical,bool forcephysical)
  5105. {
  5106. __int64 ret = (__int64)(forcephysical?-1:queryAttributes().getPropInt64("@size",-1));
  5107. if (ret==-1)
  5108. {
  5109. ret = 0;
  5110. ForEachItemIn(i,subfiles)
  5111. {
  5112. __int64 ps = subfiles.item(i).getFileSize(allowphysical,forcephysical);
  5113. if (ps == -1)
  5114. return -1; // i.e. if cannot determine size of any part, total is unknown
  5115. ret += ps;
  5116. }
  5117. }
  5118. return ret;
  5119. }
  5120. __int64 getDiskSize(bool allowphysical,bool forcephysical)
  5121. {
  5122. if (!isCompressed(NULL))
  5123. return getFileSize(allowphysical, forcephysical);
  5124. __int64 ret = (__int64)(forcephysical?-1:queryAttributes().getPropInt64("@compressedSize",-1));
  5125. if (ret==-1)
  5126. {
  5127. ret = 0;
  5128. ForEachItemIn(i,subfiles)
  5129. {
  5130. __int64 ps = subfiles.item(i).getDiskSize(allowphysical,forcephysical);
  5131. if (ps == -1)
  5132. return -1; // i.e. if cannot determine size of any part, total is unknown
  5133. ret += ps;
  5134. }
  5135. }
  5136. return ret;
  5137. }
  5138. __int64 getRecordCount()
  5139. {
  5140. __int64 ret = queryAttributes().getPropInt64("@recordCount",-1);
  5141. if (ret==-1) {
  5142. ret = 0;
  5143. ForEachItemIn(i,subfiles) {
  5144. __int64 rc = subfiles.item(i).queryAttributes().getPropInt64("@recordCount",-1);
  5145. if (rc == -1) {
  5146. ret = rc;
  5147. break;
  5148. }
  5149. ret += rc;
  5150. }
  5151. }
  5152. return ret;
  5153. }
  5154. bool getFileCheckSum(unsigned &checkSum)
  5155. {
  5156. if (queryAttributes().hasProp("@checkSum"))
  5157. checkSum = (unsigned)queryAttributes().getPropInt64("@checkSum");
  5158. else
  5159. {
  5160. checkSum = ~0;
  5161. ForEachItemIn(i,subfiles) {
  5162. unsigned cs;
  5163. if (!subfiles.item(i).getFileCheckSum(cs))
  5164. return false;
  5165. checkSum ^= cs;
  5166. }
  5167. }
  5168. return true;
  5169. }
  5170. IDistributedSuperFile *querySuperFile()
  5171. {
  5172. return this;
  5173. }
  5174. virtual IDistributedFile &querySubFile(unsigned idx,bool sub)
  5175. {
  5176. CriticalBlock block (sect);
  5177. if (sub) {
  5178. ForEachItemIn(i,subfiles) {
  5179. IDistributedFile &f=subfiles.item(i);
  5180. IDistributedSuperFile *super = f.querySuperFile();
  5181. if (super) {
  5182. unsigned ns = super->numSubFiles(true);
  5183. if (ns>idx)
  5184. return super->querySubFile(idx,true);
  5185. idx -= ns;
  5186. }
  5187. else if (idx--==0)
  5188. return f;
  5189. }
  5190. // fall through to error
  5191. }
  5192. return subfiles.item(idx);
  5193. }
  5194. virtual IDistributedFile *querySubFileNamed(const char *name, bool sub)
  5195. {
  5196. CriticalBlock block (sect);
  5197. unsigned idx=findSubFileOrd(name);
  5198. if ((idx!=NotFound)&&(idx<subfiles.ordinality()))
  5199. return &subfiles.item(idx);
  5200. idx=findSubFile(name);
  5201. if (idx!=NotFound)
  5202. return &subfiles.item(idx);
  5203. if (sub) {
  5204. ForEachItemIn(i,subfiles) {
  5205. IDistributedFile &f=subfiles.item(i);
  5206. IDistributedSuperFile *super = f.querySuperFile();
  5207. if (super) {
  5208. IDistributedFile *ret = super->querySubFileNamed(name);
  5209. if (ret)
  5210. return ret;
  5211. }
  5212. }
  5213. }
  5214. return NULL;
  5215. }
  5216. virtual IDistributedFile *getSubFile(unsigned idx,bool sub)
  5217. {
  5218. CriticalBlock block (sect);
  5219. return LINK(&querySubFile(idx,sub));
  5220. }
  5221. virtual unsigned numSubFiles(bool sub)
  5222. {
  5223. CriticalBlock block (sect);
  5224. unsigned ret = 0;
  5225. if (sub) {
  5226. ForEachItemIn(i,subfiles) {
  5227. IDistributedFile &f=subfiles.item(i);
  5228. IDistributedSuperFile *super = f.querySuperFile();
  5229. if (super)
  5230. ret += super->numSubFiles();
  5231. else
  5232. ret++;
  5233. }
  5234. }
  5235. else
  5236. ret = subfiles.ordinality();
  5237. return ret;
  5238. }
  5239. virtual bool getFormatCrc(unsigned &crc)
  5240. {
  5241. if (queryAttributes().hasProp("@formatCrc")) {
  5242. crc = (unsigned)queryAttributes().getPropInt("@formatCrc");
  5243. return true;
  5244. }
  5245. bool found = false;
  5246. ForEachItemIn(i,subfiles) {
  5247. unsigned c;
  5248. if (subfiles.item(i).getFormatCrc(c)) {
  5249. if (found&&(c!=crc))
  5250. return false;
  5251. found = true;
  5252. crc = c;
  5253. }
  5254. }
  5255. return found;
  5256. }
  5257. virtual bool getRecordLayout(MemoryBuffer &layout)
  5258. {
  5259. layout.clear();
  5260. if (queryAttributes().getPropBin("_record_layout",layout))
  5261. return true;
  5262. bool found = false;
  5263. ForEachItemIn(i,subfiles) {
  5264. MemoryBuffer b;
  5265. if (subfiles.item(i).getRecordLayout(found?b:layout)) {
  5266. if (found) {
  5267. if ((b.length()!=layout.length())||(memcmp(b.bufferBase(),layout.bufferBase(),b.length())!=0))
  5268. return false;
  5269. }
  5270. else
  5271. found = true;
  5272. }
  5273. }
  5274. return found;
  5275. }
  5276. virtual bool getRecordSize(size32_t &rsz)
  5277. {
  5278. if (queryAttributes().hasProp("@recordSize")) {
  5279. rsz = (size32_t)queryAttributes().getPropInt("@recordSize");
  5280. return true;
  5281. }
  5282. bool found = false;
  5283. ForEachItemIn(i,subfiles) {
  5284. size32_t sz;
  5285. if (subfiles.item(i).getRecordSize(sz)) {
  5286. if (found&&(sz!=rsz))
  5287. return false;
  5288. found = true;
  5289. rsz = sz;
  5290. }
  5291. }
  5292. return found;
  5293. }
  5294. virtual bool isInterleaved()
  5295. {
  5296. return interleaved!=0;
  5297. }
  5298. virtual IDistributedFile *querySubPart(unsigned partidx,unsigned &subfileidx)
  5299. {
  5300. CriticalBlock block (sect);
  5301. subfileidx = 0;
  5302. Owned<IDistributedFilePart> part = getPart(partidx);
  5303. if (!part)
  5304. return NULL;
  5305. CDistributedFilePart *cpart = QUERYINTERFACE(part.get(),CDistributedFilePart);
  5306. if (!cpart)
  5307. return NULL;
  5308. IDistributedFile &ret = cpart->queryParent();
  5309. unsigned n = ret.numParts();
  5310. for (unsigned i=0;i<n;i++) {
  5311. Owned<IDistributedFilePart> spart = ret.getPart(i);
  5312. if (spart.get()==part.get()) {
  5313. subfileidx = i;
  5314. return &ret;
  5315. }
  5316. }
  5317. return NULL;
  5318. }
  5319. virtual unsigned getPositionPart(offset_t pos, offset_t &base)
  5320. { // not very quick!
  5321. CriticalBlock block (sect);
  5322. unsigned n = numParts();
  5323. base = 0;
  5324. for (unsigned i=0;i<n;i++) {
  5325. Owned<IDistributedFilePart> part = getPart(i);
  5326. offset_t ps = part->getFileSize(true,false);
  5327. if (ps==(offset_t)-1)
  5328. break;
  5329. if (ps>pos)
  5330. return i;
  5331. pos -= ps;
  5332. base += ps;
  5333. }
  5334. return NotFound;
  5335. }
  5336. IDistributedFileIterator *getSubFileIterator(bool supersub=false)
  5337. {
  5338. CriticalBlock block (sect);
  5339. return new cSubFileIterator(subfiles,supersub);
  5340. }
  5341. void updateFileAttrs()
  5342. {
  5343. if (subfiles.ordinality()==0) {
  5344. StringBuffer desc;
  5345. root->getProp("Attr/@description",desc);
  5346. root->removeProp("Attr"); // remove all other attributes if superfile empty
  5347. IPropertyTree *t=resetFileAttr(getEmptyAttr());
  5348. if (desc.length())
  5349. t->setProp("@description",desc.str());
  5350. return;
  5351. }
  5352. root->removeProp("Attr/@size");
  5353. root->removeProp("Attr/@compressedSize");
  5354. root->removeProp("Attr/@checkSum");
  5355. root->removeProp("Attr/@recordCount"); // recordCount not currently supported by superfiles
  5356. root->removeProp("Attr/@formatCrc"); // formatCrc set if all consistant
  5357. root->removeProp("Attr/@recordSize"); // record size set if all consistant
  5358. root->removeProp("Attr/_record_layout");
  5359. __int64 fs = getFileSize(false,false);
  5360. if (fs!=-1)
  5361. root->setPropInt64("Attr/@size",fs);
  5362. if (isCompressed(NULL))
  5363. {
  5364. fs = getDiskSize(false,false);
  5365. if (fs!=-1)
  5366. root->setPropInt64("Attr/@compressedSize",fs);
  5367. }
  5368. unsigned checkSum;
  5369. if (getFileCheckSum(checkSum))
  5370. root->setPropInt64("Attr/@checkSum", checkSum);
  5371. __int64 rc = getRecordCount();
  5372. if (rc!=-1)
  5373. root->setPropInt64("Attr/@recordCount",rc);
  5374. unsigned fcrc;
  5375. if (getFormatCrc(fcrc))
  5376. root->setPropInt("Attr/@formatCrc", fcrc);
  5377. size32_t rsz;
  5378. if (getRecordSize(rsz))
  5379. root->setPropInt("Attr/@recordSize", rsz);
  5380. MemoryBuffer mb;
  5381. if (getRecordLayout(mb))
  5382. root->setPropBin("Attr/_record_layout", mb.length(), mb.bufferBase());
  5383. }
  5384. void updateParentFileAttrs(IDistributedFileTransaction *transaction)
  5385. {
  5386. Owned<IPropertyTreeIterator> iter = root->getElements("SuperOwner");
  5387. StringBuffer pname;
  5388. ForEach(*iter) {
  5389. iter->query().getProp("@name",pname.clear());
  5390. Owned<IDistributedSuperFile> psfile = transaction?transaction->lookupSuperFile(pname.str()):
  5391. queryDistributedFileDirectory().lookupSuperFile(pname.str(),udesc,NULL);
  5392. CDistributedSuperFile *file = QUERYINTERFACE(psfile.get(),CDistributedSuperFile);
  5393. if (file) {
  5394. {
  5395. DistributedFilePropertyLock lock(file);
  5396. file->setModified();
  5397. file->updateFileAttrs();
  5398. }
  5399. file->updateParentFileAttrs(transaction);
  5400. }
  5401. }
  5402. }
  5403. void validateAddSubFile(IDistributedFile *sub)
  5404. {
  5405. if (strcmp(sub->queryLogicalName(),queryLogicalName())==0)
  5406. throw MakeStringException(-1,"addSubFile: Cannot add file %s to itself", queryLogicalName());
  5407. if (subfiles.ordinality())
  5408. checkFormatAttr(sub,"addSubFile");
  5409. if (NotFound!=findSubFile(sub->queryLogicalName()))
  5410. throw MakeStringException(-1,"addSubFile: File %s is already a subfile of %s", sub->queryLogicalName(),queryLogicalName());
  5411. }
  5412. private:
  5413. void doAddSubFile(IDistributedFile *_sub,bool before,const char *other,IDistributedFileTransactionExt *transaction) // takes ownership of sub
  5414. {
  5415. Owned<IDistributedFile> sub = _sub;
  5416. validateAddSubFile(sub); // shouldn't really be necessary, was validated in transaction before here
  5417. unsigned pos;
  5418. if (other&&*other) {
  5419. pos = findSubFileOrd(other);
  5420. if (pos==NotFound)
  5421. pos = findSubFile(other);
  5422. if (pos==NotFound)
  5423. pos = before?0:subfiles.ordinality();
  5424. else if (!before&&(pos<subfiles.ordinality()))
  5425. pos++;
  5426. }
  5427. else
  5428. pos = before?0:subfiles.ordinality();
  5429. if (pos > subfiles.ordinality())
  5430. throw MakeStringException(-1,"addSubFile: Insert position %d out of range for file %s in superfile %s", pos+1, sub->queryLogicalName(), queryLogicalName());
  5431. addItem(pos,sub.getClear()); // remove if failure TBD?
  5432. setModified();
  5433. updateFileAttrs();
  5434. linkSubFile(pos);
  5435. }
  5436. bool doRemoveSubFiles(IDistributedFileTransactionExt *transaction)
  5437. {
  5438. // have to be quite careful here
  5439. unsigned pos = subfiles.ordinality();
  5440. if (pos)
  5441. {
  5442. DistributedFilePropertyLock lock(this);
  5443. if (lock.needsReload())
  5444. loadSubFiles(transaction,1000*60*10);
  5445. pos = subfiles.ordinality();
  5446. if (pos)
  5447. {
  5448. do
  5449. {
  5450. pos--;
  5451. unlinkSubFile(pos);
  5452. removeItem(pos);
  5453. } while (pos);
  5454. setModified();
  5455. updateFileAttrs();
  5456. lock.unlock();
  5457. updateParentFileAttrs(transaction);
  5458. }
  5459. }
  5460. return true;
  5461. }
  5462. bool doRemoveSubFile(const char *subfile,
  5463. IDistributedFileTransactionExt *transaction)
  5464. {
  5465. // have to be quite careful here
  5466. unsigned pos=findSubFileOrd(subfile);
  5467. if ((pos==NotFound)||(pos>=subfiles.ordinality()))
  5468. pos = findSubFile(subfile);
  5469. if (pos==NotFound)
  5470. return false;
  5471. {
  5472. DistributedFilePropertyLock lock(this);
  5473. // don't reload subfiles here
  5474. pos=findSubFileOrd(subfile);
  5475. if ((pos==NotFound)||(pos>=subfiles.ordinality()))
  5476. pos = findSubFile(subfile);
  5477. if (pos==NotFound)
  5478. return false;
  5479. unlinkSubFile(pos);
  5480. removeItem(pos);
  5481. setModified();
  5482. updateFileAttrs();
  5483. }
  5484. updateParentFileAttrs(transaction);
  5485. return true;
  5486. }
  5487. bool doSwapSuperFile(IDistributedSuperFile *_file,
  5488. IDistributedFileTransactionExt *transaction)
  5489. {
  5490. assertex(transaction);
  5491. CDistributedSuperFile *file = QUERYINTERFACE(_file,CDistributedSuperFile);
  5492. if (!file)
  5493. return false;
  5494. // Cache names (so we can delete without problems)
  5495. StringArray subnames1;
  5496. StringArray subnames2;
  5497. for (unsigned i=0; i<this->numSubFiles(false); i++)
  5498. subnames1.append(querySubFile(i, false).queryLogicalName());
  5499. for (unsigned i=0; i<file->numSubFiles(false); i++)
  5500. subnames2.append(file->querySubFile(i, false).queryLogicalName());
  5501. // Delete all files
  5502. ForEachItemIn(d1,subnames1) {
  5503. Owned<IDistributedFile> sub = transaction->lookupFile(subnames1.item(d1));
  5504. if (!doRemoveSubFile(sub->queryLogicalName(), transaction))
  5505. return false;
  5506. }
  5507. ForEachItemIn(d2,subnames2) {
  5508. Owned<IDistributedFile> sub = transaction->lookupFile(subnames2.item(d2));
  5509. if (!file->doRemoveSubFile(sub->queryLogicalName(), transaction))
  5510. return false;
  5511. }
  5512. // Add files swapped
  5513. ForEachItemIn(a1,subnames1) {
  5514. Owned<IDistributedFile> sub = transaction->lookupFile(subnames1.item(a1));
  5515. file->doAddSubFile(LINK(sub), false, NULL, transaction);
  5516. }
  5517. ForEachItemIn(a2,subnames2) {
  5518. Owned<IDistributedFile> sub = transaction->lookupFile(subnames2.item(a2));
  5519. doAddSubFile(LINK(sub), false, NULL, transaction);
  5520. }
  5521. return true;
  5522. }
  5523. public:
  5524. void addSubFile(const char * subfile,
  5525. bool before=false, // if true before other
  5526. const char *other=NULL, // in NULL add at end (before=false) or start(before=true)
  5527. bool addcontents=false,
  5528. IDistributedFileTransaction *transaction=NULL
  5529. )
  5530. {
  5531. CriticalBlock block (sect);
  5532. if (!subfile||!*subfile)
  5533. return;
  5534. checkModify("addSubFile");
  5535. partscache.kill();
  5536. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  5537. Linked<IDistributedFileTransactionExt> localtrans;
  5538. if (transaction)
  5539. {
  5540. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  5541. localtrans.set(_transaction);
  5542. }
  5543. else
  5544. localtrans.setown(new CDistributedFileTransaction(udesc, this));
  5545. localtrans->ensureFile(this);
  5546. if (addcontents)
  5547. {
  5548. localtrans->descend();
  5549. StringArray subs;
  5550. Owned<IDistributedSuperFile> sfile = localtrans->lookupSuperFile(subfile);
  5551. if (sfile)
  5552. {
  5553. Owned<IDistributedFileIterator> iter = sfile->getSubFileIterator();
  5554. ForEach(*iter)
  5555. subs.append(iter->query().queryLogicalName());
  5556. }
  5557. sfile.clear();
  5558. ForEachItemIn(i,subs)
  5559. addSubFile(subs.item(i),before,other,false,localtrans);
  5560. localtrans->ascend();
  5561. }
  5562. else
  5563. {
  5564. cAddSubFileAction *action = new cAddSubFileAction(queryLogicalName(),subfile,before,other);
  5565. localtrans->addAction(action); // takes ownership
  5566. }
  5567. localtrans->autoCommit();
  5568. }
  5569. virtual bool removeSubFile(const char *subfile, // if NULL removes all
  5570. bool remsub, // if true removes subfiles from DFS
  5571. bool remcontents, // if true, recurse super-files
  5572. IDistributedFileTransaction *transaction)
  5573. {
  5574. CriticalBlock block (sect);
  5575. if (subfile&&!*subfile)
  5576. return false;
  5577. checkModify("removeSubFile");
  5578. partscache.kill();
  5579. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  5580. Linked<IDistributedFileTransactionExt> localtrans;
  5581. if (transaction)
  5582. {
  5583. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  5584. localtrans.set(_transaction);
  5585. }
  5586. else
  5587. localtrans.setown(new CDistributedFileTransaction(udesc, this));
  5588. // Make sure this file is in cache (reuse below)
  5589. localtrans->ensureFile(this);
  5590. // If recurring, traverse super-file subs (if super)
  5591. if (remcontents)
  5592. {
  5593. localtrans->descend();
  5594. CDfsLogicalFileName logicalname;
  5595. logicalname.set(subfile);
  5596. IDistributedFile *sub = querySubFileNamed(logicalname.get(),false);
  5597. if (!sub)
  5598. return false;
  5599. IDistributedSuperFile *sfile = sub->querySuperFile();
  5600. if (sfile)
  5601. {
  5602. Owned<IDistributedFileIterator> iter = sfile->getSubFileIterator(true);
  5603. bool ret = true;
  5604. StringArray toremove;
  5605. ForEach(*iter)
  5606. toremove.append(iter->query().queryLogicalName());
  5607. iter.clear();
  5608. ForEachItemIn(i,toremove)
  5609. {
  5610. if (!sfile->removeSubFile(toremove.item(i),remsub,false,localtrans))
  5611. ret = false;
  5612. }
  5613. if (!ret||!remsub)
  5614. return ret;
  5615. }
  5616. localtrans->ascend();
  5617. }
  5618. cRemoveSubFileAction *action = new cRemoveSubFileAction(queryLogicalName(),subfile,remsub);
  5619. localtrans->addAction(action); // takes ownership
  5620. localtrans->autoCommit();
  5621. // MORE - auto-commit will throw an exception, change this to void
  5622. return true;
  5623. }
  5624. virtual bool removeOwnedSubFiles(bool remsub, // if true removes subfiles from DFS
  5625. IDistributedFileTransaction *transaction)
  5626. {
  5627. CriticalBlock block (sect);
  5628. checkModify("removeOwnedSubFiles");
  5629. partscache.kill();
  5630. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  5631. Linked<IDistributedFileTransactionExt> localtrans;
  5632. if (transaction)
  5633. {
  5634. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  5635. localtrans.set(_transaction);
  5636. }
  5637. else
  5638. localtrans.setown(new CDistributedFileTransaction(udesc, this));
  5639. // Make sure this file is in cache (reuse below)
  5640. localtrans->addFile(this);
  5641. cRemoveOwnedSubFilesAction *action = new cRemoveOwnedSubFilesAction(localtrans, queryLogicalName(), remsub);
  5642. localtrans->addAction(action); // takes ownership
  5643. localtrans->autoCommit();
  5644. // MORE - auto-commit will throw an exception, change this to void
  5645. return true;
  5646. }
  5647. virtual bool swapSuperFile( IDistributedSuperFile *_file,
  5648. IDistributedFileTransaction *transaction)
  5649. {
  5650. CriticalBlock block (sect);
  5651. if (!_file)
  5652. return false;
  5653. checkModify("swapSuperFile");
  5654. partscache.kill();
  5655. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  5656. Linked<IDistributedFileTransactionExt> localtrans;
  5657. if (transaction)
  5658. {
  5659. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  5660. localtrans.set(_transaction);
  5661. }
  5662. else
  5663. localtrans.setown(new CDistributedFileTransaction(udesc, this));
  5664. // Make sure this file is in cache
  5665. localtrans->ensureFile(this);
  5666. cSwapFileAction *action = new cSwapFileAction(queryLogicalName(),_file->queryLogicalName());
  5667. localtrans->addAction(action); // takes ownership
  5668. localtrans->autoCommit();
  5669. return true;
  5670. }
  5671. void savePartsAttr(bool force)
  5672. {
  5673. }
  5674. void fillClustersCache()
  5675. {
  5676. if (clusterscache.ordinality()==0) {
  5677. StringBuffer name;
  5678. ForEachItemIn(i,subfiles) {
  5679. StringArray clusters;
  5680. IDistributedFile &f=subfiles.item(i);
  5681. unsigned nc = f.numClusters();
  5682. for(unsigned j=0;j<nc;j++) {
  5683. f.getClusterName(j,name.clear());
  5684. if (clusterscache.find(name.str())==NotFound) {
  5685. IClusterInfo &cluster = *createClusterInfo(name.str(),f.queryClusterGroup(j),f.queryPartDiskMapping(j),&queryNamedGroupStore());
  5686. clusterscache.append(cluster);
  5687. }
  5688. }
  5689. }
  5690. }
  5691. }
  5692. unsigned getClusterNames(StringArray &clusters)
  5693. {
  5694. CriticalBlock block (sect);
  5695. fillClustersCache();
  5696. return clusterscache.getNames(clusters);
  5697. }
  5698. unsigned numClusters()
  5699. {
  5700. CriticalBlock block (sect);
  5701. fillClustersCache();
  5702. return clusterscache.ordinality();
  5703. }
  5704. unsigned findCluster(const char *clustername)
  5705. {
  5706. CriticalBlock block (sect);
  5707. fillClustersCache();
  5708. return clusterscache.find(clustername);
  5709. }
  5710. ClusterPartDiskMapSpec &queryPartDiskMapping(unsigned clusternum)
  5711. {
  5712. CriticalBlock block (sect);
  5713. fillClustersCache();
  5714. return clusterscache.queryPartDiskMapping(clusternum);
  5715. }
  5716. void updatePartDiskMapping(const char *clustername,const ClusterPartDiskMapSpec &spec)
  5717. {
  5718. if (!clustername||!*clustername)
  5719. return;
  5720. CriticalBlock block (sect);
  5721. fillClustersCache();
  5722. ForEachItemIn(i,subfiles) {
  5723. IDistributedFile &f=subfiles.item(i);
  5724. f.updatePartDiskMapping(clustername,spec);
  5725. }
  5726. }
  5727. IGroup *queryClusterGroup(unsigned clusternum)
  5728. {
  5729. CriticalBlock block (sect);
  5730. fillClustersCache();
  5731. return clusterscache.queryGroup(clusternum);
  5732. }
  5733. void addCluster(const char *clustername,const ClusterPartDiskMapSpec &mspec)
  5734. {
  5735. if (!clustername||!*clustername)
  5736. return;
  5737. CriticalBlock block (sect);
  5738. clusterscache.clear();
  5739. subfiles.item(0).addCluster(clustername,mspec);
  5740. }
  5741. virtual bool removeCluster(const char *clustername)
  5742. {
  5743. bool clusterRemoved=false;
  5744. CriticalBlock block (sect);
  5745. clusterscache.clear();
  5746. ForEachItemIn(i,subfiles) {
  5747. IDistributedFile &f=subfiles.item(i);
  5748. clusterRemoved |= f.removeCluster(clustername);
  5749. }
  5750. return clusterRemoved;
  5751. }
  5752. void setPreferredClusters(const char *clusters)
  5753. {
  5754. CriticalBlock block (sect);
  5755. clusterscache.clear();
  5756. ForEachItemIn(i,subfiles) {
  5757. IDistributedFile &f=subfiles.item(i);
  5758. f.setPreferredClusters(clusters);
  5759. }
  5760. }
  5761. virtual bool checkClusterCompatible(IFileDescriptor &fdesc, StringBuffer &err)
  5762. {
  5763. CriticalBlock block (sect);
  5764. if (subfiles.ordinality()!=1) {
  5765. err.append("only singleton superfiles allowed");
  5766. return false;
  5767. }
  5768. ForEachItemIn(i,subfiles) {
  5769. IDistributedFile &f=subfiles.item(i);
  5770. if (!f.checkClusterCompatible(fdesc,err))
  5771. return false;
  5772. }
  5773. return true;
  5774. }
  5775. void setSingleClusterOnly()
  5776. {
  5777. CriticalBlock block (sect);
  5778. ForEachItemIn(i,subfiles) {
  5779. IDistributedFile &f=subfiles.item(i);
  5780. f.setSingleClusterOnly();
  5781. }
  5782. }
  5783. void enqueueReplicate()
  5784. {
  5785. CriticalBlock block (sect);
  5786. ForEachItemIn(i,subfiles) {
  5787. IDistributedFile &f=subfiles.item(i);
  5788. f.enqueueReplicate();
  5789. }
  5790. }
  5791. bool getAccessedTime(CDateTime &dt)
  5792. {
  5793. bool set=false;
  5794. CriticalBlock block (sect);
  5795. ForEachItemIn(i,subfiles) {
  5796. IDistributedFile &f=subfiles.item(i);
  5797. if (set)
  5798. set = f.getAccessedTime(dt);
  5799. else {
  5800. CDateTime cmp;
  5801. if (f.getAccessedTime(cmp)) {
  5802. if (cmp.compare(dt)>0)
  5803. dt.set(cmp);
  5804. }
  5805. }
  5806. }
  5807. return false;
  5808. }
  5809. void setAccessedTime(const CDateTime &dt)
  5810. {
  5811. {
  5812. CriticalBlock block (sect);
  5813. ForEachItemIn(i,subfiles) {
  5814. IDistributedFile &f=subfiles.item(i);
  5815. f.setAccessedTime(dt);
  5816. }
  5817. }
  5818. }
  5819. };
  5820. // --------------------------------------------------------
  5821. void CDistributedFileTransaction::validateAddSubFile(IDistributedSuperFile *super, IDistributedFile *sub, const char *subName)
  5822. {
  5823. CTransactionFile *trackedSuper = lookupTrackedFile(super);
  5824. if (!trackedSuper)
  5825. return;
  5826. const char *superName = trackedSuper->queryName();
  5827. if (strcmp(subName, superName)==0)
  5828. throw MakeStringException(-1,"addSubFile: Cannot add file %s to itself", superName);
  5829. if (trackedSuper->numSubFiles())
  5830. {
  5831. CDistributedSuperFile *sf = dynamic_cast<CDistributedSuperFile *>(super);
  5832. sf->checkFormatAttr(sub, "addSubFile");
  5833. if (trackedSuper->find(subName, false))
  5834. throw MakeStringException(-1,"addSubFile: File %s is already a subfile of %s", subName, superName);
  5835. }
  5836. }
  5837. // --------------------------------------------------------
  5838. CDistributedFilePart::CDistributedFilePart(CDistributedFile &_parent,unsigned _part,IPartDescriptor *pd)
  5839. : parent(_parent)
  5840. {
  5841. partIndex = _part;
  5842. dirty = false;
  5843. if (pd) {
  5844. if (pd->isMulti())
  5845. ERRLOG("Multi filenames not supported in Dali DFS Part %d of %s",_part+1,_parent.queryLogicalName());
  5846. overridename.set(pd->queryOverrideName());
  5847. setAttr(*pd->getProperties());
  5848. }
  5849. else
  5850. ERRLOG("CDistributedFilePart::CDistributedFilePart no IPartDescriptor for part");
  5851. }
  5852. void CDistributedFilePart::Link(void) const
  5853. {
  5854. parent.Link();
  5855. CInterface::Link();
  5856. }
  5857. bool CDistributedFilePart::Release(void) const
  5858. {
  5859. parent.Release();
  5860. return CInterface::Release();
  5861. }
  5862. offset_t CDistributedFilePart::getSize(bool checkCompressed)
  5863. {
  5864. offset_t ret = (offset_t)-1;
  5865. StringBuffer firstname;
  5866. bool compressed = ::isCompressed(parent.queryAttributes());
  5867. unsigned nc=parent.numCopies(partIndex);
  5868. for (unsigned copy=0;copy<nc;copy++)
  5869. {
  5870. RemoteFilename rfn;
  5871. try
  5872. {
  5873. Owned<IFile> partfile = createIFile(getFilename(rfn,copy));
  5874. if (checkCompressed && compressed)
  5875. {
  5876. Owned<ICompressedFileIO> compressedIO = createCompressedFileReader(partfile);
  5877. if (compressedIO)
  5878. ret = compressedIO->size();
  5879. }
  5880. else
  5881. ret = partfile->size();
  5882. if (ret!=(offset_t)-1)
  5883. return ret;
  5884. }
  5885. catch (IException *e)
  5886. {
  5887. StringBuffer s("CDistributedFilePart::getSize ");
  5888. rfn.getRemotePath(s);
  5889. EXCLOG(e, s.str());
  5890. e->Release();
  5891. }
  5892. if (copy==0)
  5893. rfn.getRemotePath(firstname);
  5894. }
  5895. throw new CDFS_Exception(DFSERR_CannotFindPartFileSize,firstname.str());;
  5896. }
  5897. StringBuffer & CDistributedFilePart::getPartName(StringBuffer &partname)
  5898. {
  5899. if (!overridename.isEmpty()) {
  5900. if (isSpecialPath(overridename)) {
  5901. // bit of a kludge
  5902. if (isPathSepChar(*overridename)&&partname.length()&&isPathSepChar(partname.charAt(partname.length()-1)))
  5903. partname.setLength(partname.length()-1);
  5904. return partname.append(overridename);
  5905. }
  5906. return partname.append(pathTail(overridename));
  5907. }
  5908. const char *mask=parent.queryPartMask();
  5909. if (!mask||!*mask) {
  5910. const char *err ="CDistributedFilePart::getPartName cannot determine part name (no mask)";
  5911. ERRLOG("%s", err);
  5912. throw MakeStringExceptionDirect(-1, err);
  5913. }
  5914. expandMask(partname,mask,partIndex,parent.numParts());
  5915. return partname;
  5916. }
  5917. unsigned CDistributedFilePart::bestCopyNum(const IpAddress &ip,unsigned rel)
  5918. {
  5919. unsigned n = numCopies();
  5920. unsigned *dist = new unsigned[n];
  5921. unsigned *idx = new unsigned[n];
  5922. for (unsigned c=0;c<n;c++) {
  5923. dist[c] = ip.ipdistance(queryNode(c)->endpoint());
  5924. idx[c] = c;
  5925. }
  5926. if (rel>=n)
  5927. rel = n-1;
  5928. // do bubble sort as not that many!
  5929. for (unsigned i=0; i<n-1; i++)
  5930. for (unsigned j=0; j<n-1-i; j++)
  5931. if (dist[idx[j+1]] < dist[idx[j]]) {
  5932. unsigned t = idx[j];
  5933. idx[j] = idx[j+1];
  5934. idx[j+1] = t;
  5935. }
  5936. unsigned ret = idx[rel];
  5937. delete [] idx;
  5938. delete [] dist;
  5939. return ret;
  5940. }
  5941. unsigned CDistributedFilePart::copyClusterNum(unsigned copy,unsigned *replicate)
  5942. {
  5943. return parent.copyClusterNum(partIndex,copy,replicate);
  5944. }
  5945. StringBuffer &CDistributedFilePart::getPartDirectory(StringBuffer &ret,unsigned copy)
  5946. {
  5947. const char *defdir = parent.queryDefaultDir();
  5948. StringBuffer dir;
  5949. const char *pn;
  5950. if (overridename.isEmpty())
  5951. pn = parent.queryPartMask();
  5952. else {
  5953. pn = overridename.get();
  5954. if (isSpecialPath(pn)) // its a query
  5955. return ret; // ret.append('/'); // not sure if really need '/' here
  5956. }
  5957. if (pn&&*pn) {
  5958. StringBuffer odir;
  5959. splitDirTail(pn,odir);
  5960. if (odir.length()) {
  5961. if (isAbsolutePath(pn))
  5962. dir.append(odir);
  5963. else if (defdir&&*defdir)
  5964. addPathSepChar(dir.append(defdir)).append(odir);
  5965. }
  5966. else
  5967. dir.append(defdir);
  5968. }
  5969. if (dir.length()==0)
  5970. ERRLOG("IDistributedFilePart::getPartDirectory unable to determine part directory");
  5971. else {
  5972. parent.adjustClusterDir(partIndex,copy,dir);
  5973. ret.append(dir);
  5974. }
  5975. return ret;
  5976. }
  5977. unsigned CDistributedFilePart::numCopies()
  5978. {
  5979. return parent.numCopies(partIndex);
  5980. }
  5981. INode *CDistributedFilePart::queryNode(unsigned copy)
  5982. {
  5983. return parent.queryNode(partIndex,copy);
  5984. }
  5985. unsigned CDistributedFilePart::queryDrive(unsigned copy)
  5986. {
  5987. return parent.queryDrive(partIndex,copy,parent.directory);
  5988. }
  5989. bool CDistributedFilePart::isHost(unsigned copy)
  5990. {
  5991. return (queryNode(copy)->isHost());
  5992. }
  5993. IPropertyTree &CDistributedFilePart::queryAttributes()
  5994. {
  5995. CriticalBlock block (sect); // avoid nested blocks
  5996. if (attr)
  5997. return *attr;
  5998. WARNLOG("CDistributedFilePart::queryAttributes missing part attributes");
  5999. attr.setown(getEmptyAttr());
  6000. return *attr;
  6001. }
  6002. RemoteFilename &CDistributedFilePart::getFilename(RemoteFilename &ret,unsigned copy)
  6003. {
  6004. // this is probably not as efficient as could be
  6005. StringBuffer fullpath;
  6006. getPartDirectory(fullpath,copy);
  6007. addPathSepChar(fullpath);
  6008. getPartName(fullpath);
  6009. SocketEndpoint ep;
  6010. INode *node=queryNode(copy);
  6011. if (node)
  6012. ep = node->endpoint();
  6013. ret.setPath(ep,fullpath.str());
  6014. return ret;
  6015. }
  6016. bool CDistributedFilePart::getCrc(unsigned &crc)
  6017. {
  6018. return getCrcFromPartProps(parent.queryAttributes(),queryAttributes(), crc);
  6019. }
  6020. unsigned CDistributedFilePart::getPhysicalCrc()
  6021. {
  6022. StringBuffer firstname;
  6023. unsigned nc=parent.numCopies(partIndex);
  6024. for (unsigned copy=0;copy<nc;copy++) {
  6025. RemoteFilename rfn;
  6026. try {
  6027. Owned<IFile> partfile = createIFile(getFilename(rfn,copy));
  6028. if (partfile&&partfile->exists())
  6029. return partfile->getCRC();
  6030. }
  6031. catch (IException *e)
  6032. {
  6033. StringBuffer s("CDistributedFilePart::getPhysicalCrc ");
  6034. rfn.getRemotePath(s);
  6035. EXCLOG(e, s.str());
  6036. e->Release();
  6037. }
  6038. if (copy==0)
  6039. rfn.getRemotePath(firstname);
  6040. }
  6041. IDFS_Exception *e = new CDFS_Exception(DFSERR_CannotFindPartFileCrc,firstname.str());
  6042. throw e;
  6043. }
  6044. // TODO: Create DistributedFilePropertyLock for parts
  6045. bool CDistributedFilePart::lockProperties(unsigned timeoutms)
  6046. {
  6047. dirty = true;
  6048. return parent.lockProperties(timeoutms);
  6049. }
  6050. // TODO: Create DistributedFilePropertyLock for parts
  6051. void CDistributedFilePart::unlockProperties(DFTransactionState state=TAS_NONE)
  6052. {
  6053. parent.unlockProperties(state);
  6054. }
  6055. offset_t CDistributedFilePart::getFileSize(bool allowphysical,bool forcephysical)
  6056. {
  6057. offset_t ret = (offset_t)((forcephysical&&allowphysical)?-1:queryAttributes().getPropInt64("@size", -1));
  6058. if (allowphysical&&(ret==(offset_t)-1))
  6059. ret = getSize(true);
  6060. return ret;
  6061. }
  6062. offset_t CDistributedFilePart::getDiskSize(bool allowphysical,bool forcephysical)
  6063. {
  6064. if (!::isCompressed(parent.queryAttributes()))
  6065. return getFileSize(allowphysical, forcephysical);
  6066. if (forcephysical && allowphysical)
  6067. return getSize(false); // i.e. only if force, because all compressed should have @compressedSize attribute
  6068. // NB: compressSize is disk size
  6069. return queryAttributes().getPropInt64("@compressedSize", -1);
  6070. }
  6071. bool CDistributedFilePart::getModifiedTime(bool allowphysical,bool forcephysical, CDateTime &dt)
  6072. {
  6073. StringBuffer s;
  6074. if (!forcephysical&&queryAttributes().getProp("@modified", s)) {
  6075. dt.setString(s.str());
  6076. if (!dt.isNull())
  6077. return true;
  6078. }
  6079. if (allowphysical) {
  6080. unsigned nc=parent.numCopies(partIndex);
  6081. for (unsigned copy=0;copy<nc;copy++) {
  6082. RemoteFilename rfn;
  6083. try {
  6084. Owned<IFile> partfile = createIFile(getFilename(rfn,copy));
  6085. if (partfile->getTime(NULL,&dt,NULL))
  6086. return true;
  6087. }
  6088. catch (IException *e)
  6089. {
  6090. StringBuffer s("CDistributedFilePart::getFileTime ");
  6091. rfn.getRemotePath(s);
  6092. EXCLOG(e, s.str());
  6093. e->Release();
  6094. }
  6095. }
  6096. }
  6097. return false;
  6098. }
  6099. unsigned getSuperFileSubs(IDistributedSuperFile *super, IArrayOf<IDistributedFile> &subFiles, bool superSub)
  6100. {
  6101. unsigned numSubs = super->numSubFiles(superSub);
  6102. for (unsigned s=0; s<numSubs; s++)
  6103. {
  6104. IDistributedFile &subFile = super->querySubFile(s, superSub);
  6105. subFiles.append(*LINK(&subFile));
  6106. }
  6107. return numSubs;
  6108. }
  6109. // --------------------------------------------------------
  6110. class CNamedGroupIterator: public CInterface, implements INamedGroupIterator
  6111. {
  6112. Owned<IPropertyTreeIterator> pe;
  6113. Linked<IRemoteConnection> conn;
  6114. Linked<IGroup> matchgroup;
  6115. bool exactmatch;
  6116. bool match();
  6117. public:
  6118. IMPLEMENT_IINTERFACE;
  6119. CNamedGroupIterator(IRemoteConnection *_conn,IGroup *_matchgroup=NULL,bool _exactmatch=false)
  6120. : conn(_conn), matchgroup(_matchgroup)
  6121. {
  6122. exactmatch = _exactmatch;
  6123. if (matchgroup.get()) {
  6124. StringBuffer query;
  6125. query.append("Group[Node/@ip=\"");
  6126. matchgroup->queryNode(0).endpoint().getUrlStr(query);
  6127. query.append("\"]");
  6128. pe.setown(conn->getElements(query.str()));
  6129. }
  6130. else
  6131. pe.setown(conn->queryRoot()->getElements("Group"));
  6132. }
  6133. bool first()
  6134. {
  6135. if (!pe->first())
  6136. return false;
  6137. if (match())
  6138. return true;
  6139. return next();
  6140. }
  6141. bool next()
  6142. {
  6143. while (pe->next())
  6144. if (match())
  6145. return true;
  6146. return false;
  6147. }
  6148. bool isValid()
  6149. {
  6150. return pe->isValid();
  6151. }
  6152. StringBuffer &get(StringBuffer &name)
  6153. {
  6154. pe->query().getProp("@name",name);
  6155. return name;
  6156. }
  6157. StringBuffer &getdir(StringBuffer &dir)
  6158. {
  6159. pe->query().getProp("@dir",dir);
  6160. return dir;
  6161. }
  6162. bool isCluster()
  6163. {
  6164. return pe->query().getPropBool("@cluster");
  6165. }
  6166. };
  6167. // --------------------------------------------------------
  6168. #define GROUP_CACHE_INTERVAL (1000*60)
  6169. #define GROUP_EXCEPTION_CACHE_INTERVAL (1000*60*10)
  6170. static GroupType translateGroupType(const char *groupType)
  6171. {
  6172. if (!groupType)
  6173. return grp_unknown;
  6174. if (strieq(groupType, "Thor"))
  6175. return grp_thor;
  6176. else if (strieq(groupType, "Roxie"))
  6177. return grp_roxie;
  6178. else if (strieq(groupType, "hthor"))
  6179. return grp_hthor;
  6180. else
  6181. return grp_unknown;
  6182. }
  6183. class CNamedGroupCacheEntry: public CInterface
  6184. {
  6185. public:
  6186. Linked<IGroup> group;
  6187. StringAttr name;
  6188. StringAttr groupDir;
  6189. GroupType groupType;
  6190. Linked<IException> exception;
  6191. CNamedGroupCacheEntry(IGroup *_group, const char *_name, const char *_dir, GroupType _groupType)
  6192. : group(_group), name(_name), groupDir(_dir), groupType(_groupType)
  6193. {
  6194. cachedtime = msTick();
  6195. }
  6196. CNamedGroupCacheEntry(IException *_exception, const char *_name)
  6197. : exception(_exception), name(_name), groupType(grp_unknown)
  6198. {
  6199. cachedtime = msTick();
  6200. }
  6201. bool expired(unsigned timeNow)
  6202. {
  6203. if (exception)
  6204. return timeNow-cachedtime > GROUP_EXCEPTION_CACHE_INTERVAL;
  6205. else
  6206. return timeNow-cachedtime > GROUP_CACHE_INTERVAL;
  6207. }
  6208. protected:
  6209. unsigned cachedtime;
  6210. };
  6211. class CNamedGroupStore: public CInterface, implements INamedGroupStore
  6212. {
  6213. CriticalSection cachesect;
  6214. CIArrayOf<CNamedGroupCacheEntry> cache;
  6215. unsigned defaultTimeout;
  6216. unsigned defaultRemoteTimeout;
  6217. public:
  6218. IMPLEMENT_IINTERFACE;
  6219. CNamedGroupStore()
  6220. {
  6221. defaultTimeout = INFINITE;
  6222. defaultRemoteTimeout = FOREIGN_DALI_TIMEOUT;
  6223. }
  6224. IGroup *dolookup(const char *logicalgroupname,IRemoteConnection *conn, StringBuffer *dirret, GroupType &groupType)
  6225. {
  6226. SocketEndpointArray epa;
  6227. StringBuffer gname(logicalgroupname);
  6228. gname.trim();
  6229. if (!gname.length())
  6230. return NULL;
  6231. gname.toLowerCase();
  6232. logicalgroupname = gname.str();
  6233. bool isiprange = (*logicalgroupname!=0);
  6234. for (const char *s1=logicalgroupname;*s1;s1++)
  6235. if (isalpha(*s1)) {
  6236. isiprange = false;
  6237. break;
  6238. }
  6239. if (isiprange) {
  6240. // allow IP or IP list instead of group name
  6241. // I don't think this is a security problem as groups not checked
  6242. // NB ports not allowed here
  6243. char *buf = strdup(logicalgroupname);
  6244. char *s = buf;
  6245. while (*s) {
  6246. char *next = strchr(s,',');
  6247. if (next)
  6248. *next = 0;
  6249. SocketEndpoint ep;
  6250. unsigned n = ep.ipsetrange(s);
  6251. for (unsigned i=0;i<n;i++) {
  6252. if (ep.isNull()) { // failed
  6253. epa.kill();
  6254. break;
  6255. }
  6256. epa.append(ep);
  6257. ep.ipincrement(1);
  6258. }
  6259. if (!next)
  6260. break;
  6261. s = next+1;
  6262. }
  6263. free(buf);
  6264. if (epa.ordinality())
  6265. {
  6266. groupType = grp_unknown;
  6267. return createIGroup(epa);
  6268. }
  6269. }
  6270. StringBuffer range;
  6271. StringBuffer parent;
  6272. if (decodeChildGroupName(gname.str(),parent,range)) {
  6273. gname.clear().append(parent);
  6274. logicalgroupname = gname.str();
  6275. }
  6276. StringAttr groupdir;
  6277. GroupType type;
  6278. bool cached = false;
  6279. unsigned timeNow = msTick();
  6280. {
  6281. CriticalBlock block(cachesect);
  6282. ForEachItemInRev(idx, cache)
  6283. {
  6284. CNamedGroupCacheEntry &entry = cache.item(idx);
  6285. if (entry.expired(timeNow))
  6286. {
  6287. cache.remove(idx);
  6288. }
  6289. else if (strcmp(gname.str(),entry.name.get())==0)
  6290. {
  6291. cached = true;
  6292. if (entry.exception)
  6293. throw LINK(entry.exception);
  6294. if (range.length()==0)
  6295. {
  6296. if (dirret)
  6297. dirret->append(entry.groupDir);
  6298. groupType = entry.groupType;
  6299. return entry.group.getLink();
  6300. }
  6301. // there is a range so copy to epa
  6302. entry.group->getSocketEndpoints(epa);
  6303. groupdir.set(entry.groupDir);
  6304. type = entry.groupType;
  6305. break;
  6306. }
  6307. }
  6308. }
  6309. try
  6310. {
  6311. if ((gname.length()>9)&&(memcmp(logicalgroupname,"foreign::",9)==0))
  6312. {
  6313. StringBuffer eps;
  6314. const char *s = logicalgroupname+9;
  6315. while (*s&&((*s!=':')||(s[1]!=':')))
  6316. eps.append(*(s++));
  6317. if (*s)
  6318. {
  6319. s+=2;
  6320. if (*s)
  6321. {
  6322. Owned<INode> dali = createINode(eps.str());
  6323. if (!dali || !getRemoteGroup(dali, s, defaultRemoteTimeout, groupdir, type, epa))
  6324. {
  6325. if (!cached)
  6326. {
  6327. CriticalBlock block(cachesect);
  6328. cache.append(*new CNamedGroupCacheEntry(NULL, gname, NULL, grp_unknown));
  6329. }
  6330. return NULL;
  6331. }
  6332. }
  6333. }
  6334. }
  6335. else if (epa.ordinality()==0) {
  6336. struct sLock
  6337. {
  6338. sLock() { lock = NULL; };
  6339. ~sLock() { delete lock; };
  6340. CConnectLock *lock;
  6341. } slock;
  6342. if (!conn)
  6343. {
  6344. slock.lock = new CConnectLock("CNamedGroup::lookup", SDS_GROUPSTORE_ROOT, false, false, false, defaultTimeout);
  6345. conn = slock.lock->conn;
  6346. if (!conn)
  6347. {
  6348. if (!cached)
  6349. {
  6350. CriticalBlock block(cachesect);
  6351. cache.append(*new CNamedGroupCacheEntry(NULL, gname, NULL, grp_unknown));
  6352. }
  6353. return NULL;
  6354. }
  6355. }
  6356. Owned<IPropertyTree> pt = getNamedPropTree(conn->queryRoot(),"Group","@name",gname.str(),true);
  6357. if (!pt)
  6358. return NULL;
  6359. type = translateGroupType(pt->queryProp("@kind"));
  6360. groupdir.set(pt->queryProp("@dir"));
  6361. if (groupdir.isEmpty())
  6362. groupdir.set(queryBaseDirectory(type));
  6363. Owned<IPropertyTreeIterator> pe2 = pt->getElements("Node");
  6364. ForEach(*pe2)
  6365. {
  6366. SocketEndpoint ep(pe2->query().queryProp("@ip"));
  6367. epa.append(ep);
  6368. }
  6369. }
  6370. }
  6371. catch (IException *E)
  6372. {
  6373. // cache the exception
  6374. CriticalBlock block(cachesect);
  6375. cache.append(*new CNamedGroupCacheEntry(E, gname));
  6376. throw;
  6377. }
  6378. Owned<IGroup> ret = createIGroup(epa);
  6379. if (!cached)
  6380. {
  6381. CriticalBlock block(cachesect);
  6382. cache.append(*new CNamedGroupCacheEntry(ret, gname, groupdir, type));
  6383. }
  6384. if (range.length())
  6385. {
  6386. SocketEndpointArray epar;
  6387. const char *s = range.str();
  6388. while (*s)
  6389. {
  6390. unsigned start = 0;
  6391. while (isdigit(*s))
  6392. {
  6393. start = start*10+*s-'0';
  6394. s++;
  6395. }
  6396. if (!start)
  6397. break;
  6398. unsigned end;
  6399. if (*s=='-')
  6400. {
  6401. s++;
  6402. end = 0;
  6403. while (isdigit(*s))
  6404. {
  6405. end = end*10+*s-'0';
  6406. s++;
  6407. }
  6408. if (!end)
  6409. end = epa.ordinality();
  6410. }
  6411. else
  6412. end = start;
  6413. if ((start>epa.ordinality())||(end>epa.ordinality()))
  6414. {
  6415. s = range.str();
  6416. break;
  6417. }
  6418. if (*s==',')
  6419. s++;
  6420. unsigned i=start-1;
  6421. do { // allow 400-1 etc
  6422. i++;
  6423. if (i>epa.ordinality())
  6424. i = 1;
  6425. epar.append(epa.item(i-1));
  6426. } while (i!=end);
  6427. }
  6428. if (*s)
  6429. throw MakeStringException(-1,"Invalid group range %s",range.str());
  6430. ret.setown(createIGroup(epar));
  6431. }
  6432. if (dirret)
  6433. dirret->append(groupdir);
  6434. groupType = type;
  6435. return ret.getClear();
  6436. }
  6437. IGroup *lookup(const char *logicalgroupname)
  6438. {
  6439. GroupType dummy;
  6440. return dolookup(logicalgroupname, NULL, NULL, dummy);
  6441. }
  6442. IGroup *lookup(const char *logicalgroupname, StringBuffer &dir, GroupType &groupType)
  6443. {
  6444. return dolookup(logicalgroupname, NULL, &dir, groupType);
  6445. }
  6446. INamedGroupIterator *getIterator()
  6447. {
  6448. CConnectLock connlock("CNamedGroup::getIterator", SDS_GROUPSTORE_ROOT, false, true, false, defaultTimeout);
  6449. return new CNamedGroupIterator(connlock.conn); // links connection
  6450. }
  6451. INamedGroupIterator *getIterator(IGroup *match,bool exact)
  6452. {
  6453. CConnectLock connlock("CNamedGroup::getIterator", SDS_GROUPSTORE_ROOT, false, false, false, defaultTimeout);
  6454. return new CNamedGroupIterator(connlock.conn,match,exact); // links connection
  6455. }
  6456. void doadd(CConnectLock &connlock,const char *name,IGroup *group,bool cluster,const char *dir)
  6457. {
  6458. if (!group)
  6459. return;
  6460. IPropertyTree *val = createPTree("Group");
  6461. val->setProp("@name",name);
  6462. if (cluster)
  6463. val->setPropBool("@cluster", true);
  6464. if (dir)
  6465. val->setProp("@dir",dir);
  6466. INodeIterator &gi = *group->getIterator();
  6467. StringBuffer str;
  6468. ForEach(gi) {
  6469. IPropertyTree *n = createPTree("Node");
  6470. n = val->addPropTree("Node",n);
  6471. gi.query().endpoint().getIpText(str.clear());
  6472. n->setProp("@ip",str.str());
  6473. }
  6474. gi.Release();
  6475. connlock.conn->queryRoot()->addPropTree("Group",val);
  6476. }
  6477. void addUnique(IGroup *group,StringBuffer &lname, const char *dir)
  6478. {
  6479. if (group->ordinality()==1)
  6480. {
  6481. group->getText(lname);
  6482. return;
  6483. }
  6484. CConnectLock connlock("CNamedGroup::addUnique", SDS_GROUPSTORE_ROOT, true, false, false, defaultTimeout);
  6485. StringBuffer name;
  6486. StringBuffer prop;
  6487. unsigned scale = 16;
  6488. loop {
  6489. name.clear();
  6490. if (lname.length()) { // try suggested name
  6491. name.append(lname);
  6492. name.toLowerCase();
  6493. lname.clear();
  6494. }
  6495. else
  6496. name.append("__anon").append(getRandom()%scale);
  6497. prop.clear().appendf("Group[@name=\"%s\"]",name.str());
  6498. if (!connlock.conn->queryRoot()->hasProp(prop.str()))
  6499. break;
  6500. scale*=2;
  6501. }
  6502. doadd(connlock,name.str(),group,false,dir);
  6503. lname.append(name);
  6504. }
  6505. void add(const char *logicalgroupname, IGroup *group, bool cluster, const char *dir, GroupType groupType)
  6506. {
  6507. StringBuffer name(logicalgroupname);
  6508. name.toLowerCase();
  6509. name.trim();
  6510. StringBuffer prop;
  6511. prop.appendf("Group[@name=\"%s\"]",name.str());
  6512. CConnectLock connlock("CNamedGroup::add", SDS_GROUPSTORE_ROOT, true, false, false, defaultTimeout);
  6513. connlock.conn->queryRoot()->removeProp(prop.str());
  6514. doadd(connlock,name.str(),group,cluster,dir);
  6515. {
  6516. CriticalBlock block(cachesect);
  6517. cache.kill();
  6518. if (group)
  6519. cache.append(*new CNamedGroupCacheEntry(group, name.str(), dir, groupType));
  6520. }
  6521. }
  6522. void remove(const char *logicalgroupname)
  6523. {
  6524. add(logicalgroupname, NULL, false, NULL, grp_unknown);
  6525. }
  6526. bool find(IGroup *grp, StringBuffer &gname, bool add)
  6527. {
  6528. // gname on entry is suggested name for add if set
  6529. unsigned n = grp->ordinality();
  6530. if (!grp||!n)
  6531. return false;
  6532. Owned<INamedGroupIterator> iter=getIterator(grp,(n==1)); // one node clusters must be exact match
  6533. StringAttr bestname;
  6534. StringBuffer name;
  6535. ForEach(*iter) {
  6536. bool iscluster = iter->isCluster();
  6537. if (iscluster||(bestname.isEmpty())) {
  6538. iter->get(name.clear());
  6539. if (name.length()) {
  6540. bestname.set(name);
  6541. if (iscluster)
  6542. break;
  6543. }
  6544. }
  6545. }
  6546. iter.clear();
  6547. if (bestname.isEmpty()) {
  6548. if (add||(n==1)) // single-nodes always have implicit group of IP
  6549. addUnique(grp,gname,NULL);
  6550. return false;
  6551. }
  6552. gname.clear().append(bestname);
  6553. return true;
  6554. }
  6555. void swapNode(const IpAddress &from, const IpAddress &to)
  6556. {
  6557. if (from.ipequals(to))
  6558. return;
  6559. CConnectLock connlock("CNamedGroup::swapNode", SDS_GROUPSTORE_ROOT, true, false, false, defaultTimeout);
  6560. StringBuffer froms;
  6561. from.getIpText(froms);
  6562. StringBuffer tos;
  6563. to.getIpText(tos);
  6564. Owned<IPropertyTreeIterator> pe = connlock.conn->queryRoot()->getElements("Group");
  6565. ForEach(*pe) {
  6566. IPropertyTree &group = pe->query();
  6567. const char *kind = group.queryProp("@kind");
  6568. if (kind && streq("Spare", kind))
  6569. continue;
  6570. StringBuffer name;
  6571. group.getProp("@name",name);
  6572. StringBuffer xpath("Node[@ip = \"");
  6573. xpath.append(froms).append("\"]");
  6574. for (unsigned guard=0; guard<1000; guard++) {
  6575. Owned<IPropertyTreeIterator> ne = group.getElements(xpath.str());
  6576. if (!ne->first())
  6577. break;
  6578. ne->query().setProp("@ip",tos.str());
  6579. PROGLOG("swapNode swapping %s for %s in group %s",froms.str(),tos.str(),name.str());
  6580. }
  6581. }
  6582. CriticalBlock block(cachesect);
  6583. cache.kill();
  6584. }
  6585. unsigned setDefaultTimeout(unsigned timems)
  6586. {
  6587. unsigned ret = defaultTimeout;
  6588. defaultTimeout = timems;
  6589. return ret;
  6590. }
  6591. unsigned setRemoteTimeout(unsigned timems)
  6592. {
  6593. unsigned ret = defaultRemoteTimeout;
  6594. defaultRemoteTimeout = timems;
  6595. return ret;
  6596. }
  6597. void resetCache()
  6598. {
  6599. CriticalBlock block(cachesect);
  6600. cache.kill();
  6601. }
  6602. private:
  6603. bool getRemoteGroup(const INode *foreigndali, const char *gname, unsigned foreigndalitimeout,
  6604. StringAttr &groupdir, GroupType &type, SocketEndpointArray &epa)
  6605. {
  6606. StringBuffer lcname(gname);
  6607. gname = lcname.trim().toLowerCase().str();
  6608. CMessageBuffer mb;
  6609. mb.append((int)MDFS_GET_GROUP_TREE).append(gname);
  6610. size32_t mbsz = mb.length();
  6611. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  6612. checkDfsReplyException(mb);
  6613. if (mb.length()==0)
  6614. return false;
  6615. byte ok;
  6616. mb.read(ok);
  6617. if (ok!=1) {
  6618. // kludge for prev bug
  6619. if ((ok==(byte)MDFS_GET_GROUP_TREE)&&mb.length()>mbsz) {
  6620. mb.skip(mbsz-1);
  6621. mb.read(ok);
  6622. if (ok!=1)
  6623. return false;
  6624. }
  6625. else
  6626. return false;
  6627. }
  6628. Owned<IPropertyTree> pt = createPTree(mb);
  6629. Owned<IPropertyTreeIterator> pe = pt->getElements("Node");
  6630. groupdir.set(pt->queryProp("@dir"));
  6631. type = translateGroupType(pt->queryProp("@kind"));
  6632. ForEach(*pe) {
  6633. SocketEndpoint ep(pe->query().queryProp("@ip"));
  6634. epa.append(ep);
  6635. }
  6636. return epa.ordinality() > 0;
  6637. }
  6638. };
  6639. static CNamedGroupStore *groupStore = NULL;
  6640. static CriticalSection groupsect;
  6641. bool CNamedGroupIterator::match()
  6642. {
  6643. if (conn.get()) {
  6644. if (matchgroup.get()) {
  6645. if (!groupStore)
  6646. return false;
  6647. const char *name = pe->query().queryProp("@name");
  6648. if (!name||!*name)
  6649. return false;
  6650. GroupType dummy;
  6651. Owned<IGroup> lgrp = groupStore->dolookup(name, conn, NULL, dummy);
  6652. if (lgrp) {
  6653. if (exactmatch)
  6654. return lgrp->equals(matchgroup);
  6655. GroupRelation gr = matchgroup->compare(lgrp);
  6656. return (gr==GRidentical)||(gr==GRbasesubset)||(gr==GRwrappedsuperset);
  6657. }
  6658. }
  6659. else
  6660. return true;
  6661. }
  6662. return false;
  6663. }
  6664. INamedGroupStore &queryNamedGroupStore()
  6665. {
  6666. if (!groupStore) {
  6667. CriticalBlock block(groupsect);
  6668. if (!groupStore)
  6669. groupStore = new CNamedGroupStore();
  6670. }
  6671. return *groupStore;
  6672. }
  6673. // --------------------------------------------------------
  6674. IDistributedFile *CDistributedFileDirectory::lookup(const char *_logicalname, IUserDescriptor *user, bool writeattr, bool hold, bool lockSuperOwner, IDistributedFileTransaction *transaction, unsigned timeout)
  6675. {
  6676. CDfsLogicalFileName logicalname;
  6677. logicalname.set(_logicalname);
  6678. return lookup(logicalname, user, writeattr, hold, lockSuperOwner, transaction, timeout);
  6679. }
  6680. IDistributedFile *CDistributedFileDirectory::dolookup(CDfsLogicalFileName &_logicalname, IUserDescriptor *user, bool writeattr, bool hold, bool lockSuperOwner, IDistributedFileTransaction *transaction, unsigned timeout)
  6681. {
  6682. CDfsLogicalFileName *logicalname = &_logicalname;
  6683. if (logicalname->isMulti())
  6684. // don't bother checking because the sub file creation will
  6685. return new CDistributedSuperFile(this,*logicalname,user,transaction); // temp superfile
  6686. Owned<IDfsLogicalFileNameIterator> redmatch;
  6687. loop
  6688. {
  6689. checkLogicalName(*logicalname,user,true,writeattr,true,NULL);
  6690. if (logicalname->isExternal()) {
  6691. CDateTime modTime;
  6692. Owned<IFileDescriptor> fDesc = getExternalFileDescriptor(logicalname->get(), &modTime);
  6693. if (!fDesc)
  6694. return NULL;
  6695. CDistributedFile *ret = new CDistributedFile(this, fDesc, NULL, true);
  6696. ret->setLogicalName(logicalname->get());
  6697. ret->setModificationTime(modTime);
  6698. return ret;
  6699. }
  6700. if (logicalname->isForeign()) {
  6701. IDistributedFile * ret = getFile(logicalname->get(),user,NULL);
  6702. if (ret)
  6703. return ret;
  6704. }
  6705. else {
  6706. unsigned start = 0;
  6707. loop {
  6708. CFileLock fcl;
  6709. unsigned mode = RTM_LOCK_READ | RTM_SUB;
  6710. if (hold) mode |= RTM_LOCK_HOLD;
  6711. if (!fcl.init(*logicalname, mode, timeout, "CDistributedFileDirectory::lookup"))
  6712. break;
  6713. CFileSuperOwnerLock superOwnerLock;
  6714. if (lockSuperOwner)
  6715. verifyex(superOwnerLock.init(*logicalname, NULL, defaultTimeout, "CDistributedFileDirectory::dolookup(SuperOwnerLock)"));
  6716. if (fcl.getKind() == DXB_File)
  6717. {
  6718. StringBuffer cname;
  6719. if (logicalname->getCluster(cname).length())
  6720. {
  6721. IPropertyTree *froot=fcl.queryRoot();
  6722. if (froot)
  6723. {
  6724. StringBuffer query;
  6725. query.appendf("Cluster[@name=\"%s\"]",cname.str());
  6726. if (!froot->hasProp(query.str()))
  6727. break;
  6728. }
  6729. }
  6730. CDistributedFile *ret = new CDistributedFile(this,fcl.detach(),*logicalname,user); // found
  6731. ret->setSuperOwnerLock(superOwnerLock.detach());
  6732. return ret;
  6733. }
  6734. // now super file
  6735. if (fcl.getKind() != DXB_SuperFile)
  6736. break;
  6737. if (start==0)
  6738. start = msTick();
  6739. unsigned elapsed;
  6740. try
  6741. {
  6742. CDistributedSuperFile *ret = new CDistributedSuperFile(this,fcl.detach(),*logicalname,user,transaction,SDS_SUB_LOCK_TIMEOUT);
  6743. ret->setSuperOwnerLock(superOwnerLock.detach());
  6744. return ret;
  6745. }
  6746. catch (IDFS_Exception *e)
  6747. {
  6748. elapsed = msTick()-start;
  6749. if ((e->errorCode()!=DFSERR_LookupConnectionTimout)||(elapsed>((timeout==INFINITE)?SDS_CONNECT_TIMEOUT:timeout)))
  6750. throw;
  6751. EXCLOG(e,"Superfile lookup");
  6752. e->Release();
  6753. }
  6754. PROGLOG("CDistributedSuperFile connect timeout (%dms) pausing",elapsed);
  6755. Sleep(SDS_TRANSACTION_RETRY/2+(getRandom()%SDS_TRANSACTION_RETRY));
  6756. }
  6757. }
  6758. if (redmatch.get()) {
  6759. if (!redmatch->next())
  6760. break;
  6761. }
  6762. else {
  6763. redmatch.setown(queryRedirection().getMatch(logicalname->get()));
  6764. if (!redmatch.get())
  6765. break;
  6766. if (!redmatch->first())
  6767. break;
  6768. }
  6769. logicalname = &redmatch->query();
  6770. }
  6771. return NULL;
  6772. }
  6773. IDistributedFile *CDistributedFileDirectory::lookup(CDfsLogicalFileName &logicalname, IUserDescriptor *user, bool writeattr, bool hold, bool lockSuperOwner, IDistributedFileTransaction *transaction, unsigned timeout)
  6774. {
  6775. return dolookup(logicalname, user, writeattr, hold, lockSuperOwner, transaction, timeout);
  6776. }
  6777. IDistributedSuperFile *CDistributedFileDirectory::lookupSuperFile(const char *_logicalname,IUserDescriptor *user,IDistributedFileTransaction *transaction, unsigned timeout)
  6778. {
  6779. CDfsLogicalFileName logicalname;
  6780. logicalname.set(_logicalname);
  6781. IDistributedFile *file = dolookup(logicalname, user, false, false, false, transaction, timeout);
  6782. if (file) {
  6783. IDistributedSuperFile *sf = file->querySuperFile();
  6784. if (sf)
  6785. return sf;
  6786. file->Release();
  6787. }
  6788. return NULL;
  6789. }
  6790. bool CDistributedFileDirectory::isSuperFile( const char *logicalname,
  6791. IUserDescriptor *user,
  6792. INode *foreigndali,
  6793. unsigned timeout)
  6794. {
  6795. Owned<IPropertyTree> tree = getFileTree(logicalname, user, foreigndali,timeout, false);
  6796. return tree.get()&&(strcmp(tree->queryName(),queryDfsXmlBranchName(DXB_SuperFile))==0);
  6797. }
  6798. bool CDistributedFileDirectory::exists(const char *_logicalname,IUserDescriptor *user,bool notsuper,bool superonly)
  6799. {
  6800. // (currently) no check on scope permissions for exists
  6801. bool external;
  6802. bool foreign;
  6803. CDfsLogicalFileName dlfn;
  6804. dlfn.set(_logicalname);
  6805. const char *logicalname = dlfn.get();
  6806. external = dlfn.isExternal();
  6807. foreign = dlfn.isForeign();
  6808. if (foreign) {
  6809. Owned<IDistributedFile> file = lookup(_logicalname, user, false, false, false, NULL, defaultTimeout);
  6810. if (file.get()==NULL)
  6811. return false;
  6812. if (file->querySuperFile()) {
  6813. if (notsuper)
  6814. return false;
  6815. }
  6816. else
  6817. if (superonly)
  6818. return false;
  6819. }
  6820. else if (external) {
  6821. if (!existsPhysical(_logicalname,user))
  6822. return false;
  6823. }
  6824. else {
  6825. StringBuffer str;
  6826. if (!superonly) {
  6827. dlfn.makeFullnameQuery(str,DXB_File,true);
  6828. CConnectLock connlockfile("CDistributedFileDirectory::exists",str.str(),false,false,false,defaultTimeout);
  6829. if (connlockfile.conn.get())
  6830. return true;
  6831. }
  6832. if (notsuper)
  6833. return false;
  6834. dlfn.makeFullnameQuery(str.clear(),DXB_SuperFile,true);
  6835. CConnectLock connlocksuper("CDistributedFileDirectory::exists",str.str(),false,false,false,defaultTimeout);
  6836. if (!connlocksuper.conn.get())
  6837. return false;
  6838. }
  6839. return true;
  6840. }
  6841. bool CDistributedFileDirectory::existsPhysical(const char *_logicalname, IUserDescriptor *user)
  6842. {
  6843. Owned<IDistributedFile> file = lookup(_logicalname, user, false, false, false, NULL, defaultTimeout);
  6844. if (!file)
  6845. return false;
  6846. return file->existsPhysicalPartFiles(0);
  6847. }
  6848. IDistributedFile *CDistributedFileDirectory::createNew(IFileDescriptor *fdesc, bool includeports)
  6849. {
  6850. return new CDistributedFile(this, fdesc, NULL, includeports);
  6851. }
  6852. ////////////////////////////////////
  6853. class DistributedFilePropertyLockFree
  6854. {
  6855. unsigned lockedCount;
  6856. CDistributedFile *file;
  6857. CDistributedSuperFile *sfile;
  6858. public:
  6859. DistributedFilePropertyLockFree(IDistributedFile *_file)
  6860. {
  6861. file = dynamic_cast<CDistributedFile *>(_file);
  6862. sfile = NULL;
  6863. if (file)
  6864. lockedCount = file->setPropLockCount(0);
  6865. else
  6866. {
  6867. sfile = dynamic_cast<CDistributedSuperFile *>(_file);
  6868. lockedCount = sfile->setPropLockCount(0);
  6869. }
  6870. }
  6871. ~DistributedFilePropertyLockFree()
  6872. {
  6873. if (file)
  6874. verifyex(0 == file->setPropLockCount(lockedCount));
  6875. else if (sfile)
  6876. verifyex(0 == sfile->setPropLockCount(lockedCount));
  6877. }
  6878. };
  6879. /**
  6880. * Creates a super-file within a transaction.
  6881. */
  6882. class CCreateSuperFileAction: public CDFAction
  6883. {
  6884. CDfsLogicalFileName logicalname;
  6885. CDistributedFileDirectory *parent;
  6886. Linked<IDistributedSuperFile> super;
  6887. IUserDescriptor *user;
  6888. bool interleaved, created;
  6889. void clearSuper()
  6890. {
  6891. if (created)
  6892. {
  6893. created = false;
  6894. super->detach();
  6895. }
  6896. super.clear();
  6897. }
  6898. public:
  6899. CCreateSuperFileAction(CDistributedFileDirectory *_parent,
  6900. IUserDescriptor *_user,
  6901. const char *_flname,
  6902. bool _interleaved)
  6903. : parent(_parent), user(_user), created(false), interleaved(_interleaved)
  6904. {
  6905. logicalname.set(_flname);
  6906. }
  6907. IDistributedSuperFile *getSuper()
  6908. {
  6909. if (!super)
  6910. {
  6911. Owned<IDistributedSuperFile> _super = transaction->lookupSuperFile(logicalname.get(), SDS_SUB_LOCK_TIMEOUT);
  6912. if (_super)
  6913. super.setown(_super.getClear());
  6914. else
  6915. {
  6916. /* No super, create one if necessary.
  6917. * This really shouldn't have to work this way, looking up super early, or creating super stub now,
  6918. * because other super file transactions are based on
  6919. * TBD: There should be a way to obtain lock independently of actually attaching.
  6920. */
  6921. Owned<IPropertyTree> root = createPTree();
  6922. root->setPropInt("@interleaved",interleaved?2:0); // this is ill placed
  6923. super.setown(new CDistributedSuperFile(parent, root, logicalname, user));
  6924. created = true;
  6925. transaction->addFile(super);
  6926. }
  6927. }
  6928. return super.getLink();
  6929. }
  6930. bool prepare()
  6931. {
  6932. Owned<IDistributedFile> _super = getSuper();
  6933. // Attach the file to DFS, if wasn't there already
  6934. if (created)
  6935. super->attach(logicalname.get(), user);
  6936. addFileLock(super);
  6937. if (lock())
  6938. return true;
  6939. unlock();
  6940. return false;
  6941. }
  6942. void run()
  6943. {
  6944. // Do nothing, file is already created
  6945. }
  6946. void retry()
  6947. {
  6948. // on retry, we need to remove the file so next lock doesn't fail
  6949. clearSuper();
  6950. CDFAction::retry();
  6951. }
  6952. void rollback()
  6953. {
  6954. state = TAS_FAILURE;
  6955. clearSuper();
  6956. CDFAction::rollback();
  6957. }
  6958. };
  6959. /**
  6960. * Removes a super-file within a transaction.
  6961. */
  6962. class CRemoveSuperFileAction: public CDFAction
  6963. {
  6964. CDfsLogicalFileName logicalname;
  6965. Linked<IDistributedSuperFile> super;
  6966. IUserDescriptor *user;
  6967. bool delSub;
  6968. Owned<IDistributedFileTransactionExt> nestedTransaction;
  6969. class CNestedTransaction : public CDistributedFileTransaction
  6970. {
  6971. IDistributedFileTransactionExt *transaction;
  6972. CIArrayOf<CDFAction> actions;
  6973. public:
  6974. IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
  6975. CNestedTransaction(IDistributedFileTransactionExt *_transaction, IUserDescriptor *user)
  6976. : CDistributedFileTransaction(user), transaction(_transaction)
  6977. {
  6978. if (transaction->active())
  6979. start();
  6980. }
  6981. // wrap rest of calls into parent transaction calls
  6982. virtual IDistributedFile *lookupFile(const char *lfn,unsigned timeout=INFINITE)
  6983. {
  6984. return transaction->lookupFile(lfn, timeout);
  6985. }
  6986. virtual IDistributedSuperFile *lookupSuperFile(const char *slfn,unsigned timeout=INFINITE)
  6987. {
  6988. return transaction->lookupSuperFile(slfn, timeout);
  6989. }
  6990. virtual IUserDescriptor *queryUser() { return transaction->queryUser(); }
  6991. virtual void descend() { transaction->descend(); }
  6992. virtual void ascend() { transaction->ascend(); }
  6993. virtual void addFile(IDistributedFile *file) { transaction->addFile(file); }
  6994. virtual void ensureFile(IDistributedFile *file) { transaction->ensureFile(file); }
  6995. virtual void clearFile(IDistributedFile *file) { transaction->clearFile(file); }
  6996. virtual void noteAddSubFile(IDistributedSuperFile *super, const char *superName, IDistributedFile *sub)
  6997. {
  6998. transaction->noteAddSubFile(super, superName, sub);
  6999. }
  7000. virtual void noteRemoveSubFile(IDistributedSuperFile *super, IDistributedFile *sub)
  7001. {
  7002. transaction->noteRemoveSubFile(super, sub);
  7003. }
  7004. virtual void noteSuperSwap(IDistributedSuperFile *super1, IDistributedSuperFile *super2)
  7005. {
  7006. transaction->noteSuperSwap(super1, super2);
  7007. }
  7008. virtual void clearSubFiles(IDistributedSuperFile *super)
  7009. {
  7010. transaction->clearSubFiles(super);
  7011. }
  7012. virtual void noteRename(IDistributedFile *file, const char *newName)
  7013. {
  7014. transaction->noteRename(file, newName);
  7015. }
  7016. virtual void validateAddSubFile(IDistributedSuperFile *super, IDistributedFile *sub, const char *subName)
  7017. {
  7018. transaction->validateAddSubFile(super, sub, subName);
  7019. }
  7020. virtual bool isSubFile(IDistributedSuperFile *super, const char *subFile, bool sub)
  7021. {
  7022. return transaction->isSubFile(super, subFile, sub);
  7023. }
  7024. virtual bool addDelayedDelete(CDfsLogicalFileName &lfn,unsigned timeoutms=INFINITE)
  7025. {
  7026. return transaction->addDelayedDelete(lfn, timeoutms);
  7027. }
  7028. };
  7029. public:
  7030. CRemoveSuperFileAction(IUserDescriptor *_user,
  7031. const char *_flname,
  7032. bool _delSub)
  7033. : user(_user), delSub(_delSub)
  7034. {
  7035. logicalname.set(_flname);
  7036. }
  7037. virtual bool prepare()
  7038. {
  7039. // We *have* to make sure the file exists here
  7040. super.setown(transaction->lookupSuperFile(logicalname.get(), SDS_SUB_LOCK_TIMEOUT));
  7041. if (!super)
  7042. ThrowStringException(-1, "Super File %s doesn't exist in the file system", logicalname.get());
  7043. addFileLock(super);
  7044. // Adds actions to transactions before this one and gets executed only on commit
  7045. if (delSub)
  7046. {
  7047. // As 'delSub' means additional actions, handle them in their own transaction context
  7048. // Wrap lookups and record of removed/added subs to parent transaction, for common cache purposes
  7049. nestedTransaction.setown(new CNestedTransaction(transaction, user));
  7050. super->removeSubFile(NULL, true, false, nestedTransaction);
  7051. }
  7052. if (lock())
  7053. {
  7054. if (nestedTransaction)
  7055. {
  7056. if (nestedTransaction->prepareActions())
  7057. return true;
  7058. }
  7059. else
  7060. return true;
  7061. }
  7062. unlock();
  7063. super.clear();
  7064. return false;
  7065. }
  7066. virtual void retry()
  7067. {
  7068. super.clear();
  7069. if (nestedTransaction)
  7070. nestedTransaction->retryActions();
  7071. CDFAction::retry();
  7072. }
  7073. virtual void run()
  7074. {
  7075. if (nestedTransaction)
  7076. nestedTransaction->runActions();
  7077. super->detach();
  7078. }
  7079. virtual void commit()
  7080. {
  7081. if (nestedTransaction)
  7082. nestedTransaction->commitAndClearup();
  7083. CDFAction::commit();
  7084. }
  7085. };
  7086. /**
  7087. * Renames a file within a transaction.
  7088. */
  7089. class CRenameFileAction: public CDFAction
  7090. {
  7091. CDfsLogicalFileName fromName, toName;
  7092. CDistributedFileDirectory *parent;
  7093. Linked<IDistributedFile> file;
  7094. IUserDescriptor *user;
  7095. bool renamed;
  7096. enum RenameAction { ra_regular, ra_splitfrom, ra_mergeinto } ra;
  7097. public:
  7098. CRenameFileAction(CDistributedFileDirectory *_parent,
  7099. IUserDescriptor *_user,
  7100. const char *_flname,
  7101. const char *_newname)
  7102. : user(_user), parent(_parent)
  7103. {
  7104. fromName.set(_flname);
  7105. // Basic consistency checking
  7106. toName.set(_newname);
  7107. if (fromName.isExternal() || toName.isExternal())
  7108. throw MakeStringException(-1,"rename: cannot rename external files"); // JCSMORE perhaps you should be able to?
  7109. if (fromName.isForeign() || toName.isForeign())
  7110. throw MakeStringException(-1,"rename: cannot rename foreign files");
  7111. // Make sure files are not the same
  7112. if (0 == strcmp(fromName.get(), toName.get()))
  7113. ThrowStringException(-1, "rename: cannot rename file %s to itself", toName.get());
  7114. ra = ra_regular;
  7115. renamed = false;
  7116. }
  7117. virtual bool prepare()
  7118. {
  7119. // We *have* to make sure the source file exists and can be renamed
  7120. file.setown(transaction->lookupFile(fromName.get(), SDS_SUB_LOCK_TIMEOUT));
  7121. if (!file)
  7122. ThrowStringException(-1, "rename: file %s doesn't exist in the file system", fromName.get());
  7123. if (file->querySuperFile())
  7124. ThrowStringException(-1,"rename: cannot rename file %s as is SuperFile", fromName.get()); // Why not
  7125. StringBuffer reason;
  7126. if (!file->canRemove(reason))
  7127. ThrowStringException(-1,"rename: %s",reason.str());
  7128. addFileLock(file);
  7129. renamed = false;
  7130. if (lock())
  7131. {
  7132. StringBuffer oldcluster, newcluster;
  7133. fromName.getCluster(oldcluster);
  7134. toName.getCluster(newcluster);
  7135. Owned<IDistributedFile> newFile = transaction->lookupFile(toName.get(), SDS_SUB_LOCK_TIMEOUT);
  7136. if (newFile)
  7137. {
  7138. if (newcluster.length())
  7139. {
  7140. if (oldcluster.length())
  7141. ThrowStringException(-1,"rename: cannot specify both source and destination clusters on rename");
  7142. if (newFile->findCluster(newcluster.str())!=NotFound)
  7143. ThrowStringException(-1,"rename: cluster %s already part of file %s",newcluster.str(),toName.get());
  7144. if (file->numClusters()!=1)
  7145. ThrowStringException(-1,"rename: source file %s has more than one cluster",fromName.get());
  7146. // check compatible here ** TBD
  7147. ra = ra_mergeinto;
  7148. }
  7149. else
  7150. ThrowStringException(-1, "rename: file %s already exist in the file system", toName.get());
  7151. }
  7152. else if (oldcluster.length())
  7153. {
  7154. if (newcluster.length())
  7155. ThrowStringException(-1,"rename: cannot specify both source and destination clusters on rename");
  7156. if (file->numClusters()==1)
  7157. ThrowStringException(-1,"rename: cannot rename sole cluster %s",oldcluster.str());
  7158. if (file->findCluster(oldcluster.str())==NotFound)
  7159. ThrowStringException(-1,"rename: cannot find cluster %s",oldcluster.str());
  7160. ra = ra_splitfrom;
  7161. }
  7162. else
  7163. {
  7164. // TODO: something should check that file being renamed is not a subfile of a super where both created in transaction
  7165. transaction->noteRename(file, toName.get());
  7166. ra = ra_regular;
  7167. }
  7168. return true;
  7169. }
  7170. unlock();
  7171. file.clear();
  7172. return false;
  7173. }
  7174. virtual void run()
  7175. {
  7176. doRename(fromName, toName, ra);
  7177. renamed = true;
  7178. }
  7179. virtual void retry()
  7180. {
  7181. file.clear();
  7182. CDFAction::retry();
  7183. }
  7184. virtual void rollback()
  7185. {
  7186. // Only roll back if already renamed
  7187. if (renamed)
  7188. {
  7189. switch (ra)
  7190. {
  7191. case ra_regular:
  7192. doRename(toName, fromName, ra_regular);
  7193. break;
  7194. case ra_splitfrom:
  7195. doRename(toName, fromName, ra_mergeinto);
  7196. break;
  7197. case ra_mergeinto:
  7198. doRename(toName, fromName, ra_splitfrom);
  7199. break;
  7200. default:
  7201. throwUnexpected();
  7202. }
  7203. renamed = false;
  7204. }
  7205. CDFAction::rollback();
  7206. }
  7207. private:
  7208. void doRename(CDfsLogicalFileName &from, CDfsLogicalFileName &to, RenameAction ra)
  7209. {
  7210. CriticalBlock block(physicalChange);
  7211. StringBuffer oldcluster, newcluster;
  7212. fromName.getCluster(oldcluster);
  7213. toName.getCluster(newcluster);
  7214. Owned<IDistributedFile> oldfile;
  7215. if (ra_splitfrom == ra)
  7216. {
  7217. oldfile.setown(file.getClear());
  7218. Owned<IFileDescriptor> newdesc = oldfile->getFileDescriptor(oldcluster.str());
  7219. file.setown(parent->createNew(newdesc));
  7220. }
  7221. // Physical Rename
  7222. Owned<IMultiException> exceptions = MakeMultiException();
  7223. if (!file->renamePhysicalPartFiles(to.get(),newcluster,exceptions))
  7224. {
  7225. unlock();
  7226. StringBuffer errors;
  7227. exceptions->errorMessage(errors);
  7228. ThrowStringException(-1, "rename: could not rename logical file %s to %s: %s", fromName.get(), to.get(), errors.str());
  7229. }
  7230. // Logical rename and cleanup
  7231. switch (ra)
  7232. {
  7233. case ra_splitfrom:
  7234. {
  7235. unlock();
  7236. oldfile->removeCluster(oldcluster.str());
  7237. file->attach(to.get(), user);
  7238. lock();
  7239. break;
  7240. }
  7241. case ra_mergeinto:
  7242. {
  7243. Owned<IDistributedFile> newFile = transaction->lookupFile(to.get(), SDS_SUB_LOCK_TIMEOUT);
  7244. ClusterPartDiskMapSpec mspec = file->queryPartDiskMapping(0);
  7245. // Unlock the old file
  7246. unlock();
  7247. CDistributedFile *_file = dynamic_cast<CDistributedFile *>(file.get());
  7248. _file->detachLogical(INFINITE); // don't delete physicals, now used by newFile
  7249. transaction->clearFile(file); // no long used in transaction
  7250. newFile->addCluster(newcluster.str(),mspec);
  7251. parent->fixDates(newFile);
  7252. // need to clear and re-lookup as changed outside of transaction
  7253. // TBD: Allow 'addCluster' 'fixDates' etc. to be delayed/work inside transaction
  7254. transaction->clearFile(newFile);
  7255. newFile.clear();
  7256. file.setown(transaction->lookupFile(to.get(), SDS_SUB_LOCK_TIMEOUT));
  7257. addFileLock(file);
  7258. lock();
  7259. break;
  7260. }
  7261. case ra_regular:
  7262. {
  7263. /* It is not enough to unlock this actions locks on the file being renamed,
  7264. * because other actions, before and after may hold locks to the same file.
  7265. * For now, IDistributeFile::rename, needs to work on a lock free instance.
  7266. * TBD: Allow IDistributedFile::rename to work properly within transaction.
  7267. */
  7268. DistributedFilePropertyLockFree unlock(file);
  7269. file->rename(to.get(), user);
  7270. break;
  7271. }
  7272. default:
  7273. throwUnexpected();
  7274. }
  7275. // MORE: If the logical rename fails, we should roll back the physical renaming
  7276. // What if the physical renaming-back fails?!
  7277. // For now, leaving as it was, since physical renaming is more prone to errors than logical
  7278. // And checks were made earlier to make sure it was safe to rename
  7279. }
  7280. };
  7281. // MORE: This should be implemented in DFSAccess later on
  7282. IDistributedSuperFile *CDistributedFileDirectory::createSuperFile(const char *_logicalname,IUserDescriptor *user, bool _interleaved,bool ifdoesnotexist,IDistributedFileTransaction *transaction)
  7283. {
  7284. CDfsLogicalFileName logicalname;
  7285. logicalname.set(_logicalname);
  7286. checkLogicalName(logicalname,user,true,true,false,"have a superfile with");
  7287. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  7288. Linked<IDistributedFileTransactionExt> localtrans;
  7289. if (transaction)
  7290. {
  7291. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  7292. localtrans.set(_transaction);
  7293. }
  7294. else
  7295. localtrans.setown(new CDistributedFileTransaction(user));
  7296. IDistributedSuperFile *sfile = localtrans->lookupSuperFile(logicalname.get());
  7297. if (sfile)
  7298. {
  7299. if (ifdoesnotexist)
  7300. return sfile;
  7301. else
  7302. throw MakeStringException(-1,"createSuperFile: SuperFile %s already exists",logicalname.get());
  7303. }
  7304. Owned<CCreateSuperFileAction> action = new CCreateSuperFileAction(this,user,_logicalname,_interleaved);
  7305. localtrans->addAction(action.getLink()); // takes ownership
  7306. localtrans->autoCommit();
  7307. return action->getSuper();
  7308. }
  7309. // MORE: This should be implemented in DFSAccess later on
  7310. void CDistributedFileDirectory::removeSuperFile(const char *_logicalname, bool delSubs, IUserDescriptor *user, IDistributedFileTransaction *transaction)
  7311. {
  7312. CDfsLogicalFileName logicalname;
  7313. logicalname.set(_logicalname);
  7314. checkLogicalName(logicalname,user,true,true,false,"have a superfile with");
  7315. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  7316. Linked<IDistributedFileTransactionExt> localtrans;
  7317. if (transaction)
  7318. {
  7319. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  7320. localtrans.set(_transaction);
  7321. }
  7322. else
  7323. localtrans.setown(new CDistributedFileTransaction(user));
  7324. CRemoveSuperFileAction *action = new CRemoveSuperFileAction(user, _logicalname, delSubs);
  7325. localtrans->addAction(action); // takes ownership
  7326. localtrans->autoCommit();
  7327. }
  7328. bool CDistributedFileDirectory::removeEntry(const char *name, IUserDescriptor *user, IDistributedFileTransaction *transaction, unsigned timeoutms, bool throwException)
  7329. {
  7330. CDfsLogicalFileName logicalname;
  7331. logicalname.set(name);
  7332. if (!logicalname.isExternal())
  7333. checkLogicalName(logicalname,user,true,true,false,"delete");
  7334. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  7335. Linked<IDistributedFileTransactionExt> localtrans;
  7336. if (transaction)
  7337. {
  7338. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  7339. localtrans.set(_transaction);
  7340. }
  7341. else
  7342. localtrans.setown(new CDistributedFileTransaction(user));
  7343. // Action will be executed at the end of the transaction (commit)
  7344. localtrans->addDelayedDelete(logicalname, timeoutms);
  7345. try
  7346. {
  7347. localtrans->autoCommit();
  7348. }
  7349. catch (IException *e)
  7350. {
  7351. // TODO: Transform removeEntry into void
  7352. StringBuffer msg;
  7353. e->errorMessage(msg);
  7354. ERRLOG("Error while deleting %s: %s", logicalname.get(), msg.str());
  7355. if (throwException)
  7356. throw;
  7357. e->Release();
  7358. return false;
  7359. }
  7360. return true;
  7361. }
  7362. void CDistributedFileDirectory::removeEmptyScope(const char *scope)
  7363. {
  7364. if (scope&&*scope) {
  7365. StringBuffer fn(scope);
  7366. fn.append("::x");
  7367. CDfsLogicalFileName dlfn;
  7368. dlfn.set(fn.str());
  7369. removeFileEmptyScope(dlfn,defaultTimeout);
  7370. }
  7371. }
  7372. void CDistributedFileDirectory::renamePhysical(const char *oldname,const char *newname,IUserDescriptor *user,IDistributedFileTransaction *transaction)
  7373. {
  7374. if (!user)
  7375. {
  7376. #ifdef NULL_DALIUSER_STACKTRACE
  7377. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp CDistributedFileDirectory::renamePhysical %d",__LINE__);
  7378. //following debug code to be removed
  7379. PrintStackReport();
  7380. #endif
  7381. user = defaultudesc.get();
  7382. }
  7383. CDfsLogicalFileName oldlogicalname;
  7384. oldlogicalname.set(oldname);
  7385. checkLogicalName(oldlogicalname,user,true,true,false,"rename");
  7386. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  7387. Linked<IDistributedFileTransactionExt> localtrans;
  7388. if (transaction)
  7389. {
  7390. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  7391. localtrans.set(_transaction);
  7392. }
  7393. else
  7394. localtrans.setown(new CDistributedFileTransaction(user));
  7395. CRenameFileAction *action = new CRenameFileAction(this, user, oldname, newname);
  7396. localtrans->addAction(action); // takes ownership
  7397. localtrans->autoCommit();
  7398. }
  7399. void CDistributedFileDirectory::fixDates(IDistributedFile *file)
  7400. {
  7401. // should do in parallel
  7402. unsigned width = file->numParts();
  7403. CriticalSection crit;
  7404. class casyncfor: public CAsyncFor
  7405. {
  7406. IDistributedFile *file;
  7407. CriticalSection &crit;
  7408. unsigned width;
  7409. public:
  7410. bool ok;
  7411. casyncfor(IDistributedFile *_file,unsigned _width,CriticalSection &_errcrit)
  7412. : crit(_errcrit)
  7413. {
  7414. file = _file;
  7415. ok = true;
  7416. width = _width;
  7417. ok = true;
  7418. }
  7419. void Do(unsigned i)
  7420. {
  7421. CriticalBlock block(crit);
  7422. Owned<IDistributedFilePart> part = file->getPart(i);
  7423. CDateTime dt;
  7424. if (!part->getModifiedTime(false,false,dt))
  7425. return;
  7426. unsigned nc = part->numCopies();
  7427. for (unsigned copy = 0; copy < nc; copy++) {
  7428. RemoteFilename rfn;
  7429. part->getFilename(rfn,copy);
  7430. Owned<IFile> partfile = createIFile(rfn);
  7431. try {
  7432. CriticalUnblock unblock(crit);
  7433. CDateTime dt2;
  7434. if (partfile->getTime(NULL,&dt2,NULL)) {
  7435. if (!dt.equals(dt2)) {
  7436. partfile->setTime(NULL,&dt,NULL);
  7437. }
  7438. }
  7439. }
  7440. catch (IException *e) {
  7441. CriticalBlock block(crit);
  7442. StringBuffer s("Failed to find file part ");
  7443. s.append(partfile->queryFilename()).append(" on ");
  7444. rfn.queryEndpoint().getUrlStr(s);
  7445. EXCLOG(e, s.str());
  7446. e->Release();
  7447. }
  7448. }
  7449. }
  7450. } afor(file,width,crit);
  7451. afor.For(width,10,false,true);
  7452. }
  7453. void CDistributedFileDirectory::addEntry(CDfsLogicalFileName &dlfn,IPropertyTree *root,bool superfile, bool ignoreexists)
  7454. {
  7455. // add bit awkward
  7456. bool external;
  7457. bool foreign;
  7458. external = dlfn.isExternal();
  7459. foreign = dlfn.isForeign();
  7460. if (external) {
  7461. root->Release();
  7462. return; // ignore attempts to add external
  7463. }
  7464. CScopeConnectLock sconnlock("CDistributedFileDirectory::addEntry", dlfn, true, false, false, defaultTimeout);
  7465. if (!sconnlock.conn()) {// warn?
  7466. root->Release();
  7467. return;
  7468. }
  7469. IPropertyTree* sroot = sconnlock.conn()->queryRoot();
  7470. StringBuffer tail;
  7471. dlfn.getTail(tail);
  7472. IPropertyTree *prev = getNamedPropTree(sroot,superfile?queryDfsXmlBranchName(DXB_SuperFile):queryDfsXmlBranchName(DXB_File),"@name",tail.str(),false);
  7473. if (!prev) // check super/file doesn't exist
  7474. prev = getNamedPropTree(sroot,superfile?queryDfsXmlBranchName(DXB_File):queryDfsXmlBranchName(DXB_SuperFile),"@name",tail.str(),false);
  7475. if (prev!=NULL) {
  7476. prev->Release();
  7477. root->Release();
  7478. if (ignoreexists)
  7479. return;
  7480. IDFS_Exception *e = new CDFS_Exception(DFSERR_LogicalNameAlreadyExists,dlfn.get());
  7481. throw e;
  7482. }
  7483. root->setProp("@name",tail.str());
  7484. root->setProp("OrigName",dlfn.get());
  7485. sroot->addPropTree(superfile?queryDfsXmlBranchName(DXB_SuperFile):queryDfsXmlBranchName(DXB_File),root); // now owns root
  7486. }
  7487. IDistributedFileIterator *CDistributedFileDirectory::getIterator(const char *wildname, bool includesuper, IUserDescriptor *user)
  7488. {
  7489. return new CDistributedFileIterator(this,wildname,includesuper,user);
  7490. }
  7491. GetFileClusterNamesType CDistributedFileDirectory::getFileClusterNames(const char *_logicalname,StringArray &out)
  7492. {
  7493. CDfsLogicalFileName logicalname;
  7494. logicalname.set(_logicalname);
  7495. if (logicalname.isForeign())
  7496. return GFCN_Foreign;
  7497. if (logicalname.isExternal())
  7498. return GFCN_External;
  7499. CScopeConnectLock sconnlock("CDistributedFileDirectory::getFileClusterList", logicalname, false, false, false, defaultTimeout);
  7500. DfsXmlBranchKind bkind;
  7501. IPropertyTree *froot = sconnlock.queryFileRoot(logicalname,bkind);
  7502. if (froot) {
  7503. if (bkind==DXB_File) {
  7504. getFileGroups(froot,out);
  7505. return GFCN_Normal;
  7506. }
  7507. if (bkind==DXB_SuperFile)
  7508. return GFCN_Super;
  7509. }
  7510. return GFCN_NotFound;
  7511. }
  7512. // --------------------------------------------------------
  7513. static CDistributedFileDirectory *DFdir = NULL;
  7514. static CriticalSection dfdirCrit;
  7515. /**
  7516. * Public method to control DistributedFileDirectory access
  7517. * as a singleton. This is the only way to get directories,
  7518. * files, super-files and logic-files.
  7519. */
  7520. IDistributedFileDirectory &queryDistributedFileDirectory()
  7521. {
  7522. if (!DFdir) {
  7523. CriticalBlock block(dfdirCrit);
  7524. if (!DFdir)
  7525. DFdir = new CDistributedFileDirectory();
  7526. }
  7527. return *DFdir;
  7528. }
  7529. /**
  7530. * Shutdown distributed file system (root directory).
  7531. */
  7532. void closedownDFS() // called by dacoven
  7533. {
  7534. CriticalBlock block(dfdirCrit);
  7535. try {
  7536. delete DFdir;
  7537. }
  7538. catch (IMP_Exception *e) {
  7539. if (e->errorCode()!=MPERR_link_closed)
  7540. throw;
  7541. PrintExceptionLog(e,"closedownDFS");
  7542. e->Release();
  7543. }
  7544. catch (IDaliClient_Exception *e) {
  7545. if (e->errorCode()!=DCERR_server_closed)
  7546. throw;
  7547. e->Release();
  7548. }
  7549. DFdir = NULL;
  7550. CriticalBlock block2(groupsect);
  7551. ::Release(groupStore);
  7552. groupStore = NULL;
  7553. }
  7554. class CDFPartFilter : public CInterface, implements IDFPartFilter
  7555. {
  7556. protected:
  7557. bool *partincluded;
  7558. unsigned max;
  7559. public:
  7560. IMPLEMENT_IINTERFACE;
  7561. CDFPartFilter(const char *filter)
  7562. {
  7563. max = 0;
  7564. partincluded = NULL;
  7565. unsigned pn=0;
  7566. const char *s=filter;
  7567. if (!s)
  7568. return;
  7569. while (*s) {
  7570. if (isdigit(*s)) {
  7571. pn = pn*10+(*s-'0');
  7572. if (pn>max)
  7573. max = pn;
  7574. }
  7575. else
  7576. pn = 0;
  7577. s++;
  7578. }
  7579. if (max==0)
  7580. return;
  7581. partincluded = new bool[max];
  7582. unsigned i;
  7583. for (i=0;i<max;i++)
  7584. partincluded[i] = false;
  7585. pn=0;
  7586. s=filter;
  7587. unsigned start=0;
  7588. loop {
  7589. if ((*s==0)||(*s==',')||isspace(*s)) {
  7590. if (start) {
  7591. for (i=start-1;i<pn;i++)
  7592. partincluded[i] = true;
  7593. start = 0;
  7594. }
  7595. else
  7596. partincluded[pn-1] = true;
  7597. if (*s==0)
  7598. break;
  7599. pn = 0;
  7600. }
  7601. else if (isdigit(*s)) {
  7602. pn = pn*10+(*s-'0');
  7603. if (pn>max)
  7604. max = pn;
  7605. if (s[1]=='-') {
  7606. s++;
  7607. start = pn;
  7608. pn = 0;
  7609. }
  7610. }
  7611. s++;
  7612. }
  7613. }
  7614. ~CDFPartFilter()
  7615. {
  7616. delete [] partincluded;
  7617. }
  7618. bool includePart(unsigned part)
  7619. {
  7620. if (max==0)
  7621. return true;
  7622. if (part>=max)
  7623. return false;
  7624. return partincluded[part];
  7625. };
  7626. };
  7627. IDFPartFilter *createPartFilter(const char *filter)
  7628. {
  7629. return new CDFPartFilter(filter);
  7630. }
  7631. //=====================================================================================
  7632. // Server Side Support
  7633. class CFileMatch : public CInterface
  7634. {
  7635. StringAttr name;
  7636. Linked<IPropertyTree> tree;
  7637. bool isSuper;
  7638. public:
  7639. CFileMatch(const char *_name, IPropertyTree *_tree, bool _isSuper) : name(_name), tree(_tree), isSuper(_isSuper)
  7640. {
  7641. }
  7642. IPropertyTree &queryFileTree() const { return *tree; }
  7643. const char *queryName() const { return name; }
  7644. bool queryIsSuper() const { return isSuper; }
  7645. };
  7646. typedef CIArrayOf<CFileMatch> CFileMatchArray;
  7647. class CScope : public CInterface
  7648. {
  7649. StringAttr name;
  7650. CIArrayOf<CFileMatch> files; // matches
  7651. CIArrayOf<CScope> subScopes;
  7652. public:
  7653. CScope(const char *_name) : name(_name)
  7654. {
  7655. }
  7656. const char *getName() const { return name; }
  7657. void addMatch(const char *name, IPropertyTree &fileTree, bool isSuper)
  7658. {
  7659. files.append(*new CFileMatch(name, &fileTree, isSuper));
  7660. }
  7661. CScope *addScope(const char *scope)
  7662. {
  7663. CScope *subScope = new CScope(scope);
  7664. subScopes.append(*subScope);
  7665. return subScope;
  7666. }
  7667. void popLastScope()
  7668. {
  7669. subScopes.pop();
  7670. }
  7671. CIArrayOf<CScope> &querySubScopes() { return subScopes; }
  7672. CFileMatchArray &queryFiles() { return files; }
  7673. };
  7674. typedef CIArrayOf<CScope> CScopeArray;
  7675. const char* DFUQFilterFieldNames[] = { "", "@description", "@directory", "@group", "@modified", "@name", "@numclusters", "@numparts",
  7676. "@partmask", "@OrigName", "Attr", "Attr/@job", "Attr/@owner", "Attr/@recordCount", "Attr/@recordSize", "Attr/@size",
  7677. "Attr/@compressedsize", "Attr/@workunit", "Cluster", "Cluster/@defaultBaseDir", "Cluster/@defaultReplDir", "Cluster/@mapFlags",
  7678. "Cluster/@name", "Part", "Part/@name", "Part/@num", "Part/@size", "SuperOwner", "SuperOwner/@name",
  7679. "SubFile", "SubFile/@name", "SubFile/@num" };
  7680. extern da_decl const char* getDFUQFilterFieldName(DFUQFilterField feild)
  7681. {
  7682. return DFUQFilterFieldNames[feild];
  7683. }
  7684. class CDFUSFFilter : public CInterface
  7685. {
  7686. DFUQFilterType filterType;
  7687. StringAttr attrPath;
  7688. bool hasFilter;
  7689. bool hasFilterHigh;
  7690. StringAttr filterValue;
  7691. StringAttr filterValueHigh;
  7692. int filterValueInt;
  7693. int filterValueHighInt;
  7694. __int64 filterValueInt64;
  7695. __int64 filterValueHighInt64;
  7696. bool filterValueBoolean;
  7697. StringAttr sep;
  7698. StringArray filterArray;
  7699. public:
  7700. CDFUSFFilter(DFUQFilterType _filterType, const char *_attrPath, const char *_filterValue, const char *_filterValueHigh)
  7701. : filterType(_filterType), attrPath(_attrPath), filterValue(_filterValue), filterValueHigh(_filterValueHigh) {};
  7702. CDFUSFFilter(DFUQFilterType _filterType, const char *_attrPath, bool _hasFilter, const int _filterValue, bool _hasFilterHigh, const int _filterValueHigh)
  7703. : filterType(_filterType), attrPath(_attrPath), hasFilter(_hasFilter), filterValueInt(_filterValue), hasFilterHigh(_hasFilterHigh), filterValueHighInt(_filterValueHigh) {};
  7704. CDFUSFFilter(DFUQFilterType _filterType, const char *_attrPath, bool _hasFilter, const __int64 _filterValue, bool _hasFilterHigh, const __int64 _filterValueHigh)
  7705. : filterType(_filterType), attrPath(_attrPath), hasFilter(_hasFilter), filterValueInt64(_filterValue), hasFilterHigh(_hasFilterHigh), filterValueHighInt64(_filterValueHigh) {};
  7706. CDFUSFFilter(DFUQFilterType _filterType, const char *_attrPath, bool _filterValue)
  7707. : filterType(_filterType), attrPath(_attrPath), filterValueBoolean(_filterValue) {};
  7708. CDFUSFFilter(DFUQFilterType _filterType, const char *_attrPath, const char *_filterValue, const char *_sep, StringArray& _filterArray)
  7709. : filterType(_filterType), attrPath(_attrPath), filterValue(_filterValue), sep(_sep)
  7710. {
  7711. ForEachItemIn(i,_filterArray)
  7712. {
  7713. const char* filter = _filterArray.item(i);
  7714. if (filter && *filter)
  7715. filterArray.append(filter);
  7716. }
  7717. };
  7718. DFUQFilterType getFilterType() { return filterType;}
  7719. const char * getAttrPath() { return attrPath.get();}
  7720. const char * getFilterValue() { return filterValue.get();}
  7721. const char * getFilterValueHigh() { return filterValueHigh.get();}
  7722. const int getFilterValueInt() { return filterValueInt;}
  7723. const int getFilterValueHighInt() { return filterValueHighInt;}
  7724. const __int64 getFilterValueInt64() { return filterValueInt64;}
  7725. const __int64 getFilterValueHighInt64() { return filterValueHighInt64;}
  7726. const bool getFilterValueBoolean() { return filterValueBoolean;}
  7727. const char * getSep() { return sep.get();}
  7728. void getFilterArray(StringArray &filters)
  7729. {
  7730. ForEachItemIn(c, filterArray)
  7731. filters.append(filterArray.item(c));
  7732. }
  7733. bool checkFilter(IPropertyTree &file)
  7734. {
  7735. bool match = true;
  7736. switch(filterType)
  7737. {
  7738. case DFUQFTwildcardMatch:
  7739. match = doWildMatch(file);
  7740. break;
  7741. case DFUQFTbooleanMatch:
  7742. match = doBooleanMatch(file);
  7743. break;
  7744. case DFUQFThasProp:
  7745. match = checkHasPropFilter(file);
  7746. break;
  7747. case DFUQFTcontainString:
  7748. match = checkContainStringFilter(file);
  7749. break;
  7750. case DFUQFTstringRange:
  7751. match = checkStringRangeFilter(file);
  7752. break;
  7753. case DFUQFTintegerRange:
  7754. match = checkIntegerRangeFilter(file);
  7755. break;
  7756. case DFUQFTinteger64Range:
  7757. match = checkInteger64RangeFilter(file);
  7758. break;
  7759. }
  7760. return match;
  7761. }
  7762. bool doWildMatch(IPropertyTree &file)
  7763. {
  7764. const char* filter = filterValue.get();
  7765. if (!attrPath.get() || !filter || !*filter || streq(filter, "*"))
  7766. return true;
  7767. const char* prop = file.queryProp(attrPath.get());
  7768. if (prop && WildMatch(prop, filter, true))
  7769. return true;
  7770. return false;
  7771. }
  7772. bool doBooleanMatch(IPropertyTree &file)
  7773. {
  7774. if (!attrPath.get())
  7775. return true;
  7776. return filterValueBoolean == file.getPropBool(attrPath.get(), true);
  7777. }
  7778. bool checkHasPropFilter(IPropertyTree &file)
  7779. {
  7780. if (!attrPath.get())
  7781. return true;
  7782. return filterValueBoolean == file.hasProp(attrPath.get());
  7783. }
  7784. bool checkContainStringFilter(IPropertyTree &file)
  7785. {
  7786. if (!attrPath.get())
  7787. return true;
  7788. const char* prop = file.queryProp(attrPath.get());
  7789. if (!prop || !*prop)
  7790. return false;
  7791. bool found = false;
  7792. if (!sep.get())
  7793. {
  7794. if (filterArray.find(prop) != NotFound) //Match with one of values in the filter
  7795. found = true;
  7796. return found;
  7797. }
  7798. StringArray propArray;
  7799. propArray.appendListUniq(prop, sep.get());
  7800. ForEachItemIn(i,propArray)
  7801. {
  7802. const char* value = propArray.item(i);
  7803. if (!value || !*value)
  7804. continue;
  7805. if (filterArray.find(value) != NotFound) //Match with one of values in the filter
  7806. {
  7807. found = true;
  7808. break;
  7809. }
  7810. }
  7811. return found;
  7812. }
  7813. bool checkStringRangeFilter(IPropertyTree &file)
  7814. {
  7815. if (!attrPath.get())
  7816. return true;
  7817. const char* prop = file.queryProp(attrPath.get());
  7818. if (!prop || !*prop)
  7819. return false;
  7820. if (filterValue && (strcmp(filterValue, prop) > 0))
  7821. return false;
  7822. if (filterValueHigh && (strcmp(filterValueHigh, prop) < 0))
  7823. return false;
  7824. return true;
  7825. }
  7826. bool checkIntegerRangeFilter(IPropertyTree &file)
  7827. {
  7828. if (!attrPath.get())
  7829. return true;
  7830. int prop = file.getPropInt(attrPath.get());
  7831. if (hasFilter && (prop < filterValueInt))
  7832. return false;
  7833. if (hasFilterHigh && (prop > filterValueHighInt))
  7834. return false;
  7835. return true;
  7836. }
  7837. bool checkInteger64RangeFilter(IPropertyTree &file)
  7838. {
  7839. if (!attrPath.get())
  7840. return true;
  7841. __int64 prop = file.getPropInt64(attrPath.get());
  7842. if (hasFilter && (prop < filterValueInt64))
  7843. return false;
  7844. if (hasFilterHigh && (prop > filterValueHighInt64))
  7845. return false;
  7846. return true;
  7847. }
  7848. };
  7849. typedef CIArrayOf<CDFUSFFilter> CDFUSFFilterArray;
  7850. class CFileScanFilterContainer : public CInterface
  7851. {
  7852. StringAttr filterBuf; //Hold original filter string just in case
  7853. StringAttr wildNameFilter;
  7854. DFUQFileTypeFilter fileTypeFilter;
  7855. CIArrayOf<CDFUSFFilter> filters;
  7856. //The 'filters' contains the file scan filters other than wildNameFilter and fileTypeFilter. Those filters are used for
  7857. //filtering the files using File Attributes tree and CDFUSFFilter::checkFilter(). The wildNameFilter and fileTypeFilter need
  7858. //special code to filter the files.
  7859. bool isValidInteger(const char *s)
  7860. {
  7861. if (!s)
  7862. return false;
  7863. while (*s)
  7864. {
  7865. if ((*s != '-') && !isdigit(*s))
  7866. return false;
  7867. s++;
  7868. }
  7869. return true;
  7870. }
  7871. void addFilter(DFUQFilterType filterType, const char* attr, const char* value, const char* valueHigh)
  7872. {
  7873. if (!attr || !*attr)
  7874. return;
  7875. if ((DFUQFTwildcardMatch == filterType) || (DFUQFTstringRange == filterType))
  7876. {
  7877. filters.append(*new CDFUSFFilter(filterType, attr, value, valueHigh));
  7878. return;
  7879. }
  7880. if ((DFUQFTbooleanMatch == filterType) || (DFUQFThasProp == filterType))
  7881. {
  7882. bool filter = true;
  7883. if (value && (streq(value, "0") || strieq(value, "false")))
  7884. filter = false;
  7885. filters.append(*new CDFUSFFilter(filterType, attr, filter));
  7886. return;
  7887. }
  7888. if ((DFUQFTintegerRange == filterType) || (DFUQFTinteger64Range == filterType))
  7889. {
  7890. bool hasFilter = false;
  7891. bool hasFilterHigh = false;
  7892. if (value && isValidInteger(value))
  7893. hasFilter = true;
  7894. if (valueHigh && isValidInteger(valueHigh))
  7895. hasFilterHigh = true;
  7896. if (!hasFilter && !hasFilterHigh)
  7897. return;
  7898. if (DFUQFTintegerRange == filterType)
  7899. filters.append(*new CDFUSFFilter(filterType, attr, hasFilter, atoi(value), hasFilterHigh, atoi(valueHigh)));
  7900. else
  7901. filters.append(*new CDFUSFFilter(filterType, attr, hasFilter, (__int64) atol(value), hasFilterHigh, (__int64) atol(valueHigh)));
  7902. return;
  7903. }
  7904. }
  7905. void addFilterArray(DFUQFilterType filterType, const char* attr, const char* value, const char* sep)
  7906. {
  7907. if (!attr || !*attr || !value || !*value)
  7908. return;
  7909. StringArray filterArray;
  7910. filterArray.appendListUniq(value, sep);
  7911. filters.append(*new CDFUSFFilter(filterType, attr, value, sep, filterArray));
  7912. }
  7913. void addSpecialFilter(const char* attr, const char* value)
  7914. {
  7915. if (!attr || !*attr || !value || !*value)
  7916. return;
  7917. if (!isdigit(*attr))
  7918. {
  7919. PROGLOG("Unsupported Speical Filter: %s", attr);
  7920. return;
  7921. }
  7922. DFUQSpecialFilter filterName = (DFUQSpecialFilter) atoi(attr);
  7923. switch(filterName)
  7924. {
  7925. case DFUQSFFileNameWithPrefix:
  7926. wildNameFilter.set(value);
  7927. break;
  7928. case DFUQSFFileType:
  7929. if (isdigit(*value))
  7930. fileTypeFilter = (DFUQFileTypeFilter) atoi(value);
  7931. else
  7932. PROGLOG("Unsupported Speical Filter: %s, value %s", attr, value);
  7933. break;
  7934. default:
  7935. PROGLOG("Unsupported Speical Filter: %d", filterName);
  7936. break;
  7937. }
  7938. }
  7939. bool doWildMatch(const char* filter, const char* value)
  7940. {
  7941. if (!filter || !*filter || streq(filter, "*") || (value && WildMatch(value, filter, true)))
  7942. return true;
  7943. return false;
  7944. }
  7945. public:
  7946. CFileScanFilterContainer()
  7947. {
  7948. fileTypeFilter = DFUQFFTall;
  7949. wildNameFilter.set("*");
  7950. filterBuf.clear();
  7951. };
  7952. void readScanFilters(const char *filterStr)
  7953. {
  7954. if (!filterStr || !*filterStr)
  7955. return;
  7956. filterBuf.set(filterStr);
  7957. StringArray filterStringArray;
  7958. char sep[] = { DFUQFilterSeparator, '\0' };
  7959. filterStringArray.appendList(filterStr, sep);
  7960. unsigned filterFieldsToRead = filterStringArray.length();
  7961. ForEachItemIn(i,filterStringArray)
  7962. {
  7963. const char* filterTypeStr = filterStringArray.item(i);
  7964. if (!filterTypeStr || !*filterTypeStr)
  7965. continue;
  7966. if (!isdigit(*filterTypeStr))
  7967. continue;
  7968. unsigned filterSize = 4;
  7969. DFUQFilterType filterType = (DFUQFilterType) atoi(filterTypeStr);
  7970. switch(filterType)
  7971. {
  7972. case DFUQFTcontainString:
  7973. if (filterFieldsToRead >= filterSize) //DFUQFilterType | filter name | separator | filter value separated by the separator
  7974. addFilterArray(DFUQFTcontainString, filterStringArray.item(i+1), (const char*)filterStringArray.item(i+2), (const char*)filterStringArray.item(i+3));
  7975. break;
  7976. case DFUQFThasProp:
  7977. case DFUQFTbooleanMatch:
  7978. case DFUQFTwildcardMatch:
  7979. filterSize = 3;
  7980. if (filterFieldsToRead >= filterSize) //DFUQFilterType | filter name | filter value
  7981. addFilter(filterType, filterStringArray.item(i+1), (const char*)filterStringArray.item(i+2), NULL);
  7982. break;
  7983. case DFUQFTstringRange:
  7984. case DFUQFTintegerRange:
  7985. case DFUQFTinteger64Range:
  7986. if (filterFieldsToRead >= filterSize) //DFUQFilterType | filter name | from filter | to filter
  7987. addFilter(filterType, filterStringArray.item(i+1), (const char*)filterStringArray.item(i+2), (const char*)filterStringArray.item(i+3));
  7988. break;
  7989. case DFUQFTspecial:
  7990. filterSize = 3;
  7991. if (filterFieldsToRead >= filterSize) //DFUQFilterType | filter name | filter value
  7992. addSpecialFilter(filterStringArray.item(i+1), (const char*)filterStringArray.item(i+2));
  7993. break;
  7994. }
  7995. filterFieldsToRead -= filterSize;
  7996. i += (filterSize - 1);
  7997. }
  7998. }
  7999. bool matchFileScanFilter(const char* name, IPropertyTree &file)
  8000. {
  8001. if (!doWildMatch(wildNameFilter.get(), name))
  8002. return false;
  8003. if (!filters.length())
  8004. return true;
  8005. ForEachItemIn(i,filters)
  8006. {
  8007. CDFUSFFilter &filter = filters.item(i);
  8008. bool match = filter.checkFilter(file);
  8009. if (!match)
  8010. return match;
  8011. }
  8012. return true;
  8013. }
  8014. DFUQFileTypeFilter getFileTypeFilter() { return fileTypeFilter; }
  8015. void setFileTypeFilter(DFUQFileTypeFilter _fileType)
  8016. {
  8017. fileTypeFilter = _fileType;
  8018. }
  8019. const char* getNameFilter() { return wildNameFilter.get(); }
  8020. void setNameFilter(const char* _wildName)
  8021. {
  8022. if (!_wildName || !*_wildName)
  8023. return;
  8024. wildNameFilter.set(_wildName);
  8025. }
  8026. };
  8027. class CFileScanner
  8028. {
  8029. bool recursive;
  8030. bool includesuper;
  8031. StringAttr wildname;
  8032. Owned<CScope> topLevelScope;
  8033. CScope *currentScope;
  8034. bool fileScanWithFilter;
  8035. CFileScanFilterContainer fileScanFilterContainer;
  8036. bool scopeMatch(const char *name)
  8037. { // name has trailing '::'
  8038. if (!name || !*name)
  8039. return true;
  8040. const char *s1 = NULL;
  8041. if (!fileScanWithFilter)
  8042. s1 = wildname.get();
  8043. else
  8044. s1 = fileScanFilterContainer.getNameFilter();
  8045. if (!s1 || !*s1)
  8046. return true;
  8047. const char *s2 = name;
  8048. while (*s2) {
  8049. if (*s1=='*') {
  8050. if (recursive)
  8051. return true;
  8052. if (*s2==':')
  8053. return false;
  8054. // '*' can only come at end of scope in non-recursive
  8055. while (*s1&&(*s1!=':'))
  8056. s1++;
  8057. while (*s2&&(*s2!=':'))
  8058. s2++;
  8059. }
  8060. else if ((*s1==*s2)||(*s1=='?')) {
  8061. s1++;
  8062. s2++;
  8063. }
  8064. else
  8065. return false;
  8066. }
  8067. return true;
  8068. }
  8069. bool processScopes(IPropertyTree &root,StringBuffer &name)
  8070. {
  8071. bool ret = false;
  8072. CScope *parentScope = currentScope;
  8073. if (parentScope)
  8074. currentScope = parentScope->addScope(name);
  8075. else
  8076. { // once only
  8077. topLevelScope.setown(new CScope(""));
  8078. currentScope = topLevelScope;
  8079. }
  8080. size32_t ns = name.length();
  8081. if (ns)
  8082. name.append("::");
  8083. size32_t ns2 = name.length();
  8084. if (scopeMatch(name.str())) {
  8085. Owned<IPropertyTreeIterator> iter = root.getElements(queryDfsXmlBranchName(DXB_Scope));
  8086. if (iter->first()) {
  8087. do {
  8088. IPropertyTree &scope = iter->query();
  8089. if (scope.hasChildren()) {
  8090. name.append(scope.queryProp("@name"));
  8091. ret |= processScopes(scope, name);
  8092. name.setLength(ns2);
  8093. }
  8094. } while (iter->next());
  8095. }
  8096. if (!fileScanWithFilter)
  8097. ret |= processFiles(root,name);
  8098. else
  8099. ret |= processFilesWithFilters(root,name);
  8100. }
  8101. if (!ret && parentScope)
  8102. parentScope->popLastScope(); // discard scopes where no matches
  8103. currentScope = parentScope;
  8104. name.setLength(ns);
  8105. return ret;
  8106. }
  8107. bool processFiles(IPropertyTree &root,StringBuffer &name)
  8108. {
  8109. bool ret = false;
  8110. const char *s1 = wildname.get();
  8111. size32_t ns = name.length();
  8112. Owned<IPropertyTreeIterator> iter = root.getElements(queryDfsXmlBranchName(DXB_File));
  8113. if (iter->first()) {
  8114. IPropertyTree &scope = iter->query();
  8115. do {
  8116. IPropertyTree &file = iter->query();
  8117. name.append(file.queryProp("@name"));
  8118. if (!s1||WildMatch(name.str(),s1,true)) {
  8119. currentScope->addMatch(name,file,false);
  8120. ret = true;
  8121. }
  8122. name.setLength(ns);
  8123. } while (iter->next());
  8124. }
  8125. if (includesuper) {
  8126. iter.setown(root.getElements(queryDfsXmlBranchName(DXB_SuperFile)));
  8127. if (iter->first()) {
  8128. do {
  8129. IPropertyTree &file = iter->query();
  8130. name.append(file.queryProp("@name"));
  8131. if (!s1||WildMatch(name.str(),s1,true)) {
  8132. currentScope->addMatch(name,file,true);
  8133. ret = true;
  8134. }
  8135. name.setLength(ns);
  8136. } while (iter->next());
  8137. }
  8138. }
  8139. return ret;
  8140. }
  8141. bool processFilesWithFilters(IPropertyTree &root, StringBuffer &name)
  8142. {
  8143. bool ret = false;
  8144. size32_t ns = name.length();
  8145. DFUQFileTypeFilter fileTypeFilter = fileScanFilterContainer.getFileTypeFilter();
  8146. if (fileTypeFilter != DFUQFFTsuperfileonly)
  8147. addMatchedFiles(root.getElements(queryDfsXmlBranchName(DXB_File)), false, name, ns, ret);
  8148. if ((fileTypeFilter == DFUQFFTall) || (fileTypeFilter == DFUQFFTsuperfileonly))
  8149. addMatchedFiles(root.getElements(queryDfsXmlBranchName(DXB_SuperFile)), true, name, ns, ret);
  8150. return ret;
  8151. }
  8152. void addMatchedFiles(IPropertyTreeIterator* files, bool isSuper, StringBuffer &name, size32_t ns, bool& ret)
  8153. {
  8154. Owned<IPropertyTreeIterator> iter = files;
  8155. ForEach(*iter)
  8156. {
  8157. IPropertyTree &file = iter->query();
  8158. name.append(file.queryProp("@name"));
  8159. if (fileScanFilterContainer.matchFileScanFilter(name.str(), file))
  8160. {
  8161. currentScope->addMatch(name,file,isSuper);
  8162. ret = true;
  8163. }
  8164. name.setLength(ns);
  8165. }
  8166. }
  8167. public:
  8168. void scan(IPropertyTree *sroot, const char *_wildname,bool _recursive,bool _includesuper)
  8169. {
  8170. fileScanWithFilter = false;
  8171. if (_wildname)
  8172. wildname.set(_wildname);
  8173. else
  8174. wildname.clear();
  8175. recursive = _recursive;
  8176. includesuper = _includesuper;
  8177. StringBuffer name;
  8178. topLevelScope.clear();
  8179. currentScope = NULL;
  8180. processScopes(*sroot->queryPropTree(querySdsFilesRoot()),name);
  8181. }
  8182. void scan(IPropertyTree *sroot, const char *filters, bool _recursive)
  8183. {
  8184. fileScanWithFilter = true;
  8185. recursive = _recursive;
  8186. fileScanFilterContainer.readScanFilters(filters);
  8187. StringBuffer name;
  8188. topLevelScope.clear();
  8189. currentScope = NULL;
  8190. processScopes(*sroot->queryPropTree(querySdsFilesRoot()),name);
  8191. }
  8192. void _getResults(bool auth, IUserDescriptor *user, CScope &scope, CFileMatchArray &matchingFiles, StringArray &authScopes, unsigned &count)
  8193. {
  8194. if (auth)
  8195. {
  8196. int perm = getScopePermissions(scope.getName(),user,0); // don't audit
  8197. if (!HASREADPERMISSION(perm))
  8198. return;
  8199. authScopes.append(scope.getName());
  8200. }
  8201. CFileMatchArray &files = scope.queryFiles();
  8202. ForEachItemIn(f, files)
  8203. {
  8204. CFileMatch *match = &files.item(f);
  8205. matchingFiles.append(*LINK(match));
  8206. ++count;
  8207. }
  8208. CScopeArray &subScopes = scope.querySubScopes();
  8209. ForEachItemIn(s, subScopes)
  8210. {
  8211. CScope &subScope = subScopes.item(s);
  8212. _getResults(auth, user, subScope, matchingFiles, authScopes, count);
  8213. }
  8214. }
  8215. unsigned getResults(bool auth, IUserDescriptor *user, CFileMatchArray &matchingFiles, StringArray &authScopes)
  8216. {
  8217. unsigned count = 0;
  8218. _getResults(auth, user, *topLevelScope, matchingFiles, authScopes, count);
  8219. return count;
  8220. }
  8221. };
  8222. struct CMachineEntry: public CInterface
  8223. {
  8224. CMachineEntry(const char *_mname,SocketEndpoint _ep)
  8225. : mname(_mname),ep(_ep)
  8226. {
  8227. }
  8228. StringAttr mname;
  8229. SocketEndpoint ep;
  8230. };
  8231. typedef CMachineEntry *CMachineEntryPtr;
  8232. typedef MapStringTo<CMachineEntryPtr> CMachineEntryMap;
  8233. StringBuffer &getClusterGroupName(IPropertyTree &cluster, StringBuffer &groupName)
  8234. {
  8235. const char *name = cluster.queryProp("@name");
  8236. const char *nodeGroupName = cluster.queryProp("@nodeGroup");
  8237. if (nodeGroupName && *nodeGroupName)
  8238. name = nodeGroupName;
  8239. groupName.append(name);
  8240. return groupName.trim().toLowerCase();
  8241. }
  8242. StringBuffer &getClusterSpareGroupName(IPropertyTree &cluster, StringBuffer &groupName)
  8243. {
  8244. return getClusterGroupName(cluster, groupName).append("_spares");
  8245. }
  8246. // JCSMORE - dfs group handling may be clearer if in own module
  8247. class CInitGroups
  8248. {
  8249. CMachineEntryMap machinemap;
  8250. CIArrayOf<CMachineEntry> machinelist;
  8251. CConnectLock groupsconnlock;
  8252. StringArray clusternames;
  8253. unsigned defaultTimeout;
  8254. bool clusterGroupCompare(IPropertyTree *newClusterGroup, IPropertyTree *oldClusterGroup)
  8255. {
  8256. if (!newClusterGroup && oldClusterGroup)
  8257. return false;
  8258. else if (!oldClusterGroup && newClusterGroup)
  8259. return false;
  8260. if (!newClusterGroup) // both null
  8261. return true;
  8262. // see if identical
  8263. const char *oldKind = oldClusterGroup?oldClusterGroup->queryProp("@kind"):NULL;
  8264. const char *oldDir = oldClusterGroup?oldClusterGroup->queryProp("@dir"):NULL;
  8265. const char *newKind = newClusterGroup?newClusterGroup->queryProp("@kind"):NULL;
  8266. const char *newDir = newClusterGroup?newClusterGroup->queryProp("@dir"):NULL;
  8267. if (oldKind) {
  8268. if (newKind) {
  8269. if (!streq(newKind, newKind))
  8270. return false;
  8271. }
  8272. else
  8273. return false;
  8274. }
  8275. else if (newKind)
  8276. return false;
  8277. if (oldDir) {
  8278. if (newDir) {
  8279. if (!streq(newDir,oldDir))
  8280. return false;
  8281. }
  8282. else
  8283. return false;
  8284. }
  8285. else if (NULL!=newDir)
  8286. return false;
  8287. unsigned oldGroupCount = oldClusterGroup->getCount("Node");
  8288. unsigned newGroupCount = newClusterGroup->getCount("Node");
  8289. if (oldGroupCount != newGroupCount)
  8290. return false;
  8291. if (0 == newGroupCount)
  8292. return true;
  8293. Owned<IPropertyTreeIterator> newIter = newClusterGroup->getElements("Node");
  8294. Owned<IPropertyTreeIterator> oldIter = oldClusterGroup->getElements("Node");
  8295. if (newIter->first() && oldIter->first()) {
  8296. loop {
  8297. const char *oldIp = oldIter->query().queryProp("@ip");
  8298. const char *newIp = newIter->query().queryProp("@ip");
  8299. if (!streq(oldIp, newIp))
  8300. return false;
  8301. if (!oldIter->next() || !newIter->next())
  8302. break;
  8303. }
  8304. }
  8305. return true;
  8306. }
  8307. void addClusterGroup(const char *name, IPropertyTree *newClusterGroup, bool realCluster)
  8308. {
  8309. VStringBuffer prop("Group[@name=\"%s\"]", name);
  8310. IPropertyTree *root = groupsconnlock.conn->queryRoot();
  8311. IPropertyTree *old = root->queryPropTree(prop.str());
  8312. if (old) {
  8313. // JCSMORE
  8314. // clone
  8315. // iterate through files and point to clone
  8316. // i) if change is minor, worth swapping to new group anyway?
  8317. // ii) if old group has machines that are no longer in new environment, mark file bad?
  8318. root->removeTree(old);
  8319. }
  8320. if (!newClusterGroup)
  8321. return;
  8322. if (realCluster)
  8323. clusternames.append(name);
  8324. IPropertyTree *grp = root->addPropTree("Group", newClusterGroup);
  8325. grp->setProp("@name", name);
  8326. }
  8327. IGroup *getGroupFromCluster(GroupType groupType, IPropertyTree &cluster)
  8328. {
  8329. SocketEndpointArray eps;
  8330. const char *processName=NULL;
  8331. switch (groupType) {
  8332. case grp_thor:
  8333. processName = "ThorSlaveProcess";
  8334. break;
  8335. case grp_thorspares:
  8336. processName = "ThorSpareProcess";
  8337. break;
  8338. case grp_roxie:
  8339. processName = "RoxieServerProcess";
  8340. break;
  8341. default:
  8342. throwUnexpected();
  8343. }
  8344. SocketEndpoint nullep;
  8345. Owned<IPropertyTreeIterator> nodes = cluster.getElements(processName);
  8346. ForEach(*nodes) {
  8347. IPropertyTree &node = nodes->query();
  8348. SocketEndpoint ep;
  8349. const char *computer = node.queryProp("@computer");
  8350. const char *netAddress = node.queryProp("@netAddress");
  8351. if (computer && *computer)
  8352. {
  8353. CMachineEntryPtr *m = machinemap.getValue(computer);
  8354. if (!m) {
  8355. ERRLOG("Cannot construct %s, computer name %s not found\n", cluster.queryProp("@name"), computer);
  8356. return NULL;
  8357. }
  8358. ep.set((*m)->ep);
  8359. }
  8360. else if (netAddress && *netAddress)
  8361. {
  8362. ep.set(netAddress, 0);
  8363. }
  8364. else
  8365. {
  8366. ERRLOG("Cannot construct %s, missing computer spec on node\n", cluster.queryProp("@name"));
  8367. return NULL;
  8368. }
  8369. switch (groupType) {
  8370. case grp_roxie:
  8371. // Redundant copies are located via the flags.
  8372. // Old environments may contain duplicated sever information for multiple ports
  8373. eps.appendUniq(ep);
  8374. break;
  8375. case grp_thor:
  8376. case grp_thorspares:
  8377. eps.append(ep);
  8378. break;
  8379. default:
  8380. throwUnexpected();
  8381. }
  8382. }
  8383. if (!eps.ordinality())
  8384. return NULL;
  8385. Owned<IGroup> grp;
  8386. unsigned slavesPerNode = 0;
  8387. if (grp_thor == groupType)
  8388. slavesPerNode = cluster.getPropInt("@slavesPerNode");
  8389. if (slavesPerNode)
  8390. {
  8391. SocketEndpointArray msEps;
  8392. for (unsigned s=0; s<slavesPerNode; s++) {
  8393. ForEachItemIn(e, eps)
  8394. msEps.append(eps.item(e));
  8395. }
  8396. grp.setown(createIGroup(msEps));
  8397. }
  8398. else
  8399. grp.setown(createIGroup(eps));
  8400. return grp.getClear();
  8401. }
  8402. bool loadMachineMap()
  8403. {
  8404. Owned<IRemoteConnection> conn = querySDS().connect("/Environment/Hardware", myProcessSession(), RTM_LOCK_READ, SDS_CONNECT_TIMEOUT);
  8405. if (!conn) {
  8406. WARNLOG("Cannot connect to /Environment/Hardware");
  8407. return false;
  8408. }
  8409. IPropertyTree* root = conn->queryRoot();
  8410. Owned<IPropertyTreeIterator> machines= root->getElements("Computer");
  8411. ForEach(*machines) {
  8412. IPropertyTree &machine = machines->query();
  8413. SocketEndpoint ep(machine.queryProp("@netAddress"));
  8414. const char *name = machine.queryProp("@name");
  8415. CMachineEntry *entry = new CMachineEntry(name,ep);
  8416. machinemap.setValue(name, entry);
  8417. machinelist.append(*entry);
  8418. }
  8419. return true;
  8420. }
  8421. IPropertyTree *createClusterGroup(GroupType groupType, IGroup *group, const char *dir, bool realCluster)
  8422. {
  8423. Owned<IPropertyTree> cluster = createPTree("Group");
  8424. if (realCluster)
  8425. cluster->setPropBool("@cluster", true);
  8426. const char *kind=NULL;
  8427. switch (groupType) {
  8428. case grp_thor:
  8429. kind = "Thor";
  8430. break;
  8431. case grp_roxie:
  8432. kind = "Roxie";
  8433. break;
  8434. case grp_hthor:
  8435. kind = "hthor";
  8436. break;
  8437. }
  8438. if (kind)
  8439. cluster->setProp("@kind",kind);
  8440. if (dir)
  8441. cluster->setProp("@dir",dir);
  8442. Owned<INodeIterator> iter = group->getIterator();
  8443. StringBuffer str;
  8444. ForEach(*iter) {
  8445. iter->query().endpoint().getIpText(str.clear());
  8446. IPropertyTree *n = createPTree("Node");
  8447. n->setProp("@ip",str.str());
  8448. cluster->addPropTree("Node", n);
  8449. }
  8450. return cluster.getClear();
  8451. }
  8452. IPropertyTree *createClusterGroupFromEnvCluster(GroupType groupType, IPropertyTree &cluster, const char *dir, bool realCluster)
  8453. {
  8454. Owned<IGroup> group = getGroupFromCluster(groupType, cluster);
  8455. if (!group)
  8456. return NULL;
  8457. return createClusterGroup(groupType, group, dir, realCluster);
  8458. }
  8459. bool constructGroup(IPropertyTree &cluster, const char *altName, IPropertyTree *oldEnvCluster, GroupType groupType, bool force, StringBuffer &messages)
  8460. {
  8461. /* a 'realCluster' is a cluster who's name matches it's nodeGroup
  8462. * if the nodeGroup differs it implies it's sharing the nodeGroup with other thor instance(s).
  8463. */
  8464. bool realCluster = true;
  8465. bool oldRealCluster = true;
  8466. StringBuffer gname, oldGname;
  8467. const char *defDir = NULL;
  8468. switch (groupType)
  8469. {
  8470. case grp_thor:
  8471. getClusterGroupName(cluster, gname);
  8472. if (!streq(cluster.queryProp("@name"), gname.str()))
  8473. realCluster = false;
  8474. if (oldEnvCluster)
  8475. {
  8476. getClusterGroupName(*oldEnvCluster, oldGname);
  8477. if (!streq(oldEnvCluster->queryProp("@name"), oldGname.str()))
  8478. oldRealCluster = false;
  8479. }
  8480. break;
  8481. case grp_thorspares:
  8482. getClusterSpareGroupName(cluster, gname);
  8483. realCluster = false;
  8484. break;
  8485. case grp_roxie:
  8486. gname.append(cluster.queryProp("@name"));
  8487. break;
  8488. default:
  8489. throwUnexpected();
  8490. }
  8491. if (altName)
  8492. gname.clear().append(altName).toLowerCase();
  8493. VStringBuffer xpath("Group[@name=\"%s\"]", gname.str());
  8494. IPropertyTree *existingClusterGroup = groupsconnlock.conn->queryRoot()->queryPropTree(xpath.str()); // 'live' cluster group
  8495. bool matchOldEnv = false;
  8496. Owned<IPropertyTree> newClusterGroup = createClusterGroupFromEnvCluster(groupType, cluster, defDir, realCluster);
  8497. bool matchExisting = clusterGroupCompare(newClusterGroup, existingClusterGroup);
  8498. if (oldEnvCluster)
  8499. {
  8500. // new matches old, only if neither has changed it's name to mismatch it's nodeGroup name
  8501. if (realCluster == oldRealCluster)
  8502. {
  8503. Owned<IPropertyTree> oldClusterGroup = createClusterGroupFromEnvCluster(groupType, *oldEnvCluster, defDir, oldRealCluster);
  8504. matchOldEnv = clusterGroupCompare(newClusterGroup, oldClusterGroup);
  8505. }
  8506. else
  8507. matchOldEnv = false;
  8508. }
  8509. if (force && !matchExisting)
  8510. {
  8511. VStringBuffer msg("Forcing new group layout for %s [ matched active = %s, matched old environment = %s ]", gname.str(), matchExisting?"true":"false", matchOldEnv?"true":"false");
  8512. WARNLOG("%s", msg.str());
  8513. messages.append(msg).newline();
  8514. matchExisting = matchOldEnv = false;
  8515. }
  8516. if (!existingClusterGroup || (!matchExisting && !matchOldEnv))
  8517. {
  8518. VStringBuffer msg("New cluster layout for cluster %s", gname.str());
  8519. WARNLOG("%s", msg.str());
  8520. messages.append(msg).newline();
  8521. addClusterGroup(gname.str(), newClusterGroup.getClear(), realCluster);
  8522. return true;
  8523. }
  8524. return false;
  8525. }
  8526. void constructHThorGroups(IPropertyTree &cluster)
  8527. {
  8528. const char *groupname = cluster.queryProp("@name");
  8529. if (!groupname || !*groupname)
  8530. return;
  8531. unsigned ins = 0;
  8532. Owned<IPropertyTreeIterator> insts = cluster.getElements("Instance");
  8533. ForEach(*insts) {
  8534. const char *na = insts->query().queryProp("@netAddress");
  8535. if (na&&*na) {
  8536. SocketEndpoint ep(na);
  8537. if (!ep.isNull()) {
  8538. ins++;
  8539. VStringBuffer gname("hthor__%s", groupname);
  8540. if (ins>1)
  8541. gname.append('_').append(ins);
  8542. Owned<IGroup> group = createIGroup(1, &ep);
  8543. Owned<IPropertyTree> clusterGroup = createClusterGroup(grp_hthor, group, NULL, true);
  8544. addClusterGroup(gname.str(), clusterGroup.getClear(), true);
  8545. }
  8546. }
  8547. }
  8548. }
  8549. enum CgCmd { cg_null, cg_reset, cg_add, cg_remove };
  8550. public:
  8551. CInitGroups(unsigned _defaultTimeout)
  8552. : groupsconnlock("constructGroup",SDS_GROUPSTORE_ROOT,true,false,false,_defaultTimeout)
  8553. {
  8554. defaultTimeout = _defaultTimeout;
  8555. }
  8556. bool doClusterGroup(CgCmd cmd, const char *_clusterName, const char *type, bool spares, SocketEndpointArray *eps, StringBuffer &messages)
  8557. {
  8558. Owned<IRemoteConnection> conn = querySDS().connect("/Environment/Software", myProcessSession(), RTM_LOCK_READ, SDS_CONNECT_TIMEOUT);
  8559. if (!conn)
  8560. return false;
  8561. if (!_clusterName || !*_clusterName)
  8562. return false;
  8563. StringAttr clusterName = _clusterName;
  8564. clusterName.toLowerCase();
  8565. if (!type || !*type)
  8566. return false;
  8567. bool ret = true;
  8568. IPropertyTree* root = conn->queryRoot();
  8569. Owned<IPropertyTreeIterator> clusters;
  8570. StringBuffer errMsg;
  8571. const char *clusterType = type;
  8572. if (loadMachineMap()) {
  8573. VStringBuffer xpath("%s[@name=\"%s\"]", type, clusterName.get());
  8574. clusters.setown(root->getElements(xpath.str()));
  8575. if (!clusters || !clusters->first()) {
  8576. VStringBuffer errMsg("Could not find type %s, %s cluster", type, clusterName.get());
  8577. WARNLOG("%s", errMsg.str());
  8578. messages.append(errMsg).newline();
  8579. ret = false;
  8580. }
  8581. else {
  8582. if (!streq("ThorCluster", type))
  8583. return false; // currently only Thor supported here.
  8584. IPropertyTree &cluster = clusters->query();
  8585. switch (cmd) {
  8586. case cg_reset:
  8587. {
  8588. if (spares) {
  8589. if (!constructGroup(cluster,NULL,NULL,grp_thorspares,true,messages))
  8590. ret = false;
  8591. }
  8592. else {
  8593. if (!constructGroup(cluster,NULL,NULL,grp_thor,true,messages))
  8594. ret = false;
  8595. }
  8596. break;
  8597. }
  8598. case cg_add:
  8599. {
  8600. assertex(eps);
  8601. StringBuffer groupName;
  8602. getClusterSpareGroupName(cluster, groupName);
  8603. IPropertyTree *root = groupsconnlock.conn->queryRoot();
  8604. VStringBuffer xpath("Group[@name=\"%s\"]",groupName.str());
  8605. IPropertyTree *existing = root->queryPropTree(xpath.str());
  8606. if (existing) {
  8607. Owned<IPropertyTreeIterator> iter = existing->getElements("Node");
  8608. ForEach(*iter) {
  8609. SocketEndpoint ep(iter->query().queryProp("@ip"));
  8610. if (eps->zap(ep)) {
  8611. StringBuffer epStr;
  8612. VStringBuffer errMsg("addSpares: not adding: %s, already in spares", ep.getUrlStr(epStr).str());
  8613. WARNLOG("%s", errMsg.str());
  8614. messages.append(errMsg).newline();
  8615. while (eps->zap(ep)); // delete any other duplicates
  8616. }
  8617. }
  8618. }
  8619. else {
  8620. existing = createPTree();
  8621. existing->setProp("@name", groupName.str());
  8622. existing = root->addPropTree("Group", existing);
  8623. }
  8624. // add remaining
  8625. ForEachItemIn(e, *eps) {
  8626. SocketEndpoint &ep = eps->item(e);
  8627. StringBuffer ipStr;
  8628. ep.getIpText(ipStr);
  8629. IPropertyTree *node = createPTree();
  8630. node->setProp("@ip", ipStr.str());
  8631. existing->addPropTree("Node", node);
  8632. }
  8633. break;
  8634. }
  8635. case cg_remove:
  8636. {
  8637. assertex(eps);
  8638. StringBuffer groupName;
  8639. getClusterSpareGroupName(cluster, groupName);
  8640. IPropertyTree *root = groupsconnlock.conn->queryRoot();
  8641. VStringBuffer xpath("Group[@name=\"%s\"]", groupName.str());
  8642. IPropertyTree *existing = root->queryPropTree(xpath.str());
  8643. if (existing) {
  8644. ForEachItemIn(e, *eps) {
  8645. SocketEndpoint &ep = eps->item(e);
  8646. StringBuffer ipStr;
  8647. ep.getIpText(ipStr);
  8648. VStringBuffer xpath("Node[@ip=\"%s\"]", ipStr.str());
  8649. if (!existing->removeProp(xpath.str())) {
  8650. VStringBuffer errMsg("removeSpares: %s not found in spares", ipStr.str());
  8651. WARNLOG("%s", errMsg.str());
  8652. messages.append(errMsg).newline();
  8653. while (eps->zap(ep)); // delete any other duplicates
  8654. }
  8655. else
  8656. while (existing->removeProp(xpath.str())); // remove any others, shouldn't be any
  8657. }
  8658. }
  8659. break;
  8660. }
  8661. }
  8662. if (clusters->next()) {
  8663. VStringBuffer errMsg("resetThorGroup: more than one cluster named: %s", clusterName.get());
  8664. WARNLOG("%s", errMsg.str());
  8665. messages.append(errMsg).newline();
  8666. ret = false;
  8667. }
  8668. }
  8669. }
  8670. return ret;
  8671. }
  8672. bool resetClusterGroup(const char *clusterName, const char *type, bool spares, StringBuffer &messages)
  8673. {
  8674. return doClusterGroup(cg_reset, clusterName, type, spares, NULL, messages);
  8675. }
  8676. bool addSpares(const char *clusterName, const char *type, SocketEndpointArray &eps, StringBuffer &messages)
  8677. {
  8678. return doClusterGroup(cg_add, clusterName, type, true, &eps, messages);
  8679. }
  8680. bool removeSpares(const char *clusterName, const char *type, SocketEndpointArray &eps, StringBuffer &messages)
  8681. {
  8682. return doClusterGroup(cg_remove, clusterName, type, true, &eps, messages);
  8683. }
  8684. void constructGroups(bool force, StringBuffer &messages, IPropertyTree *oldEnvironment)
  8685. {
  8686. Owned<IRemoteConnection> conn = querySDS().connect("/Environment/Software", myProcessSession(), RTM_LOCK_READ, SDS_CONNECT_TIMEOUT);
  8687. if (!conn)
  8688. return;
  8689. clusternames.kill();
  8690. IPropertyTree* root = conn->queryRoot();
  8691. Owned<IPropertyTreeIterator> clusters;
  8692. if (loadMachineMap()) {
  8693. clusters.setown(root->getElements("ThorCluster"));
  8694. ForEach(*clusters) {
  8695. IPropertyTree &cluster = clusters->query();
  8696. IPropertyTree *oldCluster = NULL;
  8697. if (oldEnvironment) {
  8698. VStringBuffer xpath("Software/ThorCluster[@name=\"%s\"]", cluster.queryProp("@name"));
  8699. oldCluster = oldEnvironment->queryPropTree(xpath.str());
  8700. }
  8701. constructGroup(cluster,NULL,oldCluster,grp_thor,force,messages);
  8702. constructGroup(cluster,NULL,oldCluster,grp_thorspares,force,messages);
  8703. }
  8704. clusters.setown(root->getElements("RoxieCluster"));
  8705. ForEach(*clusters) {
  8706. IPropertyTree &cluster = clusters->query();
  8707. IPropertyTree *oldCluster = NULL;
  8708. if (oldEnvironment) {
  8709. VStringBuffer xpath("Software/RoxieCluster[@name=\"%s\"]", cluster.queryProp("@name"));
  8710. oldCluster = oldEnvironment->queryPropTree(xpath.str());
  8711. }
  8712. constructGroup(cluster,NULL,oldCluster,grp_roxie,force,messages);
  8713. }
  8714. clusters.setown(root->getElements("EclAgentProcess"));
  8715. ForEach(*clusters) {
  8716. IPropertyTree &cluster = clusters->query();
  8717. constructHThorGroups(cluster);
  8718. }
  8719. // correct cluster flags
  8720. // JCSMORE - why was this necessary, may well be legacy..
  8721. Owned<IPropertyTreeIterator> grps = groupsconnlock.conn->queryRoot()->getElements("Group");
  8722. ForEach(*grps) {
  8723. IPropertyTree &grp = grps->query();
  8724. const char *name = grp.queryProp("@name");
  8725. bool iscluster = NotFound != clusternames.find(name);
  8726. if (iscluster!=grp.getPropBool("@cluster"))
  8727. if (iscluster)
  8728. grp.setPropBool("@cluster", true);
  8729. else
  8730. grp.removeProp("@cluster");
  8731. }
  8732. }
  8733. }
  8734. };
  8735. void initClusterGroups(bool force, StringBuffer &response, IPropertyTree *oldEnvironment, unsigned timems)
  8736. {
  8737. CInitGroups init(timems);
  8738. init.constructGroups(force, response, oldEnvironment);
  8739. }
  8740. bool resetClusterGroup(const char *clusterName, const char *type, bool spares, StringBuffer &response, unsigned timems)
  8741. {
  8742. CInitGroups init(timems);
  8743. return init.resetClusterGroup(clusterName, type, spares, response);
  8744. }
  8745. bool addClusterSpares(const char *clusterName, const char *type, SocketEndpointArray &eps, StringBuffer &response, unsigned timems)
  8746. {
  8747. CInitGroups init(timems);
  8748. return init.addSpares(clusterName, type, eps, response);
  8749. }
  8750. bool removeClusterSpares(const char *clusterName, const char *type, SocketEndpointArray &eps, StringBuffer &response, unsigned timems)
  8751. {
  8752. CInitGroups init(timems);
  8753. return init.removeSpares(clusterName, type, eps, response);
  8754. }
  8755. class CDaliDFSServer: public Thread, public CTransactionLogTracker, implements IDaliServer, implements IExceptionHandler
  8756. { // Coven size
  8757. bool stopped;
  8758. unsigned defaultTimeout;
  8759. unsigned numThreads;
  8760. public:
  8761. IMPLEMENT_IINTERFACE;
  8762. CDaliDFSServer(IPropertyTree *config)
  8763. : Thread("CDaliDFSServer"), CTransactionLogTracker(MDFS_MAX)
  8764. {
  8765. stopped = true;
  8766. defaultTimeout = INFINITE; // server uses default
  8767. numThreads = config->getPropInt("DFS/@numThreads", DEFAULT_NUM_DFS_THREADS);
  8768. PROGLOG("DFS Server: numThreads=%d", numThreads);
  8769. }
  8770. ~CDaliDFSServer()
  8771. {
  8772. }
  8773. void start()
  8774. {
  8775. Thread::start();
  8776. }
  8777. void ready()
  8778. {
  8779. }
  8780. void suspend()
  8781. {
  8782. }
  8783. void stop()
  8784. {
  8785. if (!stopped) {
  8786. stopped = true;
  8787. queryCoven().cancel(RANK_ALL,MPTAG_DFS_REQUEST);
  8788. }
  8789. join();
  8790. }
  8791. int run()
  8792. {
  8793. ICoven &coven=queryCoven();
  8794. CMessageHandler<CDaliDFSServer> handler("CDaliDFSServer", this, &CDaliDFSServer::processMessage, this, numThreads, TIMEOUT_ON_CLOSEDOWN, INFINITE);
  8795. CMessageBuffer mb;
  8796. stopped = false;
  8797. while (!stopped)
  8798. {
  8799. try
  8800. {
  8801. mb.clear();
  8802. if (coven.recv(mb,RANK_ALL,MPTAG_DFS_REQUEST,NULL))
  8803. {
  8804. handler.handleMessage(mb);
  8805. mb.clear(); // ^ has copied mb
  8806. }
  8807. else
  8808. stopped = true;
  8809. }
  8810. catch (IException *e)
  8811. {
  8812. EXCLOG(e, "CDaliDFSServer");
  8813. e->Release();
  8814. }
  8815. }
  8816. return 0;
  8817. }
  8818. void iterateFiles(CMessageBuffer &mb,StringBuffer &trc)
  8819. {
  8820. TransactionLog transactionLog(*this, MDFS_ITERATE_FILES, mb.getSender());
  8821. StringAttr wildname;
  8822. bool recursive;
  8823. bool includesuper = false;
  8824. StringAttr attr;
  8825. mb.read(wildname).read(recursive).read(attr);
  8826. trc.appendf("iterateFiles(%s,%s,%s)",wildname.sget(),recursive?"recursive":"",attr.sget());
  8827. if (queryTransactionLogging())
  8828. transactionLog.log("%s", trc.str());
  8829. Owned<IUserDescriptor> udesc;
  8830. if (mb.getPos()<mb.length()) {
  8831. mb.read(includesuper);
  8832. if (mb.getPos()<mb.length()) {
  8833. udesc.setown(createUserDescriptor());
  8834. udesc->deserialize(mb);
  8835. }
  8836. }
  8837. mb.clear();
  8838. unsigned count=0;
  8839. mb.append(count);
  8840. CFileScanner scanner;
  8841. CSDSServerLockBlock sdsLock; // lock sds while scanning
  8842. unsigned start = msTick();
  8843. scanner.scan(sdsLock, wildname.get(),recursive,includesuper);
  8844. unsigned tookMs = msTick()-start;
  8845. if (tookMs>100)
  8846. PROGLOG("TIMING(filescan): %s: took %dms",trc.str(), tookMs);
  8847. sdsLock.unlock(); // unlock to perform authentification
  8848. bool auth = querySessionManager().checkScopeScansLDAP()&&getScopePermissions(NULL,udesc,(unsigned)-1);
  8849. StringArray authScopes;
  8850. CIArrayOf<CFileMatch> matchingFiles;
  8851. start = msTick();
  8852. count = scanner.getResults(auth, udesc, matchingFiles, authScopes);
  8853. tookMs = msTick()-start;
  8854. if (tookMs>100)
  8855. PROGLOG("TIMING(LDAP): %s: took %dms, %d lookups, file matches = %d", trc.str(), tookMs, authScopes.ordinality(), count);
  8856. sdsLock.lock(); // re-lock sds while serializing
  8857. start = msTick();
  8858. ForEachItemIn(m, matchingFiles)
  8859. {
  8860. CFileMatch &fileMatch = matchingFiles.item(m);
  8861. CDFAttributeIterator::serializeFileAttributes(mb, fileMatch.queryFileTree(), fileMatch.queryName(), fileMatch.queryIsSuper());
  8862. }
  8863. tookMs = msTick()-start;
  8864. if (tookMs>100)
  8865. PROGLOG("TIMING(filescan-serialization): %s: took %dms, %d files",trc.str(), tookMs, count);
  8866. mb.writeDirect(0,sizeof(count),&count);
  8867. }
  8868. void iterateFilteredFiles(CMessageBuffer &mb,StringBuffer &trc)
  8869. {
  8870. TransactionLog transactionLog(*this, MDFS_ITERATE_FILTEREDFILES, mb.getSender());
  8871. Owned<IUserDescriptor> udesc;
  8872. StringAttr filters;
  8873. bool recursive;
  8874. mb.read(filters).read(recursive);
  8875. trc.appendf("iterateFilteredFiles(%s,%s)",filters.sget(),recursive?"recursive":"");
  8876. if (queryTransactionLogging())
  8877. transactionLog.log("%s", trc.str());
  8878. if (mb.getPos()<mb.length())
  8879. {
  8880. udesc.setown(createUserDescriptor());
  8881. udesc->deserialize(mb);
  8882. }
  8883. mb.clear();
  8884. unsigned count=0;
  8885. mb.append(count);
  8886. CFileScanner scanner;
  8887. CSDSServerLockBlock sdsLock; // lock sds while scanning
  8888. unsigned start = msTick();
  8889. scanner.scan(sdsLock, filters.get(), recursive);
  8890. unsigned tookMs = msTick()-start;
  8891. if (tookMs>100)
  8892. PROGLOG("TIMING(filescan): %s: took %dms",trc.str(), tookMs);
  8893. sdsLock.unlock(); // unlock to perform authentification
  8894. bool auth = querySessionManager().checkScopeScansLDAP()&&getScopePermissions(NULL,udesc,(unsigned)-1);
  8895. StringArray authScopes;
  8896. CIArrayOf<CFileMatch> matchingFiles;
  8897. start = msTick();
  8898. count = scanner.getResults(auth, udesc, matchingFiles, authScopes);
  8899. tookMs = msTick()-start;
  8900. if (tookMs>100)
  8901. PROGLOG("TIMING(LDAP): %s: took %dms, %d lookups, file matches = %d", trc.str(), tookMs, authScopes.ordinality(), count);
  8902. sdsLock.lock(); // re-lock sds while serializing
  8903. start = msTick();
  8904. ForEachItemIn(m, matchingFiles)
  8905. {
  8906. CFileMatch &fileMatch = matchingFiles.item(m);
  8907. CDFAttributeIterator::serializeFileAttributes(mb, fileMatch.queryFileTree(), fileMatch.queryName(), fileMatch.queryIsSuper());
  8908. }
  8909. tookMs = msTick()-start;
  8910. if (tookMs>100)
  8911. PROGLOG("TIMING(filescan-serialization): %s: took %dms, %d files",trc.str(), tookMs, count);
  8912. mb.writeDirect(0,sizeof(count),&count);
  8913. }
  8914. void iterateRelationships(CMessageBuffer &mb,StringBuffer &trc)
  8915. {
  8916. TransactionLog transactionLog(*this, MDFS_ITERATE_RELATIONSHIPS, mb.getSender());
  8917. StringAttr primary;
  8918. StringAttr secondary;
  8919. StringAttr primflds;
  8920. StringAttr secflds;
  8921. StringAttr kind;
  8922. StringAttr cardinality;
  8923. byte payloadb;
  8924. mb.read(primary).read(secondary).read(primflds).read(secflds).read(kind).read(cardinality).read(payloadb);
  8925. mb.clear();
  8926. bool payload = (payloadb==1);
  8927. trc.appendf("iterateRelationships(%s,%s,%s,%s,%s,%s,%d)",primary.sget(),secondary.sget(),primflds.sget(),secflds.sget(),kind.sget(),cardinality.sget(),(int)payloadb);
  8928. if (queryTransactionLogging())
  8929. transactionLog.log("%s", trc.str());
  8930. unsigned start = msTick();
  8931. unsigned count=0;
  8932. CSDSServerLockBlock sdsLock; // lock sds while scanning
  8933. StringBuffer xpath;
  8934. CDistributedFileDirectory::getFileRelationshipXPath(xpath,primary,secondary,primflds,secflds,kind,cardinality,((payloadb==0)||(payloadb==1))?&payload:NULL);
  8935. IPropertyTree *root = sdsLock->queryPropTree(querySdsRelationshipsRoot());
  8936. Owned<IPropertyTreeIterator> iter = root?root->getElements(xpath.str()):NULL;
  8937. mb.append(count);
  8938. // save as sequence of branches
  8939. if (iter) {
  8940. ForEach(*iter.get()) {
  8941. iter->query().serialize(mb);
  8942. count++;
  8943. }
  8944. }
  8945. if (msTick()-start>100) {
  8946. PROGLOG("TIMING(relationshipscan): %s: took %dms, %d relations",trc.str(),msTick()-start,count);
  8947. }
  8948. mb.writeDirect(0,sizeof(count),&count);
  8949. }
  8950. void setFileAccessed(CMessageBuffer &mb,StringBuffer &trc)
  8951. {
  8952. TransactionLog transactionLog(*this, MDFS_SET_FILE_ACCESSED, mb.getSender());
  8953. StringAttr lname;
  8954. mb.read(lname);
  8955. CDateTime dt;
  8956. dt.deserialize(mb);
  8957. trc.appendf("setFileAccessed(%s)",lname.sget());
  8958. Owned<IUserDescriptor> udesc;
  8959. if (mb.getPos()<mb.length()) {
  8960. udesc.setown(createUserDescriptor());
  8961. udesc->deserialize(mb);
  8962. }
  8963. if (queryTransactionLogging())
  8964. transactionLog.log("%s", trc.str());
  8965. mb.clear();
  8966. StringBuffer tail;
  8967. CDfsLogicalFileName dlfn;
  8968. dlfn.set(lname);
  8969. if (!checkLogicalName(dlfn,udesc,true,false,true,"setFileAccessed on"))
  8970. return;
  8971. CScopeConnectLock sconnlock("setFileAccessed", dlfn, false, false, false, defaultTimeout);
  8972. IPropertyTree* sroot = sconnlock.conn()?sconnlock.conn()->queryRoot():NULL;
  8973. dlfn.getTail(tail);
  8974. Owned<IPropertyTree> tree = getNamedPropTree(sroot,queryDfsXmlBranchName(DXB_File),"@name",tail.str(),false);
  8975. if (tree) {
  8976. StringBuffer str;
  8977. tree->setProp("@accessed",dt.getString(str).str());
  8978. }
  8979. }
  8980. void setFileProtect(CMessageBuffer &mb,StringBuffer &trc)
  8981. {
  8982. TransactionLog transactionLog(*this, MDFS_SET_FILE_PROTECT, mb.getSender());
  8983. StringAttr lname;
  8984. StringAttr owner;
  8985. bool set;
  8986. mb.read(lname).read(owner).read(set);
  8987. trc.appendf("setFileProtect(%s,%s,%s)",lname.sget(),owner.sget(),set?"true":"false");
  8988. if (queryTransactionLogging())
  8989. transactionLog.log("%s", trc.str());
  8990. Owned<IUserDescriptor> udesc;
  8991. if (mb.getPos()<mb.length()) {
  8992. udesc.setown(createUserDescriptor());
  8993. udesc->deserialize(mb);
  8994. }
  8995. mb.clear();
  8996. StringBuffer tail;
  8997. CDfsLogicalFileName dlfn;
  8998. dlfn.set(lname);
  8999. if (!checkLogicalName(dlfn,udesc,true,false,true,"setFileProtect"))
  9000. return;
  9001. CScopeConnectLock sconnlock("setFileProtect", dlfn, false, false, false, defaultTimeout);
  9002. IPropertyTree* sroot = sconnlock.conn()?sconnlock.conn()->queryRoot():NULL;
  9003. dlfn.getTail(tail);
  9004. Owned<IPropertyTree> tree = getNamedPropTree(sroot,queryDfsXmlBranchName(DXB_File),"@name",tail.str(),false);
  9005. if (!tree)
  9006. tree.setown(getNamedPropTree(sroot,queryDfsXmlBranchName(DXB_SuperFile),"@name",tail.str(),false));
  9007. if (tree) {
  9008. IPropertyTree *pt = tree->queryPropTree("Attr");
  9009. if (pt)
  9010. setFileProtectTree(*pt,*owner?owner:owner,set);
  9011. }
  9012. }
  9013. void getFileTree(CMessageBuffer &mb,StringBuffer &trc)
  9014. {
  9015. TransactionLog transactionLog(*this, MDFS_GET_FILE_TREE, mb.getSender());
  9016. StringAttr lname;
  9017. mb.read(lname);
  9018. unsigned ver;
  9019. if (mb.length()<mb.getPos()+sizeof(unsigned))
  9020. ver = 0;
  9021. else {
  9022. mb.read(ver);
  9023. // this is a bit of a mess - for backward compatibility where user descriptor specified
  9024. if (ver>MDFS_GET_FILE_TREE_V2) {
  9025. mb.reset(mb.getPos()-sizeof(unsigned));
  9026. ver = 0;
  9027. }
  9028. }
  9029. trc.appendf("getFileTree(%s,%d)",lname.sget(),ver);
  9030. if (queryTransactionLogging())
  9031. transactionLog.log("%s", trc.str());
  9032. Owned<IUserDescriptor> udesc;
  9033. if (mb.getPos()<mb.length()) {
  9034. udesc.setown(createUserDescriptor());
  9035. udesc->deserialize(mb);
  9036. }
  9037. mb.clear();
  9038. CDfsLogicalFileName dlfn;
  9039. dlfn.set(lname);
  9040. CDfsLogicalFileName *logicalname=&dlfn;
  9041. Owned<IDfsLogicalFileNameIterator> redmatch;
  9042. loop {
  9043. StringBuffer tail;
  9044. checkLogicalName(*logicalname,udesc,true,false,true,"getFileTree on");
  9045. CScopeConnectLock sconnlock("getFileTree", *logicalname, false, false, false, defaultTimeout);
  9046. IPropertyTree* sroot = sconnlock.conn()?sconnlock.conn()->queryRoot():NULL;
  9047. logicalname->getTail(tail);
  9048. Owned<IPropertyTree> tree = getNamedPropTree(sroot,queryDfsXmlBranchName(DXB_File),"@name",tail.str(),false);
  9049. if (tree) {
  9050. if (ver>=MDFS_GET_FILE_TREE_V2) {
  9051. Owned<IFileDescriptor> fdesc = deserializeFileDescriptorTree(tree,&queryNamedGroupStore(),IFDSF_EXCLUDE_CLUSTERNAMES);
  9052. if (fdesc) {
  9053. ver = MDFS_GET_FILE_TREE_V2;
  9054. mb.append((int)-2).append(ver);
  9055. fdesc->serialize(mb);
  9056. StringBuffer dts;
  9057. if (tree->getProp("@modified",dts)) {
  9058. CDateTime dt;
  9059. dt.setString(dts.str());
  9060. dt.serialize(mb);
  9061. }
  9062. }
  9063. else
  9064. ver = 0;
  9065. }
  9066. if (ver==0) {
  9067. tree.setown(createPTreeFromIPT(tree));
  9068. StringBuffer cname;
  9069. logicalname->getCluster(cname);
  9070. expandFileTree(tree,true,cname.str()); // resolve @node values that may not be set
  9071. tree->serialize(mb);
  9072. }
  9073. break;
  9074. }
  9075. else {
  9076. tree.setown(getNamedPropTree(sroot,queryDfsXmlBranchName(DXB_SuperFile),"@name",tail.str(),false));
  9077. if (tree) {
  9078. tree->serialize(mb);
  9079. break;
  9080. }
  9081. }
  9082. if (redmatch.get()) {
  9083. if (!redmatch->next())
  9084. break;
  9085. }
  9086. else {
  9087. redmatch.setown(queryDistributedFileDirectory().queryRedirection().getMatch(logicalname->get()));
  9088. if (!redmatch.get())
  9089. break;
  9090. if (!redmatch->first())
  9091. break;
  9092. }
  9093. logicalname = &redmatch->query();
  9094. }
  9095. }
  9096. void getGroupTree(CMessageBuffer &mb,StringBuffer &trc)
  9097. {
  9098. TransactionLog transactionLog(*this, MDFS_GET_GROUP_TREE, mb.getSender());
  9099. StringAttr gname;
  9100. mb.read(gname);
  9101. mb.clear();
  9102. trc.appendf("getGroupTree(%s)",gname.sget());
  9103. if (queryTransactionLogging())
  9104. transactionLog.log("%s", trc.str());
  9105. byte ok;
  9106. CConnectLock connlock("getGroupTree",SDS_GROUPSTORE_ROOT,false,false,false,defaultTimeout);
  9107. Owned<IPropertyTree> pt = getNamedPropTree(connlock.conn->queryRoot(),"Group","@name",gname.get(),true);
  9108. if (pt) {
  9109. ok = 1;
  9110. mb.append(ok);
  9111. pt->serialize(mb);
  9112. }
  9113. else {
  9114. ok = 0;
  9115. mb.append(ok);
  9116. }
  9117. }
  9118. void processMessage(CMessageBuffer &mb)
  9119. {
  9120. CheckTime block0("CDaliDFSServer::processMessage ");
  9121. ICoven &coven=queryCoven();
  9122. StringBuffer trc;
  9123. int fn;
  9124. mb.read(fn);
  9125. try {
  9126. switch (fn) {
  9127. case MDFS_ITERATE_FILES: {
  9128. iterateFiles(mb,trc);
  9129. }
  9130. break;
  9131. case MDFS_ITERATE_FILTEREDFILES: {
  9132. iterateFilteredFiles(mb,trc);
  9133. }
  9134. break;
  9135. case MDFS_ITERATE_RELATIONSHIPS: {
  9136. iterateRelationships(mb,trc);
  9137. }
  9138. break;
  9139. case MDFS_GET_FILE_TREE: {
  9140. getFileTree(mb,trc);
  9141. }
  9142. break;
  9143. case MDFS_GET_GROUP_TREE: {
  9144. getGroupTree(mb,trc);
  9145. }
  9146. break;
  9147. case MDFS_SET_FILE_ACCESSED: {
  9148. setFileAccessed(mb,trc);
  9149. }
  9150. break;
  9151. case MDFS_SET_FILE_PROTECT: {
  9152. setFileProtect(mb,trc);
  9153. }
  9154. break;
  9155. default: {
  9156. mb.clear();
  9157. }
  9158. break;
  9159. }
  9160. }
  9161. catch (IException *e) {
  9162. int err=-1; // exception marker
  9163. mb.clear().append(err);
  9164. serializeException(e, mb);
  9165. e->Release();
  9166. }
  9167. coven.reply(mb);
  9168. if (block0.slow()) {
  9169. SocketEndpoint ep = mb.getSender();
  9170. ep.getUrlStr(block0.appendMsg(trc).append(" from "));
  9171. }
  9172. }
  9173. void nodeDown(rank_t rank)
  9174. {
  9175. assertex(!"TBD");
  9176. }
  9177. // CTransactionLogTracker
  9178. virtual StringBuffer &getCmdText(unsigned cmd, StringBuffer &ret) const
  9179. {
  9180. switch (cmd)
  9181. {
  9182. case MDFS_ITERATE_FILES:
  9183. return ret.append("MDFS_ITERATE_FILES");
  9184. case MDFS_ITERATE_FILTEREDFILES:
  9185. return ret.append("MDFS_ITERATE_FILTEREDFILES");
  9186. case MDFS_ITERATE_RELATIONSHIPS:
  9187. return ret.append("MDFS_ITERATE_RELATIONSHIPS");
  9188. case MDFS_GET_FILE_TREE:
  9189. return ret.append("MDFS_GET_FILE_TREE");
  9190. case MDFS_GET_GROUP_TREE:
  9191. return ret.append("MDFS_GET_GROUP_TREE");
  9192. case MDFS_SET_FILE_ACCESSED:
  9193. return ret.append("MDFS_SET_FILE_ACCESSED");
  9194. case MDFS_SET_FILE_PROTECT:
  9195. return ret.append("MDFS_SET_FILE_PROTECT");
  9196. default:
  9197. return ret.append("UNKNOWN");
  9198. }
  9199. }
  9200. // IExceptionHandler impl.
  9201. virtual bool fireException(IException *e)
  9202. {
  9203. EXCLOG(e, "CDaliDFSServer exception");
  9204. return true;
  9205. }
  9206. } *daliDFSServer = NULL;
  9207. IDFAttributesIterator *CDistributedFileDirectory::getDFAttributesIterator(const char *wildname, IUserDescriptor *user, bool recursive, bool includesuper,INode *foreigndali,unsigned foreigndalitimeout)
  9208. {
  9209. if (!wildname||!*wildname||(strcmp(wildname,"*")==0)) {
  9210. recursive = true;
  9211. }
  9212. CMessageBuffer mb;
  9213. mb.append((int)MDFS_ITERATE_FILES).append(wildname).append(recursive).append("").append(includesuper); // "" is legacy
  9214. if (user)
  9215. user->serialize(mb);
  9216. #ifdef NULL_DALIUSER_STACKTRACE
  9217. else
  9218. {
  9219. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp getDFAttributesIterator() line %d",__LINE__);
  9220. PrintStackReport();
  9221. }
  9222. #endif
  9223. if (foreigndali)
  9224. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  9225. else
  9226. queryCoven().sendRecv(mb,RANK_RANDOM,MPTAG_DFS_REQUEST);
  9227. checkDfsReplyException(mb);
  9228. return new CDFAttributeIterator(mb);
  9229. }
  9230. IDFScopeIterator *CDistributedFileDirectory::getScopeIterator(IUserDescriptor *user, const char *basescope, bool recursive,bool includeempty)
  9231. {
  9232. return new CDFScopeIterator(this,basescope,recursive,includeempty,defaultTimeout);
  9233. }
  9234. static bool isValidLFN(const char *lfn)
  9235. { // bit OTT
  9236. if (!lfn||!*lfn||(strcmp(lfn,".")==0))
  9237. return false;
  9238. StringBuffer tmp(".::");
  9239. tmp.append(lfn);
  9240. CDfsLogicalFileName dlfn;
  9241. return dlfn.setValidate(tmp.str());
  9242. }
  9243. bool CDistributedFileDirectory::loadScopeContents(const char *scopelfn,
  9244. StringArray *scopes,
  9245. StringArray *supers,
  9246. StringArray *files,
  9247. bool includeemptyscopes
  9248. )
  9249. {
  9250. StringBuffer baseq;
  9251. if (scopelfn&&*scopelfn) {
  9252. if (memcmp(scopelfn,".::",3)==0) // scopes not in .
  9253. scopelfn += 3;
  9254. StringBuffer tmp(scopelfn);
  9255. if (tmp.trim().length()) {
  9256. tmp.append("::.");
  9257. CDfsLogicalFileName dlfn;
  9258. if (!dlfn.setValidate(tmp.str()))
  9259. return false;
  9260. dlfn.makeScopeQuery(baseq,false);
  9261. }
  9262. }
  9263. CConnectLock connlock("CDistributedFileDirectory::loadScopeContents",querySdsFilesRoot(),false,false,false,defaultTimeout);
  9264. if (!connlock.conn)
  9265. return false;
  9266. IPropertyTree *root = connlock.conn->queryRoot();
  9267. if (!root)
  9268. return false;
  9269. if (baseq.length()) {
  9270. root = root->queryPropTree(baseq.str());
  9271. if (!root)
  9272. return false;
  9273. }
  9274. Owned<IPropertyTreeIterator> iter;
  9275. if (scopes) {
  9276. iter.setown(root->getElements(queryDfsXmlBranchName(DXB_Scope)));
  9277. ForEach(*iter) {
  9278. IPropertyTree &ct = iter->query();
  9279. if (includeemptyscopes||!recursiveCheckEmptyScope(ct)) {
  9280. StringBuffer name;
  9281. if (ct.getProp("@name",name)&&name.trim().length()&&isValidLFN(name.str()))
  9282. scopes->append(name.str());
  9283. }
  9284. }
  9285. }
  9286. if (!supers&&!files)
  9287. return true;
  9288. if (baseq.length()==0) { // bit odd but top level files are in '.'
  9289. CDfsLogicalFileName dlfn;
  9290. dlfn.set(".",".");
  9291. dlfn.makeScopeQuery(baseq,false);
  9292. root = root->queryPropTree(baseq.str());
  9293. if (!root)
  9294. return true;
  9295. }
  9296. if (supers) {
  9297. iter.setown(root->getElements(queryDfsXmlBranchName(DXB_SuperFile)));
  9298. ForEach(*iter) {
  9299. IPropertyTree &ct = iter->query();
  9300. StringBuffer name;
  9301. if (ct.getProp("@name",name)&&name.trim().length()&&isValidLFN(name.str()))
  9302. supers->append(name.str());
  9303. }
  9304. }
  9305. if (files) {
  9306. iter.setown(root->getElements(queryDfsXmlBranchName(DXB_File)));
  9307. ForEach(*iter) {
  9308. StringBuffer name;
  9309. IPropertyTree &ct = iter->query();
  9310. if (ct.getProp("@name",name)&&name.trim().length()&&isValidLFN(name.str()))
  9311. files->append(name.str());
  9312. }
  9313. }
  9314. return true;
  9315. }
  9316. void CDistributedFileDirectory::setFileAccessed(CDfsLogicalFileName &dlfn,IUserDescriptor *user, const CDateTime &dt, const INode *foreigndali,unsigned foreigndalitimeout)
  9317. {
  9318. // this accepts either a foreign dali node or a foreign lfn
  9319. Owned<INode> fnode;
  9320. SocketEndpoint ep;
  9321. const char *lname;
  9322. if (dlfn.isForeign()) {
  9323. if (!dlfn.getEp(ep))
  9324. throw MakeStringException(-1,"cannot resolve dali ip in foreign file name (%s)",dlfn.get());
  9325. fnode.setown(createINode(ep));
  9326. foreigndali = fnode;
  9327. lname = dlfn.get(true);
  9328. }
  9329. else if (dlfn.isExternal())
  9330. return;
  9331. else
  9332. lname = dlfn.get();
  9333. if (isLocalDali(foreigndali))
  9334. foreigndali = NULL;
  9335. CMessageBuffer mb;
  9336. mb.append((int)MDFS_SET_FILE_ACCESSED).append(lname);
  9337. dt.serialize(mb);
  9338. if (user)
  9339. user->serialize(mb);
  9340. #ifdef NULL_DALIUSER_STACKTRACE
  9341. else
  9342. {
  9343. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp setFileAccessed() line %d",__LINE__);
  9344. PrintStackReport();
  9345. }
  9346. #endif
  9347. if (foreigndali)
  9348. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  9349. else
  9350. queryCoven().sendRecv(mb,RANK_RANDOM,MPTAG_DFS_REQUEST);
  9351. checkDfsReplyException(mb);
  9352. }
  9353. void CDistributedFileDirectory::setFileProtect(CDfsLogicalFileName &dlfn,IUserDescriptor *user, const char *owner, bool set, const INode *foreigndali,unsigned foreigndalitimeout)
  9354. {
  9355. // this accepts either a foreign dali node or a foreign lfn
  9356. Owned<INode> fnode;
  9357. SocketEndpoint ep;
  9358. const char *lname;
  9359. if (dlfn.isForeign()) {
  9360. if (!dlfn.getEp(ep))
  9361. throw MakeStringException(-1,"cannot resolve dali ip in foreign file name (%s)",dlfn.get());
  9362. fnode.setown(createINode(ep));
  9363. foreigndali = fnode;
  9364. lname = dlfn.get(true);
  9365. }
  9366. else if (dlfn.isExternal())
  9367. return;
  9368. else
  9369. lname = dlfn.get();
  9370. if (isLocalDali(foreigndali))
  9371. foreigndali = NULL;
  9372. CMessageBuffer mb;
  9373. if (!owner)
  9374. owner = "";
  9375. mb.append((int)MDFS_SET_FILE_PROTECT).append(lname).append(owner).append(set);
  9376. if (user)
  9377. user->serialize(mb);
  9378. #ifdef NULL_DALIUSER_STACKTRACE
  9379. else
  9380. {
  9381. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp setFileProtect() line %d",__LINE__);
  9382. PrintStackReport();
  9383. }
  9384. #endif
  9385. if (foreigndali)
  9386. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  9387. else
  9388. queryCoven().sendRecv(mb,RANK_RANDOM,MPTAG_DFS_REQUEST);
  9389. checkDfsReplyException(mb);
  9390. }
  9391. IPropertyTree *CDistributedFileDirectory::getFileTree(const char *lname, IUserDescriptor *user, const INode *foreigndali,unsigned foreigndalitimeout, bool expandnodes, bool appendForeign)
  9392. {
  9393. // this accepts either a foreign dali node or a foreign lfn
  9394. Owned<INode> fnode;
  9395. CDfsLogicalFileName dlfn;
  9396. SocketEndpoint ep;
  9397. dlfn.set(lname);
  9398. if (dlfn.isForeign()) {
  9399. if (!dlfn.getEp(ep))
  9400. throw MakeStringException(-1,"cannot resolve dali ip in foreign file name (%s)",lname);
  9401. fnode.setown(createINode(ep));
  9402. foreigndali = fnode;
  9403. lname = dlfn.get(true);
  9404. }
  9405. if (isLocalDali(foreigndali))
  9406. foreigndali = NULL;
  9407. CMessageBuffer mb;
  9408. mb.append((int)MDFS_GET_FILE_TREE).append(lname);
  9409. mb.append(MDFS_GET_FILE_TREE_V2);
  9410. if (user)
  9411. user->serialize(mb);
  9412. #ifdef NULL_DALIUSER_STACKTRACE
  9413. else
  9414. {
  9415. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp getFileTree() line %d",__LINE__);
  9416. PrintStackReport();
  9417. }
  9418. #endif
  9419. if (foreigndali)
  9420. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  9421. else
  9422. queryCoven().sendRecv(mb,RANK_RANDOM,MPTAG_DFS_REQUEST);
  9423. checkDfsReplyException(mb);
  9424. if (mb.length()==0)
  9425. return NULL;
  9426. unsigned ver = 0;
  9427. if ((mb.length()>=sizeof(int))&&(*(int *)mb.bufferBase()) == -2) { // version indicator
  9428. int i;
  9429. mb.read(i);
  9430. mb.read(ver);
  9431. }
  9432. Owned<IPropertyTree> ret;
  9433. if (ver==0)
  9434. ret.setown(createPTree(mb));
  9435. else {
  9436. Owned<IFileDescriptor> fdesc;
  9437. CDateTime modified;
  9438. if (ver==MDFS_GET_FILE_TREE_V2) { // no longer in use but support for back compatibility
  9439. fdesc.setown(deserializeFileDescriptor(mb));
  9440. if (mb.remaining()>0)
  9441. modified.deserialize(mb);
  9442. }
  9443. else
  9444. throw MakeStringException(-1,"Unknown GetFileTree serialization version %d",ver);
  9445. ret.setown(createPTree(queryDfsXmlBranchName(DXB_File)));
  9446. fdesc->serializeTree(*ret,expandnodes?0:CPDMSF_packParts);
  9447. if (!modified.isNull()) {
  9448. StringBuffer dts;
  9449. ret->setProp("@modified",modified.getString(dts).str());
  9450. }
  9451. }
  9452. if (expandnodes) {
  9453. StringBuffer cname;
  9454. dlfn.getCluster(cname);
  9455. expandFileTree(ret,true,cname.str());
  9456. CDfsLogicalFileName dlfn2;
  9457. dlfn2.set(dlfn);
  9458. if (foreigndali)
  9459. dlfn2.setForeign(foreigndali->endpoint(),false);
  9460. ret->setProp("OrigName",dlfn.get());
  9461. }
  9462. if (foreigndali && appendForeign)
  9463. resolveForeignFiles(ret,foreigndali);
  9464. return ret.getClear();
  9465. }
  9466. IFileDescriptor *CDistributedFileDirectory::getFileDescriptor(const char *lname,IUserDescriptor *user,const INode *foreigndali,unsigned foreigndalitimeout)
  9467. {
  9468. Owned<IPropertyTree> tree = getFileTree(lname,user,foreigndali,foreigndalitimeout,false);
  9469. if (!tree)
  9470. return NULL;
  9471. if (strcmp(tree->queryName(),queryDfsXmlBranchName(DXB_SuperFile))==0) {
  9472. CDfsLogicalFileName dlfn;
  9473. dlfn.set(lname);
  9474. Owned<CDistributedSuperFile> sfile = new CDistributedSuperFile(this,tree, dlfn, user);
  9475. return sfile->getFileDescriptor(NULL);
  9476. }
  9477. if (strcmp(tree->queryName(),queryDfsXmlBranchName(DXB_File))!=0)
  9478. return NULL; // what is it?
  9479. IFileDescriptor * fdesc = deserializeFileDescriptorTree(tree,&queryNamedGroupStore(),0);
  9480. if (fdesc)
  9481. fdesc->setTraceName(lname);
  9482. return fdesc;
  9483. }
  9484. IDistributedFile *CDistributedFileDirectory::getFile(const char *lname,IUserDescriptor *user,const INode *foreigndali,unsigned foreigndalitimeout)
  9485. {
  9486. Owned<IPropertyTree> tree = getFileTree(lname,user,foreigndali,foreigndalitimeout,false);
  9487. if (!tree)
  9488. return NULL;
  9489. if (strcmp(tree->queryName(),queryDfsXmlBranchName(DXB_SuperFile))==0) {
  9490. CDfsLogicalFileName dlfn;
  9491. dlfn.set(lname);
  9492. return new CDistributedSuperFile(this,tree, dlfn, user);
  9493. }
  9494. if (strcmp(tree->queryName(),queryDfsXmlBranchName(DXB_File))!=0)
  9495. return NULL; // what is it?
  9496. Owned<IFileDescriptor> fdesc = deserializeFileDescriptorTree(tree,&queryNamedGroupStore(),IFDSF_FOREIGN_GROUP);
  9497. if (!fdesc)
  9498. return NULL;
  9499. fdesc->setTraceName(lname);
  9500. CDistributedFile *ret = new CDistributedFile(this, fdesc, user, true);
  9501. ret->setLogicalName(lname);
  9502. const char *date = tree->queryProp("@modified");
  9503. if (ret) {
  9504. CDateTime dt;
  9505. if (date&&*date)
  9506. dt.setString(date);
  9507. ret->setModificationTime(dt);
  9508. }
  9509. return ret;
  9510. }
  9511. static void addForeignName(IPropertyTree &t,const INode *foreigndali,const char *attr)
  9512. {
  9513. StringBuffer sb;
  9514. const char *name = t.queryProp(attr);
  9515. if (!name||!*name)
  9516. return;
  9517. CDfsLogicalFileName logicalname;
  9518. logicalname.set(name);
  9519. if (logicalname.isExternal()||logicalname.isQuery())
  9520. return; // how did that get in here?
  9521. if (logicalname.isForeign()) {
  9522. SocketEndpoint ep;
  9523. Owned<INode> fd = createINode(ep);
  9524. if (logicalname.getEp(ep)&&isLocalDali(fd)) { // see if pointing back at self
  9525. logicalname.clearForeign();
  9526. t.setProp(attr,logicalname.get());
  9527. }
  9528. }
  9529. else if (foreigndali) {
  9530. logicalname.setForeign(foreigndali->endpoint(),false);
  9531. t.setProp(attr,logicalname.get());
  9532. }
  9533. }
  9534. void CDistributedFileDirectory::resolveForeignFiles(IPropertyTree *tree,const INode *foreigndali)
  9535. {
  9536. if (!tree||!foreigndali)
  9537. return;
  9538. // now add to all sub files
  9539. Owned<IPropertyTreeIterator> pe = tree->getElements("SubFile");
  9540. ForEach(*pe)
  9541. addForeignName(pe->query(),foreigndali,"@name");
  9542. pe.setown(tree->getElements("SuperOwner"));
  9543. ForEach(*pe)
  9544. addForeignName(pe->query(),foreigndali,"@name");
  9545. // do origname?
  9546. }
  9547. int CDistributedFileDirectory::getFilePermissions(const char *lname,IUserDescriptor *user,unsigned auditflags)
  9548. {
  9549. CDfsLogicalFileName dlfn;
  9550. dlfn.set(lname);
  9551. StringBuffer scopes;
  9552. dlfn.getScopes(scopes);
  9553. return getScopePermissions(scopes.str(),user,auditflags);
  9554. }
  9555. int CDistributedFileDirectory::getNodePermissions(const IpAddress &ip,IUserDescriptor *user,unsigned auditflags)
  9556. {
  9557. if (ip.isNull())
  9558. return 0;
  9559. CDfsLogicalFileName dlfn;
  9560. SocketEndpoint ep(0,ip);
  9561. dlfn.setExternal(ep,"/x");
  9562. StringBuffer scopes;
  9563. dlfn.getScopes(scopes,true);
  9564. return getScopePermissions(scopes.str(),user,auditflags);
  9565. }
  9566. int CDistributedFileDirectory::getFDescPermissions(IFileDescriptor *fdesc,IUserDescriptor *user,unsigned auditflags)
  9567. {
  9568. // this checks have access to the nodes in the file descriptor
  9569. int ret = 255;
  9570. unsigned np = fdesc->numParts();
  9571. for (unsigned i=0;i<np;i++) {
  9572. INode *node = fdesc->queryNode(i);
  9573. if (node) {
  9574. bool multi = false;
  9575. RemoteMultiFilename mfn;
  9576. unsigned n = 1;
  9577. if (fdesc->isMulti()) {
  9578. fdesc->getMultiFilename(i,0,mfn);
  9579. multi = true;
  9580. n = mfn.ordinality();
  9581. }
  9582. for (unsigned j = 0;j<n;j++) {
  9583. RemoteFilename rfn;
  9584. if (multi) {
  9585. rfn.set(mfn.item(j));
  9586. }
  9587. else
  9588. fdesc->getFilename(i,0,rfn);
  9589. StringBuffer localpath;
  9590. rfn.getLocalPath(localpath);
  9591. // translate wild cards
  9592. for (unsigned k=0;k<localpath.length();k++)
  9593. if ((localpath.charAt(k)=='?')||(localpath.charAt(k)=='*'))
  9594. localpath.setCharAt(k,'_');
  9595. CDfsLogicalFileName dlfn;
  9596. dlfn.setExternal(rfn.queryEndpoint(),localpath.str());
  9597. StringBuffer scopes;
  9598. dlfn.getScopes(scopes);
  9599. int p = getScopePermissions(scopes.str(),user,auditflags);
  9600. if (p<ret) {
  9601. ret = p;
  9602. if (ret==0)
  9603. return 0;
  9604. }
  9605. }
  9606. }
  9607. }
  9608. return ret;
  9609. }
  9610. void CDistributedFileDirectory::setDefaultUser(IUserDescriptor *user)
  9611. {
  9612. if (user)
  9613. defaultudesc.set(user);
  9614. else
  9615. defaultudesc.setown(createUserDescriptor());
  9616. }
  9617. IUserDescriptor* CDistributedFileDirectory::queryDefaultUser()
  9618. {
  9619. return defaultudesc.get();
  9620. }
  9621. void CDistributedFileDirectory::setDefaultPreferredClusters(const char *clusters)
  9622. {
  9623. defprefclusters.set(clusters);
  9624. }
  9625. bool removePhysicalFiles(IGroup *grp,const char *_filemask,unsigned short port,ClusterPartDiskMapSpec &mspec,IMultiException *mexcept)
  9626. {
  9627. // TBD this won't remove repeated parts
  9628. PROGLOG("removePhysicalFiles(%s)",_filemask);
  9629. if (!isAbsolutePath(_filemask))
  9630. throw MakeStringException(-1,"removePhysicalFiles: Filename %s must be complete path",_filemask);
  9631. size32_t l = strlen(_filemask);
  9632. while (l&&isdigit(_filemask[l-1]))
  9633. l--;
  9634. unsigned width=0;
  9635. if (l&&(_filemask[l-1]=='_'))
  9636. width = atoi(_filemask+l);
  9637. if (!width)
  9638. width = grp->ordinality();
  9639. CriticalSection errcrit;
  9640. class casyncfor: public CAsyncFor
  9641. {
  9642. unsigned short port;
  9643. CriticalSection &errcrit;
  9644. IMultiException *mexcept;
  9645. unsigned width;
  9646. StringAttr filemask;
  9647. IGroup *grp;
  9648. ClusterPartDiskMapSpec &mspec;
  9649. public:
  9650. bool ok;
  9651. casyncfor(IGroup *_grp,const char *_filemask,unsigned _width,unsigned short _port,ClusterPartDiskMapSpec &_mspec,IMultiException *_mexcept,CriticalSection &_errcrit)
  9652. : mspec(_mspec),filemask(_filemask),errcrit(_errcrit)
  9653. {
  9654. grp = _grp;
  9655. port = _port;
  9656. ok = true;
  9657. mexcept = _mexcept;
  9658. width = _width;
  9659. }
  9660. void Do(unsigned i)
  9661. {
  9662. for (unsigned copy = 0; copy < 2; copy++) // ** TBD
  9663. {
  9664. RemoteFilename rfn;
  9665. constructPartFilename(grp,i+1,width,NULL,filemask,"",copy>0,mspec,rfn);
  9666. if (port)
  9667. rfn.setPort(port); // if daliservix
  9668. Owned<IFile> partfile = createIFile(rfn);
  9669. StringBuffer eps;
  9670. try
  9671. {
  9672. unsigned start = msTick();
  9673. #if 1
  9674. if (partfile->remove()) {
  9675. PROGLOG("Removed '%s'",partfile->queryFilename());
  9676. unsigned t = msTick()-start;
  9677. if (t>5*1000)
  9678. LOG(MCwarning, unknownJob, "Removing %s from %s took %ds", partfile->queryFilename(), rfn.queryEndpoint().getUrlStr(eps).str(), t/1000);
  9679. }
  9680. else
  9681. LOG(MCwarning, unknownJob, "Failed to remove file part %s from %s", partfile->queryFilename(),rfn.queryEndpoint().getUrlStr(eps).str());
  9682. #else
  9683. if (partfile->exists())
  9684. PROGLOG("Would remove '%s'",partfile->queryFilename());
  9685. #endif
  9686. }
  9687. catch (IException *e)
  9688. {
  9689. CriticalBlock block(errcrit);
  9690. if (mexcept)
  9691. mexcept->append(*e);
  9692. else {
  9693. StringBuffer s("Failed to remove file part ");
  9694. s.append(partfile->queryFilename()).append(" from ");
  9695. rfn.queryEndpoint().getUrlStr(s);
  9696. EXCLOG(e, s.str());
  9697. e->Release();
  9698. }
  9699. ok = false;
  9700. }
  9701. }
  9702. }
  9703. } afor(grp,_filemask,width,port,mspec,mexcept,errcrit);
  9704. afor.For(width,10,false,true);
  9705. return afor.ok;
  9706. }
  9707. IDaliServer *createDaliDFSServer(IPropertyTree *config)
  9708. {
  9709. assertex(!daliDFSServer); // initialization problem
  9710. daliDFSServer = new CDaliDFSServer(config);
  9711. return daliDFSServer;
  9712. }
  9713. IDistributedFileTransaction *createDistributedFileTransaction(IUserDescriptor *user)
  9714. {
  9715. return new CDistributedFileTransaction(user);
  9716. }
  9717. static void encodeCompareResult(DistributedFileCompareResult &ret,bool differs,CDateTime &newestdt1,CDateTime &newestdt2)
  9718. {
  9719. if (ret!=DFS_COMPARE_RESULT_FAILURE) {
  9720. int cmp = 0;
  9721. if (!newestdt1.isNull()) {
  9722. if (!newestdt2.isNull()) {
  9723. int cmp = newestdt1.compare(newestdt2,false);
  9724. if (cmp>=0)
  9725. ret = DFS_COMPARE_RESULT_SAME_NEWER;
  9726. else
  9727. ret = DFS_COMPARE_RESULT_SAME_OLDER;
  9728. }
  9729. else
  9730. ret = DFS_COMPARE_RESULT_SAME_NEWER;
  9731. }
  9732. else if (!newestdt2.isNull())
  9733. ret = DFS_COMPARE_RESULT_SAME_OLDER;
  9734. if (differs) {
  9735. if (ret==DFS_COMPARE_RESULT_SAME_OLDER) // ok they could be same but seems rather unlikely!
  9736. ret = DFS_COMPARE_RESULT_DIFFER_OLDER;
  9737. else
  9738. ret = DFS_COMPARE_RESULT_DIFFER_NEWER;
  9739. }
  9740. }
  9741. }
  9742. DistributedFileCompareResult CDistributedFileDirectory::fileCompare(const char *lfn1,const char *lfn2,DistributedFileCompareMode mode,StringBuffer &errstr,IUserDescriptor *user)
  9743. {
  9744. DistributedFileCompareResult ret = DFS_COMPARE_RESULT_SAME;
  9745. StringBuffer msg;
  9746. try
  9747. {
  9748. Owned<IDistributedFile> file1 = lookup(lfn1, user, false, false, false, NULL, defaultTimeout);
  9749. Owned<IDistributedFile> file2 = lookup(lfn2, user, false, false, false, NULL, defaultTimeout);
  9750. if (!file1)
  9751. {
  9752. errstr.appendf("File %s not found",lfn1);
  9753. ret = DFS_COMPARE_RESULT_FAILURE;
  9754. }
  9755. else if (!file2)
  9756. {
  9757. errstr.appendf("File %s not found",lfn2);
  9758. ret = DFS_COMPARE_RESULT_FAILURE;
  9759. }
  9760. else
  9761. {
  9762. unsigned np = file1->numParts();
  9763. if (np!=file2->numParts())
  9764. {
  9765. errstr.appendf("Files %s and %s have differing number of parts",lfn1,lfn2);
  9766. ret = DFS_COMPARE_RESULT_FAILURE;
  9767. }
  9768. else
  9769. {
  9770. CDateTime newestdt1;
  9771. CDateTime newestdt2;
  9772. bool differs = false;
  9773. class casyncfor: public CAsyncFor
  9774. {
  9775. CriticalSection crit;
  9776. DistributedFileCompareResult &ret;
  9777. IDistributedFile *file1;
  9778. IDistributedFile *file2;
  9779. const char *lfn1;
  9780. const char *lfn2;
  9781. StringBuffer &errstr;
  9782. DistributedFileCompareMode mode;
  9783. bool physdatesize;
  9784. CDateTime &newestdt1;
  9785. CDateTime &newestdt2;
  9786. bool &differs;
  9787. public:
  9788. casyncfor(const char *_lfn1,const char *_lfn2,IDistributedFile *_file1,IDistributedFile *_file2,DistributedFileCompareMode _mode,DistributedFileCompareResult &_ret,StringBuffer &_errstr,
  9789. CDateTime &_newestdt1,CDateTime &_newestdt2,bool &_differs)
  9790. : ret(_ret), errstr(_errstr),newestdt1(_newestdt1),newestdt2(_newestdt2),differs(_differs)
  9791. {
  9792. lfn1 = _lfn1;
  9793. lfn2 = _lfn2;
  9794. file1 = _file1;
  9795. file2 = _file2;
  9796. mode = _mode;
  9797. physdatesize = (mode==DFS_COMPARE_FILES_PHYSICAL)||(mode==DFS_COMPARE_FILES_PHYSICAL_CRCS);
  9798. }
  9799. void Do(unsigned p)
  9800. {
  9801. CriticalBlock block (crit);
  9802. StringBuffer msg;
  9803. Owned<IDistributedFilePart> part1 = file1->getPart(p);
  9804. Owned<IDistributedFilePart> part2 = file2->getPart(p);
  9805. CDateTime dt1;
  9806. RemoteFilename rfn;
  9807. bool ok;
  9808. {
  9809. CriticalUnblock unblock(crit);
  9810. ok = part1->getModifiedTime(true,physdatesize,dt1);
  9811. }
  9812. if (!ok) {
  9813. if (errstr.length()==0) {
  9814. errstr.append("Could not find ");
  9815. part1->getFilename(rfn);
  9816. rfn.getPath(errstr);
  9817. }
  9818. ret = DFS_COMPARE_RESULT_FAILURE;
  9819. }
  9820. CDateTime dt2;
  9821. {
  9822. CriticalUnblock unblock(crit);
  9823. ok = part2->getModifiedTime(true,physdatesize,dt2);
  9824. }
  9825. if (!ok) {
  9826. if (errstr.length()==0) {
  9827. errstr.append("Could not find ");
  9828. part2->getFilename(rfn);
  9829. rfn.getPath(errstr);
  9830. }
  9831. ret = DFS_COMPARE_RESULT_FAILURE;
  9832. }
  9833. if (ret!=DFS_COMPARE_RESULT_FAILURE) {
  9834. int cmp = dt1.compare(dt2,false);
  9835. if (cmp>0) {
  9836. if (newestdt1.isNull()||(dt1.compare(newestdt1,false)>0))
  9837. newestdt1.set(dt1);
  9838. }
  9839. else if (cmp<0) {
  9840. if (newestdt2.isNull()||(dt2.compare(newestdt2,false)>0))
  9841. newestdt2.set(dt2);
  9842. }
  9843. }
  9844. if ((ret!=DFS_COMPARE_RESULT_FAILURE)&&!differs) {
  9845. offset_t sz1;
  9846. offset_t sz2;
  9847. {
  9848. CriticalUnblock unblock(crit);
  9849. sz1 = part1->getFileSize(true,physdatesize);
  9850. sz2 = part2->getFileSize(true,physdatesize);
  9851. }
  9852. if (sz1!=sz2)
  9853. differs = true;
  9854. }
  9855. if ((ret!=DFS_COMPARE_RESULT_FAILURE)&&!differs) {
  9856. unsigned crc1;
  9857. unsigned crc2;
  9858. if (mode==DFS_COMPARE_FILES_PHYSICAL_CRCS) {
  9859. {
  9860. CriticalUnblock unblock(crit);
  9861. crc1 = part1->getPhysicalCrc();
  9862. crc2 = part2->getPhysicalCrc();
  9863. }
  9864. }
  9865. else {
  9866. if (!part1->getCrc(crc1))
  9867. return;
  9868. if (!part2->getCrc(crc2))
  9869. return;
  9870. }
  9871. if (crc1!=crc2)
  9872. differs = true;
  9873. }
  9874. }
  9875. } afor(lfn1,lfn2,file1,file2,mode,ret,errstr,newestdt1,newestdt2,differs);
  9876. afor.For(np,20,false,false);
  9877. encodeCompareResult(ret,differs,newestdt1,newestdt2);
  9878. }
  9879. }
  9880. }
  9881. catch (IException *e) {
  9882. if (errstr.length()==0)
  9883. e->errorMessage(errstr);
  9884. else
  9885. EXCLOG(e,"CDistributedFileDirectory::fileCompare");
  9886. e->Release();
  9887. ret = DFS_COMPARE_RESULT_FAILURE;
  9888. }
  9889. return ret;
  9890. }
  9891. bool CDistributedFileDirectory::filePhysicalVerify(const char *lfn, IUserDescriptor *user, bool includecrc, StringBuffer &errstr)
  9892. {
  9893. bool differs = false;
  9894. Owned<IDistributedFile> file = lookup(lfn, user, false, false, false, NULL, defaultTimeout);
  9895. if (!file)
  9896. {
  9897. errstr.appendf("Could not find file: %s",lfn);
  9898. return false;
  9899. }
  9900. try
  9901. {
  9902. unsigned np = file->numParts();
  9903. class casyncfor: public CAsyncFor
  9904. {
  9905. CriticalSection crit;
  9906. IDistributedFile *file;
  9907. const char *lfn;
  9908. StringBuffer &errstr;
  9909. bool includecrc;
  9910. bool &differs;
  9911. unsigned defaultTimeout;
  9912. public:
  9913. casyncfor(const char *_lfn,IDistributedFile *_file,StringBuffer &_errstr, bool _includecrc,
  9914. bool &_differs, unsigned _defaultTimeout)
  9915. : errstr(_errstr), differs(_differs)
  9916. {
  9917. lfn = _lfn;
  9918. file = _file;
  9919. includecrc = _includecrc;
  9920. defaultTimeout = _defaultTimeout;
  9921. }
  9922. void Do(unsigned p)
  9923. {
  9924. CriticalBlock block (crit);
  9925. StringBuffer msg;
  9926. Owned<IDistributedFilePart> part = file->getPart(p);
  9927. CDateTime dt1; // logical
  9928. CDateTime dt2; // physical
  9929. RemoteFilename rfn;
  9930. bool ok;
  9931. bool nological = !part->getModifiedTime(false,false,dt1);
  9932. {
  9933. CriticalUnblock unblock(crit);
  9934. ok = part->getModifiedTime(true,true,dt2);
  9935. }
  9936. if (!ok) {
  9937. if (errstr.length()==0) {
  9938. errstr.append("Could not find part file: ");
  9939. part->getFilename(rfn);
  9940. rfn.getPath(errstr);
  9941. }
  9942. differs = true;
  9943. }
  9944. if (!differs&&!includecrc) {
  9945. if (nological) {
  9946. StringBuffer str;
  9947. // TODO: Create DistributedFilePropertyLock for parts
  9948. part->lockProperties(defaultTimeout);
  9949. part->queryAttributes().setProp("@modified",dt2.getString(str).str());
  9950. part->unlockProperties();
  9951. }
  9952. else {
  9953. if (dt1.compare(dt2,false)!=0) {
  9954. if (errstr.length()==0) {
  9955. errstr.append("Modified time differs for: ");
  9956. part->getFilename(rfn);
  9957. rfn.getPath(errstr);
  9958. }
  9959. differs = true;
  9960. }
  9961. }
  9962. }
  9963. if (!differs) {
  9964. offset_t sz1;
  9965. offset_t sz2;
  9966. {
  9967. CriticalUnblock unblock(crit);
  9968. sz1 = part->getFileSize(false,false);
  9969. sz2 = part->getFileSize(true,true);
  9970. }
  9971. if (sz1!=sz2) {
  9972. if (sz1==(offset_t)-1) {
  9973. // TODO: Create DistributedFilePropertyLock for parts
  9974. part->lockProperties(defaultTimeout);
  9975. part->queryAttributes().setPropInt64("@size",sz2);
  9976. part->unlockProperties();
  9977. }
  9978. else if (sz2!=(offset_t)-1) {
  9979. if (errstr.length()==0) {
  9980. errstr.append("File size differs for: ");
  9981. part->getFilename(rfn);
  9982. rfn.getPath(errstr);
  9983. }
  9984. differs = true;
  9985. }
  9986. }
  9987. }
  9988. if (!differs&&includecrc) {
  9989. unsigned crc1;
  9990. unsigned crc2;
  9991. {
  9992. CriticalUnblock unblock(crit);
  9993. crc2 = part->getPhysicalCrc();
  9994. }
  9995. if (!part->getCrc(crc1)) {
  9996. // TODO: Create DistributedFilePropertyLock for parts
  9997. part->lockProperties(defaultTimeout);
  9998. part->queryAttributes().setPropInt64("@fileCrc",(unsigned)crc2);
  9999. part->unlockProperties();
  10000. }
  10001. else if (crc1!=crc2) {
  10002. if (errstr.length()==0) {
  10003. errstr.append("File CRC differs for: ");
  10004. part->getFilename(rfn);
  10005. rfn.getPath(errstr);
  10006. }
  10007. differs = true;
  10008. }
  10009. }
  10010. }
  10011. } afor(lfn,file,errstr,includecrc,differs,defaultTimeout);
  10012. afor.For(np,10,false,false);
  10013. }
  10014. catch (IException *e) {
  10015. if (errstr.length()==0)
  10016. e->errorMessage(errstr);
  10017. else
  10018. EXCLOG(e,"CDistributedFileDirectory::fileCompare");
  10019. e->Release();
  10020. differs = true;
  10021. }
  10022. return !differs;
  10023. }
  10024. typedef MapStringTo<bool> SubfileSet;
  10025. class CFilterAttrIterator: public CInterface, implements IDFAttributesIterator
  10026. {
  10027. Owned<IDFAttributesIterator> iter;
  10028. Linked<IUserDescriptor> user;
  10029. SubfileSet sfset;
  10030. bool includesub;
  10031. public:
  10032. IMPLEMENT_IINTERFACE;
  10033. CFilterAttrIterator(IDFAttributesIterator *_iter,IUserDescriptor* _user,bool _includesub,unsigned timeoutms)
  10034. : iter(_iter), user(_user)
  10035. {
  10036. includesub = _includesub;
  10037. CDfsLogicalFileName lfn;
  10038. StringBuffer query;
  10039. Owned<IDFScopeIterator> siter = queryDistributedFileDirectory().getScopeIterator(user,NULL,true,false);
  10040. ForEach(*siter) {
  10041. lfn.set(siter->query(),"X");
  10042. lfn.makeScopeQuery(query.clear());
  10043. Owned<IRemoteConnection> conn = querySDS().connect(query.str(),myProcessSession(),0, timeoutms);
  10044. if (conn) {
  10045. IPropertyTree *t = conn->queryRoot();
  10046. Owned<IPropertyTreeIterator> iter = t->getElements("SuperFile/SubFile");
  10047. ForEach(*iter) {
  10048. const char *name = iter->query().queryProp("@name");
  10049. if (!sfset.getValue(name))
  10050. sfset.setValue(name, true);
  10051. }
  10052. }
  10053. }
  10054. }
  10055. inline bool match()
  10056. {
  10057. const char *name = iter->query().queryProp("@name");
  10058. return ((sfset.getValue(name)!=NULL)==includesub);
  10059. }
  10060. bool first()
  10061. {
  10062. if (!iter->first())
  10063. return false;
  10064. while (!match())
  10065. if (!iter->next())
  10066. return false;
  10067. return true;
  10068. }
  10069. bool next()
  10070. {
  10071. do {
  10072. if (!iter->next())
  10073. return false;
  10074. } while (!match());
  10075. return true;
  10076. }
  10077. bool isValid() { return iter->isValid(); }
  10078. IPropertyTree & query() { return iter->query(); }
  10079. };
  10080. IDFAttributesIterator *createSubFileFilter(IDFAttributesIterator *_iter,IUserDescriptor* _user, bool includesub, unsigned timeoutms)
  10081. {
  10082. return new CFilterAttrIterator(_iter,_user,includesub,timeoutms);
  10083. }
  10084. bool decodeChildGroupName(const char *gname,StringBuffer &parentname, StringBuffer &range)
  10085. {
  10086. if (!gname||!*gname)
  10087. return false;
  10088. size32_t l = strlen(gname);
  10089. if (gname[l-1]!=']')
  10090. return false;
  10091. const char *ss = strchr(gname,'[');
  10092. if (!ss||(ss==gname))
  10093. return false;
  10094. range.append(l-(ss-gname)-2,ss+1);
  10095. range.trim();
  10096. if (!range.length())
  10097. return false;
  10098. parentname.append(ss-gname,gname);
  10099. return true;
  10100. }
  10101. class CLightWeightSuperFileConn: public CInterface, implements ISimpleSuperFileEnquiry
  10102. {
  10103. CFileLock lock;
  10104. bool readonly;
  10105. IArrayOf<IRemoteConnection> children;
  10106. unsigned defaultTimeout;
  10107. Owned<IUserDescriptor> udesc;
  10108. static StringBuffer &getSubPath(StringBuffer &path,unsigned idx)
  10109. {
  10110. return path.append("SubFile[@num=\"").append(idx+1).append("\"]");
  10111. }
  10112. void migrateProp(const char *name, unsigned num,IPropertyTree *from,IPropertyTree *to,IPropertyTree *newt, bool allowunchanged)
  10113. {
  10114. StringBuffer aname("Attr/");
  10115. aname.append(name);
  10116. StringBuffer s;
  10117. StringBuffer o;
  10118. if (from->getProp(aname.str(),s))
  10119. if ((num==1)||(allowunchanged&&to->getProp(aname.str(),o)&&(strcmp(s.str(),o.str())==0)))
  10120. newt->setProp(name,s.str());
  10121. }
  10122. void migrateAttr(IPropertyTree *from,IPropertyTree *to)
  10123. {
  10124. // this tries hard to set what it knows but avoids sibling traversal
  10125. if (!to)
  10126. return;
  10127. const char *desc = to->queryProp("Attr/@description");
  10128. IPropertyTree* newt = getEmptyAttr();
  10129. if (desc)
  10130. newt->setProp("@description",desc);
  10131. if (from) {
  10132. unsigned num=to->getPropInt("@numsubfiles");
  10133. migrateProp("@size",num,from,to,newt,false);
  10134. migrateProp("@checkSum",num,from,to,newt,true);
  10135. migrateProp("@formatCrc",num,from,to,newt,true);
  10136. migrateProp("@recordSize",num,from,to,newt,true);
  10137. MemoryBuffer mb;
  10138. MemoryBuffer mbo;
  10139. const char *aname = "Attr/_record_layout";
  10140. if (from->getPropBin(aname,mb))
  10141. if ((num==1)||(to->getPropBin(aname,mbo)&&
  10142. (mb.length()==mbo.length())&&
  10143. (memcmp(mb.bufferBase(),mbo.bufferBase(),mb.length())==0)))
  10144. newt->setPropBin("_record_layout", mb.length(), mb.bufferBase());
  10145. }
  10146. to->setPropTree("Attr",newt);
  10147. }
  10148. void migrateSuperOwnersAttr(IPropertyTree *from)
  10149. {
  10150. if (!from)
  10151. return;
  10152. Owned<IPropertyTreeIterator> iter = from->getElements("SuperOwner");
  10153. StringBuffer pname;
  10154. StringBuffer query;
  10155. ForEach(*iter) {
  10156. if (iter->query().getProp("@name",pname.clear())) {
  10157. CDfsLogicalFileName lfn;
  10158. lfn.set(pname.str());
  10159. lfn.makeFullnameQuery(query.clear(),DXB_SuperFile,true);
  10160. Owned<IRemoteConnection> conn;
  10161. try {
  10162. conn.setown(querySDS().connect(query.str(),myProcessSession(),RTM_LOCK_WRITE,1000*60*5));
  10163. }
  10164. catch (ISDSException *e) {
  10165. if (SDSExcpt_LockTimeout != e->errorCode())
  10166. throw;
  10167. e->Release();
  10168. WARNLOG("migrateSuperOwnersAttr: Could not lock parent %s",query.str());
  10169. conn.setown(querySDS().connect(query.str(),myProcessSession(),0,defaultTimeout));
  10170. }
  10171. if (conn) {
  10172. migrateAttr(from,conn->queryRoot());
  10173. migrateSuperOwnersAttr(conn->queryRoot());
  10174. }
  10175. else
  10176. WARNLOG("migrateSuperOwnersAttr could not connect to parent superfile %s",lfn.get());
  10177. }
  10178. }
  10179. }
  10180. public:
  10181. IMPLEMENT_IINTERFACE;
  10182. CLightWeightSuperFileConn(unsigned _defaultTimeout, IUserDescriptor *_udesc)
  10183. {
  10184. defaultTimeout = _defaultTimeout;
  10185. readonly = false;
  10186. udesc.set(_udesc);
  10187. }
  10188. bool connect(CDistributedFileDirectory *parent,const char *title, const char *name, bool _readonly, bool *autocreate, unsigned timeout)
  10189. {
  10190. if (autocreate)
  10191. *autocreate = false;
  10192. readonly = _readonly;
  10193. disconnect(false);
  10194. CDfsLogicalFileName lfn;
  10195. if (!lfn.setValidate(name))
  10196. throw MakeStringException(-1,"%s: Invalid superfile name '%s'",title,name);
  10197. if (lfn.isMulti()||lfn.isExternal()||lfn.isForeign())
  10198. return false;
  10199. unsigned mode = RTM_SUB | (readonly ? RTM_LOCK_READ : RTM_LOCK_WRITE);
  10200. if (!lock.init(lfn, DXB_SuperFile, mode, timeout, title))
  10201. {
  10202. if (!autocreate) // NB not !*autocreate here !
  10203. return false;
  10204. IPropertyTree *root = createPTree();
  10205. root->setPropInt("@interleaved",2);
  10206. root->setPropInt("@numsubfiles",0);
  10207. root->setPropTree("Attr",getEmptyAttr());
  10208. parent->addEntry(lfn,root,true,false);
  10209. mode = RTM_SUB | RTM_LOCK_WRITE;
  10210. if (!lock.init(lfn, DXB_SuperFile, mode, timeout, title))
  10211. throw MakeStringException(-1,"%s: Cannot create superfile '%s'",title,name);
  10212. if (autocreate)
  10213. *autocreate = true;
  10214. }
  10215. StringBuffer reason;
  10216. if (!readonly&&checkProtectAttr(name,lock.queryRoot(),reason))
  10217. throw MakeStringException(-1,"CDistributedSuperFile::%s %s",title,reason.str());
  10218. return true;
  10219. }
  10220. void disconnect(bool commit)
  10221. {
  10222. if (lock.queryConnection()&&!readonly) {
  10223. if (commit) {
  10224. migrateSuperOwnersAttr(lock.queryRoot());
  10225. CDateTime dt;
  10226. dt.setNow();
  10227. StringBuffer s;
  10228. lock.queryRoot()->setProp("@modified",dt.getString(s).str());
  10229. }
  10230. else {
  10231. ForEachItemIn(i,children)
  10232. children.item(i).rollback();
  10233. lock.queryConnection()->rollback();
  10234. }
  10235. }
  10236. lock.clear();
  10237. children.kill();
  10238. }
  10239. unsigned numSubFiles() const
  10240. {
  10241. return (unsigned)lock.queryRoot()->getPropInt("@numsubfiles");
  10242. }
  10243. bool getSubFileName(unsigned num,StringBuffer &name) const
  10244. {
  10245. if ((unsigned)lock.queryRoot()->getPropInt("@numsubfiles")<=num)
  10246. return false;
  10247. StringBuffer xpath;
  10248. getSubPath(xpath,num);
  10249. IPropertyTree *sub = lock.queryRoot()->queryPropTree(xpath.str());
  10250. if (!sub)
  10251. return false;
  10252. name.append(sub->queryProp("@name"));
  10253. return true;
  10254. }
  10255. unsigned findSubName(const char *subname) const
  10256. {
  10257. unsigned n = findSubFileOrd(subname);
  10258. if (n!=NotFound)
  10259. return n;
  10260. StringBuffer lfn;
  10261. normalizeLFN(subname,lfn);
  10262. Owned<IPropertyTreeIterator> iter = lock.queryRoot()->getElements("SubFile");
  10263. ForEach(*iter) {
  10264. if (stricmp(iter->query().queryProp("@name"),lfn.str())==0) {
  10265. unsigned ret=iter->query().getPropInt("@num");
  10266. if (ret&&((unsigned)lock.queryRoot()->getPropInt("@numsubfiles")>=ret))
  10267. return ret-1;
  10268. }
  10269. }
  10270. return NotFound;
  10271. }
  10272. unsigned getContents(StringArray &contents) const
  10273. {
  10274. // slightly inefficient
  10275. unsigned n = lock.queryRoot()->getPropInt("@numsubfiles");
  10276. StringBuffer xpath;
  10277. for (unsigned sni=0;sni<n;sni++) {
  10278. getSubPath(xpath.clear(),sni);
  10279. IPropertyTree *sub = lock.queryRoot()->queryPropTree(xpath.str());
  10280. if (!sub)
  10281. break;
  10282. contents.append(sub->queryProp("@name"));
  10283. }
  10284. return contents.ordinality();
  10285. }
  10286. };
  10287. // Contention never expected for this function!
  10288. #define PROMOTE_CONN_TIMEOUT (60*1000) // how long to wait for a single superfile
  10289. #define PROMOTE_DELAY (30*1000)
  10290. // Check files don't share subfiles (MORE - make this part of swap files action?)
  10291. static int hasCommonSubChildren(IDistributedSuperFile *orig, IDistributedSuperFile *dest)
  10292. {
  10293. unsigned origSubs = orig->numSubFiles();
  10294. unsigned destSubs = dest->numSubFiles();
  10295. if (origSubs == 0)
  10296. return NotFound;
  10297. for (unsigned j=0; j<origSubs; j++) {
  10298. for (unsigned k=0; k<destSubs; k++) {
  10299. if (strcmp(orig->querySubFile(j).queryLogicalName(), dest->querySubFile(k).queryLogicalName())==0)
  10300. return j;
  10301. }
  10302. }
  10303. return NotFound;
  10304. }
  10305. // MORE - use string arrays, rather than char* arrays or comma-separated strings
  10306. void CDistributedFileDirectory::promoteSuperFiles(unsigned numsf,const char **sfnames,const char *addsubnames,bool delsub,bool createonlyonesuperfile,IUserDescriptor *user,unsigned timeout,StringArray &outunlinked)
  10307. {
  10308. if (!numsf)
  10309. return;
  10310. // Create a local transaction that will be destroyed
  10311. Owned<IDistributedFileTransactionExt> transaction = new CDistributedFileTransaction(user);
  10312. transaction->start();
  10313. // Lookup all files (keep them in transaction's cache)
  10314. bool created = false;
  10315. unsigned files = numsf;
  10316. for (unsigned i=0; i<numsf; i++) {
  10317. Owned<IDistributedSuperFile> super = transaction->lookupSuperFile(sfnames[i]);
  10318. if (!super.get()) {
  10319. if (created && createonlyonesuperfile) {
  10320. files = i;
  10321. break;
  10322. }
  10323. Owned<IDistributedSuperFile> sfile = createSuperFile(sfnames[i],user,false,false,transaction);
  10324. created = true;
  10325. }
  10326. }
  10327. // If last file had sub-files, clean and fill outlinked
  10328. Owned<IDistributedSuperFile> last = transaction->lookupSuperFile(sfnames[files-1]);
  10329. assertex(last.get());
  10330. unsigned lastSubs = last->numSubFiles();
  10331. if (files == numsf && lastSubs > 0) {
  10332. for (unsigned i=0; i<lastSubs; i++) {
  10333. outunlinked.append(last->querySubFile(i).queryLogicalName());
  10334. }
  10335. last->removeSubFile(NULL,false,false,transaction);
  10336. }
  10337. last.clear();
  10338. // Move up, starting from last
  10339. for (unsigned i=files-1; i; i--) {
  10340. Owned<IDistributedSuperFile> orig = transaction->lookupSuperFile(sfnames[i-1]);
  10341. Owned<IDistributedSuperFile> dest = transaction->lookupSuperFile(sfnames[i]);
  10342. assertex(orig.get());
  10343. assertex(dest.get());
  10344. int common = hasCommonSubChildren(orig, dest);
  10345. if (common != NotFound) {
  10346. throw MakeStringException(-1,"promoteSuperFiles: superfiles %s and %s share same subfile %s",
  10347. orig->queryLogicalName(), dest->queryLogicalName(), orig->querySubFile(common).queryLogicalName());
  10348. }
  10349. orig->swapSuperFile(dest, transaction);
  10350. }
  10351. // Move new subs to first super, if any
  10352. Owned<IDistributedSuperFile> first = transaction->lookupSuperFile(sfnames[0]);
  10353. assertex(first.get());
  10354. StringArray toadd;
  10355. toadd.appendListUniq(addsubnames, ",");
  10356. ForEachItemIn(i,toadd) {
  10357. CDfsLogicalFileName lfn;
  10358. if (!lfn.setValidate(toadd.item(i)))
  10359. throw MakeStringException(-1,"promoteSuperFiles: invalid logical name to add: %s",toadd.item(i));
  10360. first->addSubFile(toadd.item(i),false,NULL,false,transaction);
  10361. }
  10362. first.clear();
  10363. transaction->commit();
  10364. // MORE - once deletion of logic files are also in transaction we can move this up (and allow promote within transactions)
  10365. if (delsub) {
  10366. ForEachItemIn(j,outunlinked)
  10367. removeEntry(outunlinked.item(j),user,transaction,timeout);
  10368. }
  10369. }
  10370. ISimpleSuperFileEnquiry * CDistributedFileDirectory::getSimpleSuperFileEnquiry(const char *logicalname,const char *title,IUserDescriptor *udesc,unsigned timeout)
  10371. {
  10372. Owned<CLightWeightSuperFileConn> ret = new CLightWeightSuperFileConn(defaultTimeout,udesc);
  10373. if (ret->connect(this,title,logicalname,true,NULL,timeout))
  10374. return ret.getClear();
  10375. return NULL;
  10376. }
  10377. bool CDistributedFileDirectory::getFileSuperOwners(const char *logicalname, StringArray &owners)
  10378. {
  10379. CFileLock lock;
  10380. CDfsLogicalFileName lfn;
  10381. if (!lfn.setValidate(logicalname))
  10382. throw MakeStringException(-1,"CDistributedFileDirectory::getFileSuperOwners: Invalid file name '%s'",logicalname);
  10383. if (lfn.isMulti()||lfn.isExternal()||lfn.isForeign())
  10384. return false;
  10385. if (!lock.init(lfn, RTM_LOCK_READ, defaultTimeout, "CDistributedFileDirectory::getFileSuperOwners"))
  10386. return false;
  10387. CFileSuperOwnerLock superOwnerLock;
  10388. verifyex(superOwnerLock.init(lfn, NULL, defaultTimeout, "CDistributedFileDirectory::getFileSuperOwners(SuperOwnerLock)"));
  10389. Owned<IPropertyTreeIterator> iter = lock.queryRoot()->getElements("SuperOwner");
  10390. StringBuffer pname;
  10391. ForEach(*iter) {
  10392. iter->query().getProp("@name",pname.clear());
  10393. if (pname.length())
  10394. owners.append(pname.str());
  10395. }
  10396. return true;
  10397. }
  10398. class CFileRelationship: public CInterface, implements IFileRelationship
  10399. {
  10400. Linked<IPropertyTree> pt;
  10401. const char *queryProp(const char *name)
  10402. {
  10403. if (pt.get()) {
  10404. const char *ret = pt->queryProp(name);
  10405. if (ret)
  10406. return ret;
  10407. }
  10408. return "";
  10409. }
  10410. public:
  10411. IMPLEMENT_IINTERFACE;
  10412. CFileRelationship(IPropertyTree *_pt)
  10413. : pt(_pt)
  10414. {
  10415. }
  10416. virtual const char *queryKind() { return queryProp("@kind"); }
  10417. virtual const char *queryPrimaryFilename() { return queryProp("@primary"); }
  10418. virtual const char *querySecondaryFilename() { return queryProp("@secondary"); }
  10419. virtual const char *queryPrimaryFields() { return queryProp("@primflds"); }
  10420. virtual const char *querySecondaryFields() { return queryProp("@secflds"); }
  10421. virtual const char *queryCardinality() { return queryProp("@cardinality"); }
  10422. virtual bool isPayload() { return pt->getPropBool("@payload"); }
  10423. virtual const char *queryDescription() { return queryProp("Description"); }
  10424. virtual IPropertyTree *queryTree() { return pt.get(); }
  10425. };
  10426. class CFileRelationshipIterator: public CInterface, implements IFileRelationshipIterator
  10427. {
  10428. unsigned num;
  10429. unsigned idx;
  10430. CMessageBuffer mb;
  10431. Owned<CFileRelationship> r;
  10432. Owned<IPropertyTree> pt;
  10433. Linked<INode> foreigndali;
  10434. unsigned defaultTimeout;
  10435. bool setPT()
  10436. {
  10437. if (idx<num) {
  10438. pt.setown(createPTree(mb));
  10439. addForeignName(*pt,foreigndali,"@primary");
  10440. addForeignName(*pt,foreigndali,"@secondary");
  10441. }
  10442. return pt.get()!=NULL;
  10443. }
  10444. public:
  10445. IMPLEMENT_IINTERFACE;
  10446. CFileRelationshipIterator(unsigned timems)
  10447. {
  10448. num = 0;
  10449. idx = 0;
  10450. mb.append(num);
  10451. defaultTimeout = timems;
  10452. }
  10453. void init(
  10454. INode *_foreigndali,
  10455. unsigned foreigndalitimeout,
  10456. const char *primary,
  10457. const char *secondary,
  10458. const char *primflds,
  10459. const char *secflds,
  10460. const char *kind,
  10461. const char *cardinality,
  10462. const bool *payload )
  10463. {
  10464. foreigndali.set(_foreigndali);
  10465. if (isLocalDali(foreigndali)) {
  10466. CConnectLock connlock("lookupFileRelationships",querySdsRelationshipsRoot(),false,false,false,defaultTimeout);
  10467. StringBuffer xpath;
  10468. CDistributedFileDirectory::getFileRelationshipXPath(xpath,primary,secondary,primflds,secflds,kind,cardinality,payload);
  10469. Owned<IPropertyTreeIterator> iter = connlock.conn?connlock.conn->getElements(xpath.str()):NULL;
  10470. mb.clear();
  10471. unsigned count = 0;
  10472. mb.append(count);
  10473. // save as sequence of branches
  10474. if (iter) {
  10475. ForEach(*iter.get()) {
  10476. iter->query().serialize(mb);
  10477. count++;
  10478. }
  10479. mb.writeDirect(0,sizeof(count),&count);
  10480. }
  10481. }
  10482. else {
  10483. byte payloadb = 255;
  10484. if (payload)
  10485. payloadb = *payload?1:0;
  10486. mb.clear().append((int)MDFS_ITERATE_RELATIONSHIPS).append(primary).append(secondary).append(primflds).append(secflds).append(kind).append(cardinality).append(payloadb);
  10487. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  10488. checkDfsReplyException(mb);
  10489. if (mb.length()<sizeof(unsigned))
  10490. mb.clear().append((unsigned)0);
  10491. }
  10492. }
  10493. void initall(const char *filename)
  10494. {
  10495. StringBuffer xpath;
  10496. Owned<IPropertyTreeIterator> iter;
  10497. mb.clear();
  10498. unsigned count = 0;
  10499. mb.append(count);
  10500. {
  10501. CConnectLock connlock("lookupFileRelationships",querySdsRelationshipsRoot(),false,false,false,defaultTimeout);
  10502. CDistributedFileDirectory::getFileRelationshipXPath(xpath,filename,NULL,NULL,NULL,NULL,NULL,NULL);
  10503. // save as sequence of branches
  10504. iter.setown(connlock.conn?connlock.conn->getElements(xpath.str()):NULL);
  10505. if (iter) {
  10506. ForEach(*iter.get()) {
  10507. iter->query().serialize(mb);
  10508. count++;
  10509. }
  10510. }
  10511. }
  10512. { // Kludge - seems to be a bug in getElements without second conn lock
  10513. CConnectLock connlock("lookupFileRelationships",querySdsRelationshipsRoot(),false,false,false,defaultTimeout);
  10514. xpath.clear();
  10515. CDistributedFileDirectory::getFileRelationshipXPath(xpath,NULL,filename,NULL,NULL,NULL,NULL,NULL);
  10516. iter.clear();
  10517. iter.setown(connlock.conn?connlock.conn->getElements(xpath.str()):NULL);
  10518. if (iter) {
  10519. ForEach(*iter.get()) {
  10520. IPropertyTree &it = iter->query();
  10521. const char *fn1 = it.queryProp("@primary");
  10522. if (!fn1||(strcmp(fn1,filename)!=0)) { // see if already done
  10523. it.serialize(mb);
  10524. count++;
  10525. }
  10526. }
  10527. }
  10528. }
  10529. mb.writeDirect(0,sizeof(count),&count);
  10530. }
  10531. bool first()
  10532. {
  10533. r.clear();
  10534. pt.clear();
  10535. idx = 0;
  10536. mb.reset().read(num);
  10537. return setPT();
  10538. }
  10539. bool next()
  10540. {
  10541. r.clear();
  10542. pt.clear();
  10543. idx++;
  10544. return setPT();
  10545. }
  10546. bool isValid()
  10547. {
  10548. return pt.get()!=NULL;
  10549. }
  10550. IFileRelationship & query()
  10551. {
  10552. if (!r)
  10553. r.setown(new CFileRelationship(pt));
  10554. return *r;
  10555. }
  10556. };
  10557. static bool isWild(const char *path,bool emptydefault=false)
  10558. {
  10559. if (!path||!*path)
  10560. return emptydefault;
  10561. return ((strchr(path,'?')||strchr(path,'*')));
  10562. }
  10563. static void addRelationCondition(StringBuffer &xpath,const char *fld,const char *mask)
  10564. {
  10565. if (!mask||!*mask||((*mask=='*')&&(!mask[1])))
  10566. return;
  10567. xpath.append('[').append(fld).append('=');
  10568. if (isWild(mask))
  10569. xpath.append('~');
  10570. xpath.append('"').append(mask).append("\"]");
  10571. }
  10572. static void addRelationBoolCondition(StringBuffer &xpath,const char *fld,const bool *mask)
  10573. {
  10574. if (!mask)
  10575. return;
  10576. xpath.append('[').append(fld).append("=\"");
  10577. if (*mask)
  10578. xpath.append("1\"]");
  10579. else
  10580. xpath.append("0\"]");
  10581. }
  10582. static const char *normLFN(const char *name,CDfsLogicalFileName &logicalname,const char *title)
  10583. {
  10584. if (isWild(name,true))
  10585. return name;
  10586. if (!logicalname.setValidate(name))
  10587. throw MakeStringException(-1,"%s: invalid logical file name '%s'",title,name);
  10588. if (logicalname.isForeign()) {
  10589. SocketEndpoint ep;
  10590. Owned<INode> fd = createINode(ep);
  10591. if (logicalname.getEp(ep)&&isLocalDali(fd)) // see if pointing back at self
  10592. logicalname.clearForeign();
  10593. }
  10594. return logicalname.get();
  10595. }
  10596. StringBuffer &CDistributedFileDirectory::getFileRelationshipXPath(
  10597. StringBuffer &xpath,
  10598. const char *primary,
  10599. const char *secondary,
  10600. const char *primflds,
  10601. const char *secflds,
  10602. const char *kind,
  10603. const char *cardinality,
  10604. const bool *payload
  10605. )
  10606. {
  10607. xpath.append("Relationship");
  10608. CDfsLogicalFileName lfn;
  10609. addRelationCondition(xpath,"@kind",kind);
  10610. addRelationCondition(xpath,"@primary",normLFN(primary,lfn,"findFileRelationship(primary)"));
  10611. addRelationCondition(xpath,"@secondary",normLFN(secondary,lfn,"findFileRelationship(secondary)"));
  10612. addRelationCondition(xpath,"@primflds",primflds);
  10613. addRelationCondition(xpath,"@secflds",secflds);
  10614. addRelationCondition(xpath,"@cardinality",cardinality);
  10615. addRelationBoolCondition(xpath,"@payload",payload);
  10616. return xpath;
  10617. }
  10618. void CDistributedFileDirectory::doRemoveFileRelationship(
  10619. IRemoteConnection *conn,
  10620. const char *primary,
  10621. const char *secondary,
  10622. const char *primflds,
  10623. const char *secflds,
  10624. const char *kind
  10625. )
  10626. {
  10627. if (!conn)
  10628. return;
  10629. StringBuffer xpath;
  10630. CDistributedFileDirectory::getFileRelationshipXPath(xpath,primary,secondary,primflds,secflds,kind,NULL,NULL);
  10631. Owned<IPropertyTreeIterator> iter = conn->getElements(xpath.str());
  10632. IArrayOf<IPropertyTree> toremove;
  10633. ForEach(*iter) {
  10634. IPropertyTree &t = iter->query();
  10635. toremove.append(*LINK(&t));
  10636. }
  10637. ForEachItemIn(i, toremove) {
  10638. conn->queryRoot()->removeTree(&toremove.item(i));
  10639. }
  10640. }
  10641. void CDistributedFileDirectory::addFileRelationship(
  10642. const char *primary,
  10643. const char *secondary,
  10644. const char *primflds,
  10645. const char *secflds,
  10646. const char *kind,
  10647. const char *cardinality,
  10648. bool payload,
  10649. IUserDescriptor *user,
  10650. const char *description=NULL
  10651. )
  10652. {
  10653. if (!kind||!*kind)
  10654. kind = S_LINK_RELATIONSHIP_KIND;
  10655. Owned<IPropertyTree> pt = createPTree("Relationship");
  10656. if (isWild(primary,true)||isWild(secondary,true)||isWild(primflds,false)||isWild(secflds,false)||isWild(cardinality,false))
  10657. throw MakeStringException(-1,"Wildcard not allowed in addFileRelation");
  10658. CDfsLogicalFileName pfn;
  10659. if (!pfn.setValidate(primary))
  10660. throw MakeStringException(-1,"addFileRelationship invalid primary name '%s'",primary);
  10661. if (pfn.isExternal()||pfn.isForeign()||pfn.isQuery())
  10662. throw MakeStringException(-1,"addFileRelationship primary %s not allowed",pfn.get());
  10663. primary = pfn.get();
  10664. if (!exists(primary,user))
  10665. throw MakeStringException(-1,"addFileRelationship primary %s does not exist",primary);
  10666. CDfsLogicalFileName sfn;
  10667. if (!sfn.setValidate(secondary))
  10668. throw MakeStringException(-1,"addFileRelationship invalid secondary name '%s'",secondary);
  10669. if (sfn.isExternal()||sfn.isForeign()||sfn.isQuery())
  10670. throw MakeStringException(-1,"addFileRelationship secondary %s not allowed",sfn.get());
  10671. secondary = sfn.get();
  10672. if (!exists(secondary,user))
  10673. throw MakeStringException(-1,"addFileRelationship secondary %s does not exist",secondary);
  10674. if (cardinality&&*cardinality&&!strchr(cardinality,':'))
  10675. throw MakeStringException(-1,"addFileRelationship cardinality %s invalid",cardinality);
  10676. pt->setProp("@kind",kind);
  10677. pt->setProp("@primary",primary);
  10678. pt->setProp("@secondary",secondary);
  10679. pt->setProp("@cardinality",cardinality);
  10680. pt->setProp("@primflds",primflds);
  10681. pt->setProp("@secflds",secflds);
  10682. pt->setPropBool("@payload",payload);
  10683. if (description&&*description)
  10684. pt->setProp("Description",description);
  10685. StringBuffer xpath(querySdsFilesRoot());
  10686. for (unsigned i=0;i<2;i++) {
  10687. CConnectLock connlock("addFileRelation",querySdsRelationshipsRoot(),true,false,false,defaultTimeout);
  10688. if (!connlock.conn) {
  10689. CConnectLock connlock2("addFileRelation.2",querySdsFilesRoot(),true,false,false,defaultTimeout);
  10690. if (!connlock2.conn)
  10691. return;
  10692. Owned<IPropertyTree> ptr = createPTree("Relationships");
  10693. connlock2.conn->queryRoot()->addPropTree("Relationships",ptr.getClear());
  10694. continue;
  10695. }
  10696. StringBuffer query;
  10697. doRemoveFileRelationship(connlock.conn,primary,secondary,primflds,secflds,kind);
  10698. connlock.conn->queryRoot()->addPropTree("Relationship",pt.getClear());
  10699. break;
  10700. }
  10701. }
  10702. void CDistributedFileDirectory::removeFileRelationships(
  10703. const char *primary,
  10704. const char *secondary,
  10705. const char *primflds,
  10706. const char *secflds,
  10707. const char *kind
  10708. )
  10709. {
  10710. if ((!primary||!*primary||(strcmp(primary,"*")==0))&&
  10711. (!secondary||!*secondary||(strcmp(secondary,"*")==0)))
  10712. throw MakeStringException(-1,"removeFileRelationships primary and secondary cannot both be wild");
  10713. CConnectLock connlock("removeFileRelation",querySdsRelationshipsRoot(),true,false,false,defaultTimeout);
  10714. doRemoveFileRelationship(connlock.conn,primary,secondary,primflds,secflds,kind);
  10715. }
  10716. IFileRelationshipIterator *CDistributedFileDirectory::lookupFileRelationships(
  10717. const char *primary,
  10718. const char *secondary,
  10719. const char *primflds,
  10720. const char *secflds,
  10721. const char *kind,
  10722. const char *cardinality,
  10723. const bool *payload,
  10724. const char *foreigndali,
  10725. unsigned foreigndalitimeout
  10726. )
  10727. {
  10728. Owned<INode> foreign;
  10729. if (foreigndali&&*foreigndali) {
  10730. SocketEndpoint ep(foreigndali);
  10731. if (ep.isNull())
  10732. throw MakeStringException(-1,"lookupFileRelationships::Cannot resolve foreign dali %s",foreigndali);
  10733. foreign.setown(createINode(ep));
  10734. }
  10735. Owned<CFileRelationshipIterator> ret = new CFileRelationshipIterator(defaultTimeout);
  10736. ret->init(foreign,foreigndalitimeout,primary,secondary,primflds,secflds,kind,cardinality,payload);
  10737. return ret.getClear();
  10738. }
  10739. void CDistributedFileDirectory::removeAllFileRelationships(const char *filename)
  10740. {
  10741. if (!filename||!*filename||(strcmp(filename,"*")==0))
  10742. throw MakeStringException(-1,"removeAllFileRelationships filename cannot be wild");
  10743. {
  10744. CConnectLock connlock("removeFileRelation",querySdsRelationshipsRoot(),true,false,false,defaultTimeout);
  10745. doRemoveFileRelationship(connlock.conn,filename,NULL,NULL,NULL,NULL);
  10746. }
  10747. { // kludge bug in getElements if connection used twice
  10748. CConnectLock connlock("removeFileRelation",querySdsRelationshipsRoot(),true,false,false,defaultTimeout);
  10749. doRemoveFileRelationship(connlock.conn,NULL,filename,NULL,NULL,NULL);
  10750. }
  10751. }
  10752. IFileRelationshipIterator *CDistributedFileDirectory::lookupAllFileRelationships(
  10753. const char *filename)
  10754. {
  10755. if (isWild(filename,true))
  10756. throw MakeStringException(-1,"Wildcard filename not allowed in lookupAllFileRelationships");
  10757. CDfsLogicalFileName lfn;
  10758. normLFN(filename,lfn,"lookupAllFileRelationships");
  10759. Owned<CFileRelationshipIterator> ret = new CFileRelationshipIterator(defaultTimeout);
  10760. ret->initall(lfn.get());
  10761. return ret.getClear();
  10762. }
  10763. void CDistributedFileDirectory::renameFileRelationships(const char *oldname,const char *newname,IFileRelationshipIterator *reliter,IUserDescriptor*user)
  10764. {
  10765. CDfsLogicalFileName oldlfn;
  10766. normLFN(oldname,oldlfn,"renameFileRelationships(old name)");
  10767. CDfsLogicalFileName newlfn;
  10768. normLFN(newname,newlfn,"renameFileRelationships(new name)");
  10769. ForEach(*reliter) {
  10770. try {
  10771. IFileRelationship &r = reliter->query();
  10772. bool adj = false;
  10773. const char *pf = r.queryPrimaryFilename();
  10774. if (!pf)
  10775. continue;
  10776. if (strcmp(pf,oldlfn.get())==0) {
  10777. adj = true;
  10778. pf = newlfn.get();
  10779. }
  10780. const char *sf = r.querySecondaryFilename();
  10781. if (!sf)
  10782. continue;
  10783. if (strcmp(sf,oldlfn.get())==0) {
  10784. adj = true;
  10785. sf = newlfn.get();
  10786. }
  10787. if (adj)
  10788. addFileRelationship(pf,sf,r.queryPrimaryFields(),r.querySecondaryFields(),r.queryKind(),r.queryCardinality(),r.isPayload(),user,r.queryDescription());
  10789. }
  10790. catch (IException *e)
  10791. {
  10792. EXCLOG(e,"renameFileRelationships");
  10793. e->Release();
  10794. }
  10795. }
  10796. }
  10797. // JCSMORE what was this for, not called by anything afaics
  10798. bool CDistributedFileDirectory::publishMetaFileXML(const CDfsLogicalFileName &logicalname,IUserDescriptor *user)
  10799. {
  10800. if (logicalname.isExternal()||logicalname.isForeign()||logicalname.isQuery())
  10801. return false;
  10802. Owned<IPropertyTree> file = getFileTree(logicalname.get(),user,NULL,FOREIGN_DALI_TIMEOUT,true);
  10803. if (!file.get())
  10804. return false;
  10805. if (strcmp(file->queryName(),queryDfsXmlBranchName(DXB_SuperFile))==0)
  10806. return false;
  10807. unsigned max = file->getPropInt("@numparts");
  10808. SocketEndpointArray ips;
  10809. StringBuffer xpath;
  10810. StringBuffer ipstr;
  10811. for (unsigned i=0;i<max;i++) { // probably could be done better
  10812. xpath.clear().append("Part[@num=\"").append(i+1).append("\"]");
  10813. Owned<IPropertyTree> child = file->getPropTree(xpath.str());
  10814. SocketEndpoint ep;
  10815. if (child.get()&&child->getProp("@node",ipstr.clear()))
  10816. ep.ipset(ipstr.str());
  10817. ips.append(ep);
  10818. }
  10819. Owned<IException> exc;
  10820. CriticalSection errcrit;
  10821. class casyncfor: public CAsyncFor
  10822. {
  10823. IPropertyTree* file;
  10824. CriticalSection &errcrit;
  10825. Owned<IException> &exc;
  10826. SocketEndpointArray &ips;
  10827. public:
  10828. casyncfor(IPropertyTree* _file,SocketEndpointArray &_ips,Owned<IException> &_exc,CriticalSection &_errcrit)
  10829. : ips(_ips), exc(_exc), errcrit(_errcrit)
  10830. {
  10831. file = _file;
  10832. }
  10833. void Do(unsigned i)
  10834. {
  10835. UnsignedArray parts;
  10836. SocketEndpoint &ep = ips.item(i);
  10837. if (ep.isNull())
  10838. return;
  10839. ForEachItemIn(j,ips) {
  10840. if (j==i)
  10841. parts.append(i);
  10842. else if (ep.ipequals(ips.item(j))) {
  10843. if (j<i)
  10844. return; // already done
  10845. parts.append(j);
  10846. }
  10847. }
  10848. try {
  10849. StringBuffer path;
  10850. StringBuffer mask;
  10851. if (file->getProp("@directory",path)&&file->getProp("@partmask",mask)) {
  10852. addPathSepChar(path).append(mask);
  10853. StringBuffer outpath;
  10854. StringBuffer tail("META__");
  10855. splitFilename(path.str(), &outpath, &outpath, &tail, NULL);
  10856. outpath.append(tail).append(".xml");
  10857. Owned<IPropertyTree> pt = createPTreeFromIPT(file);
  10858. filterParts(pt,parts);
  10859. StringBuffer str;
  10860. toXML(pt, str);
  10861. RemoteFilename rfn;
  10862. rfn.setPath(ep,outpath.str());
  10863. Owned<IFile> out = createIFile(rfn);
  10864. Owned<IFileIO> outio = out->open(IFOcreate);
  10865. if (outio)
  10866. outio->write(0,str.length(),str.str());
  10867. }
  10868. }
  10869. catch(IException *e)
  10870. {
  10871. CriticalBlock block(errcrit);
  10872. EXCLOG(e,"publishMetaFileXML");
  10873. if (!exc.get())
  10874. exc.setown(e);
  10875. else
  10876. e->Release();
  10877. }
  10878. }
  10879. } afor(file,ips,exc,errcrit);
  10880. afor.For(max,20);
  10881. if (exc)
  10882. throw exc.getClear();
  10883. return true;
  10884. }
  10885. IFileDescriptor *CDistributedFileDirectory::createDescriptorFromMetaFile(const CDfsLogicalFileName &logicalname,IUserDescriptor *user)
  10886. {
  10887. return NULL; // TBD
  10888. }
  10889. // Overwrite protection
  10890. bool CDistributedFileDirectory::isProtectedFile(const CDfsLogicalFileName &logicalName, unsigned timeout)
  10891. {
  10892. CFileAttrLock attrLock;
  10893. if (!attrLock.init(logicalName, RTM_LOCK_READ, NULL, timeout?timeout:INFINITE, "CDistributedFileDirectory::isProtectedFile"))
  10894. return false; // timeout will raise exception
  10895. Owned<IPropertyTreeIterator> wpiter = attrLock.queryRoot()->getElements("Protect");
  10896. bool prot = false;
  10897. ForEach(*wpiter) {
  10898. IPropertyTree &t = wpiter->query();
  10899. if (t.getPropInt("@count")) {
  10900. prot = true;
  10901. break;
  10902. }
  10903. }
  10904. // timeout retry TBD
  10905. return prot;
  10906. }
  10907. unsigned CDistributedFileDirectory::queryProtectedCount(const CDfsLogicalFileName &logicalName, const char *owner)
  10908. {
  10909. CFileAttrLock attrLock;
  10910. if (!attrLock.init(logicalName, RTM_LOCK_READ, NULL, defaultTimeout, "CDistributedFileDirectory::queryProtectedCount"))
  10911. return 0; // timeout will raise exception
  10912. Owned<IPropertyTreeIterator> wpiter = attrLock.queryRoot()->getElements("Protect");
  10913. unsigned count = 0;
  10914. ForEach(*wpiter) {
  10915. IPropertyTree &t = wpiter->query();
  10916. const char *name = t.queryProp("@name");
  10917. if (!owner||!*owner||(name&&(strcmp(owner,name)==0)))
  10918. count += t.getPropInt("@count");
  10919. }
  10920. return count;
  10921. }
  10922. bool CDistributedFileDirectory::getProtectedInfo(const CDfsLogicalFileName &logicalName, StringArray &names, UnsignedArray &counts)
  10923. {
  10924. CFileAttrLock attrLock;
  10925. if (!attrLock.init(logicalName, RTM_LOCK_READ, NULL, defaultTimeout, "CDistributedFileDirectory::getProtectedInfo"))
  10926. return false; // timeout will raise exception
  10927. Owned<IPropertyTreeIterator> wpiter = attrLock.queryRoot()->getElements("Protect");
  10928. bool prot = false;
  10929. ForEach(*wpiter) {
  10930. IPropertyTree &t = wpiter->query();
  10931. const char *name = t.queryProp("@name");
  10932. names.append(name?name:"<Unknown>");
  10933. unsigned c = t.getPropInt("@count");
  10934. if (c)
  10935. prot = true;
  10936. counts.append(c);
  10937. }
  10938. return prot;
  10939. }
  10940. IDFProtectedIterator *CDistributedFileDirectory::lookupProtectedFiles(const char *owner,bool notsuper,bool superonly)
  10941. {
  10942. return new CDFProtectedIterator(owner,notsuper,superonly,defaultTimeout);
  10943. }
  10944. const char* DFUQResultFieldNames[] = { "@name", "@description", "@group", "@kind", "@modified", "@job", "@owner",
  10945. "@DFUSFrecordCount", "@recordCount", "@recordSize", "@DFUSFsize", "@size", "@workunit", "@DFUSFcluster", "@numsubfiles",
  10946. "@accessed", "@numparts", "@compressedSize", "@directory", "@partmask" };
  10947. extern da_decl const char* getDFUQResultFieldName(DFUQResultField feild)
  10948. {
  10949. return DFUQResultFieldNames[feild];
  10950. }
  10951. IPropertyTreeIterator *deserializeFileAttrIterator(MemoryBuffer& mb, DFUQResultField* localFilters, const char* localFilterBuf)
  10952. {
  10953. class CFileAttrIterator: public CInterface, implements IPropertyTreeIterator
  10954. {
  10955. Owned<IPropertyTree> cur;
  10956. StringArray fileClusterGroups;
  10957. void setFileCluster(IPropertyTree *attr, const char* group, StringArray& clusterFilter)
  10958. {
  10959. if (!group || !*group)
  10960. return;
  10961. //The group may contain multiple clusters and some of them may match with the clusterFilter.
  10962. if (clusterFilter.length() == 1)
  10963. attr->setProp(getDFUQResultFieldName(DFUQRFcluster), clusterFilter.item(0));//Filter has been handled on server side.
  10964. else
  10965. {
  10966. StringArray clusters;
  10967. clusters.appendListUniq(group, ",");
  10968. ForEachItemIn(i,clusters)
  10969. {
  10970. //Add a cluster if no cluster filter or the cluster matchs with cluster filter
  10971. const char* cluster = clusters.item(i);
  10972. if (cluster && *cluster && ((!clusterFilter.length()) || (clusterFilter.find(cluster) != NotFound)))
  10973. fileClusterGroups.append(cluster);
  10974. }
  10975. if (fileClusterGroups.length())
  10976. {
  10977. //if this file exists on multiple clusters, set one of the clusters as the "@DFUSFcluster" prop for
  10978. //this attr, leaving the rest inside the fileClusterGroups array. Those clusters will be used by the
  10979. //duplicateFileAttrOnOtherClusterGroup() to duplicate this file attr on other clusters.
  10980. attr->setProp(getDFUQResultFieldName(DFUQRFcluster), fileClusterGroups.item(fileClusterGroups.length() -1));
  10981. fileClusterGroups.pop();
  10982. }
  10983. }
  10984. }
  10985. void setRecordCount(IPropertyTree* file)
  10986. {
  10987. __int64 recordCount = 0;
  10988. if (file->hasProp(getDFUQResultFieldName(DFUQRForigrecordcount)))
  10989. recordCount = file->getPropInt64(getDFUQResultFieldName(DFUQRForigrecordcount));
  10990. else
  10991. {
  10992. __int64 recordSize=file->getPropInt64(getDFUQResultFieldName(DFUQRFrecordsize),0);
  10993. if(recordSize)
  10994. {
  10995. __int64 size=file->getPropInt64(getDFUQResultFieldName(DFUQRForigsize),-1);
  10996. recordCount = size/recordSize;
  10997. }
  10998. }
  10999. file->setPropInt64(getDFUQResultFieldName(DFUQRFrecordcount),recordCount);
  11000. return;
  11001. }
  11002. IPropertyTree *deserializeFileAttr(MemoryBuffer &mb, StringArray& clusterFilter)
  11003. {
  11004. IPropertyTree *attr = getEmptyAttr();
  11005. StringAttr val;
  11006. unsigned n;
  11007. mb.read(val);
  11008. attr->setProp(getDFUQResultFieldName(DFUQRFname),val.get());
  11009. mb.read(val);
  11010. if (strieq(val,"!SF"))
  11011. {
  11012. mb.read(n);
  11013. attr->setPropInt(getDFUQResultFieldName(DFUQRFnumsubfiles),n);
  11014. mb.read(val); // not used currently
  11015. }
  11016. else
  11017. {
  11018. attr->setProp(getDFUQResultFieldName(DFUQRFdirectory),val.get());
  11019. mb.read(n);
  11020. attr->setPropInt(getDFUQResultFieldName(DFUQRFnumparts),n);
  11021. mb.read(val);
  11022. attr->setProp(getDFUQResultFieldName(DFUQRFpartmask),val.get());
  11023. }
  11024. mb.read(val);
  11025. attr->setProp(getDFUQResultFieldName(DFUQRFtimemodified),val.get());
  11026. unsigned count;
  11027. mb.read(count);
  11028. StringAttr at;
  11029. while (count--)
  11030. {
  11031. mb.read(at);
  11032. mb.read(val);
  11033. attr->setProp(at.get(),val.get());
  11034. if (strieq(at.get(), getDFUQResultFieldName(DFUQRFgroup)))
  11035. setFileCluster(attr, val.get(), clusterFilter);
  11036. }
  11037. attr->setPropInt64(getDFUQResultFieldName(DFUQRFsize), attr->getPropInt64(getDFUQResultFieldName(DFUQRForigsize), -1));//Sort the files with empty size to front
  11038. setRecordCount(attr);
  11039. return attr;
  11040. }
  11041. IPropertyTree *duplicateFileAttrOnOtherClusterGroup(IPropertyTree *previousAttr)
  11042. {
  11043. IPropertyTree *attr = getEmptyAttr();
  11044. Owned<IAttributeIterator> ai = previousAttr->getAttributes();
  11045. ForEach(*ai)
  11046. attr->setProp(ai->queryName(),ai->queryValue());
  11047. attr->setProp(getDFUQResultFieldName(DFUQRFcluster), fileClusterGroups.item(fileClusterGroups.length()-1));
  11048. fileClusterGroups.pop();
  11049. return attr;
  11050. }
  11051. public:
  11052. IMPLEMENT_IINTERFACE;
  11053. MemoryBuffer mb;
  11054. unsigned numfiles;
  11055. StringArray clusterFilter;
  11056. bool first()
  11057. {
  11058. mb.reset();
  11059. mb.read(numfiles);
  11060. return next();
  11061. }
  11062. bool next()
  11063. {
  11064. if (fileClusterGroups.length())
  11065. {
  11066. IPropertyTree *attr = duplicateFileAttrOnOtherClusterGroup(cur);
  11067. cur.clear();
  11068. cur.setown(attr);
  11069. return true;
  11070. }
  11071. cur.clear();
  11072. if (mb.getPos()>=mb.length())
  11073. return false;
  11074. cur.setown(deserializeFileAttr(mb, clusterFilter));
  11075. return true;
  11076. }
  11077. bool isValid()
  11078. {
  11079. return cur.get()!=NULL;
  11080. }
  11081. IPropertyTree & query()
  11082. {
  11083. return *cur;
  11084. }
  11085. void setLocalFilters(DFUQResultField* localFilters, const char* localFilterBuf)
  11086. {
  11087. if (!localFilters || !localFilterBuf || !*localFilterBuf)
  11088. return;
  11089. const char *fv = localFilterBuf;
  11090. for (unsigned i=0;localFilters[i]!=DFUQRFterm;i++)
  11091. {
  11092. int fmt = localFilters[i];
  11093. int subfmt = (fmt&0xff);
  11094. if ((subfmt==DFUQRFcluster) && fv && *fv)
  11095. clusterFilter.appendListUniq(fv, ",");
  11096. //Add more if needed
  11097. fv = fv + strlen(fv)+1;
  11098. }
  11099. }
  11100. } *fai = new CFileAttrIterator;
  11101. mb.swapWith(fai->mb);
  11102. fai->setLocalFilters(localFilters, localFilterBuf);
  11103. return fai;
  11104. }
  11105. IPropertyTreeIterator *CDistributedFileDirectory::getDFAttributesTreeIterator(const char* filters, DFUQResultField* localFilters,
  11106. const char* localFilterBuf, IUserDescriptor* user, INode* foreigndali, unsigned foreigndalitimeout)
  11107. {
  11108. CMessageBuffer mb;
  11109. mb.append((int)MDFS_ITERATE_FILTEREDFILES).append(filters).append(true);
  11110. if (user)
  11111. user->serialize(mb);
  11112. if (foreigndali)
  11113. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  11114. else
  11115. queryCoven().sendRecv(mb,RANK_RANDOM,MPTAG_DFS_REQUEST);
  11116. checkDfsReplyException(mb);
  11117. return deserializeFileAttrIterator(mb, localFilters, localFilterBuf);
  11118. }
  11119. IDFAttributesIterator* CDistributedFileDirectory::getLogicalFilesSorted(
  11120. IUserDescriptor* udesc,
  11121. DFUQResultField *sortOrder, // list of fields to sort by (terminated by DFUSFterm)
  11122. const void *filters, // (appended) string values for filters used by dali server
  11123. DFUQResultField *localFilters, //used for filtering query result received from dali server.
  11124. const void *localFilterBuf,
  11125. unsigned startOffset,
  11126. unsigned maxNum,
  11127. __int64 *cacheHint,
  11128. unsigned *total)
  11129. {
  11130. class CDFUPager : public CSimpleInterface, implements IElementsPager
  11131. {
  11132. IUserDescriptor* udesc;
  11133. //StringAttr clusterFilter;
  11134. StringAttr filters;
  11135. DFUQResultField *localFilters;
  11136. StringAttr localFilterBuf;
  11137. StringAttr sortOrder;
  11138. public:
  11139. IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
  11140. CDFUPager(IUserDescriptor* _udesc, const char*_filters, DFUQResultField*_localFilters, const char*_localFilterBuf,
  11141. const char*_sortOrder) : udesc(_udesc), filters(_filters), localFilters(_localFilters), localFilterBuf(_localFilterBuf),
  11142. sortOrder(_sortOrder)
  11143. {
  11144. }
  11145. virtual IRemoteConnection* getElements(IArrayOf<IPropertyTree> &elements)
  11146. {
  11147. Owned<IPropertyTreeIterator> fi = queryDistributedFileDirectory().getDFAttributesTreeIterator(filters.get(),
  11148. localFilters, localFilterBuf.get(), udesc);
  11149. StringArray unknownAttributes;
  11150. sortElements(fi, sortOrder.get(), NULL, NULL, unknownAttributes, elements);
  11151. return NULL;
  11152. }
  11153. };
  11154. StringBuffer so;
  11155. if (sortOrder)
  11156. {
  11157. for (unsigned i=0;sortOrder[i]!=DFUQRFterm;i++)
  11158. {
  11159. if (so.length())
  11160. so.append(',');
  11161. int fmt = sortOrder[i];
  11162. if (fmt&DFUQRFreverse)
  11163. so.append('-');
  11164. if (fmt&DFUQRFnocase)
  11165. so.append('?');
  11166. if (fmt&DFUQRFnumeric)
  11167. so.append('#');
  11168. so.append(getDFUQResultFieldName((DFUQResultField) (fmt&0xff)));
  11169. }
  11170. }
  11171. IArrayOf<IPropertyTree> results;
  11172. Owned<IElementsPager> elementsPager = new CDFUPager(udesc, (const char*) filters, localFilters, (const char*) localFilterBuf,
  11173. so.length()?so.str():NULL );
  11174. getElementsPaged(elementsPager,startOffset,maxNum,NULL,"",cacheHint,results,total,false);
  11175. return new CDFAttributeIterator(results);
  11176. }
  11177. #ifdef _USE_CPPUNIT
  11178. /*
  11179. * This method removes files only logically. removeEntry() used to do that, but the only
  11180. * external use for logical-files only is this test-suite, so I'd rather hack the test
  11181. * suite than expose the behaviour to more viewers.
  11182. */
  11183. extern da_decl void removeLogical(const char *fname, IUserDescriptor *user) {
  11184. if (queryDistributedFileDirectory().exists(fname, user)) {
  11185. Owned<IDistributedFile> file = queryDistributedFileDirectory().lookup(fname, user, true);
  11186. CDistributedFile *f = QUERYINTERFACE(file.get(),CDistributedFile);
  11187. assert(f);
  11188. f->detachLogical();
  11189. }
  11190. }
  11191. #endif // _USE_CPPUNIT