dadfs.cpp 346 KB

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