dadfs.cpp 440 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #define da_decl DECL_EXPORT
  14. #include "platform.h"
  15. #include "jlib.hpp"
  16. #include "jfile.hpp"
  17. #include "jlzw.hpp"
  18. #include "jmisc.hpp"
  19. #include "jtime.hpp"
  20. #include "jregexp.hpp"
  21. #include "jexcept.hpp"
  22. #include "jsort.hpp"
  23. #include "jptree.hpp"
  24. #include "jbuff.hpp"
  25. #include "dafdesc.hpp"
  26. #include "dasds.hpp"
  27. #include "dasess.hpp"
  28. #include "daclient.hpp"
  29. #include "daserver.hpp"
  30. #include "dautils.hpp"
  31. #include "danqs.hpp"
  32. #include "mputil.hpp"
  33. #include "dadfs.hpp"
  34. #include "eclhelper.hpp"
  35. #include "seclib.hpp"
  36. #ifdef _DEBUG
  37. //#define EXTRA_LOGGING
  38. //#define TRACE_LOCKS
  39. #endif
  40. #define SDS_CONNECT_TIMEOUT (1000*60*60*2) // better than infinite
  41. #define SDS_SUB_LOCK_TIMEOUT (10000)
  42. #define SDS_TRANSACTION_RETRY (60000)
  43. #define SDS_UPDATEFS_TIMEOUT (10000)
  44. #define DEFAULT_NUM_DFS_THREADS 30
  45. #define TIMEOUT_ON_CLOSEDOWN 120000 // On closedown, give up on trying to join a thread in CDaliDFSServer after two minutes
  46. #define MAX_PHYSICAL_DELETE_THREADS 1000
  47. #if _INTERNAL_EDITION == 1
  48. #ifndef _MSC_VER
  49. #warning Disabling Sub-file compatibility checking
  50. #endif
  51. #else
  52. #define SUBFILE_COMPATIBILITY_CHECKING
  53. #endif
  54. //#define PACK_ECL
  55. #define SDS_GROUPSTORE_ROOT "Groups" // followed by name
  56. class CDistributedFile;
  57. enum MDFSRequestKind
  58. {
  59. MDFS_ITERATE_FILES,
  60. MDFS_UNUSED1,
  61. MDFS_GET_FILE_TREE,
  62. MDFS_GET_GROUP_TREE,
  63. MDFS_SET_FILE_ACCESSED,
  64. MDFS_ITERATE_RELATIONSHIPS,
  65. MDFS_SET_FILE_PROTECT,
  66. MDFS_ITERATE_FILTEREDFILES,
  67. MDFS_ITERATE_FILTEREDFILES2,
  68. MDFS_MAX
  69. };
  70. // Mutex for physical operations (remove/rename)
  71. static CriticalSection physicalChange;
  72. #define MDFS_GET_FILE_TREE_V2 ((unsigned)1)
  73. static int strcompare(const void * left, const void * right)
  74. {
  75. const char * l = (const char *)left;
  76. const char * r = (const char *)right;
  77. return stricmp(l,r);
  78. }
  79. inline unsigned ipGroupDistance(const IpAddress &ip,const IGroup *grp)
  80. {
  81. if (!grp)
  82. return (unsigned)-1;
  83. return grp->distance(ip);
  84. }
  85. inline unsigned groupDistance(IGroup *grp1,IGroup *grp2)
  86. {
  87. if (grp1==grp2)
  88. return 0;
  89. if (!grp1||!grp2)
  90. return (unsigned)-1;
  91. return grp1->distance(grp2);
  92. }
  93. static StringBuffer &normalizeFormat(StringBuffer &in)
  94. {
  95. in.toLowerCase();
  96. for (unsigned i = 0;i<in.length();)
  97. {
  98. switch (in.charAt(i)) {
  99. case '-':
  100. case '_':
  101. case ' ':
  102. in.remove(i,1);
  103. break;
  104. default:
  105. i++;
  106. break;
  107. }
  108. }
  109. return in;
  110. }
  111. static StringBuffer &getAttrQueryStr(StringBuffer &str,const char *sub,const char *key,const char *name)
  112. {
  113. assertex(key[0]=='@');
  114. str.appendf("%s[%s=\"%s\"]",sub,key,name);
  115. return str;
  116. }
  117. static IPropertyTree *getNamedPropTree(IPropertyTree *parent,const char *sub,const char *key,const char *name,bool preload)
  118. { // no create
  119. if (!parent)
  120. return NULL;
  121. StringBuffer query;
  122. getAttrQueryStr(query,sub,key,name);
  123. if (preload)
  124. return parent->getBranch(query.str());
  125. return parent->getPropTree(query.str());
  126. }
  127. static IPropertyTree *addNamedPropTree(IPropertyTree *parent,const char *sub,const char *key,const char *name, IPropertyTree* init=NULL)
  128. {
  129. IPropertyTree* ret = init?createPTreeFromIPT(init):createPTree(sub);
  130. assertex(key[0]=='@');
  131. ret->setProp(key,name);
  132. ret = parent->addPropTree(sub,ret);
  133. return LINK(ret);
  134. }
  135. const char *normalizeLFN(const char *s,StringBuffer &tmp)
  136. {
  137. CDfsLogicalFileName dlfn;
  138. dlfn.set(s);
  139. return dlfn.get(tmp).str();
  140. }
  141. static IPropertyTree *getEmptyAttr()
  142. {
  143. return createPTree("Attr");
  144. }
  145. RemoteFilename &constructPartFilename(IGroup *grp,unsigned partno,unsigned partmax,const char *name,const char *partmask,const char *partdir,unsigned copy,ClusterPartDiskMapSpec &mspec,RemoteFilename &rfn)
  146. {
  147. partno--;
  148. StringBuffer tmp;
  149. if (!name||!*name) {
  150. if (!partmask||!*partmask) {
  151. partmask = "!ERROR!._$P$_of_$N$"; // could use logical tail name if I had it
  152. IERRLOG("No partmask for constructPartFilename");
  153. }
  154. name = expandMask(tmp,partmask,partno,partmax).str();
  155. }
  156. StringBuffer fullname;
  157. if (findPathSepChar(name)==NULL)
  158. addPathSepChar(fullname.append(partdir));
  159. fullname.append(name);
  160. unsigned n;
  161. unsigned d;
  162. mspec.calcPartLocation(partno,partmax,copy,grp?grp->ordinality():partmax,n,d);
  163. setReplicateFilename(fullname,d);
  164. SocketEndpoint ep;
  165. if (grp)
  166. ep=grp->queryNode(n).endpoint();
  167. rfn.setPath(ep,fullname.toLowerCase().str());
  168. return rfn;
  169. }
  170. inline void LOGPTREE(const char *title,IPropertyTree *pt)
  171. {
  172. StringBuffer buf;
  173. if (pt) {
  174. toXML(pt,buf);
  175. PROGLOG("%s:\n%s\n",title,buf.str());
  176. }
  177. else
  178. PROGLOG("%s : NULL",title);
  179. }
  180. inline void LOGFDESC(const char *title,IFileDescriptor *fdesc)
  181. {
  182. if (fdesc) {
  183. Owned<IPropertyTree> pt = fdesc->getFileTree();
  184. LOGPTREE(title,pt);
  185. }
  186. else
  187. PROGLOG("%s : NULL",title);
  188. }
  189. class DECL_EXCEPTION CDFS_Exception: implements IDFS_Exception, public CInterface
  190. {
  191. int errcode;
  192. StringAttr errstr;
  193. public:
  194. CDFS_Exception(int _errcode, const char *_errstr)
  195. : errstr(_errstr)
  196. {
  197. errcode = _errcode;
  198. }
  199. int errorCode() const { return errcode; }
  200. StringBuffer & errorMessage(StringBuffer &str) const
  201. {
  202. if (errcode==DFSERR_ok)
  203. return str;
  204. str.append("DFS Exception: ").append(errcode);
  205. switch(errcode) {
  206. case DFSERR_LogicalNameAlreadyExists:
  207. return str.append(": logical name ").append(errstr).append(" already exists");
  208. case DFSERR_CannotFindPartFileSize:
  209. return str.append(": Cannot find physical file size for ").append(errstr);
  210. case DFSERR_CannotFindPartFileCrc:
  211. return str.append(": Cannot find physical file crc for ").append(errstr);
  212. case DFSERR_LookupAccessDenied:
  213. {
  214. StringBuffer ip;
  215. queryMyNode()->endpoint().getIpText(ip);
  216. return str.appendf(" Lookup access denied for scope %s at Dali %s", errstr.str(), ip.str());
  217. }
  218. case DFSERR_CreateAccessDenied:
  219. return str.append(" Create access denied for scope ").append(errstr);
  220. case DFSERR_PhysicalPartAlreadyExists:
  221. return str.append(": physical part ").append(errstr).append(" already exists");
  222. case DFSERR_PhysicalPartDoesntExist:
  223. return str.append(": physical part ").append(errstr).append(" doesnt exist");
  224. case DFSERR_ForeignDaliTimeout:
  225. return str.append(": Timeout connecting to Dali Server on ").append(errstr);
  226. case DFSERR_ClusterNotFound:
  227. return str.append(": Cluster not found: ").append(errstr);
  228. case DFSERR_ClusterAlreadyExists:
  229. return str.append(": Cluster already exists: ").append(errstr);
  230. case DFSERR_LookupConnectionTimout:
  231. return str.append(": Lookup connection timeout: ").append(errstr);
  232. case DFSERR_FailedToDeleteFile:
  233. return str.append(": Failed to delete file: ").append(errstr);
  234. }
  235. return str.append("Unknown DFS Exception");
  236. }
  237. MessageAudience errorAudience() const { return MSGAUD_user; }
  238. IMPLEMENT_IINTERFACE;
  239. };
  240. class CConnectLock
  241. {
  242. public:
  243. Owned<IRemoteConnection> conn;
  244. CConnectLock(const char *caller, const char *name, bool write, bool preload, bool hold, unsigned timeout)
  245. {
  246. unsigned start = msTick();
  247. bool first = true;
  248. for (;;)
  249. {
  250. try
  251. {
  252. unsigned mode = write ? RTM_LOCK_WRITE : RTM_LOCK_READ;
  253. if (preload) mode |= RTM_SUB;
  254. if (hold) mode |= RTM_LOCK_HOLD;
  255. conn.setown(querySDS().connect(name, queryCoven().inCoven() ? 0 : myProcessSession(), mode, (timeout==INFINITE)?1000*60*5:timeout));
  256. #ifdef TRACE_LOCKS
  257. PROGLOG("%s: LOCKGOT(%x) %s %s",caller,(unsigned)(memsize_t)conn.get(),name,write?"WRITE":"");
  258. LogRemoteConn(conn);
  259. PrintStackReport();
  260. #endif
  261. break;
  262. }
  263. catch (ISDSException *e)
  264. {
  265. if (SDSExcpt_LockTimeout == e->errorCode())
  266. {
  267. #ifdef TRACE_LOCKS
  268. PROGLOG("%s: LOCKFAIL %s %s",caller,name,write?"WRITE":"");
  269. LogRemoteConn(conn);
  270. #endif
  271. unsigned tt = msTick()-start;
  272. if (timeout!=INFINITE)
  273. throw;
  274. IWARNLOG("CConnectLock on %s waiting for %ds",name,tt/1000);
  275. if (first)
  276. {
  277. PrintStackReport();
  278. first = false;
  279. }
  280. if (tt>SDS_CONNECT_TIMEOUT)
  281. throw;
  282. e->Release();
  283. }
  284. else
  285. throw;
  286. }
  287. catch (IException *e)
  288. {
  289. StringBuffer tmp("CConnectLock ");
  290. tmp.append(caller).append(' ').append(name);
  291. EXCLOG(e, tmp.str());
  292. throw;
  293. }
  294. }
  295. }
  296. IRemoteConnection *detach()
  297. {
  298. #ifdef TRACE_LOCKS
  299. if (conn.get()) {
  300. PROGLOG("LOCKDETACH(%x)",(unsigned)(memsize_t)conn.get());
  301. LogRemoteConn(conn);
  302. }
  303. #endif
  304. return conn.getClear();
  305. }
  306. #ifdef TRACE_LOCKS
  307. ~CConnectLock()
  308. {
  309. if (conn.get()) {
  310. PROGLOG("LOCKDELETE(%x)",(unsigned)(memsize_t)conn.get());
  311. LogRemoteConn(conn);
  312. }
  313. }
  314. #endif
  315. };
  316. void ensureFileScope(const CDfsLogicalFileName &dlfn,unsigned timeout)
  317. {
  318. CConnectLock connlock("ensureFileScope",querySdsFilesRoot(),true,false,false,timeout);
  319. StringBuffer query;
  320. IPropertyTree *r = connlock.conn->getRoot();
  321. StringBuffer scopes;
  322. const char *s=dlfn.getScopes(scopes,true).str();
  323. for (;;) {
  324. IPropertyTree *nr;
  325. const char *e = strstr(s,"::");
  326. query.clear();
  327. if (e)
  328. query.append(e-s,s);
  329. else
  330. query.append(s);
  331. nr = getNamedPropTree(r,queryDfsXmlBranchName(DXB_Scope),"@name",query.trim().toLowerCase().str(),false);
  332. if (!nr)
  333. nr = addNamedPropTree(r,queryDfsXmlBranchName(DXB_Scope),"@name",query.str());
  334. r->Release();
  335. if (!e) {
  336. ::Release(nr);
  337. break;
  338. }
  339. r = nr;
  340. s = e+2;
  341. }
  342. }
  343. void removeFileEmptyScope(const CDfsLogicalFileName &dlfn,unsigned timeout)
  344. {
  345. CConnectLock connlock("removeFileEmptyScope",querySdsFilesRoot(),true,false,false,timeout); //*1
  346. IPropertyTree *root = connlock.conn.get()?connlock.conn->queryRoot():NULL;
  347. if (!root)
  348. return;
  349. StringBuffer query;
  350. dlfn.makeScopeQuery(query.clear(),false);
  351. StringBuffer head;
  352. for (;;) {
  353. if (query.length()) {
  354. const char *tail = splitXPath(query.str(),head.clear());
  355. if (!tail||!*tail)
  356. break;
  357. IPropertyTree *pt;
  358. if (head.length()) {
  359. query.set(head);
  360. pt = root->queryPropTree(query.str());
  361. }
  362. else
  363. pt = root;
  364. IPropertyTree *t = pt?pt->queryPropTree(tail):NULL;
  365. if (t) {
  366. if (t->hasChildren())
  367. break;
  368. pt->removeTree(t);
  369. if (root==pt)
  370. break;
  371. }
  372. else
  373. break;
  374. }
  375. else
  376. break;
  377. }
  378. }
  379. class CFileLockBase
  380. {
  381. IRemoteConnection *conn;
  382. protected:
  383. Owned<IRemoteConnection> lock;
  384. bool init(const char *lockPath, unsigned mode, IRemoteConnection *_conn, unsigned timeout, const char *msg)
  385. {
  386. conn = NULL;
  387. lock.clear();
  388. CTimeMon tm(timeout);
  389. for (;;)
  390. {
  391. try
  392. {
  393. lock.setown(querySDS().connect(lockPath, myProcessSession(), mode, timeout>60000 ? 60000 : timeout));
  394. if (lock.get())
  395. {
  396. conn = _conn;
  397. return true;
  398. }
  399. return false;
  400. }
  401. catch (ISDSException *e)
  402. {
  403. if (SDSExcpt_LockTimeout != e->errorCode() || tm.timedout())
  404. throw;
  405. IWARNLOG("CFileAttrLockBase(%s) blocked for %ds", msg, tm.elapsed()/1000);
  406. e->Release();
  407. }
  408. }
  409. }
  410. public:
  411. CFileLockBase()
  412. {
  413. conn = NULL;
  414. }
  415. ~CFileLockBase()
  416. {
  417. // if conn provided, 'lock' was just a surrogate for the owner connection, commit now to conn if write lock
  418. if (conn && lock)
  419. conn->commit();
  420. }
  421. IRemoteConnection *detach()
  422. {
  423. return lock.getClear();
  424. }
  425. void clear()
  426. {
  427. lock.clear();
  428. conn = NULL;
  429. }
  430. void commit() { if (conn) conn->commit(); }
  431. IPropertyTree *queryRoot() const
  432. {
  433. return lock.get() ? lock->queryRoot() : NULL;
  434. }
  435. };
  436. class CFileLock : protected CFileLockBase
  437. {
  438. protected:
  439. DfsXmlBranchKind kind;
  440. public:
  441. CFileLock()
  442. {
  443. kind = DXB_Internal;
  444. }
  445. bool init(const CDfsLogicalFileName &logicalName, DfsXmlBranchKind bkind, unsigned mode, unsigned timeout, const char *msg)
  446. {
  447. StringBuffer lockPath;
  448. logicalName.makeFullnameQuery(lockPath, bkind, true);
  449. if (CFileLockBase::init(lockPath, mode, NULL, timeout, msg))
  450. {
  451. kind = bkind;
  452. return true;
  453. }
  454. kind = DXB_Internal;
  455. return false;
  456. }
  457. bool init(const CDfsLogicalFileName &logicalName, unsigned mode, unsigned timeout, const char *msg)
  458. {
  459. StringBuffer lockPath;
  460. logicalName.makeFullnameQuery(lockPath, DXB_File, true);
  461. if (CFileLockBase::init(lockPath, mode, NULL, timeout, msg))
  462. {
  463. kind = DXB_File;
  464. return true;
  465. }
  466. // try super
  467. logicalName.makeFullnameQuery(lockPath.clear(), DXB_SuperFile, true);
  468. if (CFileLockBase::init(lockPath, mode, NULL, timeout, msg))
  469. {
  470. kind = DXB_SuperFile;
  471. return true;
  472. }
  473. kind = DXB_Internal;
  474. return false;
  475. }
  476. IRemoteConnection *detach() { return CFileLockBase::detach(); }
  477. IPropertyTree *queryRoot() const { return CFileLockBase::queryRoot(); }
  478. IRemoteConnection *queryConnection() const
  479. {
  480. return lock;
  481. }
  482. void clear()
  483. {
  484. CFileLockBase::clear();
  485. kind = DXB_Internal;
  486. }
  487. DfsXmlBranchKind getKind() const { return kind; }
  488. };
  489. class CFileSubLock : protected CFileLockBase
  490. {
  491. public:
  492. bool init(const CDfsLogicalFileName &logicalName, DfsXmlBranchKind bkind, unsigned mode, const char *subLock, IRemoteConnection *conn, unsigned timeout, const char *msg)
  493. {
  494. StringBuffer lockPath;
  495. logicalName.makeFullnameQuery(lockPath, bkind, true);
  496. lockPath.appendf("/%s", subLock);
  497. return CFileLockBase::init(lockPath, mode, conn, timeout, msg);
  498. }
  499. bool init(const CDfsLogicalFileName &logicalName, unsigned mode, const char *subLock, IRemoteConnection *conn, unsigned timeout, const char *msg)
  500. {
  501. StringBuffer lockPath;
  502. logicalName.makeFullnameQuery(lockPath, DXB_File, true);
  503. lockPath.appendf("/%s", subLock);
  504. if (CFileLockBase::init(lockPath, mode, conn, timeout, msg))
  505. return true;
  506. // try super
  507. logicalName.makeFullnameQuery(lockPath.clear(), DXB_SuperFile, true);
  508. return CFileLockBase::init(lockPath, mode, conn, timeout, msg);
  509. }
  510. };
  511. class CFileAttrLock : protected CFileSubLock
  512. {
  513. public:
  514. bool init(const CDfsLogicalFileName &logicalName, DfsXmlBranchKind bkind, unsigned mode, IRemoteConnection *conn, unsigned timeout, const char *msg)
  515. {
  516. return CFileSubLock::init(logicalName, bkind, mode, "Attr", conn, timeout, msg);
  517. }
  518. bool init(const CDfsLogicalFileName &logicalName, unsigned mode, IRemoteConnection *conn, unsigned timeout, const char *msg)
  519. {
  520. return CFileSubLock::init(logicalName, mode, "Attr", conn, timeout, msg);
  521. }
  522. IPropertyTree *queryRoot() const { return CFileSubLock::queryRoot(); }
  523. void commit() { CFileSubLock::commit(); }
  524. };
  525. class CFileLockCompound : protected CFileLockBase
  526. {
  527. public:
  528. bool init(const CDfsLogicalFileName &logicalName, unsigned mode, IRemoteConnection *conn, const char *subLock, unsigned timeout, const char *msg)
  529. {
  530. StringBuffer lockPath;
  531. if (subLock)
  532. lockPath.appendf("/_Locks/%s/", subLock);
  533. logicalName.makeXPathLName(lockPath);
  534. return CFileLockBase::init(lockPath, mode, conn, timeout, msg);
  535. }
  536. };
  537. class CFileSuperOwnerLock : protected CFileLockCompound
  538. {
  539. public:
  540. bool init(const CDfsLogicalFileName &logicalName, IRemoteConnection *conn, unsigned timeout, const char *msg)
  541. {
  542. return CFileLockCompound::init(logicalName, RTM_CREATE_QUERY | RTM_LOCK_WRITE | RTM_DELETE_ON_DISCONNECT, conn, "SuperOwnerLock", timeout, msg);
  543. }
  544. IRemoteConnection *detach()
  545. {
  546. return CFileLockCompound::detach();
  547. }
  548. bool initWithFileLock(const CDfsLogicalFileName &logicalName, unsigned timeout, const char *msg, CFileLock &fcl, unsigned fclmode)
  549. {
  550. // SuperOwnerLock while holding fcl
  551. IRemoteConnection *fclConn = fcl.queryConnection();
  552. if (!fclConn)
  553. return false; // throw ?
  554. CTimeMon tm(timeout);
  555. unsigned remaining = timeout;
  556. for (;;)
  557. {
  558. try
  559. {
  560. if (init(logicalName, NULL, 0, msg))
  561. return true;
  562. else
  563. return false; // throw ?
  564. }
  565. catch (ISDSException *e)
  566. {
  567. if (SDSExcpt_LockTimeout != e->errorCode() || tm.timedout(&remaining))
  568. throw;
  569. e->Release();
  570. }
  571. // release lock
  572. {
  573. fclConn->changeMode(RTM_NONE, remaining);
  574. }
  575. tm.timedout(&remaining);
  576. unsigned stime = 1000 * (2+getRandom()%15); // 2-15 sec
  577. if (stime > remaining)
  578. stime = remaining;
  579. // let another get excl lock
  580. Sleep(stime);
  581. tm.timedout(&remaining);
  582. // get lock again (waiting for other to release excl)
  583. {
  584. fclConn->changeMode(fclmode, remaining);
  585. fclConn->reload();
  586. }
  587. }
  588. }
  589. };
  590. class CScopeConnectLock
  591. {
  592. CConnectLock *lock;
  593. public:
  594. CScopeConnectLock()
  595. {
  596. lock = NULL;
  597. }
  598. CScopeConnectLock(const char *caller, const CDfsLogicalFileName &lname, bool write, bool preload, bool hold, unsigned timeout)
  599. {
  600. lock = NULL;
  601. init(caller, lname, write, preload, hold, timeout);
  602. }
  603. ~CScopeConnectLock()
  604. {
  605. delete lock;
  606. }
  607. bool init(const char *caller, const CDfsLogicalFileName &lname, bool write, bool preload, bool hold, unsigned timeout)
  608. {
  609. delete lock;
  610. StringBuffer query;
  611. lname.makeScopeQuery(query,true);
  612. lock = new CConnectLock(caller, query.str(), write, preload,hold, timeout);
  613. if (lock->conn.get()==NULL)
  614. {
  615. delete lock;
  616. lock = NULL;
  617. ensureFileScope(lname);
  618. lock = new CConnectLock(caller, query.str(), write, preload, hold, timeout);
  619. }
  620. return lock->conn.get()!=NULL;
  621. }
  622. IRemoteConnection *detach()
  623. {
  624. return lock?lock->detach():NULL;
  625. }
  626. IRemoteConnection *conn()
  627. {
  628. return lock?lock->conn:NULL;
  629. }
  630. IPropertyTree *queryRoot()
  631. {
  632. return (lock&&lock->conn.get())?lock->conn->queryRoot():NULL;
  633. }
  634. void remove()
  635. {
  636. if (lock&&lock->conn.get())
  637. lock->conn->close(true);
  638. }
  639. IPropertyTree *queryFileRoot(const CDfsLogicalFileName &dlfn,DfsXmlBranchKind &bkind)
  640. {
  641. bool external;
  642. bool foreign;
  643. external = dlfn.isExternal();
  644. foreign = dlfn.isForeign();
  645. if (external||foreign)
  646. return NULL;
  647. IPropertyTree *sroot = queryRoot();
  648. if (!sroot)
  649. return NULL;
  650. StringBuffer tail;
  651. dlfn.getTail(tail);
  652. StringBuffer query;
  653. getAttrQueryStr(query,queryDfsXmlBranchName(DXB_File),"@name",tail.str());
  654. IPropertyTree *froot = sroot->queryPropTree(query.str());
  655. bkind = DXB_File;
  656. if (!froot) {
  657. // check for super file
  658. getAttrQueryStr(query.clear(),queryDfsXmlBranchName(DXB_SuperFile),"@name",tail.str());
  659. froot = sroot->queryPropTree(query.str());
  660. if (froot)
  661. bkind = DXB_SuperFile;
  662. }
  663. return froot;
  664. }
  665. };
  666. class CClustersLockedSection
  667. {
  668. Owned<IRemoteConnection> conn;
  669. public:
  670. CClustersLockedSection(CDfsLogicalFileName &dlfn, bool exclusive)
  671. {
  672. StringBuffer xpath;
  673. dlfn.makeFullnameQuery(xpath,DXB_File,true).append("/ClusterLock");
  674. /* Avoid RTM_CREATE_QUERY connect() if possible by making 1st call without. This is to avoid write contention caused by RTM_CREATE*
  675. * NB: RTM_CREATE_QUERY should probably only gain exclusive access in Dali if node is missing.
  676. */
  677. conn.setown(querySDS().connect(xpath.str(), myProcessSession(), exclusive ? RTM_LOCK_WRITE : RTM_LOCK_READ, SDS_CONNECT_TIMEOUT));
  678. if (!conn.get()) // NB: ClusterLock is now created at File create time, so this can only be true for pre-existing File's
  679. {
  680. conn.setown(querySDS().connect(xpath.str(), myProcessSession(), RTM_CREATE_QUERY | RTM_LOCK_WRITE, SDS_CONNECT_TIMEOUT));
  681. assertex(conn.get());
  682. if (!exclusive)
  683. conn->changeMode(RTM_LOCK_READ, SDS_CONNECT_TIMEOUT);
  684. }
  685. }
  686. };
  687. static void checkDfsReplyException(MemoryBuffer &mb)
  688. {
  689. if (mb.length()<=sizeof(int))
  690. return;
  691. if ((*(int *)mb.bufferBase()) == -1) { // exception indicator
  692. int i;
  693. mb.read(i);
  694. throw deserializeException(mb);
  695. }
  696. }
  697. static void foreignDaliSendRecv(const INode *foreigndali,CMessageBuffer &mb, unsigned foreigndalitimeout)
  698. {
  699. SocketEndpoint ep = foreigndali->endpoint();
  700. if (ep.port==0)
  701. ep.port = DALI_SERVER_PORT;
  702. Owned<IGroup> grp = createIGroup(1,&ep);
  703. Owned<ICommunicator> comm = createCommunicator(grp,true);
  704. if (!comm->verifyConnection(0,foreigndalitimeout)) {
  705. StringBuffer tmp;
  706. IDFS_Exception *e = new CDFS_Exception(DFSERR_ForeignDaliTimeout, foreigndali->endpoint().getUrlStr(tmp).str());
  707. throw e;
  708. }
  709. comm->sendRecv(mb,0,MPTAG_DFS_REQUEST);
  710. }
  711. static bool isLocalDali(const INode *foreigndali)
  712. {
  713. if (!foreigndali)
  714. return true;
  715. Owned<INode> node;
  716. SocketEndpoint ep = foreigndali->endpoint();
  717. if (ep.port==0) {
  718. ep.port = DALI_SERVER_PORT;
  719. node.setown(createINode(ep));
  720. foreigndali = node.get();
  721. }
  722. return queryCoven().inCoven((INode *)foreigndali);
  723. }
  724. class FileClusterInfoArray: public IArrayOf<IClusterInfo>
  725. {
  726. ClusterPartDiskMapSpec defaultmapping;
  727. bool singleclusteroverride;
  728. public:
  729. FileClusterInfoArray()
  730. {
  731. singleclusteroverride = false;
  732. }
  733. void clear()
  734. {
  735. IArrayOf<IClusterInfo>::kill();
  736. }
  737. unsigned getNames(StringArray &clusternames)
  738. {
  739. StringBuffer name;
  740. ForEachItem(i) {
  741. clusternames.append(item(i).getClusterLabel(name.clear()).str());
  742. if (singleclusteroverride)
  743. break;
  744. }
  745. return clusternames.ordinality();
  746. }
  747. unsigned find(const char *_clusterName)
  748. {
  749. StringAttr clusterName = _clusterName;
  750. clusterName.toLowerCase();
  751. StringBuffer name;
  752. ForEachItem(i) {
  753. if (strcmp(item(i).getClusterLabel(name.clear()).str(),clusterName)==0)
  754. return i;
  755. if (singleclusteroverride)
  756. break;
  757. }
  758. return NotFound;
  759. }
  760. IGroup *queryGroup(unsigned clusternum)
  761. {
  762. if (clusternum>=ordinality())
  763. return NULL;
  764. if (singleclusteroverride&&clusternum)
  765. return NULL;
  766. return item(clusternum).queryGroup();
  767. }
  768. IGroup *getGroup(unsigned clusternum)
  769. {
  770. IGroup *ret = queryGroup(clusternum);
  771. return LINK(ret);
  772. }
  773. unsigned copyNum(unsigned part,unsigned copy,unsigned maxparts, unsigned *replicate)
  774. {
  775. ForEachItem(i) {
  776. IGroup *g = queryGroup(i);
  777. unsigned cw = g?g->ordinality():1;
  778. unsigned mc = item(i).queryPartDiskMapping().numCopies(part,cw,maxparts);
  779. if (copy<mc) {
  780. if (replicate)
  781. *replicate = copy;
  782. return i;
  783. }
  784. copy -= mc;
  785. if (singleclusteroverride)
  786. break;
  787. }
  788. return NotFound;
  789. }
  790. ClusterPartDiskMapSpec &queryPartDiskMapping(unsigned clusternum)
  791. {
  792. if (clusternum>=ordinality()||(singleclusteroverride&&clusternum))
  793. return defaultmapping;
  794. return item(clusternum).queryPartDiskMapping();
  795. }
  796. void updatePartDiskMapping(unsigned clusternum,const ClusterPartDiskMapSpec &spec)
  797. {
  798. if (clusternum<ordinality())
  799. item(clusternum).queryPartDiskMapping() = spec;
  800. }
  801. StringBuffer &getName(unsigned clusternum,StringBuffer &name)
  802. {
  803. if (clusternum<ordinality())
  804. item(clusternum).getClusterLabel(name);
  805. return name;
  806. }
  807. void setPreferred(const char *clusters,CDfsLogicalFileName &lfname)
  808. {
  809. unsigned nc = ordinality();
  810. if (nc<=1)
  811. return;
  812. StringBuffer cname;
  813. StringArray clustlist;
  814. if (lfname.getCluster(cname).length())
  815. clustlist.append(cname.str());
  816. unsigned i;
  817. if (clusters) {
  818. for (;;) {
  819. const char *s = clusters;
  820. while (*s&&(*s!=','))
  821. s++;
  822. if (s!=clusters) {
  823. cname.clear().append(s-clusters,clusters);
  824. for (i=0;i<clustlist.ordinality();i++)
  825. if (strcmp(clustlist.item(i),cname.str())==0)
  826. break;
  827. if (i==clustlist.ordinality())
  828. clustlist.append(cname.str());
  829. }
  830. if (!*s)
  831. break;
  832. clusters = s+1;
  833. }
  834. }
  835. if (clustlist.ordinality()==0) {
  836. // sort by closest to this node
  837. const IpAddress &myip = queryMyNode()->endpoint();
  838. unsigned *d=new unsigned[nc];
  839. for (i=0;i<nc;i++)
  840. d[i] = ipGroupDistance(myip,item(i).queryGroup());
  841. // bubble sort it - only a few
  842. for (i=0;i+1<nc;i++)
  843. for (unsigned j=0;j+i+1<nc;j++)
  844. if (d[j+1]<d[j]) {
  845. unsigned bd = d[j+1];
  846. d[j+1] = d[j];
  847. d[j] = bd;
  848. swap(j,j+1);
  849. }
  850. delete [] d;
  851. return;
  852. }
  853. Owned<IGroup> firstgrp;
  854. unsigned done = 0;
  855. StringBuffer name;
  856. StringBuffer name2;
  857. ForEachItemIn(ci,clustlist) {
  858. const char *cls = clustlist.item(ci);
  859. Owned<IGroup> grp = queryNamedGroupStore().lookup(cls);
  860. if (!grp) {
  861. IERRLOG("IDistributedFile::setPreferred - cannot find cluster %s",cls);
  862. return;
  863. }
  864. if (!firstgrp.get())
  865. firstgrp.set(grp);
  866. for (i=done;i<nc;i++) {
  867. IClusterInfo &info=item(i);
  868. if (stricmp(info.getClusterLabel(name2.clear()).str(),name.str())==0)
  869. break;
  870. IGroup *grp2 = info.queryGroup();
  871. if (grp2&&(grp->compare(grp2)!=GRdisjoint))
  872. break;
  873. }
  874. if (i<nc) {
  875. if (i) {
  876. Linked<IClusterInfo> tmp = &item(i);
  877. remove(i);
  878. add(*tmp.getClear(),done);
  879. }
  880. done++;
  881. if (done+1>=nc)
  882. break;
  883. }
  884. }
  885. if (done+1<nc) { // sort remaining by nearest to first group
  886. unsigned *d=new unsigned[nc]; // only use done to nc
  887. for (i=done;i<nc;i++)
  888. d[i] = groupDistance(firstgrp,item(i).queryGroup());
  889. // bubble sort it - only a few
  890. for (i=done;i+1<nc;i++)
  891. for (unsigned j=done;j+i+1<nc;j++)
  892. if (d[j+1]<d[j]) {
  893. unsigned bd = d[j+1];
  894. d[j+1] = d[j];
  895. d[j] = bd;
  896. swap(j,j+1);
  897. }
  898. delete [] d;
  899. }
  900. }
  901. void setSingleClusterOnly(bool set=true)
  902. {
  903. singleclusteroverride = set;
  904. }
  905. unsigned numCopies(unsigned part,unsigned maxparts)
  906. {
  907. unsigned ret = 0;
  908. ForEachItem(i) {
  909. IGroup *g = queryGroup(i);
  910. unsigned cw = g?g->ordinality():1;
  911. ret += item(i).queryPartDiskMapping().numCopies(part,cw,maxparts);
  912. if (singleclusteroverride)
  913. break;
  914. }
  915. return ret;
  916. }
  917. };
  918. // Internal extension of transaction interface, used to manipulate and track transaction
  919. interface IDistributedFileTransactionExt : extends IDistributedFileTransaction
  920. {
  921. virtual IUserDescriptor *queryUser()=0;
  922. virtual void descend()=0; // descend into a recursive call (can't autoCommit if depth is not zero)
  923. virtual void ascend()=0; // ascend back from the deep, one step at a time
  924. virtual void autoCommit()=0; // if transaction not active, commit straight away
  925. virtual void addAction(CDFAction *action)=0;
  926. virtual void addFile(IDistributedFile *file)=0;
  927. virtual void ensureFile(IDistributedFile *file)=0;
  928. virtual void clearFile(IDistributedFile *file)=0;
  929. virtual void clearFiles()=0;
  930. virtual void noteAddSubFile(IDistributedSuperFile *super, const char *superName, IDistributedFile *sub) = 0;
  931. virtual void noteRemoveSubFile(IDistributedSuperFile *super, IDistributedFile *sub) = 0;
  932. virtual void noteSuperSwap(IDistributedSuperFile *super1, IDistributedSuperFile *super2) = 0;
  933. virtual void clearSubFiles(IDistributedSuperFile *super) = 0;
  934. virtual void noteRename(IDistributedFile *file, const char *newName) = 0;
  935. virtual void validateAddSubFile(IDistributedSuperFile *super, IDistributedFile *sub, const char *subName) = 0;
  936. virtual bool isSubFile(IDistributedSuperFile *super, const char *subFile, bool sub) = 0;
  937. virtual bool addDelayedDelete(CDfsLogicalFileName &lfn,unsigned timeoutms=INFINITE)=0; // used internally to delay deletes until commit
  938. virtual bool prepareActions()=0;
  939. virtual void retryActions()=0;
  940. virtual void runActions()=0;
  941. virtual void commitAndClearup()=0;
  942. virtual ICodeContext *queryCodeContext()=0;
  943. };
  944. class CDistributedFileDirectory: implements IDistributedFileDirectory, public CInterface
  945. {
  946. Owned<IUserDescriptor> defaultudesc;
  947. Owned<IDFSredirection> redirection;
  948. void resolveForeignFiles(IPropertyTree *tree,const INode *foreigndali);
  949. protected: friend class CDistributedFile;
  950. StringAttr defprefclusters;
  951. unsigned defaultTimeout;
  952. public:
  953. IMPLEMENT_IINTERFACE;
  954. CDistributedFileDirectory()
  955. {
  956. defaultTimeout = INFINITE;
  957. defaultudesc.setown(createUserDescriptor());
  958. redirection.setown(createDFSredirection());
  959. }
  960. unsigned queryDefaultTimeout() const { return defaultTimeout; }
  961. IDistributedFile *dolookup(CDfsLogicalFileName &logicalname, IUserDescriptor *user, bool writeattr, bool hold, bool lockSuperOwner, IDistributedFileTransaction *transaction, unsigned timeout);
  962. IDistributedFile *lookup(const char *_logicalname, IUserDescriptor *user, bool writeattr, bool hold, bool lockSuperOwner, IDistributedFileTransaction *transaction, unsigned timeout);
  963. IDistributedFile *lookup(CDfsLogicalFileName &logicalname, IUserDescriptor *user, bool writeattr, bool hold, bool lockSuperOwner, IDistributedFileTransaction *transaction, unsigned timeout);
  964. /* createNew always creates an unnamed unattached distributed file
  965. * The caller must associated it with a name and credentials when it is attached (attach())
  966. */
  967. IDistributedFile *createNew(IFileDescriptor * fdesc);
  968. IDistributedFile *createExternal(IFileDescriptor *desc, const char *name);
  969. IDistributedSuperFile *createSuperFile(const char *logicalname,IUserDescriptor *user,bool interleaved,bool ifdoesnotexist,IDistributedFileTransaction *transaction=NULL);
  970. IDistributedSuperFile *createNewSuperFile(IPropertyTree *tree, const char *optionalName=nullptr);
  971. void removeSuperFile(const char *_logicalname, bool delSubs, IUserDescriptor *user, IDistributedFileTransaction *transaction);
  972. IDistributedFileIterator *getIterator(const char *wildname, bool includesuper,IUserDescriptor *user);
  973. IDFAttributesIterator *getDFAttributesIterator(const char *wildname, IUserDescriptor *user, bool recursive, bool includesuper,INode *foreigndali,unsigned foreigndalitimeout);
  974. IPropertyTreeIterator *getDFAttributesTreeIterator(const char *filters, DFUQResultField* localFilters, const char *localFilterBuf,
  975. IUserDescriptor *user, bool recursive, bool& allMatchingFilesReceived, INode *foreigndali,unsigned foreigndalitimeout);
  976. IDFAttributesIterator *getForeignDFAttributesIterator(const char *wildname, IUserDescriptor *user, bool recursive=true, bool includesuper=false, const char *foreigndali="", unsigned foreigndalitimeout=FOREIGN_DALI_TIMEOUT)
  977. {
  978. Owned<INode> foreign;
  979. if (foreigndali&&*foreigndali) {
  980. SocketEndpoint ep(foreigndali);
  981. foreign.setown(createINode(ep));
  982. }
  983. return getDFAttributesIterator(wildname, user, recursive, includesuper,foreign,foreigndalitimeout);
  984. }
  985. IDFScopeIterator *getScopeIterator(IUserDescriptor *user, const char *subscope,bool recursive,bool includeempty);
  986. bool loadScopeContents(const char *scopelfn,StringArray *scopes, StringArray *supers,StringArray *files, bool includeemptyscopes);
  987. IPropertyTree *getFileTree(const char *lname,IUserDescriptor *user,const INode *foreigndali,unsigned foreigndalitimeout,bool expandnodes=false, bool appendForeign=true);
  988. void setFileAccessed(CDfsLogicalFileName &dlfn, IUserDescriptor *user,const CDateTime &dt,const INode *foreigndali=NULL,unsigned foreigndalitimeout=FOREIGN_DALI_TIMEOUT);
  989. IFileDescriptor *getFileDescriptor(const char *lname,IUserDescriptor *user,const INode *foreigndali=NULL,unsigned foreigndalitimeout=FOREIGN_DALI_TIMEOUT);
  990. IDistributedFile *getFile(const char *lname,IUserDescriptor *user,const INode *foreigndali=NULL,unsigned foreigndalitimeout=FOREIGN_DALI_TIMEOUT);
  991. bool exists(const char *_logicalname,IUserDescriptor *user,bool notsuper=false,bool superonly=false);
  992. bool existsPhysical(const char *_logicalname,IUserDescriptor *user);
  993. void addEntry(CDfsLogicalFileName &lfn,IPropertyTree *root,bool superfile, bool ignoreexists);
  994. bool removeEntry(const char *name, IUserDescriptor *user, IDistributedFileTransaction *transaction=NULL, unsigned timeoutms=INFINITE, bool throwException=false);
  995. void renamePhysical(const char *oldname,const char *newname,IUserDescriptor *user,IDistributedFileTransaction *transaction);
  996. void removeEmptyScope(const char *name);
  997. IDistributedSuperFile *lookupSuperFile(const char *logicalname,IUserDescriptor *user,IDistributedFileTransaction *transaction,unsigned timeout=INFINITE);
  998. SecAccessFlags getFilePermissions(const char *lname,IUserDescriptor *user,unsigned auditflags);
  999. SecAccessFlags getNodePermissions(const IpAddress &ip,IUserDescriptor *user,unsigned auditflags);
  1000. SecAccessFlags getFDescPermissions(IFileDescriptor *,IUserDescriptor *user,unsigned auditflags=0);
  1001. void setDefaultUser(IUserDescriptor *user);
  1002. IUserDescriptor* queryDefaultUser();
  1003. DistributedFileCompareResult fileCompare(const char *lfn1,const char *lfn2,DistributedFileCompareMode mode,StringBuffer &errstr,IUserDescriptor *user);
  1004. bool filePhysicalVerify(const char *lfn1,IUserDescriptor *user,bool includecrc,StringBuffer &errstr);
  1005. void setDefaultPreferredClusters(const char *clusters);
  1006. void fixDates(IDistributedFile *fil);
  1007. GetFileClusterNamesType getFileClusterNames(const char *logicalname,StringArray &out); // returns 0 for normal file, 1 for
  1008. bool isSuperFile( const char *logicalname, IUserDescriptor *user=NULL, INode *foreigndali=NULL, unsigned timeout=0);
  1009. void promoteSuperFiles(unsigned numsf,const char **sfnames,const char *addsubnames,bool delsub,bool createonlyonesuperfile,IUserDescriptor *user, unsigned timeout, StringArray &outunlinked);
  1010. ISimpleSuperFileEnquiry * getSimpleSuperFileEnquiry(const char *logicalname,const char *title,IUserDescriptor *udesc,unsigned timeout);
  1011. bool getFileSuperOwners(const char *logicalname, StringArray &owners);
  1012. IDFSredirection & queryRedirection() { return *redirection; }
  1013. static StringBuffer &getFileRelationshipXPath(StringBuffer &xpath, const char *primary, const char *secondary,const char *primflds,const char *secflds,
  1014. const char *kind, const char *cardinality, const bool *payload
  1015. );
  1016. void doRemoveFileRelationship( IRemoteConnection *conn, const char *primary,const char *secondary,const char *primflds,const char *secflds, const char *kind);
  1017. void removeFileRelationships(const char *primary,const char *secondary, const char *primflds, const char *secflds, const char *kind);
  1018. void addFileRelationship(const char *kind,const char *primary,const char *secondary,const char *primflds, const char *secflds,const char *cardinality,bool payload,IUserDescriptor *user,const char *description);
  1019. IFileRelationshipIterator *lookupFileRelationships(const char *primary,const char *secondary,const char *primflds,const char *secflds,
  1020. const char *kind,const char *cardinality,const bool *payload,
  1021. const char *foreigndali,unsigned foreigndalitimeout);
  1022. void removeAllFileRelationships(const char *filename);
  1023. IFileRelationshipIterator *lookupAllFileRelationships(const char *filenames);
  1024. void renameFileRelationships(const char *oldname,const char *newname,IFileRelationshipIterator *reliter, IUserDescriptor *user);
  1025. bool publishMetaFileXML(const CDfsLogicalFileName &logicalname,IUserDescriptor *user);
  1026. IFileDescriptor *createDescriptorFromMetaFile(const CDfsLogicalFileName &logicalname,IUserDescriptor *user);
  1027. bool isProtectedFile(const CDfsLogicalFileName &logicalname, unsigned timeout) ;
  1028. unsigned queryProtectedCount(const CDfsLogicalFileName &logicalname, const char *owner);
  1029. bool getProtectedInfo(const CDfsLogicalFileName &logicalname, StringArray &names, UnsignedArray &counts);
  1030. IDFProtectedIterator *lookupProtectedFiles(const char *owner=NULL,bool notsuper=false,bool superonly=false);
  1031. IDFAttributesIterator* getLogicalFilesSorted(IUserDescriptor* udesc, DFUQResultField *sortOrder, const void *filterBuf, DFUQResultField *specialFilters,
  1032. const void *specialFilterBuf, unsigned startOffset, unsigned maxNum, __int64 *cacheHint, unsigned *total, bool *allMatchingFilesReceived);
  1033. IDFAttributesIterator* getLogicalFiles(IUserDescriptor* udesc, DFUQResultField *sortOrder, const void *filterBuf, DFUQResultField *specialFilters,
  1034. const void *specialFilterBuf, unsigned startOffset, unsigned maxNum, __int64 *cacheHint, unsigned *total, bool *allMatchingFilesReceived, bool recursive, bool sorted);
  1035. void setFileProtect(CDfsLogicalFileName &dlfn,IUserDescriptor *user, const char *owner, bool set, const INode *foreigndali=NULL,unsigned foreigndalitimeout=FOREIGN_DALI_TIMEOUT);
  1036. unsigned setDefaultTimeout(unsigned timems)
  1037. {
  1038. unsigned ret = defaultTimeout;
  1039. defaultTimeout = timems;
  1040. return ret;
  1041. }
  1042. virtual bool removePhysicalPartFiles(const char *logicalName, IFileDescriptor *fileDesc, IMultiException *mexcept, unsigned numParallelDeletes=0) override;
  1043. };
  1044. // === Transactions
  1045. class CDFAction: public CInterface
  1046. {
  1047. unsigned locked;
  1048. protected:
  1049. IDistributedFileTransactionExt *transaction;
  1050. IArrayOf<IDistributedFile> lockedFiles;
  1051. DFTransactionState state;
  1052. void addFileLock(IDistributedFile *file)
  1053. {
  1054. // derived's prepare must call this before locking
  1055. lockedFiles.append(*LINK(file));
  1056. }
  1057. bool lock()
  1058. {
  1059. // Files most have been acquired already by derived's class prepare
  1060. ForEachItemIn(i,lockedFiles)
  1061. {
  1062. try
  1063. {
  1064. lockedFiles.item(i).lockProperties(0);
  1065. }
  1066. catch (ISDSException *e)
  1067. {
  1068. if (SDSExcpt_LockTimeout != e->errorCode())
  1069. throw;
  1070. e->Release();
  1071. PROGLOG("CDFAction lock timed out on %s",lockedFiles.item(i).queryLogicalName());
  1072. return false;
  1073. }
  1074. locked++;
  1075. }
  1076. return true;
  1077. }
  1078. void unlock()
  1079. {
  1080. for(unsigned i=0; i<locked; i++)
  1081. lockedFiles.item(i).unlockProperties(state);
  1082. locked = 0;
  1083. lockedFiles.kill();
  1084. }
  1085. public:
  1086. CDFAction() : locked(0), state(TAS_NONE)
  1087. {
  1088. transaction = NULL;
  1089. }
  1090. // Clear all locked files (when re-using transaction on auto-commit mode)
  1091. virtual ~CDFAction()
  1092. {
  1093. if (transaction)
  1094. unlock();
  1095. }
  1096. void setTransaction(IDistributedFileTransactionExt *_transaction)
  1097. {
  1098. assertex(_transaction);
  1099. assertex(!transaction);
  1100. transaction = _transaction;
  1101. }
  1102. virtual bool prepare()=0; // should call lock
  1103. virtual void run()=0; // must override this
  1104. // If some lock fails, call this
  1105. virtual void retry()
  1106. {
  1107. state = TAS_RETRY;
  1108. unlock();
  1109. }
  1110. // MORE: In the rare event of a commit failure, not all actions can be rolled back.
  1111. // Since all actions today occur during "run", and since commit phases does very little,
  1112. // this chance is minimal and will probably be caused by corrupted file descriptors.
  1113. // The problem is that the state of the sub removals and the order in which they occur might not
  1114. // be trivial on such a low level error, and there's no way to atomically do operations in SDS
  1115. // at present time. We need more thought about this.
  1116. virtual void commit()
  1117. {
  1118. state = TAS_SUCCESS;
  1119. unlock();
  1120. }
  1121. virtual void rollback()
  1122. {
  1123. state = TAS_FAILURE;
  1124. unlock();
  1125. }
  1126. };
  1127. static void setUserDescriptor(Linked<IUserDescriptor> &udesc,IUserDescriptor *user)
  1128. {
  1129. if (!user)
  1130. {
  1131. #ifdef NULL_DALIUSER_STACKTRACE
  1132. StringBuffer sb;
  1133. if (user)
  1134. user->getUserName(sb);
  1135. if (sb.length()==0)
  1136. {
  1137. IERRLOG("UNEXPECTED USER (NULL) in dadfs.cpp setUserDescriptor() %d",__LINE__);
  1138. //following debug code to be removed
  1139. PrintStackReport();
  1140. }
  1141. #endif
  1142. user = queryDistributedFileDirectory().queryDefaultUser();
  1143. }
  1144. udesc.set(user);
  1145. }
  1146. static bool scopePermissionsAvail = true;
  1147. static SecAccessFlags getScopePermissions(const char *scopename,IUserDescriptor *user,unsigned auditflags)
  1148. { // scope must be normalized already
  1149. SecAccessFlags perms = SecAccess_Full;
  1150. if (scopePermissionsAvail && scopename && *scopename) {
  1151. if (!user)
  1152. {
  1153. #ifdef NULL_DALIUSER_STACKTRACE
  1154. IERRLOG("UNEXPECTED USER (NULL) in dadfs.cpp getScopePermissions() line %d",__LINE__);
  1155. //following debug code to be removed
  1156. PrintStackReport();
  1157. #endif
  1158. user = queryDistributedFileDirectory().queryDefaultUser();
  1159. }
  1160. //Create signature
  1161. CDateTime now;
  1162. StringBuffer b64sig;
  1163. createDaliSignature(scopename, user, now, b64sig);
  1164. perms = querySessionManager().getPermissionsLDAP(queryDfsXmlBranchName(DXB_Scope),scopename,user,auditflags, b64sig.str(), now);
  1165. if (perms<0) {
  1166. if (perms == SecAccess_Unavailable) {
  1167. scopePermissionsAvail=false;
  1168. perms = SecAccess_Full;
  1169. }
  1170. else
  1171. perms = SecAccess_None;
  1172. }
  1173. }
  1174. return perms;
  1175. }
  1176. static void checkLogicalScope(const char *scopename,IUserDescriptor *user,bool readreq,bool createreq)
  1177. {
  1178. // scope must be normalized already
  1179. if (!readreq&&!createreq)
  1180. return;
  1181. unsigned auditflags = 0;
  1182. if (readreq)
  1183. auditflags |= (DALI_LDAP_AUDIT_REPORT|DALI_LDAP_READ_WANTED);
  1184. if (createreq)
  1185. auditflags |= (DALI_LDAP_AUDIT_REPORT|DALI_LDAP_WRITE_WANTED);
  1186. #ifdef NULL_DALIUSER_STACKTRACE
  1187. if (!user)
  1188. {
  1189. IERRLOG("UNEXPECTED USER (NULL) in dadfs.cpp checkLogicalScope() line %d",__LINE__);
  1190. PrintStackReport();
  1191. }
  1192. #endif
  1193. SecAccessFlags perm = getScopePermissions(scopename,user,auditflags);
  1194. IDFS_Exception *e = NULL;
  1195. if (readreq&&!HASREADPERMISSION(perm))
  1196. e = new CDFS_Exception(DFSERR_LookupAccessDenied,scopename);
  1197. else if (createreq&&!HASWRITEPERMISSION(perm))
  1198. e = new CDFS_Exception(DFSERR_CreateAccessDenied,scopename);
  1199. if (e)
  1200. throw e;
  1201. }
  1202. bool checkLogicalName(CDfsLogicalFileName &dlfn,IUserDescriptor *user,bool readreq,bool createreq,bool allowquery,const char *specialnotallowedmsg)
  1203. {
  1204. bool ret = true;
  1205. if (dlfn.isMulti()) { //is temporary superFile?
  1206. if (specialnotallowedmsg)
  1207. throw MakeStringException(-1,"cannot %s a multi file name (%s)",specialnotallowedmsg,dlfn.get());
  1208. if (!dlfn.isExpanded())
  1209. dlfn.expand(user);//expand wildcards
  1210. unsigned i = dlfn.multiOrdinality();
  1211. while (--i)//continue looping even when ret is false, in order to check for illegal elements (foreigns/externals), and to check each scope permission
  1212. ret = checkLogicalName((CDfsLogicalFileName &)dlfn.multiItem(i),user,readreq,createreq,allowquery,specialnotallowedmsg)&&ret;
  1213. }
  1214. else {
  1215. if (specialnotallowedmsg) {
  1216. if (dlfn.isExternal()) {
  1217. if (dlfn.isQuery()&&allowquery)
  1218. ret = false;
  1219. else
  1220. throw MakeStringException(-1,"cannot %s an external file name (%s)",specialnotallowedmsg,dlfn.get());
  1221. }
  1222. if (dlfn.isForeign()) {
  1223. throw MakeStringException(-1,"cannot %s a foreign file name (%s)",specialnotallowedmsg,dlfn.get());
  1224. }
  1225. }
  1226. StringBuffer scopes;
  1227. dlfn.getScopes(scopes);
  1228. checkLogicalScope(scopes.str(),user,readreq,createreq);
  1229. }
  1230. return ret;
  1231. }
  1232. bool checkLogicalName(const char *lfn,IUserDescriptor *user,bool readreq,bool createreq,bool allowquery,const char *specialnotallowedmsg)
  1233. {
  1234. CDfsLogicalFileName dlfn;
  1235. dlfn.set(lfn);
  1236. return checkLogicalName(dlfn, user, readreq, createreq, allowquery, specialnotallowedmsg);
  1237. }
  1238. /*
  1239. * This class removes all files marked for deletion during transactions.
  1240. *
  1241. * TODO: the doDelete method re-acquires the lock to remove the files, and
  1242. * that creates a window (between end of commit and deletion) where other
  1243. * processes can acquire locks and blow things up. To fix this, you'd have
  1244. * to be selective on what files you unlock during commit, so that you
  1245. * can still keep an unified cache AND release the deletions later on.
  1246. */
  1247. class CDelayedDelete: public CInterface
  1248. {
  1249. CDfsLogicalFileName lfn;
  1250. Linked<IUserDescriptor> user;
  1251. unsigned timeoutms;
  1252. public:
  1253. CDelayedDelete(CDfsLogicalFileName &_lfn,IUserDescriptor *_user,unsigned _timeoutms)
  1254. : user(_user), timeoutms(_timeoutms)
  1255. {
  1256. lfn.set(_lfn);
  1257. }
  1258. void doDelete() // Throw on error!
  1259. {
  1260. const char *logicalname = lfn.get();
  1261. if (!lfn.isExternal() && !checkLogicalName(lfn,user,true,true,true,"remove"))
  1262. ThrowStringException(-1, "Logical Name fails for removal on %s", lfn.get());
  1263. for (;;)
  1264. {
  1265. // Transaction files have already been unlocked at this point, delete all remaining files
  1266. Owned<IDistributedFile> file = queryDistributedFileDirectory().lookup(lfn, user, true, false, true, NULL, SDS_SUB_LOCK_TIMEOUT);
  1267. if (!file.get())
  1268. return;
  1269. StringBuffer reason;
  1270. if (!file->canRemove(reason, false))
  1271. ThrowStringException(-1, "Can't remove %s: %s", lfn.get(), reason.str());
  1272. // This will do the right thing for either super-files and logical-files.
  1273. try
  1274. {
  1275. file->detach(0, NULL); // 0 == timeout immediately if cannot get exclusive lock
  1276. return;
  1277. }
  1278. catch (ISDSException *e)
  1279. {
  1280. switch (e->errorCode())
  1281. {
  1282. case SDSExcpt_LockTimeout:
  1283. case SDSExcpt_LockHeld:
  1284. e->Release();
  1285. break;
  1286. default:
  1287. throw;
  1288. }
  1289. }
  1290. file.clear();
  1291. PROGLOG("CDelayedDelete: pausing due to locked file = %s", logicalname);
  1292. Sleep(SDS_TRANSACTION_RETRY/2+(getRandom()%SDS_TRANSACTION_RETRY));
  1293. }
  1294. }
  1295. };
  1296. class CDistributedFileTransaction: implements IDistributedFileTransactionExt, public CInterface
  1297. {
  1298. class CTransactionFile : public CSimpleInterface
  1299. {
  1300. class HTMapping : public CInterface
  1301. {
  1302. IDistributedFile *file;
  1303. StringAttr name;
  1304. public:
  1305. HTMapping(const char *_name, IDistributedFile *_file) : name(_name), file(_file) { }
  1306. IDistributedFile &query() { return *file; }
  1307. const char *queryFindString() const { return name; }
  1308. const void *queryFindParam() const { return &file; }
  1309. };
  1310. class CSubFileIter : protected SuperHashIteratorOf<HTMapping>, implements IDistributedFileIterator
  1311. {
  1312. typedef SuperHashIteratorOf<HTMapping> PARENT;
  1313. public:
  1314. IMPLEMENT_IINTERFACE_USING(PARENT);
  1315. CSubFileIter(OwningStringSuperHashTableOf<HTMapping> &table) : PARENT(table)
  1316. {
  1317. }
  1318. // IDistributedFileIterator impl.
  1319. virtual IDistributedFile &query()
  1320. {
  1321. HTMapping &map = PARENT::query();
  1322. return map.query();
  1323. }
  1324. virtual bool first() { return PARENT::first(); }
  1325. virtual bool isValid() { return PARENT::isValid(); }
  1326. virtual bool next() { return PARENT::next(); }
  1327. virtual StringBuffer &getName(StringBuffer &name)
  1328. {
  1329. HTMapping &map = PARENT::query();
  1330. return name.append(map.queryFindString());
  1331. }
  1332. };
  1333. CDistributedFileTransaction &owner;
  1334. OwningStringSuperHashTableOf<HTMapping> subFilesByName;
  1335. StringAttr name;
  1336. Linked<IDistributedFile> file;
  1337. public:
  1338. CTransactionFile(CDistributedFileTransaction &_owner, const char *_name, IDistributedFile *_file) : owner(_owner), name(_name), file(_file)
  1339. {
  1340. }
  1341. const char *queryName() const { return name; }
  1342. IDistributedFile *queryFile() { return file; }
  1343. IDistributedFileIterator *getSubFiles()
  1344. {
  1345. IDistributedSuperFile *super = file->querySuperFile();
  1346. if (!super)
  1347. return NULL;
  1348. return new CSubFileIter(subFilesByName);
  1349. }
  1350. void clearSubs()
  1351. {
  1352. subFilesByName.kill();
  1353. }
  1354. unsigned numSubFiles() const { return subFilesByName.count(); }
  1355. void noteAddSubFile(IDistributedFile *sub)
  1356. {
  1357. if (NULL == subFilesByName.find(sub->queryLogicalName()))
  1358. {
  1359. Owned<HTMapping> map = new HTMapping(sub->queryLogicalName(), sub);
  1360. subFilesByName.replace(*map.getLink());
  1361. }
  1362. }
  1363. void noteRemoveSubFile(IDistributedFile *sub)
  1364. {
  1365. HTMapping *map = subFilesByName.find(sub->queryLogicalName());
  1366. if (map)
  1367. verifyex(subFilesByName.removeExact(map));
  1368. }
  1369. bool find(const char *subFile, bool sub)
  1370. {
  1371. StringBuffer tmp;
  1372. subFile = normalizeLFN(subFile, tmp);
  1373. HTMapping *match = subFilesByName.find(subFile);
  1374. if (match)
  1375. return true;
  1376. else if (sub)
  1377. {
  1378. SuperHashIteratorOf<HTMapping> iter(subFilesByName);
  1379. ForEach(iter)
  1380. {
  1381. HTMapping &map = iter.query();
  1382. IDistributedFile &file = map.query();
  1383. IDistributedSuperFile *super = file.querySuperFile();
  1384. if (super)
  1385. {
  1386. if (owner.isSubFile(super, subFile, sub))
  1387. return true;
  1388. }
  1389. }
  1390. }
  1391. return false;
  1392. }
  1393. const void *queryFindParam() const { return &file; }
  1394. const char *queryFindString() const { return name; }
  1395. };
  1396. CIArrayOf<CDFAction> actions;
  1397. OwningSimpleHashTableOf<CTransactionFile, IDistributedFile *> trackedFiles;
  1398. OwningStringSuperHashTableOf<CTransactionFile> trackedFilesByName;
  1399. bool isactive;
  1400. Linked<IUserDescriptor> udesc;
  1401. CIArrayOf<CDelayedDelete> delayeddelete;
  1402. // auto-commit only works at depth zero (for recursive calls)
  1403. // MORE: Maybe this needs a context object (descend on c-tor, ascend on d-tor)
  1404. // But we need all actions within transactions first to find out if there is
  1405. // any exception to the rule used by addSubFile / removeSubFile
  1406. unsigned depth;
  1407. unsigned prepared;
  1408. ICodeContext *codeCtx;
  1409. /* 'owner' is set if, transaction object is implicitly created, because none provided
  1410. * The owner cannot be release or unlocked. The transaction can still retry if other files are locked,
  1411. * so need to ensure 'owner' remains in tracked file cache.
  1412. */
  1413. IDistributedSuperFile *owner;
  1414. CTransactionFile *queryCreate(const char *name, IDistributedFile *file, bool recreate=false)
  1415. {
  1416. Owned<CTransactionFile> trackedFile;
  1417. if (!recreate)
  1418. trackedFile.set(trackedFiles.find(file));
  1419. if (!trackedFile)
  1420. {
  1421. StringBuffer tmp;
  1422. name = normalizeLFN(name, tmp);
  1423. trackedFile.setown(new CTransactionFile(*this, tmp.str(), file));
  1424. trackedFiles.replace(*trackedFile.getLink());
  1425. trackedFilesByName.replace(*trackedFile.getLink());
  1426. }
  1427. return trackedFile;
  1428. }
  1429. CTransactionFile *lookupTrackedFile(IDistributedFile *file)
  1430. {
  1431. return trackedFiles.find(file);
  1432. }
  1433. void commitActions()
  1434. {
  1435. while (actions.ordinality()) // if we get here everything should work!
  1436. {
  1437. Owned<CDFAction> action = &actions.popGet();
  1438. action->commit();
  1439. }
  1440. }
  1441. IDistributedFile *findFile(const char *name)
  1442. {
  1443. StringBuffer tmp;
  1444. name = normalizeLFN(name, tmp);
  1445. CTransactionFile *trackedFile = trackedFilesByName.find(tmp.str());
  1446. if (!trackedFile)
  1447. return NULL;
  1448. return trackedFile->queryFile();
  1449. }
  1450. void deleteFiles() // no rollback at this point
  1451. {
  1452. Owned<IMultiException> me = MakeMultiException("Transaction");
  1453. ForEachItemIn(i,delayeddelete) {
  1454. try {
  1455. delayeddelete.item(i).doDelete();
  1456. } catch (IException *e) {
  1457. me->append(*e);
  1458. }
  1459. }
  1460. delayeddelete.kill();
  1461. if (me->ordinality())
  1462. throw me.getClear();
  1463. }
  1464. public:
  1465. IMPLEMENT_IINTERFACE;
  1466. CDistributedFileTransaction(IUserDescriptor *user, IDistributedSuperFile *_owner=NULL, ICodeContext *_codeCtx=NULL)
  1467. : isactive(false), depth(0), prepared(0), owner(_owner), codeCtx(_codeCtx)
  1468. {
  1469. setUserDescriptor(udesc,user);
  1470. }
  1471. ~CDistributedFileTransaction()
  1472. {
  1473. // New files should be removed automatically if not committed
  1474. // MORE - refactor cCreateSuperFileAction to avoid this
  1475. if (isactive)
  1476. rollback();
  1477. assert(depth == 0);
  1478. }
  1479. // IDistributedFileTransaction impl.
  1480. virtual void start()
  1481. {
  1482. if (isactive)
  1483. throw MakeStringException(-1,"Transaction already started");
  1484. clearFiles();
  1485. actions.kill();
  1486. isactive = true;
  1487. prepared = 0;
  1488. assertex(actions.ordinality()==0);
  1489. }
  1490. virtual void commit()
  1491. {
  1492. if (!isactive)
  1493. return;
  1494. IException *rete=NULL;
  1495. // =============== PREPARE AND RETRY UNTIL READY
  1496. try
  1497. {
  1498. for (;;)
  1499. {
  1500. if (prepareActions())
  1501. break;
  1502. else
  1503. retryActions();
  1504. PROGLOG("CDistributedFileTransaction: Transaction pausing");
  1505. Sleep(SDS_TRANSACTION_RETRY/2+(getRandom()%SDS_TRANSACTION_RETRY));
  1506. }
  1507. runActions();
  1508. commitAndClearup();
  1509. return;
  1510. }
  1511. catch (IException *e)
  1512. {
  1513. rete = e;
  1514. }
  1515. rollback();
  1516. throw rete;
  1517. }
  1518. virtual void rollback()
  1519. {
  1520. // =============== ROLLBACK AND CLEANUP
  1521. while (actions.ordinality())
  1522. {
  1523. try
  1524. {
  1525. // we don't want to unlock what hasn't been locked
  1526. // if an exception was thrown while locking, but we
  1527. // do want to pop them all
  1528. Owned<CDFAction> action = &actions.popGet();
  1529. if (actions.ordinality()<prepared)
  1530. action->rollback();
  1531. }
  1532. catch (IException *e)
  1533. {
  1534. e->Release();
  1535. }
  1536. }
  1537. actions.kill(); // should be empty
  1538. clearFiles(); // release locks
  1539. if (!isactive)
  1540. return;
  1541. isactive = false;
  1542. // this we only want to do if active
  1543. delayeddelete.kill();
  1544. }
  1545. virtual bool active()
  1546. {
  1547. return isactive;
  1548. }
  1549. virtual IDistributedFile *lookupFile(const char *name,unsigned timeout)
  1550. {
  1551. IDistributedFile *ret = findFile(name);
  1552. if (ret)
  1553. return LINK(ret);
  1554. else
  1555. {
  1556. ret = queryDistributedFileDirectory().lookup(name, udesc, false, false, false, this, timeout);
  1557. if (ret)
  1558. queryCreate(name, ret, true);
  1559. return ret;
  1560. }
  1561. }
  1562. virtual IDistributedSuperFile *lookupSuperFile(const char *name, unsigned timeout)
  1563. {
  1564. IDistributedFile *f = findFile(name);
  1565. if (f)
  1566. return LINK(f->querySuperFile());
  1567. else
  1568. {
  1569. IDistributedSuperFile *ret = queryDistributedFileDirectory().lookupSuperFile(name,udesc,this,timeout);
  1570. if (ret)
  1571. addFile(ret);
  1572. return ret;
  1573. }
  1574. }
  1575. // IDistributedFileTransactionExt impl.
  1576. virtual IUserDescriptor *queryUser()
  1577. {
  1578. return udesc;
  1579. }
  1580. virtual void descend() // Call this when you're recurring
  1581. {
  1582. depth++;
  1583. }
  1584. virtual void ascend() // Call this at the end of the block that started recursion
  1585. {
  1586. assertex(depth);
  1587. depth--;
  1588. }
  1589. virtual void autoCommit()
  1590. {
  1591. // Recursive calls to transaction will not commit until
  1592. // all calls have finished (gone back to zero depth)
  1593. if (!depth && !isactive) {
  1594. try {
  1595. isactive = true;
  1596. commit();
  1597. }
  1598. catch (IException *) {
  1599. rollback();
  1600. throw;
  1601. }
  1602. }
  1603. }
  1604. virtual void addAction(CDFAction *action)
  1605. {
  1606. actions.append(*action); // takes ownership
  1607. action->setTransaction(this);
  1608. }
  1609. virtual void addFile(IDistributedFile *file)
  1610. {
  1611. CTransactionFile *trackedFile = queryCreate(file->queryLogicalName(), file, false);
  1612. // Also add subfiles to cache
  1613. IDistributedSuperFile *sfile = file->querySuperFile();
  1614. if (sfile)
  1615. {
  1616. Owned<IDistributedFileIterator> iter = sfile->getSubFileIterator();
  1617. ForEach(*iter)
  1618. {
  1619. IDistributedFile *f = &iter->query();
  1620. trackedFile->noteAddSubFile(f);
  1621. addFile(f);
  1622. }
  1623. }
  1624. }
  1625. virtual void ensureFile(IDistributedFile *file)
  1626. {
  1627. if (!trackedFiles.find(file))
  1628. addFile(file);
  1629. }
  1630. virtual void clearFile(IDistributedFile *file)
  1631. {
  1632. CTransactionFile *trackedFile = lookupTrackedFile(file);
  1633. IDistributedSuperFile *sfile = file->querySuperFile();
  1634. if (trackedFile)
  1635. {
  1636. Owned<IDistributedFileIterator> iter = trackedFile->getSubFiles();
  1637. if (iter)
  1638. {
  1639. ForEach(*iter)
  1640. clearFile(&iter->query());
  1641. }
  1642. trackedFiles.removeExact(trackedFile);
  1643. trackedFilesByName.removeExact(trackedFile);
  1644. }
  1645. }
  1646. virtual void clearFiles()
  1647. {
  1648. trackedFiles.kill();
  1649. trackedFilesByName.kill();
  1650. if (owner)
  1651. addFile(owner); // ensure remains tracked
  1652. }
  1653. virtual void noteAddSubFile(IDistributedSuperFile *super, const char *superName, IDistributedFile *sub)
  1654. {
  1655. CTransactionFile *trackedSuper = queryCreate(superName, super);
  1656. trackedSuper->noteAddSubFile(sub);
  1657. }
  1658. virtual void noteRemoveSubFile(IDistributedSuperFile *super, IDistributedFile *sub)
  1659. {
  1660. CTransactionFile *trackedSuper = lookupTrackedFile(super);
  1661. if (trackedSuper)
  1662. trackedSuper->noteRemoveSubFile(sub);
  1663. }
  1664. virtual void noteSuperSwap(IDistributedSuperFile *super1, IDistributedSuperFile *super2)
  1665. {
  1666. CTransactionFile *trackedSuper1 = lookupTrackedFile(super1);
  1667. CTransactionFile *trackedSuper2 = lookupTrackedFile(super2);
  1668. assertex(trackedSuper1 && trackedSuper2);
  1669. ICopyArrayOf<IDistributedFile> super1Subs, super2Subs;
  1670. Owned<IDistributedFileIterator> iter = trackedSuper1->getSubFiles();
  1671. ForEach(*iter)
  1672. super1Subs.append(iter->query());
  1673. trackedSuper1->clearSubs();
  1674. iter.setown(trackedSuper2->getSubFiles());
  1675. ForEach(*iter)
  1676. super2Subs.append(iter->query());
  1677. trackedSuper2->clearSubs();
  1678. ForEachItemIn(s, super2Subs)
  1679. trackedSuper1->noteAddSubFile(&super2Subs.item(s));
  1680. ForEachItemIn(s2, super1Subs)
  1681. trackedSuper2->noteAddSubFile(&super1Subs.item(s2));
  1682. }
  1683. virtual void clearSubFiles(IDistributedSuperFile *super)
  1684. {
  1685. CTransactionFile *trackedSuper = lookupTrackedFile(super);
  1686. if (trackedSuper)
  1687. trackedSuper->clearSubs();
  1688. }
  1689. virtual void noteRename(IDistributedFile *file, const char *newName)
  1690. {
  1691. CTransactionFile *trackedFile = lookupTrackedFile(file);
  1692. if (trackedFile)
  1693. {
  1694. trackedFiles.removeExact(trackedFile);
  1695. trackedFilesByName.removeExact(trackedFile);
  1696. trackedFile = queryCreate(newName, file);
  1697. }
  1698. }
  1699. virtual void validateAddSubFile(IDistributedSuperFile *super, IDistributedFile *sub, const char *subName);
  1700. virtual bool isSubFile(IDistributedSuperFile *super, const char *subFile, bool sub)
  1701. {
  1702. CTransactionFile *trackedSuper = lookupTrackedFile(super);
  1703. if (!trackedSuper)
  1704. return false;
  1705. return trackedSuper->find(subFile, sub);
  1706. }
  1707. virtual bool addDelayedDelete(CDfsLogicalFileName &lfn,unsigned timeoutms)
  1708. {
  1709. delayeddelete.append(*new CDelayedDelete(lfn,udesc,timeoutms));
  1710. return true;
  1711. }
  1712. virtual bool prepareActions()
  1713. {
  1714. prepared = 0;
  1715. unsigned toPrepare = actions.ordinality();
  1716. ForEachItemIn(i0,actions)
  1717. {
  1718. if (actions.item(i0).prepare())
  1719. ++prepared;
  1720. else
  1721. break;
  1722. }
  1723. return prepared == toPrepare;
  1724. }
  1725. virtual void retryActions()
  1726. {
  1727. clearFiles(); // clear all previously tracked pending file changes, e.g. renames, super file additions/removals
  1728. while (prepared) // unlock for retry
  1729. actions.item(--prepared).retry();
  1730. }
  1731. virtual void runActions()
  1732. {
  1733. ForEachItemIn(i,actions)
  1734. actions.item(i).run();
  1735. }
  1736. virtual void commitAndClearup()
  1737. {
  1738. // =============== COMMIT and CLEANUP
  1739. commitActions();
  1740. clearFiles();
  1741. isactive = false;
  1742. actions.kill();
  1743. deleteFiles();
  1744. }
  1745. virtual ICodeContext *queryCodeContext()
  1746. {
  1747. return codeCtx;
  1748. }
  1749. };
  1750. static bool recursiveCheckEmptyScope(IPropertyTree &ct)
  1751. {
  1752. Owned<IPropertyTreeIterator> iter = ct.getElements("*");
  1753. ForEach(*iter) {
  1754. IPropertyTree &item = iter->query();
  1755. const char *n = item.queryName();
  1756. if (!n||(strcmp(n,queryDfsXmlBranchName(DXB_Scope))!=0))
  1757. return false;
  1758. if (!recursiveCheckEmptyScope(item))
  1759. return false;
  1760. }
  1761. return true;
  1762. }
  1763. class CDFScopeIterator: implements IDFScopeIterator, public CInterface
  1764. {
  1765. PointerArray scopes;
  1766. unsigned index;
  1767. IDistributedFileDirectory *dir;
  1768. bool includeempty;
  1769. void add(IPropertyTree &t, bool recursive, StringBuffer &name)
  1770. {
  1771. name.trim();
  1772. size32_t nl = name.length();
  1773. size32_t l=nl;
  1774. if (nl) {
  1775. name.append("::");
  1776. l+=2;
  1777. }
  1778. Owned<IPropertyTreeIterator> iter = t.getElements(queryDfsXmlBranchName(DXB_Scope));
  1779. ForEach(*iter) {
  1780. IPropertyTree &ct = iter->query();
  1781. if (includeempty||!recursiveCheckEmptyScope(ct)) {
  1782. name.append(ct.queryProp("@name"));
  1783. scopes.append(strdup(name.str()));
  1784. if (recursive)
  1785. add(ct,recursive,name);
  1786. name.setLength(l);
  1787. }
  1788. }
  1789. name.setLength(nl);
  1790. }
  1791. public:
  1792. IMPLEMENT_IINTERFACE;
  1793. CDFScopeIterator(IDistributedFileDirectory *_dir,const char *base,bool recursive, bool _includeempty,unsigned timeout) // attrib not yet implemented
  1794. {
  1795. includeempty = _includeempty;
  1796. dir = _dir;
  1797. StringBuffer lockPath;
  1798. if (!isEmptyString(base))
  1799. {
  1800. CDfsLogicalFileName dlfn;
  1801. dlfn.set(base, "dummyfilename"); // makeScopeQuery expects a lfn to a file, 'dummyfilename' will not be used
  1802. dlfn.makeScopeQuery(lockPath, true);
  1803. }
  1804. else
  1805. lockPath.append(querySdsFilesRoot());
  1806. {
  1807. CConnectLock connlock("CDFScopeIterator", lockPath, false, false, false, timeout);
  1808. if (connlock.conn)
  1809. {
  1810. StringBuffer name;
  1811. add(*connlock.conn->queryRoot(),recursive,name);
  1812. }
  1813. }
  1814. if (scopes.ordinality()>1)
  1815. qsortvec(scopes.getArray(),scopes.ordinality(),strcompare);
  1816. index = 0;
  1817. }
  1818. ~CDFScopeIterator()
  1819. {
  1820. ForEachItemIn(i,scopes) {
  1821. free(scopes.item(i));
  1822. }
  1823. }
  1824. bool first()
  1825. {
  1826. index = 0;
  1827. return isValid();
  1828. }
  1829. bool next()
  1830. {
  1831. index++;
  1832. return isValid();
  1833. }
  1834. bool isValid()
  1835. {
  1836. return (index<scopes.ordinality());
  1837. }
  1838. const char *query()
  1839. {
  1840. return (const char *)scopes.item(index);
  1841. }
  1842. };
  1843. struct SerializeFileAttrOptions
  1844. {
  1845. bool includeSuperOwner;
  1846. //Add more as needed
  1847. SerializeFileAttrOptions()
  1848. {
  1849. includeSuperOwner = false;
  1850. }
  1851. };
  1852. class CDFAttributeIterator: implements IDFAttributesIterator, public CInterface
  1853. {
  1854. unsigned index;
  1855. IArrayOf<IPropertyTree> attrs;
  1856. public:
  1857. IMPLEMENT_IINTERFACE;
  1858. static MemoryBuffer &serializeFileAttributes(MemoryBuffer &mb, IPropertyTree &root, const char *name, bool issuper, SerializeFileAttrOptions& option)
  1859. {
  1860. StringBuffer buf;
  1861. mb.append(name);
  1862. if (issuper) {
  1863. mb.append("!SF");
  1864. mb.append(root.getPropInt("@numsubfiles",0));
  1865. mb.append("");
  1866. }
  1867. else {
  1868. mb.append(root.queryProp("@directory"));
  1869. mb.append(root.getPropInt("@numparts",0));
  1870. mb.append(root.queryProp("@partmask"));
  1871. }
  1872. mb.append(root.queryProp("@modified"));
  1873. Owned<IPropertyTree> attrs = root.getPropTree("Attr");;
  1874. Owned<IAttributeIterator> attriter;
  1875. if (attrs)
  1876. attriter.setown(attrs->getAttributes());
  1877. unsigned count=0;
  1878. size32_t countpos = mb.length();
  1879. mb.append(count);
  1880. if (attriter.get()&&attriter->first()) {
  1881. do {
  1882. mb.append(attriter->queryName());
  1883. mb.append(attriter->queryValue());
  1884. count++;
  1885. } while (attriter->next());
  1886. }
  1887. const char *ps = root.queryProp("@group");
  1888. if (ps&&*ps) {
  1889. count++;
  1890. mb.append("@group");
  1891. mb.append(ps);
  1892. }
  1893. // add protected
  1894. if (attrs) {
  1895. Owned<IPropertyTreeIterator> piter = attrs->getElements("Protect");
  1896. StringBuffer plist;
  1897. ForEach(*piter) {
  1898. const char *name = piter->get().queryProp("@name");
  1899. if (name&&*name) {
  1900. unsigned count = piter->get().getPropInt("@count");
  1901. if (count) {
  1902. if (plist.length())
  1903. plist.append(',');
  1904. plist.append(name);
  1905. if (count>1)
  1906. plist.append(':').append(count);
  1907. }
  1908. }
  1909. }
  1910. if (plist.length()) {
  1911. count++;
  1912. mb.append("@protect");
  1913. mb.append(plist.str());
  1914. }
  1915. }
  1916. if (option.includeSuperOwner) {
  1917. //add superowners
  1918. StringBuffer soList;
  1919. Owned<IPropertyTreeIterator> superOwners = root.getElements("SuperOwner");
  1920. ForEach(*superOwners) {
  1921. IPropertyTree &superOwner = superOwners->query();
  1922. const char *name = superOwner.queryProp("@name");
  1923. if (name&&*name) {
  1924. if (soList.length())
  1925. soList.append(",");
  1926. soList.append(name);
  1927. }
  1928. }
  1929. if (soList.length()) {
  1930. count++;
  1931. mb.append("@superowners");
  1932. mb.append(soList.str());
  1933. }
  1934. }
  1935. mb.writeDirect(countpos,sizeof(count),&count);
  1936. return mb;
  1937. }
  1938. CDFAttributeIterator(MemoryBuffer &mb) // attrib not yet implemented
  1939. {
  1940. unsigned numfiles;
  1941. mb.read(numfiles);
  1942. while (numfiles--) {
  1943. IPropertyTree *attr = getEmptyAttr();
  1944. StringAttr val;
  1945. unsigned n;
  1946. mb.read(val);
  1947. attr->setProp("@name",val.get());
  1948. mb.read(val);
  1949. if (stricmp(val,"!SF")==0) {
  1950. mb.read(n);
  1951. attr->setPropInt("@numsubfiles",n);
  1952. mb.read(val); // not used currently
  1953. }
  1954. else {
  1955. attr->setProp("@directory",val.get());
  1956. mb.read(n);
  1957. attr->setPropInt("@numparts",n);
  1958. mb.read(val);
  1959. attr->setProp("@partmask",val.get());
  1960. }
  1961. mb.read(val);
  1962. attr->setProp("@modified",val.get());
  1963. unsigned count;
  1964. mb.read(count);
  1965. StringAttr at;
  1966. while (count--) {
  1967. mb.read(at);
  1968. mb.read(val);
  1969. attr->setProp(at.get(),val.get());
  1970. }
  1971. attrs.append(*attr);
  1972. }
  1973. index = 0;
  1974. }
  1975. CDFAttributeIterator(IArrayOf<IPropertyTree>& trees)
  1976. {
  1977. ForEachItemIn(t, trees)
  1978. attrs.append(*LINK(&trees.item(t)));
  1979. index = 0;
  1980. }
  1981. ~CDFAttributeIterator()
  1982. {
  1983. attrs.kill();
  1984. }
  1985. bool first()
  1986. {
  1987. index = 0;
  1988. return (attrs.ordinality()!=0);
  1989. }
  1990. bool next()
  1991. {
  1992. index++;
  1993. return (index<attrs.ordinality());
  1994. }
  1995. bool isValid()
  1996. {
  1997. return (index<attrs.ordinality());
  1998. }
  1999. IPropertyTree & query()
  2000. {
  2001. return attrs.item(index);
  2002. }
  2003. };
  2004. class CDFProtectedIterator: implements IDFProtectedIterator, public CInterface
  2005. {
  2006. StringAttr owner;
  2007. StringAttr fn;
  2008. unsigned count;
  2009. bool issuper;
  2010. Owned<IRemoteConnection> conn;
  2011. Owned<IPropertyTreeIterator> fiter;
  2012. Owned<IPropertyTreeIterator> piter;
  2013. unsigned defaultTimeout;
  2014. bool notsuper;
  2015. bool superonly;
  2016. void fill()
  2017. {
  2018. IPropertyTree &t = fiter->query();
  2019. fn.set(t.queryProp("OrigName"));
  2020. IPropertyTree &pt = piter->query();
  2021. owner.set(pt.queryProp("@name"));
  2022. count = pt.getPropInt("@count");
  2023. }
  2024. void clear()
  2025. {
  2026. piter.clear();
  2027. fiter.clear();
  2028. conn.clear();
  2029. issuper = false;
  2030. }
  2031. public:
  2032. IMPLEMENT_IINTERFACE;
  2033. CDFProtectedIterator(const char *_owner,bool _notsuper,bool _superonly,unsigned _defaultTimeout)
  2034. : owner(_owner)
  2035. {
  2036. count = 0;
  2037. issuper = false;
  2038. notsuper=_notsuper;
  2039. superonly=_superonly;
  2040. defaultTimeout = _defaultTimeout;
  2041. }
  2042. ~CDFProtectedIterator()
  2043. {
  2044. clear();
  2045. }
  2046. bool first()
  2047. {
  2048. clear();
  2049. conn.setown(querySDS().connect("Files",myProcessSession(),0, defaultTimeout));
  2050. if (!conn)
  2051. return false;
  2052. IPropertyTree *t = conn->queryRoot();
  2053. if (!superonly) {
  2054. fiter.setown(t->getElements("//File[Attr/Protect]", iptiter_remote));
  2055. if (fiter->first()) {
  2056. piter.setown(fiter->query().getElements("Attr/Protect"));
  2057. if (piter->first()) {
  2058. fill();
  2059. return true;
  2060. }
  2061. }
  2062. }
  2063. if (!notsuper) {
  2064. issuper = true;
  2065. fiter.clear();
  2066. fiter.setown(t->getElements("//SuperFile[Attr/Protect]", iptiter_remote));
  2067. if (fiter->first()) {
  2068. piter.setown(fiter->query().getElements("Attr/Protect"));
  2069. if (piter->first()) {
  2070. fill();
  2071. return true;
  2072. }
  2073. }
  2074. }
  2075. clear();
  2076. return false;
  2077. }
  2078. bool next()
  2079. {
  2080. if (!fiter.get())
  2081. return false;
  2082. if (piter->next()) {
  2083. fill();
  2084. return true;
  2085. }
  2086. for (;;) {
  2087. if (fiter->next()) {
  2088. piter.setown(fiter->query().getElements("Attr/Protect"));
  2089. if (piter->first()) {
  2090. fill();
  2091. return true;
  2092. }
  2093. }
  2094. else if (!notsuper&&!issuper) {
  2095. issuper = true;
  2096. fiter.clear();
  2097. fiter.setown(conn->queryRoot()->getElements("//SuperFile[Attr/Protect]", iptiter_remote));
  2098. if (fiter->first()) {
  2099. piter.setown(fiter->query().getElements("Attr/Protect"));
  2100. if (piter->first()) {
  2101. fill();
  2102. return true;
  2103. }
  2104. }
  2105. else
  2106. break;
  2107. }
  2108. else
  2109. break;
  2110. }
  2111. clear();
  2112. return false;
  2113. }
  2114. bool isValid()
  2115. {
  2116. return fiter.get()!=NULL;
  2117. }
  2118. const char *queryFilename()
  2119. {
  2120. return fn;
  2121. }
  2122. const char *queryOwner()
  2123. {
  2124. return owner;
  2125. }
  2126. unsigned getCount()
  2127. {
  2128. return count;
  2129. }
  2130. bool isSuper()
  2131. {
  2132. return issuper;
  2133. }
  2134. };
  2135. // --------------------------------------------------------
  2136. class CDistributedFilePart: public CInterface, implements IDistributedFilePart
  2137. {
  2138. unsigned partIndex;
  2139. CDistributedFile &parent;
  2140. Owned<IPropertyTree> attr;
  2141. CriticalSection sect;
  2142. StringAttr overridename; // may or not be relative to directory
  2143. bool dirty; // whether needs updating in tree
  2144. offset_t getSize(bool checkCompressed);
  2145. public:
  2146. virtual void Link(void) const;
  2147. virtual bool Release(void) const;
  2148. void set(IPropertyTree *pt,FileClusterInfoArray &clusters,unsigned maxcluster);
  2149. RemoteFilename &getFilename(RemoteFilename &ret,unsigned copy);
  2150. void renameFile(IFile *file);
  2151. IPropertyTree &queryAttributes();
  2152. bool lockProperties(unsigned timems);
  2153. void unlockProperties(DFTransactionState state);
  2154. bool isHost(unsigned copy);
  2155. offset_t getFileSize(bool allowphysical,bool forcephysical);
  2156. offset_t getDiskSize(bool allowphysical,bool forcephysical);
  2157. bool getModifiedTime(bool allowphysical,bool forcephysical,CDateTime &dt);
  2158. bool getCrc(unsigned &crc);
  2159. unsigned getPhysicalCrc();
  2160. IPartDescriptor *getPartDescriptor();
  2161. unsigned numCopies();
  2162. INode *queryNode(unsigned copy);
  2163. unsigned queryDrive(unsigned copy);
  2164. StringBuffer &getPartName(StringBuffer &name);
  2165. StringBuffer &getPartDirectory(StringBuffer &name,unsigned copy);
  2166. const char *queryOverrideName() { return overridename; }
  2167. void clearOverrideName()
  2168. {
  2169. if (overridename.get()&&overridename.length()) {
  2170. dirty = true;
  2171. overridename.clear();
  2172. }
  2173. }
  2174. unsigned bestCopyNum(const IpAddress &ip,unsigned rel=0);
  2175. unsigned copyClusterNum(unsigned copy,unsigned *replicate=NULL);
  2176. void childLink(void) { CInterface::Link(); }
  2177. bool childRelease(void) { return CInterface::Release(); }
  2178. CDistributedFilePart(CDistributedFile &_parent,unsigned _part,IPartDescriptor *pd);
  2179. unsigned getPartIndex()
  2180. {
  2181. return partIndex;
  2182. }
  2183. INode *getNode(unsigned copy)
  2184. {
  2185. INode *ret = queryNode(copy);
  2186. if (ret)
  2187. return LINK(ret);
  2188. return NULL;
  2189. }
  2190. void setAttr(IPropertyTree &pt)
  2191. {
  2192. attr.setown(createPTreeFromIPT(&pt)); // take a copy
  2193. dirty = false;
  2194. }
  2195. IPropertyTree *queryAttr()
  2196. {
  2197. return attr;
  2198. }
  2199. inline CDistributedFile &queryParent()
  2200. {
  2201. return parent;
  2202. }
  2203. inline bool isDirty()
  2204. {
  2205. return dirty;
  2206. }
  2207. inline bool clearDirty()
  2208. {
  2209. bool ret=dirty;
  2210. dirty = false;
  2211. return ret;
  2212. }
  2213. };
  2214. // --------------------------------------------------------
  2215. class CDistributedFilePartArray: public CIArrayOf<CDistributedFilePart>
  2216. {
  2217. public:
  2218. virtual ~CDistributedFilePartArray() // this shouldn't be needed - points to problem in CIArrayOf?
  2219. {
  2220. kill();
  2221. }
  2222. void kill(bool nodel = false)
  2223. {
  2224. if (nodel)
  2225. CIArrayOf<CDistributedFilePart>::kill(true);
  2226. else {
  2227. while (ordinality()) {
  2228. CDistributedFilePart &part = popGet();
  2229. part.Release();
  2230. }
  2231. }
  2232. }
  2233. };
  2234. // --------------------------------------------------------
  2235. /**
  2236. * Base Iterator class for all iterator types. Implements basic iteration
  2237. * logic and forces all iterators to behave similarly. This will simplify
  2238. * future compatibility with STL containers/algorithms.
  2239. *
  2240. * INTERFACE needs to be extended from IIteratorOf<>
  2241. * ARRAYTY need to be extended from IArrayOf<>
  2242. */
  2243. template <class INTERFACE, class ARRAYTY>
  2244. class CDistributedFileIteratorBase: implements INTERFACE, public CInterface
  2245. {
  2246. protected:
  2247. unsigned index;
  2248. ARRAYTY list;
  2249. virtual bool set() { return isValid(); }
  2250. public:
  2251. IMPLEMENT_IINTERFACE;
  2252. CDistributedFileIteratorBase()
  2253. : index(0)
  2254. {
  2255. }
  2256. virtual ~CDistributedFileIteratorBase()
  2257. {
  2258. list.kill();
  2259. }
  2260. bool first()
  2261. {
  2262. if (list.ordinality() == 0)
  2263. return false;
  2264. index = 0;
  2265. return set();
  2266. }
  2267. bool next()
  2268. {
  2269. index++;
  2270. set();
  2271. return isValid();
  2272. }
  2273. bool isValid()
  2274. {
  2275. return (index < list.ordinality());
  2276. }
  2277. };
  2278. /**
  2279. * FilePart Iterator, used by files to manipulate its parts.
  2280. */
  2281. class CDistributedFilePartIterator: public CDistributedFileIteratorBase<IDistributedFilePartIterator, CDistributedFilePartArray>
  2282. {
  2283. public:
  2284. CDistributedFilePartIterator(CDistributedFilePartArray &parts, IDFPartFilter *filter)
  2285. {
  2286. ForEachItemIn(i,parts) {
  2287. if (!filter||filter->includePart(i))
  2288. list.append(*LINK(&parts.item(i)));
  2289. }
  2290. }
  2291. CDistributedFilePartIterator()
  2292. {
  2293. }
  2294. IDistributedFilePart & query()
  2295. {
  2296. return list.item(index);
  2297. }
  2298. CDistributedFilePartArray &queryParts()
  2299. {
  2300. return list;
  2301. }
  2302. };
  2303. /**
  2304. * File Iterator, used by directory to list file search results.
  2305. */
  2306. class CDistributedFileIterator: public CDistributedFileIteratorBase<IDistributedFileIterator, PointerArray>
  2307. {
  2308. Owned<IDistributedFile> cur;
  2309. IDistributedFileDirectory *parent;
  2310. Linked<IUserDescriptor> udesc;
  2311. Linked<IDistributedFileTransaction> transaction;
  2312. bool set()
  2313. {
  2314. while (isValid()) {
  2315. cur.setown(parent->lookup(queryName(),udesc));
  2316. if (cur)
  2317. return true;
  2318. index++;
  2319. }
  2320. return false;
  2321. }
  2322. public:
  2323. CDistributedFileIterator(IDistributedFileDirectory *_dir,const char *wildname,bool includesuper,IUserDescriptor *user,IDistributedFileTransaction *_transaction=NULL)
  2324. : transaction(_transaction)
  2325. {
  2326. setUserDescriptor(udesc,user);
  2327. if (!wildname||!*wildname)
  2328. wildname = "*";
  2329. parent = _dir;
  2330. bool recursive = (stricmp(wildname,"*")==0);
  2331. Owned<IDFAttributesIterator> attriter = parent->getDFAttributesIterator(wildname,user,recursive,includesuper,NULL);
  2332. ForEach(*attriter) {
  2333. IPropertyTree &pt = attriter->query();
  2334. list.append(strdup(pt.queryProp("@name")));
  2335. }
  2336. index = 0;
  2337. if (list.ordinality()>1)
  2338. qsortvec(list.getArray(),list.ordinality(),strcompare);
  2339. }
  2340. const char *queryName()
  2341. {
  2342. return (const char *)list.item(index);
  2343. }
  2344. StringBuffer & getName(StringBuffer &name)
  2345. {
  2346. return name.append(queryName());
  2347. }
  2348. IDistributedFile & query()
  2349. {
  2350. return *cur;
  2351. }
  2352. };
  2353. /**
  2354. * SuperFile Iterator, used by CDistributedFile to list all its super-owners by name.
  2355. */
  2356. class CDistributedSuperFileIterator: public CDistributedFileIteratorBase<IDistributedSuperFileIterator, StringAttrArray>
  2357. {
  2358. CDistributedFileDirectory *parent;
  2359. Linked<IUserDescriptor> udesc;
  2360. Linked<IDistributedFileTransaction> transaction;
  2361. Owned<IDistributedSuperFile> cur;
  2362. Linked<IDistributedFile> owner;
  2363. public:
  2364. CDistributedSuperFileIterator(IDistributedFile *_owner, CDistributedFileDirectory *_parent,IPropertyTree *root,IUserDescriptor *user, IDistributedFileTransaction *_transaction)
  2365. : owner(_owner), transaction(_transaction)
  2366. {
  2367. setUserDescriptor(udesc,user);
  2368. parent = _parent;
  2369. if (root)
  2370. {
  2371. Owned<IPropertyTreeIterator> iter = root->getElements("SuperOwner");
  2372. StringBuffer pname;
  2373. ForEach(*iter)
  2374. {
  2375. iter->query().getProp("@name",pname.clear());
  2376. if (pname.length())
  2377. list.append(* new StringAttrItem(pname.str()));
  2378. }
  2379. }
  2380. }
  2381. IDistributedSuperFile & query()
  2382. {
  2383. // NOTE: This used to include a do/while (!cur.get()&&next()) loop
  2384. // this should never be needed but match previous semantics
  2385. // throwing an exception now, to catch the error early on
  2386. if (transaction.get())
  2387. cur.setown(transaction->lookupSuperFile(queryName()));
  2388. else
  2389. cur.setown(parent->lookupSuperFile(queryName(),udesc,NULL));
  2390. if (!cur.get())
  2391. throw MakeStringException(-1,"superFileIter: invalid super-file on query at %s", queryName());
  2392. return *cur;
  2393. }
  2394. virtual const char *queryName()
  2395. {
  2396. if (isValid())
  2397. return list.item(index).text.get();
  2398. return NULL;
  2399. }
  2400. };
  2401. //-----------------------------------------------------------------------------
  2402. inline void dfCheckRoot(const char *trc,Owned<IPropertyTree> &root,IRemoteConnection *conn)
  2403. {
  2404. if (root.get()!=conn->queryRoot()) {
  2405. DBGLOG("%s - root changed",trc);
  2406. #ifdef _DEBUG
  2407. PrintStackReport();
  2408. #endif
  2409. root.setown(conn->getRoot());
  2410. }
  2411. }
  2412. static bool setFileProtectTree(IPropertyTree &p,const char *owner, bool protect)
  2413. {
  2414. bool ret = false;
  2415. CDateTime dt;
  2416. dt.setNow();
  2417. if (owner&&*owner) {
  2418. Owned<IPropertyTree> t = getNamedPropTree(&p,"Protect","@name",owner,false);
  2419. if (t) {
  2420. unsigned c = t->getPropInt("@count");
  2421. if (protect)
  2422. c++;
  2423. else {
  2424. if (c>=1) {
  2425. p.removeTree(t);
  2426. c = 0;
  2427. }
  2428. else
  2429. c--;
  2430. }
  2431. if (c) {
  2432. t->setPropInt("@count",c);
  2433. StringBuffer str;
  2434. t->setProp("@modified",dt.getString(str).str());
  2435. }
  2436. }
  2437. else if (protect) {
  2438. t.setown(addNamedPropTree(&p,"Protect","@name",owner));
  2439. t->setPropInt("@count",1);
  2440. StringBuffer str;
  2441. t->setProp("@modified",dt.getString(str).str());
  2442. }
  2443. ret = true;
  2444. }
  2445. else if (!protect) {
  2446. unsigned n=0;
  2447. IPropertyTree *pt;
  2448. while ((pt=p.queryPropTree("Protect[1]"))!=NULL) {
  2449. p.removeTree(pt);
  2450. n++;
  2451. }
  2452. if (n)
  2453. ret = true;
  2454. }
  2455. return ret;
  2456. }
  2457. static bool checkProtectAttr(const char *logicalname,IPropertyTree *froot,StringBuffer &reason)
  2458. {
  2459. Owned<IPropertyTreeIterator> wpiter = froot->getElements("Attr/Protect");
  2460. bool prot = false;
  2461. ForEach(*wpiter) {
  2462. IPropertyTree &t = wpiter->query();
  2463. if (t.getPropInt("@count")) {
  2464. const char *wpname = t.queryProp("@name");
  2465. if (!wpname||!*wpname)
  2466. wpname = "<Unknown>";
  2467. if (prot)
  2468. reason.appendf(", %s",wpname);
  2469. else {
  2470. reason.appendf("file %s protected by %s",logicalname,wpname);
  2471. prot = true;
  2472. }
  2473. }
  2474. }
  2475. return prot;
  2476. }
  2477. /**
  2478. * A template class which implements the common methods of an IDistributedFile interface.
  2479. * The actual interface (extended from IDistributedFile) is provided as a template argument.
  2480. */
  2481. template <class INTERFACE>
  2482. class CDistributedFileBase : implements INTERFACE, public CInterface
  2483. {
  2484. protected:
  2485. Owned<IPropertyTree> root;
  2486. Owned<IRemoteConnection> conn; // kept connected during lifetime for attributes
  2487. CDfsLogicalFileName logicalName;
  2488. CriticalSection sect;
  2489. CDistributedFileDirectory *parent;
  2490. unsigned proplockcount;
  2491. unsigned transactionnest;
  2492. Linked<IUserDescriptor> udesc;
  2493. unsigned defaultTimeout;
  2494. bool dirty;
  2495. bool external = false;
  2496. Owned<IRemoteConnection> superOwnerLock;
  2497. public:
  2498. IPropertyTree *queryRoot() { return root; }
  2499. CDistributedFileBase<INTERFACE>()
  2500. {
  2501. parent = NULL;
  2502. proplockcount = 0;
  2503. transactionnest = 0;
  2504. defaultTimeout = INFINITE;
  2505. dirty = false;
  2506. }
  2507. ~CDistributedFileBase<INTERFACE>()
  2508. {
  2509. root.clear();
  2510. }
  2511. void setSuperOwnerLock(IRemoteConnection *_superOwnerLock)
  2512. {
  2513. superOwnerLock.setown(_superOwnerLock);
  2514. }
  2515. unsigned setPropLockCount(unsigned _propLockCount)
  2516. {
  2517. unsigned prevPropLockCount = proplockcount;
  2518. proplockcount = _propLockCount;
  2519. return prevPropLockCount;
  2520. }
  2521. bool isCompressed(bool *blocked)
  2522. {
  2523. return ::isCompressed(queryAttributes(),blocked);
  2524. }
  2525. StringBuffer &getLogicalName(StringBuffer &lname)
  2526. {
  2527. lname.append(logicalName.get());
  2528. return lname;
  2529. }
  2530. void setLogicalName(const char *lname)
  2531. {
  2532. logicalName.set(lname);
  2533. }
  2534. const char *queryLogicalName()
  2535. {
  2536. return logicalName.get();
  2537. }
  2538. IPropertyTree &queryAttributes()
  2539. {
  2540. IPropertyTree *t = root->queryPropTree("Attr");
  2541. if (!t)
  2542. t = root->setPropTree("Attr",createPTree("Attr")); // takes ownership
  2543. return *t;
  2544. }
  2545. IPropertyTree *queryHistory() const
  2546. {
  2547. IPropertyTree *attr = root->queryPropTree("Attr");
  2548. if (attr)
  2549. return attr->queryPropTree("History");
  2550. return nullptr;
  2551. }
  2552. void resetHistory()
  2553. {
  2554. DistributedFilePropertyLock lock(this);
  2555. queryAttributes().removeTree(queryHistory());
  2556. }
  2557. protected:
  2558. class CFileChangeWriteLock
  2559. {
  2560. IRemoteConnection *conn;
  2561. unsigned timeoutMs, prevMode;
  2562. public:
  2563. CFileChangeWriteLock(IRemoteConnection *_conn, unsigned _timeoutMs)
  2564. : conn(_conn), timeoutMs(_timeoutMs)
  2565. {
  2566. if (conn)
  2567. {
  2568. prevMode = conn->queryMode();
  2569. unsigned newMode = (prevMode & ~RTM_LOCKBASIC_MASK) | RTM_LOCK_WRITE;
  2570. conn->changeMode(RTM_LOCK_WRITE, timeoutMs);
  2571. }
  2572. else
  2573. prevMode = RTM_NONE;
  2574. }
  2575. ~CFileChangeWriteLock()
  2576. {
  2577. if (conn)
  2578. conn->changeMode(prevMode, timeoutMs);
  2579. }
  2580. void clear() { conn = NULL; }
  2581. };
  2582. IPropertyTree *closeConnection(bool removeFile)
  2583. {
  2584. Owned<IPropertyTree> detachedRoot = createPTreeFromIPT(root);
  2585. root.clear();
  2586. if (conn)
  2587. {
  2588. conn->close(removeFile);
  2589. conn.clear();
  2590. }
  2591. return detachedRoot.getClear();
  2592. }
  2593. IPropertyTree *resetFileAttr(IPropertyTree *prop=NULL)
  2594. {
  2595. if (prop)
  2596. return root->setPropTree("Attr", prop);
  2597. root->removeProp("Attr");
  2598. return NULL;
  2599. }
  2600. void updateFS(const CDfsLogicalFileName &lfn, unsigned timeoutMs)
  2601. {
  2602. // Update the file system
  2603. removeFileEmptyScope(lfn, timeoutMs);
  2604. // MORE: We shouldn't have to update all relationships if we had done a better job making sure
  2605. // that all correct relationships were properly cleaned up
  2606. queryDistributedFileDirectory().removeAllFileRelationships(lfn.get());
  2607. }
  2608. public:
  2609. bool isAnon()
  2610. {
  2611. return !logicalName.isSet();
  2612. }
  2613. /*
  2614. * Change connection to write-mode, allowing multiple writers only on the same instance.
  2615. * Returns true if the lock was lost at least once before succeeding, hinting that some
  2616. * resources might need reload (like sub-files list, etc).
  2617. *
  2618. * WARN: This is not thread-safe
  2619. *
  2620. * @deprecated : use DistributedFilePropertyLock instead, when possible
  2621. */
  2622. bool lockProperties(unsigned timeoutms)
  2623. {
  2624. bool reload = false;
  2625. if (timeoutms==INFINITE)
  2626. timeoutms = defaultTimeout;
  2627. if (proplockcount++==0)
  2628. {
  2629. if (conn)
  2630. {
  2631. conn->rollback(); // changes chouldn't be done outside lock properties
  2632. #ifdef TRACE_LOCKS
  2633. PROGLOG("lockProperties: pre safeChangeModeWrite(%x)",(unsigned)(memsize_t)conn.get());
  2634. #endif
  2635. try
  2636. {
  2637. if (0 == timeoutms)
  2638. conn->changeMode(RTM_LOCK_WRITE, 0, true); // 0 timeout, test and fail immediately if contention
  2639. else
  2640. safeChangeModeWrite(conn,queryLogicalName(),reload,timeoutms);
  2641. }
  2642. catch(IException *)
  2643. {
  2644. proplockcount--;
  2645. dfCheckRoot("lockProperties",root,conn);
  2646. if (reload)
  2647. dirty = true; // safeChangeModeWrite unlocked, and reload will be need if retried
  2648. throw;
  2649. }
  2650. if (dirty) // a previous attempt unlocked and did not reload
  2651. {
  2652. dirty = false;
  2653. if (!reload) // if reload=true, safeChangeModeWrite has just reloaded, so no need to again here
  2654. {
  2655. conn->reload();
  2656. reload = true;
  2657. }
  2658. }
  2659. #ifdef TRACE_LOCKS
  2660. PROGLOG("lockProperties: done safeChangeModeWrite(%x)",(unsigned)(memsize_t)conn.get());
  2661. LogRemoteConn(conn);
  2662. #endif
  2663. dfCheckRoot("lockProperties",root,conn);
  2664. }
  2665. }
  2666. return reload;
  2667. }
  2668. /*
  2669. * Change connection back to read mode on the last unlock. There should never be
  2670. * an uneven number of locks/unlocks, since that will leave the connection with
  2671. * the DFS locked until the instance's destruction.
  2672. *
  2673. * WARN: This is not thread-safe
  2674. *
  2675. * @deprecated : use DistributedFilePropertyLock instead, when possible
  2676. */
  2677. void unlockProperties(DFTransactionState state=TAS_NONE)
  2678. {
  2679. savePartsAttr();
  2680. if (--proplockcount==0) {
  2681. if (conn) {
  2682. // Transactional logic, if any
  2683. switch(state) {
  2684. case TAS_SUCCESS:
  2685. conn->commit();
  2686. break;
  2687. case TAS_FAILURE:
  2688. conn->rollback();
  2689. break;
  2690. case TAS_RETRY:
  2691. conn->changeMode(RTM_NONE,defaultTimeout,true);
  2692. return;
  2693. // TAS_NONE, do nothing
  2694. }
  2695. #ifdef TRACE_LOCKS
  2696. PROGLOG("unlockProperties: pre changeMode(%x)",(unsigned)(memsize_t)conn.get());
  2697. #endif
  2698. conn->changeMode(RTM_LOCK_READ,defaultTimeout,true);
  2699. #ifdef TRACE_LOCKS
  2700. PROGLOG("unlockProperties: post changeMode(%x)",(unsigned)(memsize_t)conn.get());
  2701. LogRemoteConn(conn);
  2702. #endif
  2703. dfCheckRoot("unlockProperties",root,conn);
  2704. }
  2705. }
  2706. }
  2707. bool getModificationTime(CDateTime &dt)
  2708. {
  2709. StringBuffer str;
  2710. if (!root->getProp("@modified",str))
  2711. return false;
  2712. dt.setString(str.str());
  2713. return true;
  2714. }
  2715. void setModificationTime(const CDateTime &dt)
  2716. {
  2717. DistributedFilePropertyLock lock(this);
  2718. if (dt.isNull())
  2719. root->removeProp("@modified");
  2720. else {
  2721. StringBuffer str;
  2722. root->setProp("@modified",dt.getString(str).str());
  2723. }
  2724. root->removeProp("@verified");
  2725. }
  2726. void setModified()
  2727. {
  2728. CDateTime dt;
  2729. dt.setNow();
  2730. setModificationTime(dt);
  2731. }
  2732. virtual StringBuffer &getECL(StringBuffer &buf)
  2733. {
  2734. MemoryBuffer mb;
  2735. if (queryAttributes().getPropBin("ECLbin",mb))
  2736. buf.deserialize(mb);
  2737. else
  2738. queryAttributes().getProp("ECL",buf);
  2739. return buf;
  2740. }
  2741. virtual void setECL(const char *ecl)
  2742. {
  2743. DistributedFilePropertyLock lock(this);
  2744. IPropertyTree &p = queryAttributes();
  2745. #ifdef PACK_ECL
  2746. p.removeProp("ECL");
  2747. if (!ecl||!*ecl)
  2748. p.removeProp("ECLbin");
  2749. else {
  2750. MemoryBuffer mb; // could be better
  2751. StringBuffer buf(ecl);
  2752. buf.serialize(mb);
  2753. root->setPropBin("ECLbin",mb.length(),mb.toByteArray());
  2754. }
  2755. #else
  2756. p.setProp("ECL",ecl);
  2757. #endif
  2758. }
  2759. void setProtect(const char *owner, bool protect, unsigned timems)
  2760. {
  2761. if (logicalName.isForeign()) {
  2762. parent->setFileProtect(logicalName,udesc,owner,protect);
  2763. }
  2764. else {
  2765. bool ret=false;
  2766. if (conn) {
  2767. DistributedFilePropertyLock lock(this);
  2768. IPropertyTree &p = queryAttributes();
  2769. CDateTime dt;
  2770. dt.setNow();
  2771. if (setFileProtectTree(p,owner,protect))
  2772. conn->commit();
  2773. dfCheckRoot("setProtect.1",root,conn);
  2774. }
  2775. else
  2776. IERRLOG("setProtect - cannot protect %s (no connection in file)",owner?owner:"");
  2777. }
  2778. }
  2779. virtual IDistributedSuperFileIterator *getOwningSuperFiles(IDistributedFileTransaction *_transaction)
  2780. {
  2781. CriticalBlock block(sect);
  2782. return new CDistributedSuperFileIterator(this,parent,root,udesc,_transaction);
  2783. }
  2784. virtual void checkFormatAttr(IDistributedFile *sub, const char* exprefix="")
  2785. {
  2786. // check file has same (or similar) format
  2787. IPropertyTree &superProp = queryAttributes();
  2788. IPropertyTree &subProp = sub->queryAttributes();
  2789. if (!exprefix)
  2790. exprefix = "CheckFormatAttr";
  2791. bool superBlocked = false;
  2792. bool superComp = ::isCompressed(superProp,&superBlocked);
  2793. bool subBlocked = false;
  2794. bool subComp = ::isCompressed(subProp,&subBlocked);
  2795. // FIXME: this may fail if an empty superfile added to a compressed superfile
  2796. if (superComp != subComp)
  2797. throw MakeStringException(-1,"%s: %s's compression setting (%s) is different than %s's (%s)",
  2798. exprefix, sub->queryLogicalName(), (subComp?"compressed":"uncompressed"),
  2799. queryLogicalName(), (superComp?"compressed":"uncompressed"));
  2800. if (superBlocked != subBlocked)
  2801. throw MakeStringException(-1,"%s: %s's blocked setting (%s) is different than %s's (%s)",
  2802. exprefix, sub->queryLogicalName(), (subBlocked?"blocked":"unblocked"),
  2803. queryLogicalName(), (superBlocked?"blocked":"unblocked"));
  2804. #ifdef SUBFILE_COMPATIBILITY_CHECKING
  2805. // MORE - this first check looks completely useless to me
  2806. bool subSoft = subProp.hasProp("_record_layout");
  2807. bool superSoft = superProp.hasProp("_record_layout");
  2808. if (superSoft != subSoft)
  2809. throw MakeStringException(-1,"%s: %s's record layout (%s) is different than %s's (%s)",
  2810. exprefix, sub->queryLogicalName(), (subSoft?"dynamic":"fixed"),
  2811. queryLogicalName(), (superSoft?"dynamic":"fixed"));
  2812. // If they don't, they must have the same size
  2813. if (!superSoft) {
  2814. unsigned superSize = superProp.getPropInt("@recordSize",0);
  2815. unsigned subSize = subProp.getPropInt("@recordSize",0);
  2816. // Variable length files (CSV, etc) have zero record size
  2817. if (superSize && subSize && (superSize != subSize))
  2818. throw MakeStringException(-1,"%s: %s's record size (%d) is different than %s's (%d)",
  2819. exprefix, sub->queryLogicalName(), subSize, queryLogicalName(), superSize);
  2820. }
  2821. StringBuffer superFmt;
  2822. bool superHasFmt = superProp.getProp("@format",superFmt);
  2823. StringBuffer subFmt;
  2824. bool subHasFmt = subProp.getProp("@format",subFmt);
  2825. if (subHasFmt && superHasFmt)
  2826. if (strcmp(normalizeFormat(superFmt).str(),normalizeFormat(subFmt).str()) != 0)
  2827. throw MakeStringException(-1,"%s: %s's format (%s) is different than %s's (%s)",
  2828. exprefix, sub->queryLogicalName(), superFmt.str(),
  2829. queryLogicalName(), subFmt.str());
  2830. #endif
  2831. bool superLocal = superProp.getPropBool("@local",false);
  2832. bool subLocal = subProp.getPropBool("@local",false);
  2833. if (subLocal != superLocal)
  2834. throw MakeStringException(-1,"%s: %s's local setting (%s) is different than %s's (%s)",
  2835. exprefix, sub->queryLogicalName(), (subLocal?"local":"global"),
  2836. queryLogicalName(), (superLocal?"local":"global"));
  2837. int superRepO = superProp.getPropInt("@replicateOffset",1);
  2838. int subRepO = subProp.getPropInt("@replicateOffset",1);
  2839. if (subRepO != superRepO)
  2840. throw MakeStringException(-1,"%s: %s's replication offset (%d) is different than %s's (%d)",
  2841. exprefix, sub->queryLogicalName(), subRepO,
  2842. queryLogicalName(), superRepO);
  2843. }
  2844. void getSuperOwners(StringArray &owners)
  2845. {
  2846. if (root)
  2847. {
  2848. StringBuffer owner;
  2849. Owned<IPropertyTreeIterator> iter = root->getElements("SuperOwner");
  2850. ForEach (*iter)
  2851. {
  2852. iter->query().getProp("@name", owner.clear());
  2853. if (owner.length())
  2854. {
  2855. if (NotFound == owners.find(owner))
  2856. owners.append(owner);
  2857. }
  2858. }
  2859. }
  2860. }
  2861. void linkSuperOwner(const char *superfile,bool link)
  2862. {
  2863. if (!superfile||!*superfile)
  2864. return;
  2865. if (conn)
  2866. {
  2867. CFileSuperOwnerLock attrLock;
  2868. if (0 == proplockcount)
  2869. verifyex(attrLock.init(logicalName, conn, defaultTimeout, "CDistributedFile::linkSuperOwner"));
  2870. Owned<IPropertyTree> t = getNamedPropTree(root,"SuperOwner","@name",superfile,false);
  2871. if (t && !link)
  2872. root->removeTree(t);
  2873. else if (!t && link)
  2874. t.setown(addNamedPropTree(root,"SuperOwner","@name",superfile));
  2875. }
  2876. else
  2877. IERRLOG("linkSuperOwner - cannot link to %s (no connection in file)",superfile);
  2878. }
  2879. void setAccessed()
  2880. {
  2881. CDateTime dt;
  2882. dt.setNow();
  2883. setAccessedTime(dt);
  2884. }
  2885. virtual StringBuffer &getColumnMapping(StringBuffer &mapping)
  2886. {
  2887. queryAttributes().getProp("@columnMapping",mapping);
  2888. return mapping;
  2889. }
  2890. virtual void setColumnMapping(const char *mapping)
  2891. {
  2892. DistributedFilePropertyLock lock(this);
  2893. if (!mapping||!*mapping)
  2894. queryAttributes().removeProp("@columnMapping");
  2895. else
  2896. queryAttributes().setProp("@columnMapping",mapping);
  2897. }
  2898. unsigned setDefaultTimeout(unsigned timems)
  2899. {
  2900. unsigned ret = defaultTimeout;
  2901. defaultTimeout = timems;
  2902. return ret;
  2903. }
  2904. // MORE - simplify this, after removing CLightWeightSuperFileConn
  2905. bool canModify(StringBuffer &reason)
  2906. {
  2907. return !checkProtectAttr(logicalName.get(),root,reason);
  2908. }
  2909. bool checkOwned(StringBuffer &error)
  2910. {
  2911. Owned<IPropertyTreeIterator> iter = root->getElements("SuperOwner");
  2912. if (iter->first())
  2913. {
  2914. error.append("Cannot remove file ").append(logicalName.get()).append(" as owned by SuperFile(s): ");
  2915. for (;;)
  2916. {
  2917. error.append(iter->query().queryProp("@name"));
  2918. if (!iter->next())
  2919. break;
  2920. error.append(", ");
  2921. }
  2922. return true;
  2923. }
  2924. return false;
  2925. }
  2926. bool canRemove(StringBuffer &reason,bool ignoresub=false)
  2927. {
  2928. CriticalBlock block(sect);
  2929. if (!canModify(reason))
  2930. return false;
  2931. const char *logicalname = logicalName.get();
  2932. if (!logicalname||!*logicalname) {
  2933. reason.appendf("empty filename");
  2934. return false;
  2935. }
  2936. if (logicalName.isQuery())
  2937. {
  2938. reason.appendf("%s is query",logicalname);
  2939. return false;
  2940. }
  2941. if (logicalName.isForeign())
  2942. {
  2943. reason.appendf("%s is foreign",logicalname);
  2944. return false;
  2945. }
  2946. if (logicalName.isMulti())
  2947. {
  2948. reason.appendf("%s is multi",logicalname);
  2949. return false;
  2950. }
  2951. if (!ignoresub)
  2952. {
  2953. if (checkOwned(reason))
  2954. return false;
  2955. }
  2956. return true;
  2957. }
  2958. virtual const char *queryDefaultDir() = 0;
  2959. virtual unsigned numParts() = 0;
  2960. virtual IDistributedFilePart &queryPart(unsigned idx) = 0;
  2961. virtual IDistributedFilePart* getPart(unsigned idx) = 0;
  2962. virtual void savePartsAttr(bool force=false) = 0;
  2963. virtual IDistributedFilePartIterator *getIterator(IDFPartFilter *filter=NULL) = 0;
  2964. virtual IDistributedSuperFile *querySuperFile() = 0;
  2965. virtual ClusterPartDiskMapSpec &queryPartDiskMapping(unsigned clusternum)=0;
  2966. virtual void updatePartDiskMapping(const char *clustername,const ClusterPartDiskMapSpec &spec)=0;
  2967. virtual void enqueueReplicate()=0;
  2968. virtual bool getAccessedTime(CDateTime &dt) = 0; // get date and time last accessed (returns false if not set)
  2969. virtual void setAccessedTime(const CDateTime &dt) = 0; // set date and time last accessed
  2970. virtual bool isExternal() const { return external; }
  2971. };
  2972. class CDistributedFile: public CDistributedFileBase<IDistributedFile>
  2973. {
  2974. protected:
  2975. CDistributedFilePartArray parts; // use queryParts to access
  2976. CriticalSection sect;
  2977. StringAttr directory;
  2978. StringAttr partmask;
  2979. FileClusterInfoArray clusters;
  2980. void savePartsAttr(bool force) override
  2981. {
  2982. CriticalBlock block (sect);
  2983. IPropertyTree *pt;
  2984. if (parts.ordinality()==1) { // single part saved as part
  2985. if (parts.item(0).clearDirty()||force) {
  2986. CDistributedFilePart &part = parts.item(0);
  2987. while ((pt=root->queryPropTree("Part[1]"))!=NULL)
  2988. root->removeTree(pt);
  2989. pt = createPTreeFromIPT(part.queryAttr());
  2990. pt->setPropInt("@num",1);
  2991. const char *grp = root->queryProp("@group");
  2992. if (!grp||!*grp) {
  2993. StringBuffer eps;
  2994. pt->addProp("@node",part.queryNode(0)->endpoint().getUrlStr(eps).str()); // legacy
  2995. }
  2996. const char *override = part.queryOverrideName();
  2997. if (override&&*override)
  2998. pt->setProp("@name",override);
  2999. else {
  3000. pt->removeProp("@name");
  3001. const char *mask=queryPartMask();
  3002. if (mask&&*mask) {
  3003. StringBuffer tmp;
  3004. expandMask(tmp,mask,0,1);
  3005. pt->setProp("@name",tmp.str());
  3006. }
  3007. }
  3008. root->setPropTree("Part",pt);
  3009. }
  3010. }
  3011. else {
  3012. unsigned n = parts.ordinality();
  3013. unsigned i1;
  3014. for (i1=0;i1<n;i1++) {
  3015. if (parts.item(i1).clearDirty()||force) {
  3016. MemoryBuffer mb;
  3017. CriticalBlock block (sect);
  3018. ForEachItemIn(i2,parts)
  3019. serializePartAttr(mb,parts.item(i2).queryAttr());
  3020. root->setPropBin("Parts",mb.length(),mb.toByteArray());
  3021. while ((pt=root->queryPropTree("Part[1]"))!=NULL)
  3022. root->removeTree(pt);
  3023. break;
  3024. }
  3025. }
  3026. while (i1<n)
  3027. parts.item(i1++).clearDirty();
  3028. }
  3029. }
  3030. void detach(unsigned timeoutMs, bool removePhysicals, ICodeContext *ctx)
  3031. {
  3032. // Removes either a cluster in case of multi cluster file or the whole File entry from DFS
  3033. assert(proplockcount == 0 && "CDistributedFile detach: Some properties are still locked");
  3034. assertex(!isAnon()); // not attached!
  3035. if (removePhysicals)
  3036. {
  3037. // Avoid removing physically when there is no physical representation
  3038. if (logicalName.isMulti())
  3039. removePhysicals = false;
  3040. }
  3041. StringBuffer clusterName;
  3042. Owned<IFileDescriptor> fileDescCopy;
  3043. #ifdef EXTRA_LOGGING
  3044. PROGLOG("CDistributedFile::detach(%s)",logicalName.get());
  3045. LOGPTREE("CDistributedFile::detach root.1",root);
  3046. #endif
  3047. {
  3048. CriticalBlock block(sect); // JCSMORE - not convinced this is still necessary
  3049. CFileChangeWriteLock writeLock(conn, timeoutMs);
  3050. logicalName.getCluster(clusterName);
  3051. // copy file descriptor before altered, used by physical file removal routines
  3052. if (removePhysicals)
  3053. {
  3054. MemoryBuffer mb;
  3055. Owned<IFileDescriptor> fdesc = getFileDescriptor(clusterName);
  3056. fdesc->serialize(mb);
  3057. fileDescCopy.setown(deserializeFileDescriptor(mb));
  3058. }
  3059. bool removeFile=true;
  3060. if (clusterName.length())
  3061. {
  3062. // Remove just cluster specified, unless it's the last, in which case detach below will remove File entry.
  3063. if (clusters.ordinality()>1)
  3064. {
  3065. if (removeCluster(clusterName.str()))
  3066. removeFile=false;
  3067. else
  3068. ThrowStringException(-1, "Cluster %s not present in file %s", clusterName.str(), logicalName.get());
  3069. }
  3070. }
  3071. if (removeFile)
  3072. {
  3073. // check can remove, e.g. cannot if this is a subfile of a super
  3074. StringBuffer reason;
  3075. if (!canRemove(reason))
  3076. throw MakeStringException(-1,"detach: %s", reason.str());
  3077. }
  3078. // detach this IDistributeFile
  3079. /* JCSMORE - In 'removeFile=true' case, this should really delete before release exclusive lock.
  3080. */
  3081. writeLock.clear();
  3082. root.setown(closeConnection(removeFile));
  3083. // NB: The file is now unlocked
  3084. if (removeFile && !logicalName.isExternal())
  3085. updateFS(logicalName, parent->queryDefaultTimeout());
  3086. logicalName.clear();
  3087. }
  3088. // NB: beyond unlock
  3089. if (removePhysicals)
  3090. {
  3091. CriticalBlock block(physicalChange);
  3092. Owned<IMultiException> exceptions = MakeMultiException("CDistributedFile::detach");
  3093. removePhysicalPartFiles(fileDescCopy, exceptions);
  3094. if (exceptions->ordinality())
  3095. throw exceptions.getClear();
  3096. }
  3097. }
  3098. bool removePhysicalPartFiles(IFileDescriptor *fileDesc, IMultiException *mexcept, unsigned numParallelDeletes=0)
  3099. {
  3100. if (logicalName.isExternal())
  3101. {
  3102. if (logicalName.isQuery())
  3103. return false;
  3104. }
  3105. if (logicalName.isForeign())
  3106. throw MakeStringException(-1,"cannot remove a foreign file (%s)",logicalName.get());
  3107. return parent->removePhysicalPartFiles(logicalName.get(), fileDesc, mexcept, numParallelDeletes);
  3108. }
  3109. protected: friend class CDistributedFilePart;
  3110. CDistributedFilePartArray &queryParts()
  3111. {
  3112. return parts;
  3113. }
  3114. public:
  3115. IMPLEMENT_IINTERFACE_O;
  3116. CDistributedFile(CDistributedFileDirectory *_parent, IRemoteConnection *_conn,const CDfsLogicalFileName &lname,IUserDescriptor *user) // takes ownership of conn
  3117. {
  3118. setUserDescriptor(udesc,user);
  3119. logicalName.set(lname);
  3120. parent = _parent;
  3121. conn.setown(_conn);
  3122. CClustersLockedSection sect(logicalName, false);
  3123. root.setown(conn->getRoot());
  3124. root->queryBranch("."); // load branch
  3125. #ifdef EXTRA_LOGGING
  3126. LOGPTREE("CDistributedFile.a root",root);
  3127. #endif
  3128. Owned<IFileDescriptor> fdesc = deserializeFileDescriptorTree(root,&queryNamedGroupStore(),0);
  3129. #ifdef EXTRA_LOGGING
  3130. LOGFDESC("CDistributedFile.a fdesc",fdesc);
  3131. #endif
  3132. setFileAttrs(fdesc,false);
  3133. setClusters(fdesc);
  3134. setPreferredClusters(_parent->defprefclusters);
  3135. setParts(fdesc,false);
  3136. //shrinkFileTree(root); // enable when safe!
  3137. }
  3138. CDistributedFile(CDistributedFileDirectory *_parent, IFileDescriptor *fdesc, IUserDescriptor *user, bool _external)
  3139. {
  3140. #ifdef EXTRA_LOGGING
  3141. LOGFDESC("CDistributedFile.b fdesc",fdesc);
  3142. #endif
  3143. parent = _parent;
  3144. root.setown(createPTree(queryDfsXmlBranchName(DXB_File)));
  3145. root->setPropTree("ClusterLock", createPTree());
  3146. // fdesc->serializeTree(*root,IFDSF_EXCLUDE_NODES);
  3147. setFileAttrs(fdesc,true);
  3148. setClusters(fdesc);
  3149. setPreferredClusters(_parent->defprefclusters);
  3150. saveClusters();
  3151. setParts(fdesc,true);
  3152. udesc.set(user);
  3153. external = _external;
  3154. #ifdef EXTRA_LOGGING
  3155. LOGPTREE("CDistributedFile.b root.1",root);
  3156. #endif
  3157. offset_t totalsize=0;
  3158. unsigned checkSum = ~0;
  3159. bool useableCheckSum = true;
  3160. MemoryBuffer pmb;
  3161. unsigned n = fdesc->numParts();
  3162. for (unsigned i=0;i<n;i++) {
  3163. IPropertyTree *partattr = &fdesc->queryPart(i)->queryProperties();
  3164. if (!partattr)
  3165. {
  3166. totalsize = (unsigned)-1;
  3167. useableCheckSum = false;
  3168. }
  3169. else
  3170. {
  3171. offset_t psz;
  3172. if (totalsize!=(offset_t)-1) {
  3173. psz = (offset_t)partattr->getPropInt64("@size", -1);
  3174. if (psz==(offset_t)-1)
  3175. totalsize = psz;
  3176. else
  3177. totalsize += psz;
  3178. }
  3179. if (useableCheckSum) {
  3180. unsigned crc;
  3181. if (fdesc->queryPart(i)->getCrc(crc))
  3182. checkSum ^= crc;
  3183. else
  3184. useableCheckSum = false;
  3185. }
  3186. }
  3187. }
  3188. shrinkFileTree(root);
  3189. if (totalsize!=(offset_t)-1)
  3190. queryAttributes().setPropInt64("@size", totalsize);
  3191. if (useableCheckSum)
  3192. queryAttributes().setPropInt64("@checkSum", checkSum);
  3193. setModified();
  3194. #ifdef EXTRA_LOGGING
  3195. LOGPTREE("CDistributedFile.b root.2",root);
  3196. #endif
  3197. }
  3198. void killParts()
  3199. {
  3200. ForEachItemIn(i,parts)
  3201. parts.item(i).childRelease();
  3202. parts.kill(true);
  3203. }
  3204. ~CDistributedFile()
  3205. {
  3206. assert(proplockcount == 0 && "CDistributedFile destructor: Some properties are still locked");
  3207. if (conn)
  3208. conn->rollback(); // changes should always be done in locked properties
  3209. killParts();
  3210. clusters.kill();
  3211. }
  3212. IFileDescriptor *getFileDescriptor(const char *_clusterName) override
  3213. {
  3214. CriticalBlock block (sect);
  3215. Owned<IFileDescriptor> fdesc = deserializeFileDescriptorTree(root,&queryNamedGroupStore(),0);
  3216. fdesc->setTraceName(logicalName.get());
  3217. StringArray cnames;
  3218. if (_clusterName&&*_clusterName)
  3219. {
  3220. StringAttr clusterName = _clusterName;
  3221. clusterName.toLowerCase();
  3222. cnames.append(clusterName);
  3223. }
  3224. else
  3225. getClusterNames(cnames);
  3226. fdesc->setClusterOrder(cnames,_clusterName&&*_clusterName);
  3227. return fdesc.getClear();
  3228. }
  3229. void setFileAttrs(IFileDescriptor *fdesc,bool save)
  3230. {
  3231. directory.set(fdesc->queryDefaultDir());
  3232. partmask.set(fdesc->queryPartMask());
  3233. const char *lfn = logicalName.get();
  3234. if (lfn&&*lfn) {
  3235. if (partmask.isEmpty()) {
  3236. StringBuffer mask;
  3237. getPartMask(mask,lfn,0);
  3238. partmask.set(mask);
  3239. }
  3240. }
  3241. if (!save)
  3242. return;
  3243. if (directory.isEmpty())
  3244. root->removeProp("@directory");
  3245. else
  3246. root->setProp("@directory",directory);
  3247. if (partmask.isEmpty())
  3248. root->removeProp("@partmask");
  3249. else
  3250. root->setProp("@partmask",partmask);
  3251. IPropertyTree *t = &fdesc->queryProperties();
  3252. if (isEmptyPTree(t))
  3253. resetFileAttr();
  3254. else
  3255. resetFileAttr(createPTreeFromIPT(t));
  3256. }
  3257. void setClusters(IFileDescriptor *fdesc)
  3258. {
  3259. clusters.clear();
  3260. unsigned nc = fdesc->numClusters();
  3261. if (nc) {
  3262. for (unsigned i=0;i<nc;i++) {
  3263. StringBuffer cname;
  3264. StringBuffer clabel;
  3265. IClusterInfo &cluster = *createClusterInfo(
  3266. fdesc->getClusterGroupName(i,cname,NULL).str(),
  3267. fdesc->queryClusterGroup(i),
  3268. fdesc->queryPartDiskMapping(i),
  3269. &queryNamedGroupStore()
  3270. );
  3271. #ifdef EXTRA_LOGGING
  3272. PROGLOG("setClusters(%d,%s)",i,cname.str());
  3273. #endif
  3274. if (!cluster.queryGroup(&queryNamedGroupStore())) {
  3275. IERRLOG("IDistributedFileDescriptor cannot set cluster for %s",logicalName.get());
  3276. }
  3277. clusters.append(cluster);
  3278. }
  3279. }
  3280. else
  3281. IERRLOG("No cluster specified for %s",logicalName.get());
  3282. }
  3283. virtual unsigned numClusters() override
  3284. {
  3285. return clusters.ordinality();
  3286. }
  3287. virtual unsigned findCluster(const char *clustername) override
  3288. {
  3289. return clusters.find(clustername);
  3290. }
  3291. virtual unsigned getClusterNames(StringArray &clusternames) override
  3292. {
  3293. return clusters.getNames(clusternames);
  3294. }
  3295. void reloadClusters()
  3296. {
  3297. // called from CClustersLockedSection
  3298. if (!CDistributedFileBase<IDistributedFile>::conn)
  3299. return;
  3300. assertex(CDistributedFileBase<IDistributedFile>::proplockcount==0); // cannot reload clusters if properties locked
  3301. CDistributedFileBase<IDistributedFile>::conn->reload(); // should only be cluster changes but a bit dangerous
  3302. IPropertyTree *t = CDistributedFileBase<IDistributedFile>::conn->queryRoot(); // NB not CDistributedFileBase<IDistributedFile>::queryRoot();
  3303. if (!t)
  3304. return;
  3305. clusters.clear();
  3306. getClusterInfo(*t,&queryNamedGroupStore(),0,clusters);
  3307. }
  3308. void saveClusters()
  3309. {
  3310. // called from CClustersLockedSection
  3311. IPropertyTree *t;
  3312. if (CDistributedFileBase<IDistributedFile>::conn)
  3313. t = CDistributedFileBase<IDistributedFile>::conn->queryRoot();
  3314. else
  3315. t = CDistributedFileBase<IDistributedFile>::queryRoot(); //cache
  3316. if (!t)
  3317. return;
  3318. IPropertyTree *pt;
  3319. IPropertyTree *tc = CDistributedFileBase<IDistributedFile>::queryRoot(); //cache
  3320. IPropertyTree *t0 = t;
  3321. StringBuffer grplist;
  3322. // the following is complicated by fact there is a cache of the file branch
  3323. for (;;) {
  3324. while ((pt=t->queryPropTree("Cluster[1]"))!=NULL)
  3325. t->removeTree(pt);
  3326. ForEachItemIn(i,clusters) {
  3327. IPropertyTree *pt = createPTree("Cluster");
  3328. clusters.item(i).serializeTree(pt,IFDSF_EXCLUDE_GROUPS);
  3329. if (!isEmptyPTree(pt)) {
  3330. t->addPropTree("Cluster",pt);
  3331. if (t==t0) {
  3332. StringBuffer clabel;
  3333. clusters.item(i).getClusterLabel(clabel);
  3334. if (clabel.length()) {
  3335. if (grplist.length())
  3336. grplist.append(',');
  3337. grplist.append(clabel);
  3338. }
  3339. }
  3340. }
  3341. else
  3342. DBGLOG("CFileClusterOwner::saveClusters - empty cluster");
  3343. }
  3344. if (grplist.length())
  3345. t->setProp("@group",grplist.str());
  3346. else
  3347. t->removeProp("@group");
  3348. t->setPropInt("@numclusters",clusters.ordinality());
  3349. t->setProp("@directory", directory);
  3350. if (t==tc)
  3351. break;
  3352. t = tc; // now fix cache
  3353. }
  3354. if (CDistributedFileBase<IDistributedFile>::conn)
  3355. CDistributedFileBase<IDistributedFile>::conn->commit(); // should only be cluster changes but a bit dangerous
  3356. }
  3357. virtual void addCluster(const char *clustername,const ClusterPartDiskMapSpec &mspec) override
  3358. {
  3359. if (!clustername&&!*clustername)
  3360. return;
  3361. CClustersLockedSection cls(CDistributedFileBase<IDistributedFile>::logicalName, true);
  3362. reloadClusters();
  3363. if (findCluster(clustername)!=NotFound) {
  3364. IDFS_Exception *e = new CDFS_Exception(DFSERR_ClusterAlreadyExists,clustername);
  3365. throw e;
  3366. }
  3367. Owned<IClusterInfo> cluster = createClusterInfo(clustername,NULL,mspec,&queryNamedGroupStore());
  3368. if (cluster->queryGroup(&queryNamedGroupStore())) {
  3369. clusters.append(*cluster.getClear());
  3370. }
  3371. else {
  3372. IDFS_Exception *e = new CDFS_Exception(DFSERR_ClusterNotFound,clustername);
  3373. throw e;
  3374. }
  3375. saveClusters();
  3376. }
  3377. virtual bool removeCluster(const char *clustername) override
  3378. {
  3379. CClustersLockedSection cls(CDistributedFileBase<IDistributedFile>::logicalName, true);
  3380. reloadClusters();
  3381. unsigned i = findCluster(clustername);
  3382. if (i!=NotFound) {
  3383. if (clusters.ordinality()==1)
  3384. throw MakeStringException(-1,"CFileClusterOwner::removeCluster cannot remove sole cluster %s",clustername);
  3385. // If the cluster is the 'default' one we need to update the directory too
  3386. StringBuffer oldBaseDir;
  3387. char pathSepChar = getPathSepChar(directory.get());
  3388. DFD_OS os = SepCharBaseOs(pathSepChar);
  3389. clusters.item(i).getBaseDir(oldBaseDir, os);
  3390. unsigned oldLen = oldBaseDir.length();
  3391. clusters.remove(i);
  3392. if (oldLen && strncmp(directory, oldBaseDir, oldLen)==0 && (directory[oldLen]==pathSepChar || directory[oldLen]=='\0'))
  3393. {
  3394. StringBuffer newBaseDir;
  3395. clusters.item(0).getBaseDir(newBaseDir, os);
  3396. newBaseDir.append(directory.get() + oldBaseDir.length());
  3397. directory.set(newBaseDir);
  3398. }
  3399. saveClusters();
  3400. return true;
  3401. }
  3402. return false;
  3403. }
  3404. virtual void setPreferredClusters(const char *clusterlist) override
  3405. {
  3406. clusters.setPreferred(clusterlist,CDistributedFileBase<IDistributedFile>::logicalName);
  3407. }
  3408. INode *queryNode(unsigned idx,unsigned copy)
  3409. {
  3410. unsigned rep;
  3411. unsigned cluster = copyClusterNum(idx,copy,&rep);
  3412. if (cluster==NotFound)
  3413. return queryNullNode();
  3414. unsigned nn;
  3415. unsigned dn;
  3416. IGroup *grp = clusters.queryGroup(cluster);
  3417. if (!grp)
  3418. return queryNullNode();
  3419. if (!clusters.item(cluster).queryPartDiskMapping().calcPartLocation (idx, numParts(),rep, grp->ordinality(), nn, dn))
  3420. return queryNullNode();
  3421. return &grp->queryNode(nn);
  3422. }
  3423. unsigned queryDrive(unsigned idx,unsigned copy,const char *dir)
  3424. {
  3425. // this is odd routine
  3426. unsigned dn = dir?getPathDrive(dir):0;
  3427. if (dn)
  3428. return dn;
  3429. unsigned rep;
  3430. unsigned cluster = copyClusterNum(idx,copy,&rep);
  3431. if (cluster==NotFound)
  3432. return 0;
  3433. unsigned nn;
  3434. IGroup *grp = clusters.queryGroup(cluster);
  3435. if (!grp)
  3436. return 0;
  3437. if (!clusters.item(cluster).queryPartDiskMapping().calcPartLocation (idx, numParts(),rep, grp->ordinality(), nn, dn))
  3438. return 0;
  3439. return dn;
  3440. }
  3441. virtual StringBuffer &getClusterName(unsigned clusternum,StringBuffer &name) override
  3442. {
  3443. return clusters.getName(clusternum,name);
  3444. }
  3445. unsigned copyClusterNum(unsigned part, unsigned copy,unsigned *replicate)
  3446. {
  3447. return clusters.copyNum(part,copy, numParts(),replicate);
  3448. }
  3449. virtual ClusterPartDiskMapSpec &queryPartDiskMapping(unsigned clusternum) override
  3450. {
  3451. assertex(clusternum<clusters.ordinality());
  3452. return clusters.queryPartDiskMapping(clusternum);
  3453. }
  3454. virtual void updatePartDiskMapping(const char *clustername,const ClusterPartDiskMapSpec &spec) override
  3455. {
  3456. CClustersLockedSection cls(CDistributedFileBase<IDistributedFile>::logicalName, true);
  3457. reloadClusters();
  3458. unsigned i = findCluster(clustername);
  3459. if (i!=NotFound) {
  3460. clusters.updatePartDiskMapping(i,spec);
  3461. saveClusters();
  3462. }
  3463. }
  3464. virtual IGroup *queryClusterGroup(unsigned clusternum) override
  3465. {
  3466. return clusters.queryGroup(clusternum);
  3467. }
  3468. virtual StringBuffer &getClusterGroupName(unsigned clusternum, StringBuffer &name) override
  3469. {
  3470. return clusters.item(clusternum).getGroupName(name, &queryNamedGroupStore());
  3471. }
  3472. virtual unsigned numCopies(unsigned partno) override
  3473. {
  3474. return clusters.numCopies(partno,numParts());
  3475. }
  3476. virtual void setSingleClusterOnly() override
  3477. {
  3478. clusters.setSingleClusterOnly();
  3479. }
  3480. unsigned numClusterCopies(unsigned cnum,unsigned partnum)
  3481. {
  3482. IClusterInfo &cluster = clusters.item(cnum);
  3483. IGroup *grp = cluster.queryGroup();
  3484. return cluster.queryPartDiskMapping().numCopies(partnum,grp?grp->ordinality():1,numParts());
  3485. }
  3486. void adjustClusterDir(unsigned partno,unsigned copy, StringBuffer &path)
  3487. {
  3488. // this corrects the directory for a copy
  3489. // assumes default dir matches one of clusters
  3490. unsigned rep=0;
  3491. unsigned cluster = NotFound;
  3492. const char *ds = path.str();
  3493. unsigned nc = clusters.ordinality();
  3494. if (nc>1) {
  3495. StringAttr matched;
  3496. StringAttr toadd;
  3497. unsigned i=0;
  3498. bool c = 0;
  3499. int cp = (int)copy;
  3500. while (i<nc) {
  3501. StringBuffer dcmp;
  3502. clusters.item(i).getBaseDir(dcmp,SepCharBaseOs(getPathSepChar(ds))); // no trailing sep
  3503. const char *t = dcmp.str();
  3504. const char *d = ds;
  3505. while (*d&&(*t==*d)) {
  3506. d++;
  3507. t++;
  3508. }
  3509. if (!*t&&(!*d||isPathSepChar(*d))&&(dcmp.length()>matched.length()))
  3510. matched.set(dcmp);
  3511. unsigned mc = numClusterCopies(i,partno);
  3512. if ((cp>=0)&&(cp<(int)mc)) {
  3513. toadd.set(dcmp);
  3514. rep = (unsigned)cp;
  3515. cluster = i;
  3516. }
  3517. cp -= mc;
  3518. i++;
  3519. }
  3520. if (!matched.isEmpty()&&!toadd.isEmpty()&&(strcmp(matched,toadd)!=0)) {
  3521. StringBuffer tmp(toadd);
  3522. tmp.append(ds+matched.length());
  3523. path.swapWith(tmp);
  3524. }
  3525. }
  3526. else {
  3527. rep = copy;
  3528. cluster = 0;
  3529. }
  3530. // now set replicate
  3531. if (cluster!=NotFound) {
  3532. unsigned n;
  3533. unsigned d;
  3534. ClusterPartDiskMapSpec& mspec = clusters.item(cluster).queryPartDiskMapping();
  3535. mspec.calcPartLocation(partno,numParts(),rep,clusters.queryGroup(cluster)?clusters.queryGroup(cluster)->ordinality():numParts(),n,d);
  3536. if ((d==1) && (mspec.flags&CPDMSF_overloadedConfig) && mspec.defaultReplicateDir.length())
  3537. path.set(mspec.defaultReplicateDir.get());
  3538. else
  3539. setReplicateFilename(path,d);
  3540. }
  3541. }
  3542. void setParts(IFileDescriptor *fdesc,bool save)
  3543. {
  3544. unsigned np = fdesc->numParts();
  3545. for (unsigned i = 0;i<np;i++) {
  3546. CDistributedFilePart &part = *new CDistributedFilePart(*this,i,fdesc->queryPart(i));
  3547. parts.append(part);
  3548. }
  3549. if (save) {
  3550. root->setPropInt("@numparts",parts.ordinality());
  3551. savePartsAttr(true);
  3552. }
  3553. }
  3554. virtual unsigned numParts() override
  3555. {
  3556. return parts.ordinality();
  3557. }
  3558. virtual IDistributedFilePart &queryPart(unsigned idx) override
  3559. {
  3560. if (idx<parts.ordinality())
  3561. return queryParts().item(idx);
  3562. return *(IDistributedFilePart *)NULL;
  3563. }
  3564. virtual IDistributedFilePart* getPart(unsigned idx) override
  3565. {
  3566. if (idx>=parts.ordinality())
  3567. return NULL;
  3568. IDistributedFilePart *ret = &queryParts().item(idx);
  3569. return LINK(ret);
  3570. }
  3571. virtual IDistributedFilePartIterator *getIterator(IDFPartFilter *filter=NULL) override
  3572. {
  3573. return new CDistributedFilePartIterator(queryParts(),filter);
  3574. }
  3575. virtual void rename(const char *_logicalname,IUserDescriptor *user) override
  3576. {
  3577. StringBuffer prevname;
  3578. Owned<IFileRelationshipIterator> reliter;
  3579. // set prevname
  3580. if (!isAnon()) {
  3581. getLogicalName(prevname);
  3582. try {
  3583. IFileRelationshipIterator *iter = parent->lookupAllFileRelationships(prevname.str());
  3584. reliter.setown(iter);
  3585. }
  3586. catch (IException *e) {
  3587. EXCLOG(e,"CDistributedFile::rename");
  3588. e->Release();
  3589. }
  3590. detachLogical();
  3591. }
  3592. attach(_logicalname,user);
  3593. if (prevname.length()) {
  3594. DistributedFilePropertyLock lock(this);
  3595. IPropertyTree &pt = queryAttributes();
  3596. StringBuffer list;
  3597. if (pt.getProp("@renamedFrom",list)&&list.length())
  3598. list.append(',');
  3599. pt.setProp("@renamedFrom",list.append(prevname).str());
  3600. }
  3601. if (reliter.get()) {
  3602. // add back any relationships with new name
  3603. parent->renameFileRelationships(prevname.str(),_logicalname,reliter,user);
  3604. }
  3605. }
  3606. virtual const char *queryDefaultDir() override
  3607. {
  3608. CriticalBlock block (sect);
  3609. return directory.get();
  3610. }
  3611. virtual const char *queryPartMask() override
  3612. {
  3613. CriticalBlock block (sect);
  3614. if (partmask.isEmpty()) {
  3615. assertex(root);
  3616. partmask.set(root->queryProp("@partmask"));
  3617. }
  3618. return partmask.get();
  3619. }
  3620. bool isAnon()
  3621. {
  3622. return (!logicalName.isSet());
  3623. }
  3624. virtual void attach(const char *_logicalname,IUserDescriptor *user) override
  3625. {
  3626. CriticalBlock block (sect);
  3627. assertex(isAnon()); // already attached!
  3628. logicalName.set(_logicalname);
  3629. if (!checkLogicalName(logicalName,user,true,true,true,"attach"))
  3630. return; // query
  3631. #ifdef EXTRA_LOGGING
  3632. PROGLOG("CDistributedFile::attach(%s)",_logicalname);
  3633. LOGPTREE("CDistributedFile::attach root.1",root);
  3634. #endif
  3635. parent->addEntry(logicalName,root.getClear(),false,false);
  3636. killParts();
  3637. clusters.kill();
  3638. CFileLock fcl;
  3639. verifyex(fcl.init(logicalName, DXB_File, RTM_LOCK_READ, defaultTimeout, "CDistributedFile::attach"));
  3640. conn.setown(fcl.detach());
  3641. root.setown(conn->getRoot());
  3642. root->queryBranch("."); // load branch
  3643. Owned<IFileDescriptor> fdesc = deserializeFileDescriptorTree(root,&queryNamedGroupStore(),0);
  3644. setFileAttrs(fdesc,false);
  3645. setClusters(fdesc);
  3646. setParts(fdesc,false);
  3647. setUserDescriptor(udesc, user);
  3648. #ifdef EXTRA_LOGGING
  3649. LOGFDESC("CDistributedFile::attach fdesc",fdesc);
  3650. LOGPTREE("CDistributedFile::attach root.2",root);
  3651. #endif
  3652. }
  3653. /*
  3654. * Internal method (not in IDistributedFile interface) that is used
  3655. * when renaming files (so don't delete the physical representation).
  3656. *
  3657. * This is also used during CPPUINT tests, so we need to make them public
  3658. * only when tests are enabled (ie. non-production mode).
  3659. *
  3660. * See removeLogical()
  3661. */
  3662. public:
  3663. void detachLogical(unsigned timeoutms=INFINITE)
  3664. {
  3665. detach(timeoutms, false, NULL);
  3666. }
  3667. public:
  3668. virtual void detach(unsigned timeoutMs=INFINITE, ICodeContext *ctx=NULL) override
  3669. {
  3670. detach(timeoutMs, true, ctx);
  3671. }
  3672. virtual bool existsPhysicalPartFiles(unsigned short port) override
  3673. {
  3674. unsigned width = numParts();
  3675. CriticalSection errcrit;
  3676. class casyncfor: public CAsyncFor
  3677. {
  3678. IDistributedFile *file;
  3679. unsigned short port;
  3680. CriticalSection &errcrit;
  3681. unsigned width;
  3682. public:
  3683. bool ok;
  3684. casyncfor(IDistributedFile *_file,unsigned _width,unsigned short _port,CriticalSection &_errcrit)
  3685. : errcrit(_errcrit)
  3686. {
  3687. file = _file;
  3688. port = _port;
  3689. ok = true;
  3690. width = _width;
  3691. ok = true;
  3692. }
  3693. void Do(unsigned i)
  3694. {
  3695. {
  3696. CriticalBlock block(errcrit);
  3697. if (!ok)
  3698. return;
  3699. }
  3700. Owned<IDistributedFilePart> part = file->getPart(i);
  3701. unsigned nc = part->numCopies();
  3702. for (unsigned copy = 0; copy < nc; copy++)
  3703. {
  3704. RemoteFilename rfn;
  3705. part->getFilename(rfn,copy);
  3706. if (port)
  3707. rfn.setPort(port); // if daliservix
  3708. Owned<IFile> partfile = createIFile(rfn);
  3709. try
  3710. {
  3711. if (partfile->exists())
  3712. return;
  3713. }
  3714. catch (IException *e)
  3715. {
  3716. CriticalBlock block(errcrit);
  3717. StringBuffer s("Failed to find file part ");
  3718. s.append(partfile->queryFilename()).append(" on ");
  3719. rfn.queryEndpoint().getUrlStr(s);
  3720. EXCLOG(e, s.str());
  3721. e->Release();
  3722. }
  3723. }
  3724. CriticalBlock block(errcrit);
  3725. ok = false;
  3726. }
  3727. } afor(this,width,port,errcrit);
  3728. afor.For(width,10,false,true);
  3729. return afor.ok;
  3730. }
  3731. // This method takes an existing physical directory path for a logical file
  3732. // and a constructed path to the same logical file created in this context
  3733. // and deduces the original base path e.g. /var/lib/HPCCSystems/hpcc-data/thor
  3734. // This is necessary, because there is no not enough context to directly fetch the
  3735. // original base path to construct new paths for the rename
  3736. bool getBase(const char *oldPath, const char *thisPath, StringBuffer &baseDir)
  3737. {
  3738. const char *oldEnd = oldPath+strlen(oldPath)-1;
  3739. const char *thisEnd = thisPath+strlen(thisPath)-1;
  3740. if (isPathSepChar(*oldEnd))
  3741. oldEnd--;
  3742. if (isPathSepChar(*thisEnd))
  3743. thisEnd--;
  3744. const char *oldP = oldEnd, *thisP = thisEnd;
  3745. for (;;) {
  3746. if (oldP==oldPath || thisP==thisPath)
  3747. break;
  3748. if (*oldP != *thisP) {
  3749. // unless last was separator, continue until find one
  3750. if (isPathSepChar(*(oldP+1)))
  3751. oldP++;
  3752. else {
  3753. while (oldP != oldPath && (!isPathSepChar(*oldP)))
  3754. oldP--;
  3755. }
  3756. baseDir.append(oldP-oldPath, oldPath);
  3757. return true;
  3758. }
  3759. --oldP;
  3760. --thisP;
  3761. }
  3762. return false;
  3763. }
  3764. virtual bool renamePhysicalPartFiles(const char *newname,
  3765. const char *cluster,
  3766. IMultiException *mexcept,
  3767. const char *newbasedir) override
  3768. {
  3769. // cluster TBD
  3770. unsigned width = numParts();
  3771. StringBuffer newdir;
  3772. StringBuffer newmask;
  3773. const char *diroverride = NULL;
  3774. char psc = getPathSepChar(directory.get());
  3775. DFD_OS os = SepCharBaseOs(psc);
  3776. StringBuffer basedir;
  3777. const char *myBase;
  3778. if (newbasedir)
  3779. {
  3780. diroverride = newbasedir;
  3781. myBase = newbasedir;
  3782. }
  3783. else
  3784. myBase = queryBaseDirectory(grp_unknown, 0, os);
  3785. StringBuffer baseDir, newPath;
  3786. makePhysicalPartName(logicalName.get(), 0, 0, newPath, false, os, diroverride);
  3787. if (!getBase(directory, newPath, baseDir))
  3788. baseDir.append(myBase); // getBase returns false, if directory==newPath, so have common base
  3789. getPartMask(newmask,newname,width);
  3790. if (newmask.length()==0)
  3791. return false;
  3792. makePhysicalPartName(newname, 0, 0, newPath.clear(), false, os, diroverride);
  3793. if (newPath.length()==0)
  3794. return false;
  3795. if (isPathSepChar(newPath.charAt(newPath.length()-1)))
  3796. newPath.setLength(newPath.length()-1);
  3797. newPath.remove(0, strlen(myBase));
  3798. newdir.append(baseDir).append(newPath);
  3799. StringBuffer fullname;
  3800. CIArrayOf<CIStringArray> newNames;
  3801. unsigned i;
  3802. for (i=0;i<width;i++) {
  3803. newNames.append(*new CIStringArray);
  3804. CDistributedFilePart &part = parts.item(i);
  3805. for (unsigned copy=0; copy<part.numCopies(); copy++) {
  3806. makePhysicalPartName(newname, i+1, width, newPath.clear(), false, os, myBase);
  3807. newPath.remove(0, strlen(myBase));
  3808. StringBuffer copyDir(baseDir);
  3809. adjustClusterDir(i, copy, copyDir);
  3810. fullname.clear().append(copyDir).append(newPath);
  3811. newNames.item(i).append(fullname);
  3812. }
  3813. }
  3814. // NB: the code below, specifically deals with 1 primary + 1 replicate
  3815. // it will need refactoring if it's to deal with multiple clusters/copies
  3816. // first check file doestn't exist for any new part
  3817. CriticalSection crit;
  3818. class casyncforbase: public CAsyncFor
  3819. {
  3820. protected:
  3821. CriticalSection &crit;
  3822. CIArrayOf<CIStringArray> &newNames;
  3823. IDistributedFile *file;
  3824. unsigned width;
  3825. IMultiException *mexcept;
  3826. bool *ignoreprim;
  3827. bool *ignorerep;
  3828. public:
  3829. bool ok;
  3830. bool * doneprim;
  3831. bool * donerep;
  3832. IException *except;
  3833. casyncforbase(IDistributedFile *_file,CIArrayOf<CIStringArray> &_newNames,unsigned _width,IMultiException *_mexcept,CriticalSection &_crit,bool *_ignoreprim,bool *_ignorerep)
  3834. : newNames(_newNames),crit(_crit)
  3835. {
  3836. width = _width;
  3837. file = _file;
  3838. ok = true;
  3839. mexcept = _mexcept;
  3840. doneprim = (bool *)calloc(sizeof(bool),width);
  3841. donerep = (bool *)calloc(sizeof(bool),width);
  3842. except = NULL;
  3843. ignoreprim = _ignoreprim;
  3844. ignorerep = _ignorerep;
  3845. }
  3846. ~casyncforbase()
  3847. {
  3848. free(doneprim);
  3849. free(donerep);
  3850. }
  3851. virtual bool doPart(IDistributedFilePart *,bool,RemoteFilename &,RemoteFilename &, bool &)
  3852. #ifdef _WIN32
  3853. {
  3854. assertex(!"doPart"); // stupid microsoft error
  3855. return false;
  3856. }
  3857. #else
  3858. = 0;
  3859. #endif
  3860. void Do(unsigned idx)
  3861. {
  3862. {
  3863. CriticalBlock block(crit);
  3864. if (!ok)
  3865. return;
  3866. }
  3867. Owned<IDistributedFilePart> part = file->getPart(idx);
  3868. unsigned copies = part->numCopies();
  3869. for (int copy = copies-1; copy>=0; copy--)
  3870. {
  3871. if ((copy==0)&&ignoreprim&&ignoreprim[idx])
  3872. continue;
  3873. if ((copy!=0)&&ignorerep&&ignorerep[idx])
  3874. continue;
  3875. bool pok=false;
  3876. IException *ex = NULL;
  3877. RemoteFilename oldrfn;
  3878. part->getFilename(oldrfn,(unsigned)copy);
  3879. const char *newfn = newNames.item(idx).item(copy);
  3880. if (!newfn||!*newfn)
  3881. continue;
  3882. RemoteFilename newrfn;
  3883. newrfn.setPath(part->queryNode(copy)->endpoint(),newfn);
  3884. try {
  3885. pok = doPart(part,copy!=0,oldrfn,newrfn,(copy==0)?doneprim[idx]:donerep[idx]);
  3886. }
  3887. catch (IException *e) {
  3888. EXCLOG(e, NULL);
  3889. ex = e;
  3890. }
  3891. CriticalBlock block(crit);
  3892. if (!pok||ex) {
  3893. ok = false;
  3894. if (ex) {
  3895. StringBuffer s("renamePhysicalPartFiles ");
  3896. s.append(file->queryLogicalName()).append(" part ").append(newfn);
  3897. EXCLOG(ex, s.str());
  3898. if (mexcept)
  3899. mexcept->append(*ex);
  3900. else {
  3901. if (except)
  3902. ex->Release();
  3903. else
  3904. except = ex;
  3905. }
  3906. }
  3907. }
  3908. }
  3909. }
  3910. };
  3911. class casyncfor1: public casyncforbase
  3912. {
  3913. public:
  3914. casyncfor1(IDistributedFile *_file,CIArrayOf<CIStringArray> &_newNames,unsigned _width,IMultiException *_mexcept,CriticalSection &_crit,bool *_ignoreprim,bool *_ignorerep)
  3915. : casyncforbase(_file,_newNames,_width,_mexcept,_crit,_ignoreprim,_ignorerep)
  3916. {
  3917. }
  3918. bool doPart(IDistributedFilePart *part,bool isrep,RemoteFilename &oldrfn,RemoteFilename &newrfn, bool &done)
  3919. {
  3920. done = false;
  3921. Owned<IFile> src = createIFile(oldrfn);
  3922. if (src->exists())
  3923. done = true;
  3924. else {
  3925. StringBuffer s;
  3926. oldrfn.getRemotePath(s);
  3927. DBGLOG("renamePhysicalPartFiles: %s doesn't exist",s.str());
  3928. return true;
  3929. }
  3930. Owned<IFile> dest = createIFile(newrfn);
  3931. StringBuffer newname;
  3932. newrfn.getRemotePath(newname);
  3933. if (dest->exists()) {
  3934. IDFS_Exception *e = new CDFS_Exception(DFSERR_PhysicalPartAlreadyExists,newname.str());
  3935. throw e;
  3936. }
  3937. // check destination directory exists
  3938. StringBuffer newdir;
  3939. splitDirTail(newname.str(),newdir);
  3940. Owned<IFile> destdir = createIFile(newdir.str());
  3941. destdir->createDirectory();
  3942. return true;
  3943. }
  3944. } afor1 (this,newNames,width,mexcept,crit,NULL,NULL);
  3945. afor1.For(width,10,false,true);
  3946. if (afor1.except)
  3947. throw afor1.except; // no recovery needed
  3948. if (!afor1.ok)
  3949. return false; // no recovery needed
  3950. MemoryAttr ignorebuf;
  3951. bool *ignoreprim = (bool *)ignorebuf.allocate(width*sizeof(bool)*2);
  3952. bool *ignorerep = ignoreprim+width;
  3953. for (i=0;i<width;i++) {
  3954. if (afor1.donerep[i]) {
  3955. ignorerep[i] = false;
  3956. ignoreprim[i] = !afor1.doneprim[i];
  3957. }
  3958. else if (afor1.doneprim[i]) {
  3959. ignorerep[i] = true;
  3960. ignoreprim[i] = false;
  3961. }
  3962. else {
  3963. StringBuffer s(queryLogicalName());
  3964. s.append(" Part ").append(i+1);
  3965. IDFS_Exception *e = new CDFS_Exception(DFSERR_PhysicalPartDoesntExist,s.str());
  3966. throw e;
  3967. }
  3968. }
  3969. // now do the rename
  3970. class casyncfor2: public casyncforbase
  3971. {
  3972. public:
  3973. casyncfor2(IDistributedFile *_file,CIArrayOf<CIStringArray> &_newNames,unsigned _width,IMultiException *_mexcept,CriticalSection &_crit,bool *_ignoreprim,bool *_ignorerep)
  3974. : casyncforbase(_file,_newNames,_width,_mexcept,_crit,_ignoreprim,_ignorerep)
  3975. {
  3976. }
  3977. bool doPart(IDistributedFilePart *part,bool isrep,RemoteFilename &oldrfn,RemoteFilename &newrfn, bool &done)
  3978. {
  3979. done = false;
  3980. StringBuffer oldfn;
  3981. oldrfn.getRemotePath(oldfn);
  3982. StringBuffer newfn;
  3983. newrfn.getRemotePath(newfn);
  3984. Owned<IFile> f = createIFile(oldrfn);
  3985. if (!isrep||f->exists()) { // ignore non-existant replicates
  3986. f->move(newfn.str());
  3987. PROGLOG("Succeeded rename %s to %s",oldfn.str(),newfn.str());
  3988. }
  3989. done = true;
  3990. return true;;
  3991. }
  3992. } afor2 (this,newNames,width,mexcept,crit,ignoreprim,ignorerep);
  3993. afor2.For(width,10,false,true);
  3994. if (afor2.ok) {
  3995. // now rename directory and partmask
  3996. DistributedFilePropertyLock lock(this);
  3997. root->setProp("@directory",newdir.str());
  3998. root->setProp("@partmask",newmask.str());
  3999. partmask.set(newmask.str());
  4000. directory.set(newdir.str());
  4001. StringBuffer mask;
  4002. for (unsigned i=0;i<width;i++) {
  4003. mask.appendf("Part[%d]/@name",i+1);
  4004. parts.item(i).clearOverrideName();
  4005. }
  4006. savePartsAttr(false);
  4007. }
  4008. else {
  4009. // attempt recovery
  4010. // do this synchronously to maximize chance of success (I don't expect many to have been done)
  4011. for (i=0;i<width;i++) {
  4012. Owned<IDistributedFilePart> part = getPart(i);
  4013. unsigned copies = part->numCopies();
  4014. for (int copy = copies-1; copy>=0; copy--) {
  4015. bool done = (copy==0)?afor2.doneprim[i]:afor2.donerep[i];
  4016. if (done) {
  4017. RemoteFilename oldrfn;
  4018. part->getFilename(oldrfn,(unsigned)copy);
  4019. const char *newfn = newNames.item(i).item(copy);
  4020. if (!newfn||!*newfn)
  4021. continue;
  4022. RemoteFilename newrfn;
  4023. newrfn.setPath(part->queryNode(copy)->endpoint(),newfn);
  4024. for (unsigned t=1;t<3;t++) { // 3 goes
  4025. try {
  4026. StringBuffer oldfn;
  4027. oldrfn.getRemotePath(oldfn);
  4028. StringBuffer newfn;
  4029. newrfn.getRemotePath(newfn);
  4030. Owned<IFile> f = createIFile(newrfn);
  4031. f->move(oldfn.str());
  4032. PROGLOG("Succeeded rename %s back to %s",newfn.str(),oldfn.str());
  4033. break;
  4034. }
  4035. catch (IException *e) {
  4036. if (!afor2.except)
  4037. afor2.except = e;
  4038. else
  4039. e->Release();
  4040. }
  4041. }
  4042. }
  4043. }
  4044. }
  4045. }
  4046. if (afor2.except)
  4047. throw afor2.except;
  4048. return afor2.ok;
  4049. }
  4050. IPropertyTree *queryRoot() { return root; }
  4051. virtual __int64 getFileSize(bool allowphysical,bool forcephysical) override
  4052. {
  4053. __int64 ret = (__int64)(forcephysical?-1:queryAttributes().getPropInt64("@size",-1));
  4054. if (ret==-1)
  4055. {
  4056. ret = 0;
  4057. unsigned n = numParts();
  4058. for (unsigned i=0;i<n;i++)
  4059. {
  4060. Owned<IDistributedFilePart> part = getPart(i);
  4061. __int64 ps = part->getFileSize(allowphysical,forcephysical);
  4062. if (ps == -1)
  4063. {
  4064. ret = ps;
  4065. break;
  4066. }
  4067. ret += ps;
  4068. }
  4069. }
  4070. return ret;
  4071. }
  4072. virtual __int64 getDiskSize(bool allowphysical,bool forcephysical) override
  4073. {
  4074. if (!isCompressed(NULL))
  4075. return getFileSize(allowphysical, forcephysical);
  4076. __int64 ret = (__int64)(forcephysical?-1:queryAttributes().getPropInt64("@compressedSize",-1));
  4077. if (ret==-1)
  4078. {
  4079. ret = 0;
  4080. unsigned n = numParts();
  4081. for (unsigned i=0;i<n;i++)
  4082. {
  4083. Owned<IDistributedFilePart> part = getPart(i);
  4084. __int64 ps = part->getDiskSize(allowphysical,forcephysical);
  4085. if (ps == -1)
  4086. {
  4087. ret = ps;
  4088. break;
  4089. }
  4090. ret += ps;
  4091. }
  4092. }
  4093. return ret;
  4094. }
  4095. virtual bool getFileCheckSum(unsigned &checkSum) override
  4096. {
  4097. if (queryAttributes().hasProp("@checkSum"))
  4098. checkSum = (unsigned)queryAttributes().getPropInt64("@checkSum");
  4099. else
  4100. {
  4101. checkSum = ~0;
  4102. unsigned n = numParts();
  4103. for (unsigned i=0;i<n;i++) {
  4104. Owned<IDistributedFilePart> part = getPart(i);
  4105. unsigned crc;
  4106. if (!part->getCrc(crc))
  4107. return false;
  4108. checkSum ^= crc;
  4109. }
  4110. }
  4111. return true;
  4112. }
  4113. virtual bool getFormatCrc(unsigned &crc) override
  4114. {
  4115. if (queryAttributes().hasProp("@formatCrc")) {
  4116. // NB pre record_layout CRCs are not valid
  4117. crc = (unsigned)queryAttributes().getPropInt("@formatCrc");
  4118. return true;
  4119. }
  4120. return false;
  4121. }
  4122. virtual bool getRecordLayout(MemoryBuffer &layout, const char *attrname) override
  4123. {
  4124. return queryAttributes().getPropBin(attrname, layout);
  4125. }
  4126. virtual bool getRecordSize(size32_t &rsz) override
  4127. {
  4128. if (queryAttributes().hasProp("@recordSize")) {
  4129. rsz = (size32_t)queryAttributes().getPropInt("@recordSize");
  4130. return true;
  4131. }
  4132. return false;
  4133. }
  4134. virtual unsigned getPositionPart(offset_t pos, offset_t &base) override
  4135. {
  4136. unsigned n = numParts();
  4137. base = 0;
  4138. for (unsigned i=0;i<n;i++) {
  4139. Owned<IDistributedFilePart> part = getPart(i);
  4140. offset_t ps = part->getFileSize(true,false);
  4141. if (ps==(offset_t)-1)
  4142. break;
  4143. if (ps>pos)
  4144. return i;
  4145. pos -= ps;
  4146. base += ps;
  4147. }
  4148. return NotFound;
  4149. }
  4150. IDistributedSuperFile *querySuperFile() override
  4151. {
  4152. return NULL; // i.e. this isn't super file
  4153. }
  4154. virtual bool checkClusterCompatible(IFileDescriptor &fdesc, StringBuffer &err) override
  4155. {
  4156. unsigned n = numParts();
  4157. if (fdesc.numParts()!=n) {
  4158. err.appendf("Different cluster width (%d/%d)",n,fdesc.numParts());
  4159. return false;
  4160. }
  4161. if (fdesc.numClusters()!=1) {
  4162. err.append("Cannot merge more than one cluster");
  4163. return false;
  4164. }
  4165. StringBuffer cname;
  4166. fdesc.getClusterLabel(0,cname);
  4167. if (cname.length()&&(findCluster(cname.str())!=NotFound)) {
  4168. err.append("File already contains cluster");
  4169. err.append(cname.str());
  4170. return false;
  4171. }
  4172. StringBuffer pname;
  4173. StringBuffer fdtail;
  4174. for (unsigned pn=0;pn<n;pn++) {
  4175. IDistributedFilePart &part = queryPart(pn);
  4176. part.getPartName(pname.clear());
  4177. fdesc.queryPart(pn)->getTail(fdtail.clear());
  4178. if (strcmp(pname.str(),fdtail.str())!=0) {
  4179. err.appendf("Part name mismatch (%s,%s)",pname.str(),fdtail.str());
  4180. return false;
  4181. }
  4182. RemoteFilename fdrfn;
  4183. fdesc.getFilename(pn,0,fdrfn);
  4184. unsigned nc = numCopies(pn);
  4185. for (unsigned c = 0;c<nc;c++) {
  4186. RemoteFilename rfn;
  4187. part.getFilename(rfn,c);
  4188. if (rfn.equals(fdrfn)) {
  4189. err.appendf("Parts overlap %s and %s",pname.str(),fdtail.str());
  4190. return false;
  4191. }
  4192. }
  4193. }
  4194. return true;
  4195. }
  4196. virtual void enqueueReplicate() override
  4197. {
  4198. MemoryBuffer mb;
  4199. mb.append((byte)DRQ_REPLICATE).append(queryLogicalName());
  4200. udesc->serialize(mb);
  4201. CDateTime filedt;
  4202. getModificationTime(filedt);
  4203. filedt.serialize(mb);
  4204. Owned<INamedQueueConnection> qconn = createNamedQueueConnection(0);
  4205. Owned<IQueueChannel> qchannel = qconn->open(DFS_REPLICATE_QUEUE);
  4206. qchannel->put(mb);
  4207. }
  4208. virtual bool getAccessedTime(CDateTime &dt) override
  4209. {
  4210. StringBuffer str;
  4211. if (!root->getProp("@accessed",str))
  4212. return false;
  4213. dt.setString(str.str());
  4214. return true;
  4215. }
  4216. virtual void setAccessedTime(const CDateTime &dt) override
  4217. {
  4218. if (logicalName.isForeign())
  4219. parent->setFileAccessed(logicalName,udesc,dt);
  4220. else
  4221. {
  4222. CFileAttrLock attrLock;
  4223. if (conn)
  4224. {
  4225. if (!attrLock.init(logicalName, DXB_File, RTM_LOCK_WRITE, conn, defaultTimeout, "CDistributedFile::setAccessedTime"))
  4226. {
  4227. // In unlikely event File/Attr doesn't exist, must ensure created, commited and root connection is reloaded.
  4228. verifyex(attrLock.init(logicalName, DXB_File, RTM_LOCK_WRITE|RTM_CREATE_QUERY, conn, defaultTimeout, "CDistributedFile::setAccessedTime"));
  4229. attrLock.commit();
  4230. conn->commit();
  4231. conn->reload();
  4232. root.setown(conn->getRoot());
  4233. }
  4234. }
  4235. if (dt.isNull())
  4236. queryAttributes().removeProp("@accessed");
  4237. else
  4238. {
  4239. StringBuffer str;
  4240. queryAttributes().setProp("@accessed",dt.getString(str).str());
  4241. }
  4242. }
  4243. }
  4244. virtual void setAccessed() override
  4245. {
  4246. CDateTime dt;
  4247. dt.setNow();
  4248. setAccessedTime(dt);
  4249. }
  4250. virtual void validate() override
  4251. {
  4252. if (!existsPhysicalPartFiles(0))
  4253. {
  4254. const char * logicalName = queryLogicalName();
  4255. throw MakeStringException(-1, "Some physical parts do not exists, for logical file : %s",(isEmptyString(logicalName) ? "[unattached]" : logicalName));
  4256. }
  4257. }
  4258. };
  4259. static unsigned findSubFileOrd(const char *name)
  4260. {
  4261. if (*name=='#') {
  4262. const char *n = name+1;
  4263. if (*n) {
  4264. do { n++; } while (*n&&isdigit(*n));
  4265. if (!*n)
  4266. return atoi(name+1)-1;
  4267. }
  4268. }
  4269. return NotFound;
  4270. }
  4271. class CDistributedSuperFile: public CDistributedFileBase<IDistributedSuperFile>
  4272. {
  4273. void checkNotForeign()
  4274. {
  4275. if (!conn)
  4276. throw MakeStringException(-1,"Operation not allowed on foreign file");
  4277. }
  4278. CDistributedFilePartArray partscache;
  4279. FileClusterInfoArray clusterscache;
  4280. /**
  4281. * Adds a sub-file to a super-file within a transaction.
  4282. */
  4283. class cAddSubFileAction: public CDFAction
  4284. {
  4285. StringAttr parentlname;
  4286. Owned<IDistributedSuperFile> parent;
  4287. Owned<IDistributedFile> sub;
  4288. StringAttr subfile;
  4289. bool before;
  4290. StringAttr other;
  4291. public:
  4292. cAddSubFileAction(const char *_parentlname,const char *_subfile,bool _before,const char *_other)
  4293. : parentlname(_parentlname), subfile(_subfile), before(_before), other(_other)
  4294. {
  4295. }
  4296. virtual bool prepare()
  4297. {
  4298. parent.setown(transaction->lookupSuperFile(parentlname));
  4299. if (!parent)
  4300. throw MakeStringException(-1,"addSubFile: SuperFile %s cannot be found",parentlname.get());
  4301. if (!subfile.isEmpty())
  4302. {
  4303. try
  4304. {
  4305. sub.setown(transaction->lookupFile(subfile,SDS_SUB_LOCK_TIMEOUT));
  4306. if (!sub)
  4307. throw MakeStringException(-1,"cAddSubFileAction: sub file %s not found", subfile.str());
  4308. // Must validate before locking for update below, to check sub is not already in parent (and therefore locked already)
  4309. transaction->validateAddSubFile(parent, sub, subfile);
  4310. }
  4311. catch (ISDSException *e)
  4312. {
  4313. if (e->errorCode()!=SDSExcpt_LockTimeout)
  4314. throw;
  4315. e->Release();
  4316. return false;
  4317. }
  4318. if (!sub.get())
  4319. throw MakeStringException(-1,"addSubFile: File %s cannot be found to add",subfile.get());
  4320. }
  4321. // Try to lock all files
  4322. addFileLock(parent);
  4323. if (lock())
  4324. {
  4325. transaction->noteAddSubFile(parent, parentlname, sub);
  4326. return true;
  4327. }
  4328. unlock();
  4329. parent.clear();
  4330. sub.clear();
  4331. return false;
  4332. }
  4333. virtual void run()
  4334. {
  4335. if (!sub)
  4336. throw MakeStringException(-1,"addSubFile(2): File %s cannot be found to add",subfile.get());
  4337. CDistributedSuperFile *sf = QUERYINTERFACE(parent.get(),CDistributedSuperFile);
  4338. if (sf)
  4339. sf->doAddSubFile(LINK(sub),before,other,transaction);
  4340. }
  4341. virtual void commit()
  4342. {
  4343. CDistributedSuperFile *sf = QUERYINTERFACE(parent.get(),CDistributedSuperFile);
  4344. if (sf)
  4345. sf->updateParentFileAttrs(transaction);
  4346. CDFAction::commit();
  4347. }
  4348. virtual void retry()
  4349. {
  4350. parent.clear();
  4351. sub.clear();
  4352. CDFAction::retry();
  4353. }
  4354. };
  4355. /**
  4356. * Removes a sub-file of a super-file within a transaction.
  4357. */
  4358. class cRemoveSubFileAction: public CDFAction
  4359. {
  4360. StringAttr parentlname;
  4361. Owned<IDistributedSuperFile> parent;
  4362. Owned<IDistributedFile> sub;
  4363. StringAttr subfile;
  4364. bool remsub;
  4365. public:
  4366. cRemoveSubFileAction(const char *_parentlname,const char *_subfile,bool _remsub=false)
  4367. : parentlname(_parentlname), subfile(_subfile), remsub(_remsub)
  4368. {
  4369. }
  4370. virtual bool prepare()
  4371. {
  4372. parent.setown(transaction->lookupSuperFile(parentlname));
  4373. if (!parent)
  4374. throw MakeStringException(-1,"removeSubFile: SuperFile %s cannot be found",parentlname.get());
  4375. if (!subfile.isEmpty())
  4376. {
  4377. try
  4378. {
  4379. sub.setown(transaction->lookupFile(subfile,SDS_SUB_LOCK_TIMEOUT));
  4380. }
  4381. catch (ISDSException *e)
  4382. {
  4383. if (e->errorCode()!=SDSExcpt_LockTimeout)
  4384. throw;
  4385. e->Release();
  4386. return false;
  4387. }
  4388. if (!transaction->isSubFile(parent, subfile, true))
  4389. {
  4390. IWARNLOG("removeSubFile: File %s is not a subfile of %s", subfile.get(), parent->queryLogicalName());
  4391. parent.clear();
  4392. sub.clear();
  4393. return true; // NB: sub was not a member of super, issue warning and continue without locking
  4394. }
  4395. }
  4396. // Try to lock all files
  4397. addFileLock(parent);
  4398. if (sub && remsub) // NB: I only need to lock (for exclusivity, if going to delete
  4399. addFileLock(sub);
  4400. if (lock())
  4401. {
  4402. if (sub)
  4403. transaction->noteRemoveSubFile(parent, sub);
  4404. else
  4405. transaction->clearSubFiles(parent);
  4406. return true;
  4407. }
  4408. unlock();
  4409. parent.clear();
  4410. sub.clear();
  4411. return false;
  4412. }
  4413. virtual void run()
  4414. {
  4415. CDistributedSuperFile *sf = QUERYINTERFACE(parent.get(),CDistributedSuperFile);
  4416. if (sf) {
  4417. // Delay the deletion of the subs until commit
  4418. if (remsub) {
  4419. if (subfile) {
  4420. CDfsLogicalFileName lname;
  4421. lname.set(subfile.get());
  4422. transaction->addDelayedDelete(lname, SDS_SUB_LOCK_TIMEOUT);
  4423. } else { // Remove all subfiles
  4424. Owned<IDistributedFileIterator> iter = parent->getSubFileIterator(false);
  4425. ForEach (*iter) {
  4426. CDfsLogicalFileName lname;
  4427. IDistributedFile *f = &iter->query();
  4428. lname.set(f->queryLogicalName());
  4429. transaction->addDelayedDelete(lname, SDS_SUB_LOCK_TIMEOUT);
  4430. }
  4431. }
  4432. }
  4433. // Now we clean the subs
  4434. if (subfile.get())
  4435. sf->doRemoveSubFile(subfile.get(), transaction);
  4436. else
  4437. sf->doRemoveSubFiles(transaction);
  4438. }
  4439. }
  4440. virtual void retry()
  4441. {
  4442. parent.clear();
  4443. sub.clear();
  4444. CDFAction::retry();
  4445. }
  4446. };
  4447. /**
  4448. * Removes all subfiles exclusively owned by named superfile within a transaction.
  4449. */
  4450. class cRemoveOwnedSubFilesAction: public CDFAction
  4451. {
  4452. StringAttr parentlname;
  4453. Owned<IDistributedSuperFile> parent;
  4454. bool remsub;
  4455. public:
  4456. cRemoveOwnedSubFilesAction(IDistributedFileTransaction *_transaction, const char *_parentlname,bool _remsub=false)
  4457. : parentlname(_parentlname), remsub(_remsub)
  4458. {
  4459. }
  4460. virtual bool prepare()
  4461. {
  4462. parent.setown(transaction->lookupSuperFile(parentlname));
  4463. if (!parent)
  4464. throw MakeStringException(-1,"removeOwnedSubFiles: SuperFile %s cannot be found", parentlname.get());
  4465. // Try to lock all files
  4466. addFileLock(parent);
  4467. if (lock())
  4468. return true;
  4469. unlock();
  4470. parent.clear();
  4471. return false;
  4472. }
  4473. virtual void run()
  4474. {
  4475. CDistributedSuperFile *sf = QUERYINTERFACE(parent.get(),CDistributedSuperFile);
  4476. if (sf)
  4477. {
  4478. StringArray toRemove;
  4479. Owned<IDistributedFileIterator> iter = parent->getSubFileIterator(false);
  4480. ForEach (*iter)
  4481. {
  4482. IDistributedFile *file = &iter->query();
  4483. IDistributedSuperFile *super = file->querySuperFile();
  4484. StringArray owners;
  4485. if (super)
  4486. {
  4487. CDistributedSuperFile *_super = QUERYINTERFACE(super, CDistributedSuperFile);
  4488. if (_super)
  4489. _super->getSuperOwners(owners);
  4490. }
  4491. else
  4492. {
  4493. CDistributedFile *_file = QUERYINTERFACE(file, CDistributedFile);
  4494. if (_file)
  4495. _file->getSuperOwners(owners);
  4496. }
  4497. if (NotFound == owners.find(parentlname))
  4498. ThrowStringException(-1, "removeOwnedSubFiles: SuperFile %s, subfile %s - subfile not owned by superfile", parentlname.get(), file->queryLogicalName());
  4499. if (1 == owners.ordinality()) // just me
  4500. {
  4501. const char *logicalName = file->queryLogicalName();
  4502. toRemove.append(logicalName);
  4503. // Delay the deletion of the subs until commit
  4504. if (remsub)
  4505. {
  4506. CDfsLogicalFileName lname;
  4507. lname.set(logicalName);
  4508. transaction->addDelayedDelete(lname, SDS_SUB_LOCK_TIMEOUT);
  4509. }
  4510. }
  4511. }
  4512. // Now we clean the subs
  4513. if (sf->numSubFiles(false) == toRemove.ordinality())
  4514. sf->doRemoveSubFiles(transaction); // remove all
  4515. else
  4516. {
  4517. ForEachItemIn(r, toRemove)
  4518. sf->doRemoveSubFile(toRemove.item(r), transaction);
  4519. }
  4520. }
  4521. }
  4522. virtual void retry()
  4523. {
  4524. parent.clear();
  4525. CDFAction::retry();
  4526. }
  4527. };
  4528. /**
  4529. * Swaps sub-files between two super-files within a transaction.
  4530. */
  4531. class cSwapFileAction: public CDFAction
  4532. {
  4533. Linked<IDistributedSuperFile> super1, super2;
  4534. StringAttr super1Name, super2Name;
  4535. public:
  4536. cSwapFileAction(const char *_super1Name, const char *_super2Name)
  4537. : super1Name(_super1Name), super2Name(_super2Name)
  4538. {
  4539. }
  4540. virtual bool prepare()
  4541. {
  4542. super1.setown(transaction->lookupSuperFile(super1Name));
  4543. if (!super1)
  4544. throw MakeStringException(-1,"swapSuperFile: SuperFile %s cannot be found", super1Name.get());
  4545. super2.setown(transaction->lookupSuperFile(super2Name));
  4546. if (!super2)
  4547. {
  4548. super1.clear();
  4549. throw MakeStringException(-1,"swapSuperFile: SuperFile %s cannot be found", super2Name.get());
  4550. }
  4551. // Try to lock all files
  4552. addFileLock(super1);
  4553. for (unsigned i=0; i<super1->numSubFiles(); i++)
  4554. addFileLock(&super1->querySubFile(i));
  4555. addFileLock(super2);
  4556. for (unsigned i=0; i<super2->numSubFiles(); i++)
  4557. addFileLock(&super2->querySubFile(i));
  4558. if (lock())
  4559. {
  4560. transaction->noteSuperSwap(super1, super2);
  4561. return true;
  4562. }
  4563. unlock();
  4564. super1.clear();
  4565. super2.clear();
  4566. return false;
  4567. }
  4568. virtual void run()
  4569. {
  4570. CDistributedSuperFile *sf = QUERYINTERFACE(super1.get(),CDistributedSuperFile);
  4571. if (sf)
  4572. sf->doSwapSuperFile(super2,transaction);
  4573. }
  4574. virtual void retry()
  4575. {
  4576. super1.clear();
  4577. super2.clear();
  4578. CDFAction::retry();
  4579. }
  4580. };
  4581. /**
  4582. * SubFile Iterator, used only to list sub-files of a super-file.
  4583. */
  4584. class cSubFileIterator: public CDistributedFileIteratorBase< IDistributedFileIterator, IArrayOf<IDistributedFile> >
  4585. {
  4586. public:
  4587. cSubFileIterator(IArrayOf<IDistributedFile> &_subfiles, bool supersub)
  4588. {
  4589. ForEachItemIn(i,_subfiles) {
  4590. IDistributedSuperFile* super = supersub?_subfiles.item(i).querySuperFile():NULL;
  4591. if (super) {
  4592. Owned<IDistributedFileIterator> iter = super->getSubFileIterator(true);
  4593. ForEach(*iter)
  4594. list.append(iter->get());
  4595. }
  4596. else
  4597. list.append(*LINK(&_subfiles.item(i)));
  4598. }
  4599. }
  4600. StringBuffer & getName(StringBuffer &name)
  4601. {
  4602. return list.item(index).getLogicalName(name);
  4603. }
  4604. IDistributedFile & query()
  4605. {
  4606. return list.item(index);
  4607. }
  4608. };
  4609. void checkModify(const char *title)
  4610. {
  4611. StringBuffer reason;
  4612. if (!canModify(reason)) {
  4613. #ifdef EXTRA_LOGGING
  4614. PROGLOG("CDistributedSuperFile::%s(canModify) %s",title,reason.str());
  4615. #endif
  4616. if (reason.length())
  4617. throw MakeStringException(-1,"CDistributedSuperFile::%s %s",title,reason.str());
  4618. }
  4619. }
  4620. protected:
  4621. int interleaved; // 0 not interleaved, 1 interleaved old, 2 interleaved new
  4622. IArrayOf<IDistributedFile> subfiles;
  4623. void clearSuperOwners(unsigned timeoutMs, ICodeContext *ctx)
  4624. {
  4625. /* JCSMORE - Why on earth is this doing this way?
  4626. * We are in a super file, we already have [read] locks to sub files (in 'subfiles' array)
  4627. * This should iterate through those and call unlinkSubFile I think.
  4628. */
  4629. Owned<IPropertyTreeIterator> iter = root->getElements("SubFile");
  4630. StringBuffer oquery;
  4631. oquery.append("SuperOwner[@name=\"").append(logicalName.get()).append("\"]");
  4632. ForEach(*iter)
  4633. {
  4634. const char *name = iter->query().queryProp("@name");
  4635. if (name&&*name)
  4636. {
  4637. CDfsLogicalFileName subfn;
  4638. subfn.set(name);
  4639. CFileLock fconnlockSub;
  4640. // JCSMORE - this is really not right, but consistent with previous version
  4641. // MORE: Use CDistributedSuperFile::linkSuperOwner(false) - ie. unlink
  4642. if (fconnlockSub.init(subfn, RTM_LOCK_READ, timeoutMs, "CDistributedFile::doRemoveEntry"))
  4643. {
  4644. IPropertyTree *subfroot = fconnlockSub.queryRoot();
  4645. if (subfroot)
  4646. {
  4647. if (!subfroot->removeProp(oquery.str()))
  4648. {
  4649. VStringBuffer s("SubFile %s is not owned by SuperFile %s", name, logicalName.get());
  4650. if (ctx)
  4651. ctx->addWuException(s.str(), 0, SeverityWarning, "DFS[clearSuperOwner]");
  4652. else
  4653. {
  4654. Owned<IException> e = makeStringException(-1, s.str());
  4655. EXCLOG(e, "DFS[clearSuperOwner]");
  4656. }
  4657. }
  4658. }
  4659. }
  4660. }
  4661. }
  4662. }
  4663. static StringBuffer &getSubPath(StringBuffer &path,unsigned idx)
  4664. {
  4665. return path.append("SubFile[@num=\"").append(idx+1).append("\"]");
  4666. }
  4667. void loadSubFiles(IDistributedFileTransaction *transaction, unsigned timeout, bool link=false)
  4668. {
  4669. partscache.kill();
  4670. StringBuffer path;
  4671. StringBuffer subname;
  4672. subfiles.kill();
  4673. unsigned n = root->getPropInt("@numsubfiles");
  4674. if (n == 0)
  4675. return;
  4676. try
  4677. {
  4678. // Find all reported indexes and bail on bad range (before we lock any file)
  4679. Owned<IPropertyTreeIterator> subit = root->getElements("SubFile");
  4680. // Adding a sub 'before' another get the list out of order (but still valid)
  4681. OwnedMalloc<IPropertyTree *> orderedSubFiles(n, true);
  4682. ForEach (*subit)
  4683. {
  4684. IPropertyTree &sub = subit->query();
  4685. unsigned sn = sub.getPropInt("@num",0);
  4686. if (sn == 0)
  4687. ThrowStringException(-1, "CDistributedSuperFile: SuperFile %s: bad subfile part number %d of %d", logicalName.get(), sn, n);
  4688. if (sn > n)
  4689. ThrowStringException(-1, "CDistributedSuperFile: SuperFile %s: out-of-range subfile part number %d of %d", logicalName.get(), sn, n);
  4690. if (orderedSubFiles[sn-1])
  4691. ThrowStringException(-1, "CDistributedSuperFile: SuperFile %s: duplicated subfile part number %d of %d", logicalName.get(), sn, n);
  4692. orderedSubFiles[sn-1] = &sub;
  4693. }
  4694. for (unsigned i=0; i<n; i++)
  4695. {
  4696. if (!orderedSubFiles[i])
  4697. ThrowStringException(-1, "CDistributedSuperFile: SuperFile %s: missing subfile part number %d of %d", logicalName.get(), i+1, n);
  4698. }
  4699. // Now try to resolve them all (file/superfile)
  4700. for (unsigned f=0; f<n; f++)
  4701. {
  4702. IPropertyTree &sub = *(orderedSubFiles[f]);
  4703. sub.getProp("@name",subname.clear());
  4704. Owned<IDistributedFile> subfile;
  4705. subfile.setown(transaction?transaction->lookupFile(subname.str(),timeout):parent->lookup(subname.str(), udesc, false, false, false, transaction, timeout));
  4706. if (!subfile.get())
  4707. subfile.setown(transaction?transaction->lookupSuperFile(subname.str(),timeout):parent->lookupSuperFile(subname.str(),udesc,transaction,timeout));
  4708. // Some files are ok not to exist
  4709. if (!subfile.get())
  4710. {
  4711. CDfsLogicalFileName cdfsl;
  4712. cdfsl.set(subname);
  4713. if (cdfsl.isForeign())
  4714. {
  4715. IWARNLOG("CDistributedSuperFile: SuperFile %s's sub-file file '%s' is foreign, but missing", logicalName.get(), subname.str());
  4716. // Create a dummy empty superfile as a placeholder for the missing foreign file
  4717. Owned<IPropertyTree> dummySuperRoot = createPTree();
  4718. dummySuperRoot->setPropInt("@interleaved", 0);
  4719. subfile.setown(queryDistributedFileDirectory().createNewSuperFile(dummySuperRoot, subname));
  4720. if (transaction)
  4721. {
  4722. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  4723. _transaction->ensureFile(subfile);
  4724. }
  4725. }
  4726. else
  4727. ThrowStringException(-1, "CDistributedSuperFile: SuperFile %s: corrupt subfile file '%s' cannot be found", logicalName.get(), subname.str());
  4728. }
  4729. subfiles.append(*subfile.getClear());
  4730. if (link)
  4731. linkSubFile(f);
  4732. }
  4733. // This is *only* due to foreign files
  4734. if (subfiles.ordinality() != n)
  4735. {
  4736. IWARNLOG("CDistributedSuperFile: SuperFile %s's number of sub-files updated to %d", logicalName.get(), subfiles.ordinality());
  4737. root->setPropInt("@numsubfiles", subfiles.ordinality());
  4738. }
  4739. }
  4740. catch (IException *)
  4741. {
  4742. partscache.kill();
  4743. subfiles.kill(); // one out, all out
  4744. throw;
  4745. }
  4746. }
  4747. void addItem(unsigned pos,IDistributedFile *_file)
  4748. {
  4749. Owned<IDistributedFile> file = _file;
  4750. partscache.kill();
  4751. // first renumber all above
  4752. StringBuffer path;
  4753. IPropertyTree *sub;
  4754. for (unsigned i=subfiles.ordinality();i>pos;i--)
  4755. {
  4756. sub = root->queryPropTree(getSubPath(path.clear(),i-1).str());
  4757. if (!sub)
  4758. throw MakeStringException(-1,"C(2): Corrupt subfile file part %d cannot be found",i);
  4759. sub->setPropInt("@num",i+1);
  4760. }
  4761. sub = createPTree();
  4762. sub->setPropInt("@num",pos+1);
  4763. sub->setProp("@name",file->queryLogicalName());
  4764. if (pos==0)
  4765. {
  4766. Owned<IPropertyTree> superAttrs = createPTreeFromIPT(&file->queryAttributes());
  4767. superAttrs->removeProp("Protect"); // do not automatically inherit protected status
  4768. resetFileAttr(superAttrs.getClear());
  4769. }
  4770. root->addPropTree("SubFile",sub);
  4771. subfiles.add(*file.getClear(),pos);
  4772. root->setPropInt("@numsubfiles",subfiles.ordinality());
  4773. }
  4774. void removeItem(unsigned pos)
  4775. {
  4776. partscache.kill();
  4777. StringBuffer path;
  4778. IPropertyTree* sub = root->queryPropTree(getSubPath(path,pos).str());
  4779. if (!sub)
  4780. throw MakeStringException(-1,"CDistributedSuperFile(3): Corrupt subfile file part %d cannot be found",pos+1);
  4781. root->removeTree(sub);
  4782. // now renumber all above
  4783. for (unsigned i=pos+1; i<subfiles.ordinality(); i++)
  4784. {
  4785. sub = root->queryPropTree(getSubPath(path.clear(),i).str());
  4786. if (!sub)
  4787. throw MakeStringException(-1,"CDistributedSuperFile(2): Corrupt subfile file part %d cannot be found",i+1);
  4788. sub->setPropInt("@num",i);
  4789. }
  4790. subfiles.remove(pos);
  4791. if (pos==0)
  4792. {
  4793. if (subfiles.ordinality())
  4794. {
  4795. Owned<IPropertyTree> superAttrs = createPTreeFromIPT(&subfiles.item(0).queryAttributes());
  4796. superAttrs->removeProp("Protect"); // do not automatically inherit protected status
  4797. resetFileAttr(superAttrs.getClear());
  4798. }
  4799. else
  4800. resetFileAttr(getEmptyAttr());
  4801. }
  4802. root->setPropInt("@numsubfiles",subfiles.ordinality());
  4803. }
  4804. void loadParts(CDistributedFilePartArray &partsret, IDFPartFilter *filter)
  4805. {
  4806. unsigned p = 0;
  4807. if (interleaved) { // a bit convoluted but should work
  4808. IArrayOf<IDistributedFile> allsubfiles;
  4809. ForEachItemIn(i,subfiles) {
  4810. // if old format keep original interleaving
  4811. IDistributedSuperFile* super = (interleaved==1)?NULL:subfiles.item(i).querySuperFile();
  4812. if (super) {
  4813. Owned<IDistributedFileIterator> iter = super->getSubFileIterator(true);
  4814. ForEach(*iter)
  4815. allsubfiles.append(iter->get());
  4816. }
  4817. else
  4818. allsubfiles.append(*LINK(&subfiles.item(i)));
  4819. }
  4820. unsigned *pn = new unsigned[allsubfiles.ordinality()];
  4821. ForEachItemIn(j,allsubfiles)
  4822. pn[j] = allsubfiles.item(j).numParts();
  4823. unsigned f=0;
  4824. bool found=false;
  4825. for (;;) {
  4826. if (f==allsubfiles.ordinality()) {
  4827. if (!found)
  4828. break; // no more
  4829. found = false;
  4830. f = 0;
  4831. }
  4832. if (pn[f]) {
  4833. found = true;
  4834. if (!filter||filter->includePart(p)) {
  4835. IDistributedFile &subfile = allsubfiles.item(f);
  4836. IDistributedFilePart *part = subfile.getPart(subfile.numParts()-pn[f]);
  4837. partsret.append(*QUERYINTERFACE(part,CDistributedFilePart)); // bit kludgy
  4838. }
  4839. p++;
  4840. pn[f]--;
  4841. }
  4842. f++;
  4843. }
  4844. delete [] pn;
  4845. }
  4846. else { // sequential
  4847. ForEachItemIn(i,subfiles) { // not wonderfully quick
  4848. IDistributedFile &subfile = subfiles.item(i);
  4849. unsigned n = subfile.numParts();
  4850. unsigned j = 0;
  4851. while (n--) {
  4852. if (!filter||filter->includePart(p)) {
  4853. IDistributedFilePart *part = subfile.getPart(j++);
  4854. partsret.append(*QUERYINTERFACE(part,CDistributedFilePart)); // bit kludgy
  4855. }
  4856. p++;
  4857. }
  4858. }
  4859. }
  4860. }
  4861. void linkSubFile(unsigned pos, bool link=true)
  4862. {
  4863. IDistributedFile *subfile = &subfiles.item(pos);
  4864. IDistributedSuperFile *ssub = subfile->querySuperFile();
  4865. if (ssub) {
  4866. CDistributedSuperFile *cdsuper = QUERYINTERFACE(ssub,CDistributedSuperFile);
  4867. cdsuper->linkSuperOwner(queryLogicalName(),link);
  4868. }
  4869. else {
  4870. CDistributedFile *cdfile = QUERYINTERFACE(subfile,CDistributedFile);
  4871. cdfile->linkSuperOwner(queryLogicalName(),link);
  4872. }
  4873. }
  4874. void unlinkSubFile(unsigned pos)
  4875. {
  4876. linkSubFile(pos, false);
  4877. }
  4878. void checkSubFormatAttr(IDistributedFile *sub, const char* exprefix="")
  4879. {
  4880. // empty super files now pass
  4881. ForEachItemIn(i,subfiles) {
  4882. IDistributedSuperFile* super = subfiles.item(i).querySuperFile();
  4883. if (super) {
  4884. CDistributedSuperFile *cdsuper = QUERYINTERFACE(super,CDistributedSuperFile);
  4885. if (cdsuper)
  4886. cdsuper->checkSubFormatAttr(sub,exprefix);
  4887. return;
  4888. }
  4889. CDistributedFile *cdfile = QUERYINTERFACE(&subfiles.item(0),CDistributedFile);
  4890. if (cdfile)
  4891. cdfile->checkFormatAttr(sub,exprefix); // any file will do
  4892. }
  4893. }
  4894. void addPropIfCommon(IPropertyTree &target, const char *prop, const char *value)
  4895. {
  4896. bool ok = true;
  4897. // add attributes that are common
  4898. for (unsigned i=1; i<subfiles.ordinality(); i++)
  4899. {
  4900. IDistributedFile &file = subfiles.item(i);
  4901. IDistributedSuperFile *sFile = file.querySuperFile();
  4902. if (!sFile || sFile->numSubFiles(true)) // skip empty super files
  4903. {
  4904. const char *otherValue = file.queryAttributes().queryProp(prop);
  4905. if (!otherValue || !streq(otherValue, value))
  4906. {
  4907. ok = false;
  4908. break;
  4909. }
  4910. }
  4911. }
  4912. if (ok)
  4913. target.setProp(prop, value);
  4914. }
  4915. public:
  4916. virtual void checkFormatAttr(IDistributedFile *sub, const char* exprefix="") override
  4917. {
  4918. IDistributedSuperFile *superSub = sub->querySuperFile();
  4919. if (superSub && (0 == superSub->numSubFiles(true)))
  4920. return;
  4921. // only check sub files not siblings, which is excessive (format checking is really only debug aid)
  4922. checkSubFormatAttr(sub,exprefix);
  4923. }
  4924. unsigned findSubFile(const char *name)
  4925. {
  4926. StringBuffer lfn;
  4927. normalizeLFN(name,lfn);
  4928. ForEachItemIn(i,subfiles)
  4929. if (stricmp(subfiles.item(i).queryLogicalName(),lfn.str())==0)
  4930. return i;
  4931. return NotFound;
  4932. }
  4933. IMPLEMENT_IINTERFACE_O;
  4934. void commonInit(CDistributedFileDirectory *_parent, IPropertyTree *_root)
  4935. {
  4936. parent = _parent;
  4937. root.set(_root);
  4938. const char *val = root->queryProp("@interleaved");
  4939. if (val&&isdigit(*val))
  4940. interleaved = atoi(val);
  4941. else
  4942. interleaved = strToBool(val)?1:0;
  4943. }
  4944. void init(CDistributedFileDirectory *_parent, IPropertyTree *_root, const CDfsLogicalFileName &_name, IUserDescriptor* user, IDistributedFileTransaction *transaction, unsigned timeout=INFINITE)
  4945. {
  4946. assertex(_name.isSet());
  4947. setUserDescriptor(udesc,user);
  4948. logicalName.set(_name);
  4949. commonInit(_parent, _root);
  4950. loadSubFiles(transaction,timeout);
  4951. }
  4952. CDistributedSuperFile(CDistributedFileDirectory *_parent, IPropertyTree *_root,const CDfsLogicalFileName &_name,IUserDescriptor* user)
  4953. {
  4954. init(_parent,_root,_name,user,NULL);
  4955. }
  4956. CDistributedSuperFile(CDistributedFileDirectory *_parent, IRemoteConnection *_conn,const CDfsLogicalFileName &_name,IUserDescriptor* user, IDistributedFileTransaction *transaction,unsigned timeout)
  4957. {
  4958. conn.setown(_conn);
  4959. init(_parent,conn->queryRoot(),_name,user,transaction,timeout);
  4960. }
  4961. CDistributedSuperFile(CDistributedFileDirectory *_parent, CDfsLogicalFileName &_name, IUserDescriptor* user, IDistributedFileTransaction *transaction)
  4962. {
  4963. // temp super file
  4964. assertex(_name.isMulti());
  4965. if (!_name.isExpanded())
  4966. _name.expand(user);//expand wildcards
  4967. Owned<IPropertyTree> tree = _name.createSuperTree();
  4968. init(_parent,tree,_name,user,transaction);
  4969. updateFileAttrs();
  4970. }
  4971. CDistributedSuperFile(CDistributedFileDirectory *_parent, IPropertyTree *_root, const char *optionalName)
  4972. {
  4973. commonInit(_parent, _root);
  4974. if (optionalName)
  4975. logicalName.set(optionalName);
  4976. }
  4977. ~CDistributedSuperFile()
  4978. {
  4979. partscache.kill();
  4980. subfiles.kill();
  4981. }
  4982. virtual StringBuffer &getClusterName(unsigned clusternum,StringBuffer &name) override
  4983. {
  4984. // returns the cluster name if all the same
  4985. CriticalBlock block (sect);
  4986. if (subfiles.ordinality()==1)
  4987. return subfiles.item(0).getClusterName(clusternum,name);
  4988. size32_t rl = name.length();
  4989. StringBuffer test;
  4990. ForEachItemIn(i,subfiles) {
  4991. if (i) {
  4992. subfiles.item(i).getClusterName(clusternum,test.clear());
  4993. if (strcmp(name.str(),test.str())!=0) {
  4994. name.setLength(rl);
  4995. break;
  4996. }
  4997. }
  4998. else
  4999. subfiles.item(i).getClusterName(clusternum,name);
  5000. }
  5001. return name;
  5002. }
  5003. virtual IFileDescriptor *getFileDescriptor(const char *clustername) override
  5004. {
  5005. CriticalBlock block (sect);
  5006. if (subfiles.ordinality()==1)
  5007. return subfiles.item(0).getFileDescriptor(clustername);
  5008. // superfiles assume consistant replication & compression
  5009. UnsignedArray subcounts;
  5010. bool mixedwidth = false;
  5011. unsigned width = 0;
  5012. bool first = true;
  5013. Owned<IPropertyTree> at = getEmptyAttr();
  5014. Owned<IDistributedFileIterator> fiter = getSubFileIterator(true);
  5015. ForEach(*fiter)
  5016. {
  5017. IDistributedFile &file = fiter->query();
  5018. if (first)
  5019. {
  5020. first = false;
  5021. Owned<IAttributeIterator> ait = file.queryAttributes().getAttributes();
  5022. ForEach(*ait)
  5023. {
  5024. const char *name = ait->queryName();
  5025. if ((stricmp(name,"@size")!=0)&&(stricmp(name,"@recordCount")!=0))
  5026. {
  5027. const char *v = ait->queryValue();
  5028. if (!v)
  5029. continue;
  5030. addPropIfCommon(*at, name, v);
  5031. }
  5032. }
  5033. MemoryBuffer mb;
  5034. if (getRecordLayout(mb, "_record_layout"))
  5035. at->setPropBin("_record_layout", mb.length(), mb.bufferBase());
  5036. if (getRecordLayout(mb, "_rtlType"))
  5037. at->setPropBin("_rtlType", mb.length(), mb.bufferBase());
  5038. const char *ecl = file.queryAttributes().queryProp("ECL");
  5039. if (!isEmptyString(ecl))
  5040. addPropIfCommon(*at, "ECL", ecl);
  5041. }
  5042. unsigned np = file.numParts();
  5043. if (0 == width)
  5044. width = np;
  5045. else if (np!=width)
  5046. mixedwidth = true;
  5047. subcounts.append(np);
  5048. }
  5049. // need common attributes
  5050. Owned<ISuperFileDescriptor> fdesc=createSuperFileDescriptor(at.getClear());
  5051. if (interleaved&&(interleaved!=2))
  5052. IWARNLOG("getFileDescriptor: Unsupported interleave value (1)");
  5053. fdesc->setSubMapping(subcounts,interleaved!=0);
  5054. fdesc->setTraceName(logicalName.get());
  5055. Owned<IDistributedFilePartIterator> iter = getIterator(NULL);
  5056. unsigned n = 0;
  5057. SocketEndpointArray reps;
  5058. ForEach(*iter) {
  5059. IDistributedFilePart &part = iter->query();
  5060. CDistributedFilePart *cpart = (clustername&&*clustername)?QUERYINTERFACE(&part,CDistributedFilePart):NULL;
  5061. unsigned copy = 0;
  5062. if (cpart) {
  5063. IDistributedFile &f = cpart->queryParent();
  5064. unsigned cn = f.findCluster(clustername);
  5065. if (cn!=NotFound) {
  5066. for (unsigned i = 0;i<cpart->numCopies();i++)
  5067. if (cpart->copyClusterNum(i,NULL)==cn) {
  5068. copy = i;
  5069. break;
  5070. }
  5071. }
  5072. }
  5073. if (mixedwidth) {
  5074. SocketEndpoint rep;
  5075. if (copy+1<part.numCopies())
  5076. rep = part.queryNode(copy+1)->endpoint();
  5077. reps.append(rep);
  5078. }
  5079. RemoteFilename rfn;
  5080. fdesc->setPart(n,part.getFilename(rfn,copy),&part.queryAttributes());
  5081. n++;
  5082. }
  5083. ClusterPartDiskMapSpec mspec;
  5084. if (subfiles.ordinality()) {
  5085. mspec = subfiles.item(0).queryPartDiskMapping(0);
  5086. }
  5087. mspec.interleave = numSubFiles(true);
  5088. fdesc->endCluster(mspec);
  5089. if (mixedwidth) { // bleah - have to add replicate node numbers
  5090. Owned<IGroup> group = fdesc->getGroup();
  5091. unsigned gw = group->ordinality();
  5092. for (unsigned pn=0;pn<reps.ordinality();pn++) {
  5093. const SocketEndpoint &ep=reps.item(pn);
  5094. if (!ep.isNull()) {
  5095. unsigned gn = pn;
  5096. if (gn<gw) {
  5097. do {
  5098. gn++;
  5099. if (gn==gw)
  5100. gn = 0;
  5101. if (ep.equals(group->queryNode((rank_t)gn).endpoint())) {
  5102. IPartDescriptor *part = fdesc->queryPart(pn);
  5103. if (part)
  5104. part->queryProperties().setPropInt("@rn",(unsigned)gn);
  5105. break;
  5106. }
  5107. } while (gn!=pn);
  5108. }
  5109. }
  5110. }
  5111. }
  5112. return fdesc.getClear();
  5113. }
  5114. virtual unsigned numParts() override
  5115. {
  5116. CriticalBlock block(sect);
  5117. unsigned ret=0;
  5118. ForEachItemIn(i,subfiles)
  5119. ret += subfiles.item(i).numParts();
  5120. return ret;
  5121. }
  5122. virtual IDistributedFilePart &queryPart(unsigned idx) override
  5123. {
  5124. CriticalBlock block(sect);
  5125. if (subfiles.ordinality()==1)
  5126. return subfiles.item(0).queryPart(idx);
  5127. if (partscache.ordinality()==0)
  5128. loadParts(partscache,NULL);
  5129. if (idx>=partscache.ordinality())
  5130. return *(IDistributedFilePart *)NULL;
  5131. return partscache.item(idx);
  5132. }
  5133. virtual IDistributedFilePart* getPart(unsigned idx) override
  5134. {
  5135. IDistributedFilePart* ret = &queryPart(idx);
  5136. return LINK(ret);
  5137. }
  5138. virtual IDistributedFilePartIterator *getIterator(IDFPartFilter *filter=NULL) override
  5139. {
  5140. CriticalBlock block(sect);
  5141. if (subfiles.ordinality()==1)
  5142. return subfiles.item(0).getIterator(filter);
  5143. CDistributedFilePartIterator *ret = new CDistributedFilePartIterator();
  5144. loadParts(ret->queryParts(),filter);
  5145. return ret;
  5146. }
  5147. virtual void rename(const char *_logicalname,IUserDescriptor *user) override
  5148. {
  5149. StringBuffer prevname;
  5150. Owned<IFileRelationshipIterator> reliter;
  5151. // set prevname
  5152. if (!isAnon()) {
  5153. getLogicalName(prevname);
  5154. try {
  5155. IFileRelationshipIterator *iter = parent->lookupAllFileRelationships(prevname.str());
  5156. reliter.setown(iter);
  5157. }
  5158. catch (IException *e) {
  5159. EXCLOG(e,"CDistributedFileDirectory::rename");
  5160. e->Release();
  5161. }
  5162. detach();
  5163. }
  5164. attach(_logicalname,user);
  5165. if (reliter.get()) {
  5166. // add back any relationships with new name
  5167. parent->renameFileRelationships(prevname.str(),_logicalname,reliter,user);
  5168. }
  5169. }
  5170. virtual const char *queryDefaultDir() override
  5171. {
  5172. // returns the directory if all the same
  5173. const char *ret = NULL;
  5174. CriticalBlock block (sect);
  5175. ForEachItemIn(i,subfiles) {
  5176. if (subfiles.item(i).numParts())
  5177. {
  5178. const char *s = subfiles.item(i).queryDefaultDir();
  5179. if (!s)
  5180. return NULL;
  5181. if (!ret)
  5182. ret = s;
  5183. else if (strcmp(ret,s)!=0)
  5184. return NULL;
  5185. }
  5186. }
  5187. return ret;
  5188. }
  5189. virtual const char *queryPartMask() override
  5190. {
  5191. // returns the part mask if all the same
  5192. const char *ret = NULL;
  5193. CriticalBlock block (sect);
  5194. ForEachItemIn(i,subfiles) {
  5195. const char *s = subfiles.item(i).queryPartMask();
  5196. if (!s)
  5197. return NULL;
  5198. if (!ret)
  5199. ret = s;
  5200. else if (stricmp(ret,s)!=0)
  5201. return NULL;
  5202. }
  5203. return ret;
  5204. }
  5205. virtual void attach(const char *_logicalname,IUserDescriptor *user) override
  5206. {
  5207. assertex(!conn.get()); // already attached
  5208. CriticalBlock block (sect);
  5209. StringBuffer tail;
  5210. StringBuffer lfn;
  5211. logicalName.set(_logicalname);
  5212. checkLogicalName(logicalName,user,true,true,false,"attach");
  5213. parent->addEntry(logicalName,root.getClear(),true,false);
  5214. conn.clear();
  5215. CFileLock fcl;
  5216. verifyex(fcl.init(logicalName, DXB_SuperFile, RTM_LOCK_READ, defaultTimeout, "CDistributedSuperFile::attach"));
  5217. conn.setown(fcl.detach());
  5218. assertex(conn.get()); // must have been attached
  5219. root.setown(conn->getRoot());
  5220. loadSubFiles(NULL, 0, true);
  5221. }
  5222. virtual void detach(unsigned timeoutMs=INFINITE, ICodeContext *ctx=NULL) override
  5223. {
  5224. assertex(conn.get()); // must be attached
  5225. CriticalBlock block(sect);
  5226. checkModify("CDistributedSuperFile::detach");
  5227. StringBuffer reason;
  5228. if (checkOwned(reason))
  5229. throw MakeStringException(-1, "detach: %s", reason.str());
  5230. subfiles.kill();
  5231. // Remove from SDS
  5232. /* JCSMORE - this looks very kludgy...
  5233. * We have readlock, this code is doing
  5234. * 1) change to write lock (not using lockProperties or DistributedFilePropertyLock to do so) [using CFileChangeWriteLock]
  5235. * CFileChangeWriteLock doesn't preserve lock mode quite right.. (see 'newMode')
  5236. * 2) manually deleting SuperOwner from subfiles (in clearSuperOwners)
  5237. * 3) Using the connection to delete the SuperFile from Dali (clones to 'root' in process)
  5238. * 4) ~CFileChangeWriteLock() [writeLock.clear()], restores read lock from write to read
  5239. * 5) updateFS (housekeeping of empty scopes, relationships) - ok
  5240. */
  5241. CFileChangeWriteLock writeLock(conn, timeoutMs);
  5242. clearSuperOwners(timeoutMs, ctx);
  5243. writeLock.clear();
  5244. root.setown(closeConnection(true));
  5245. updateFS(logicalName, parent->queryDefaultTimeout());
  5246. logicalName.clear();
  5247. }
  5248. virtual bool existsPhysicalPartFiles(unsigned short port) override
  5249. {
  5250. CriticalBlock block (sect);
  5251. ForEachItemIn(i,subfiles) {
  5252. IDistributedFile &f=subfiles.item(i);
  5253. if (!f.existsPhysicalPartFiles(port))
  5254. return false;
  5255. }
  5256. return true;
  5257. }
  5258. virtual bool renamePhysicalPartFiles(const char *newlfn,const char *cluster,IMultiException *mexcept,const char *newbasedir) override
  5259. {
  5260. throw MakeStringException(-1,"renamePhysicalPartFiles not supported for SuperFiles");
  5261. return false;
  5262. }
  5263. void serialize(MemoryBuffer &mb)
  5264. {
  5265. UNIMPLEMENTED; // not yet needed
  5266. }
  5267. virtual unsigned numCopies(unsigned partno) override
  5268. {
  5269. unsigned ret = (unsigned)-1;
  5270. CriticalBlock block (sect);
  5271. ForEachItemIn(i,subfiles) {
  5272. IDistributedFile &f=subfiles.item(i);
  5273. unsigned fnc = f.numCopies(partno);
  5274. if (fnc<ret)
  5275. ret = fnc;
  5276. }
  5277. return (ret==(unsigned)-1)?1:ret;
  5278. }
  5279. virtual __int64 getFileSize(bool allowphysical,bool forcephysical) override
  5280. {
  5281. __int64 ret = (__int64)(forcephysical?-1:queryAttributes().getPropInt64("@size",-1));
  5282. if (ret==-1)
  5283. {
  5284. ret = 0;
  5285. ForEachItemIn(i,subfiles)
  5286. {
  5287. __int64 ps = subfiles.item(i).getFileSize(allowphysical,forcephysical);
  5288. if (ps == -1)
  5289. return -1; // i.e. if cannot determine size of any part, total is unknown
  5290. ret += ps;
  5291. }
  5292. }
  5293. return ret;
  5294. }
  5295. virtual __int64 getDiskSize(bool allowphysical,bool forcephysical) override
  5296. {
  5297. if (!isCompressed(NULL))
  5298. return getFileSize(allowphysical, forcephysical);
  5299. __int64 ret = (__int64)(forcephysical?-1:queryAttributes().getPropInt64("@compressedSize",-1));
  5300. if (ret==-1)
  5301. {
  5302. ret = 0;
  5303. ForEachItemIn(i,subfiles)
  5304. {
  5305. __int64 ps = subfiles.item(i).getDiskSize(allowphysical,forcephysical);
  5306. if (ps == -1)
  5307. return -1; // i.e. if cannot determine size of any part, total is unknown
  5308. ret += ps;
  5309. }
  5310. }
  5311. return ret;
  5312. }
  5313. __int64 getRecordCount()
  5314. {
  5315. __int64 ret = queryAttributes().getPropInt64("@recordCount",-1);
  5316. if (ret==-1) {
  5317. ret = 0;
  5318. ForEachItemIn(i,subfiles) {
  5319. __int64 rc = subfiles.item(i).queryAttributes().getPropInt64("@recordCount",-1);
  5320. if (rc == -1) {
  5321. ret = rc;
  5322. break;
  5323. }
  5324. ret += rc;
  5325. }
  5326. }
  5327. return ret;
  5328. }
  5329. virtual bool getFileCheckSum(unsigned &checkSum) override
  5330. {
  5331. if (queryAttributes().hasProp("@checkSum"))
  5332. checkSum = (unsigned)queryAttributes().getPropInt64("@checkSum");
  5333. else
  5334. {
  5335. checkSum = ~0;
  5336. ForEachItemIn(i,subfiles) {
  5337. unsigned cs;
  5338. if (!subfiles.item(i).getFileCheckSum(cs))
  5339. return false;
  5340. checkSum ^= cs;
  5341. }
  5342. }
  5343. return true;
  5344. }
  5345. virtual IDistributedSuperFile *querySuperFile() override
  5346. {
  5347. return this;
  5348. }
  5349. virtual IDistributedFile &querySubFile(unsigned idx,bool sub) override
  5350. {
  5351. CriticalBlock block (sect);
  5352. if (sub) {
  5353. ForEachItemIn(i,subfiles) {
  5354. IDistributedFile &f=subfiles.item(i);
  5355. IDistributedSuperFile *super = f.querySuperFile();
  5356. if (super) {
  5357. unsigned ns = super->numSubFiles(true);
  5358. if (ns>idx)
  5359. return super->querySubFile(idx,true);
  5360. idx -= ns;
  5361. }
  5362. else if (idx--==0)
  5363. return f;
  5364. }
  5365. // fall through to error
  5366. }
  5367. return subfiles.item(idx);
  5368. }
  5369. virtual IDistributedFile *querySubFileNamed(const char *name, bool sub) override
  5370. {
  5371. CriticalBlock block (sect);
  5372. unsigned idx=findSubFileOrd(name);
  5373. if ((idx!=NotFound)&&(idx<subfiles.ordinality()))
  5374. return &subfiles.item(idx);
  5375. idx=findSubFile(name);
  5376. if (idx!=NotFound)
  5377. return &subfiles.item(idx);
  5378. if (sub) {
  5379. ForEachItemIn(i,subfiles) {
  5380. IDistributedFile &f=subfiles.item(i);
  5381. IDistributedSuperFile *super = f.querySuperFile();
  5382. if (super) {
  5383. IDistributedFile *ret = super->querySubFileNamed(name);
  5384. if (ret)
  5385. return ret;
  5386. }
  5387. }
  5388. }
  5389. return NULL;
  5390. }
  5391. virtual IDistributedFile *getSubFile(unsigned idx,bool sub) override
  5392. {
  5393. CriticalBlock block (sect);
  5394. return LINK(&querySubFile(idx,sub));
  5395. }
  5396. virtual unsigned numSubFiles(bool sub) override
  5397. {
  5398. CriticalBlock block (sect);
  5399. unsigned ret = 0;
  5400. if (sub) {
  5401. ForEachItemIn(i,subfiles) {
  5402. IDistributedFile &f=subfiles.item(i);
  5403. IDistributedSuperFile *super = f.querySuperFile();
  5404. if (super)
  5405. ret += super->numSubFiles(sub);
  5406. else
  5407. ret++;
  5408. }
  5409. }
  5410. else
  5411. ret = subfiles.ordinality();
  5412. return ret;
  5413. }
  5414. virtual bool getFormatCrc(unsigned &crc) override
  5415. {
  5416. if (queryAttributes().hasProp("@formatCrc")) {
  5417. crc = (unsigned)queryAttributes().getPropInt("@formatCrc");
  5418. return true;
  5419. }
  5420. bool found = false;
  5421. ForEachItemIn(i,subfiles) {
  5422. unsigned c;
  5423. if (subfiles.item(i).getFormatCrc(c)) {
  5424. if (found&&(c!=crc))
  5425. return false;
  5426. found = true;
  5427. crc = c;
  5428. }
  5429. }
  5430. return found;
  5431. }
  5432. virtual bool getRecordLayout(MemoryBuffer &layout, const char *attrname) override
  5433. {
  5434. layout.clear();
  5435. if (queryAttributes().getPropBin(attrname, layout))
  5436. return true;
  5437. bool found = false;
  5438. ForEachItemIn(i,subfiles) {
  5439. MemoryBuffer b;
  5440. if (subfiles.item(i).getRecordLayout(found?b:layout, attrname)) {
  5441. if (found) {
  5442. if ((b.length()!=layout.length())||(memcmp(b.bufferBase(),layout.bufferBase(),b.length())!=0))
  5443. return false;
  5444. }
  5445. else
  5446. found = true;
  5447. }
  5448. }
  5449. return found;
  5450. }
  5451. virtual bool getRecordSize(size32_t &rsz) override
  5452. {
  5453. if (queryAttributes().hasProp("@recordSize")) {
  5454. rsz = (size32_t)queryAttributes().getPropInt("@recordSize");
  5455. return true;
  5456. }
  5457. bool found = false;
  5458. ForEachItemIn(i,subfiles) {
  5459. size32_t sz;
  5460. if (subfiles.item(i).getRecordSize(sz)) {
  5461. if (found&&(sz!=rsz))
  5462. return false;
  5463. found = true;
  5464. rsz = sz;
  5465. }
  5466. }
  5467. return found;
  5468. }
  5469. virtual bool isInterleaved() override
  5470. {
  5471. return interleaved!=0;
  5472. }
  5473. virtual IDistributedFile *querySubPart(unsigned partidx,unsigned &subfileidx) override
  5474. {
  5475. CriticalBlock block (sect);
  5476. subfileidx = 0;
  5477. Owned<IDistributedFilePart> part = getPart(partidx);
  5478. if (!part)
  5479. return NULL;
  5480. CDistributedFilePart *cpart = QUERYINTERFACE(part.get(),CDistributedFilePart);
  5481. if (!cpart)
  5482. return NULL;
  5483. IDistributedFile &ret = cpart->queryParent();
  5484. unsigned n = ret.numParts();
  5485. for (unsigned i=0;i<n;i++) {
  5486. Owned<IDistributedFilePart> spart = ret.getPart(i);
  5487. if (spart.get()==part.get()) {
  5488. subfileidx = i;
  5489. return &ret;
  5490. }
  5491. }
  5492. return NULL;
  5493. }
  5494. virtual unsigned getPositionPart(offset_t pos, offset_t &base) override
  5495. { // not very quick!
  5496. CriticalBlock block (sect);
  5497. unsigned n = numParts();
  5498. base = 0;
  5499. for (unsigned i=0;i<n;i++) {
  5500. Owned<IDistributedFilePart> part = getPart(i);
  5501. offset_t ps = part->getFileSize(true,false);
  5502. if (ps==(offset_t)-1)
  5503. break;
  5504. if (ps>pos)
  5505. return i;
  5506. pos -= ps;
  5507. base += ps;
  5508. }
  5509. return NotFound;
  5510. }
  5511. virtual IDistributedFileIterator *getSubFileIterator(bool supersub=false) override
  5512. {
  5513. CriticalBlock block (sect);
  5514. return new cSubFileIterator(subfiles,supersub);
  5515. }
  5516. void updateFileAttrs()
  5517. {
  5518. if (subfiles.ordinality()==0) {
  5519. StringBuffer desc;
  5520. root->getProp("Attr/@description",desc);
  5521. root->removeProp("Attr"); // remove all other attributes if superfile empty
  5522. IPropertyTree *t=resetFileAttr(getEmptyAttr());
  5523. if (desc.length())
  5524. t->setProp("@description",desc.str());
  5525. return;
  5526. }
  5527. root->removeProp("Attr/@size");
  5528. root->removeProp("Attr/@compressedSize");
  5529. root->removeProp("Attr/@checkSum");
  5530. root->removeProp("Attr/@recordCount"); // recordCount not currently supported by superfiles
  5531. root->removeProp("Attr/@formatCrc"); // formatCrc set if all consistant
  5532. root->removeProp("Attr/@recordSize"); // record size set if all consistant
  5533. root->removeProp("Attr/_record_layout"); // legacy info - set if all consistent
  5534. root->removeProp("Attr/_rtlType"); // new info - set if all consistent
  5535. __int64 fs = getFileSize(false,false);
  5536. if (fs!=-1)
  5537. root->setPropInt64("Attr/@size",fs);
  5538. if (isCompressed(NULL))
  5539. {
  5540. fs = getDiskSize(false,false);
  5541. if (fs!=-1)
  5542. root->setPropInt64("Attr/@compressedSize",fs);
  5543. }
  5544. unsigned checkSum;
  5545. if (getFileCheckSum(checkSum))
  5546. root->setPropInt64("Attr/@checkSum", checkSum);
  5547. __int64 rc = getRecordCount();
  5548. if (rc!=-1)
  5549. root->setPropInt64("Attr/@recordCount",rc);
  5550. unsigned fcrc;
  5551. if (getFormatCrc(fcrc))
  5552. root->setPropInt("Attr/@formatCrc", fcrc);
  5553. size32_t rsz;
  5554. if (getRecordSize(rsz))
  5555. root->setPropInt("Attr/@recordSize", rsz);
  5556. MemoryBuffer mb;
  5557. if (getRecordLayout(mb, "_record_layout"))
  5558. root->setPropBin("Attr/_record_layout", mb.length(), mb.bufferBase());
  5559. if (getRecordLayout(mb, "_rtlType"))
  5560. root->setPropBin("Attr/_rtlType", mb.length(), mb.bufferBase());
  5561. const char *kind = nullptr;
  5562. Owned<IDistributedFileIterator> subIter = getSubFileIterator(true);
  5563. ForEach(*subIter)
  5564. {
  5565. IDistributedFile &file = subIter->query();
  5566. const char *curKind = file.queryAttributes().queryProp("@kind");
  5567. if (!kind)
  5568. kind = curKind;
  5569. else if (!strsame(kind, curKind))
  5570. {
  5571. kind = nullptr;
  5572. break;
  5573. }
  5574. }
  5575. if (kind)
  5576. root->setProp("Attr/@kind", kind);
  5577. }
  5578. void updateParentFileAttrs(IDistributedFileTransaction *transaction)
  5579. {
  5580. Owned<IPropertyTreeIterator> iter = root->getElements("SuperOwner");
  5581. StringBuffer pname;
  5582. ForEach(*iter) {
  5583. iter->query().getProp("@name",pname.clear());
  5584. Owned<IDistributedSuperFile> psfile = transaction?transaction->lookupSuperFile(pname.str()):
  5585. queryDistributedFileDirectory().lookupSuperFile(pname.str(),udesc,NULL);
  5586. CDistributedSuperFile *file = QUERYINTERFACE(psfile.get(),CDistributedSuperFile);
  5587. if (file) {
  5588. {
  5589. DistributedFilePropertyLock lock(file);
  5590. file->setModified();
  5591. file->updateFileAttrs();
  5592. }
  5593. file->updateParentFileAttrs(transaction);
  5594. }
  5595. }
  5596. }
  5597. void validateAddSubFile(IDistributedFile *sub)
  5598. {
  5599. if (strcmp(sub->queryLogicalName(),queryLogicalName())==0)
  5600. throw MakeStringException(-1,"addSubFile: Cannot add file %s to itself", queryLogicalName());
  5601. if (subfiles.ordinality())
  5602. checkFormatAttr(sub,"addSubFile");
  5603. if (NotFound!=findSubFile(sub->queryLogicalName()))
  5604. throw MakeStringException(-1,"addSubFile: File %s is already a subfile of %s", sub->queryLogicalName(),queryLogicalName());
  5605. }
  5606. virtual void validate() override
  5607. {
  5608. unsigned numSubfiles = root->getPropInt("@numsubfiles",0);
  5609. if (numSubfiles)
  5610. {
  5611. Owned<IPropertyTreeIterator> treeIter = root->getElements("SubFile");
  5612. unsigned subFileCount = 0;
  5613. ForEach(*treeIter)
  5614. {
  5615. IPropertyTree & st = treeIter->query();
  5616. StringBuffer subfilename;
  5617. st.getProp("@name", subfilename);
  5618. if (!parent->exists(subfilename.str(), NULL))
  5619. throw MakeStringException(-1, "Logical subfile '%s' doesn't exists!", subfilename.str());
  5620. if (!parent->isSuperFile(subfilename.str()))
  5621. if (!parent->existsPhysical(subfilename.str(), NULL))
  5622. {
  5623. const char * logicalName = queryLogicalName();
  5624. throw MakeStringException(-1, "Some physical parts do not exists, for logical file : %s",(isEmptyString(logicalName) ? "[unattached]" : logicalName));
  5625. }
  5626. subFileCount++;
  5627. }
  5628. if (numSubfiles != subFileCount)
  5629. throw MakeStringException(-1, "The value of @numsubfiles (%d) is not equal to the number of SubFile items (%d)!",numSubfiles, subFileCount);
  5630. }
  5631. }
  5632. private:
  5633. void doAddSubFile(IDistributedFile *_sub,bool before,const char *other,IDistributedFileTransactionExt *transaction) // takes ownership of sub
  5634. {
  5635. Owned<IDistributedFile> sub = _sub;
  5636. validateAddSubFile(sub); // shouldn't really be necessary, was validated in transaction before here
  5637. unsigned pos;
  5638. if (other&&*other) {
  5639. pos = findSubFileOrd(other);
  5640. if (pos==NotFound)
  5641. pos = findSubFile(other);
  5642. if (pos==NotFound)
  5643. pos = before?0:subfiles.ordinality();
  5644. else if (!before&&(pos<subfiles.ordinality()))
  5645. pos++;
  5646. }
  5647. else
  5648. pos = before?0:subfiles.ordinality();
  5649. if (pos > subfiles.ordinality())
  5650. throw MakeStringException(-1,"addSubFile: Insert position %d out of range for file %s in superfile %s", pos+1, sub->queryLogicalName(), queryLogicalName());
  5651. addItem(pos,sub.getClear()); // remove if failure TBD?
  5652. setModified();
  5653. updateFileAttrs();
  5654. linkSubFile(pos);
  5655. }
  5656. bool doRemoveSubFiles(IDistributedFileTransactionExt *transaction)
  5657. {
  5658. // have to be quite careful here
  5659. unsigned pos = subfiles.ordinality();
  5660. if (pos)
  5661. {
  5662. DistributedFilePropertyLock lock(this);
  5663. if (lock.needsReload())
  5664. loadSubFiles(transaction,1000*60*10);
  5665. pos = subfiles.ordinality();
  5666. if (pos)
  5667. {
  5668. do
  5669. {
  5670. pos--;
  5671. unlinkSubFile(pos);
  5672. removeItem(pos);
  5673. } while (pos);
  5674. setModified();
  5675. updateFileAttrs();
  5676. lock.unlock();
  5677. updateParentFileAttrs(transaction);
  5678. }
  5679. }
  5680. return true;
  5681. }
  5682. bool doRemoveSubFile(const char *subfile,
  5683. IDistributedFileTransactionExt *transaction)
  5684. {
  5685. // have to be quite careful here
  5686. unsigned pos=findSubFileOrd(subfile);
  5687. if ((pos==NotFound)||(pos>=subfiles.ordinality()))
  5688. pos = findSubFile(subfile);
  5689. if (pos==NotFound)
  5690. return false;
  5691. {
  5692. DistributedFilePropertyLock lock(this);
  5693. // don't reload subfiles here
  5694. pos=findSubFileOrd(subfile);
  5695. if ((pos==NotFound)||(pos>=subfiles.ordinality()))
  5696. pos = findSubFile(subfile);
  5697. if (pos==NotFound)
  5698. return false;
  5699. unlinkSubFile(pos);
  5700. removeItem(pos);
  5701. setModified();
  5702. updateFileAttrs();
  5703. }
  5704. updateParentFileAttrs(transaction);
  5705. return true;
  5706. }
  5707. bool doSwapSuperFile(IDistributedSuperFile *_file,
  5708. IDistributedFileTransactionExt *transaction)
  5709. {
  5710. assertex(transaction);
  5711. CDistributedSuperFile *file = QUERYINTERFACE(_file,CDistributedSuperFile);
  5712. if (!file)
  5713. return false;
  5714. // Cache names (so we can delete without problems)
  5715. StringArray subnames1;
  5716. StringArray subnames2;
  5717. for (unsigned i=0; i<this->numSubFiles(false); i++)
  5718. subnames1.append(querySubFile(i, false).queryLogicalName());
  5719. for (unsigned i=0; i<file->numSubFiles(false); i++)
  5720. subnames2.append(file->querySubFile(i, false).queryLogicalName());
  5721. // Delete all files
  5722. ForEachItemIn(d1,subnames1) {
  5723. Owned<IDistributedFile> sub = transaction->lookupFile(subnames1.item(d1));
  5724. if (!doRemoveSubFile(sub->queryLogicalName(), transaction))
  5725. return false;
  5726. }
  5727. ForEachItemIn(d2,subnames2) {
  5728. Owned<IDistributedFile> sub = transaction->lookupFile(subnames2.item(d2));
  5729. if (!file->doRemoveSubFile(sub->queryLogicalName(), transaction))
  5730. return false;
  5731. }
  5732. // Add files swapped
  5733. ForEachItemIn(a1,subnames1) {
  5734. Owned<IDistributedFile> sub = transaction->lookupFile(subnames1.item(a1));
  5735. file->doAddSubFile(LINK(sub), false, NULL, transaction);
  5736. }
  5737. ForEachItemIn(a2,subnames2) {
  5738. Owned<IDistributedFile> sub = transaction->lookupFile(subnames2.item(a2));
  5739. doAddSubFile(LINK(sub), false, NULL, transaction);
  5740. }
  5741. return true;
  5742. }
  5743. public:
  5744. virtual void addSubFile(const char * subfile,
  5745. bool before=false, // if true before other
  5746. const char *other=NULL, // in NULL add at end (before=false) or start(before=true)
  5747. bool addcontents=false,
  5748. IDistributedFileTransaction *transaction=NULL
  5749. ) override
  5750. {
  5751. CriticalBlock block (sect);
  5752. if (!subfile||!*subfile)
  5753. return;
  5754. checkModify("addSubFile");
  5755. partscache.kill();
  5756. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  5757. Linked<IDistributedFileTransactionExt> localtrans;
  5758. if (transaction)
  5759. {
  5760. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  5761. localtrans.set(_transaction);
  5762. }
  5763. else
  5764. localtrans.setown(new CDistributedFileTransaction(udesc, this));
  5765. localtrans->ensureFile(this);
  5766. if (addcontents)
  5767. {
  5768. localtrans->descend();
  5769. StringArray subs;
  5770. Owned<IDistributedSuperFile> sfile = localtrans->lookupSuperFile(subfile);
  5771. if (sfile)
  5772. {
  5773. Owned<IDistributedFileIterator> iter = sfile->getSubFileIterator();
  5774. ForEach(*iter)
  5775. subs.append(iter->query().queryLogicalName());
  5776. }
  5777. sfile.clear();
  5778. ForEachItemIn(i,subs)
  5779. addSubFile(subs.item(i),before,other,false,localtrans);
  5780. localtrans->ascend();
  5781. }
  5782. else
  5783. {
  5784. cAddSubFileAction *action = new cAddSubFileAction(queryLogicalName(),subfile,before,other);
  5785. localtrans->addAction(action); // takes ownership
  5786. }
  5787. localtrans->autoCommit();
  5788. }
  5789. virtual bool removeSubFile(const char *subfile, // if NULL removes all
  5790. bool remsub, // if true removes subfiles from DFS
  5791. bool remcontents, // if true, recurse super-files
  5792. IDistributedFileTransaction *transaction) override
  5793. {
  5794. CriticalBlock block (sect);
  5795. if (subfile&&!*subfile)
  5796. return false;
  5797. checkModify("removeSubFile");
  5798. partscache.kill();
  5799. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  5800. Linked<IDistributedFileTransactionExt> localtrans;
  5801. if (transaction)
  5802. {
  5803. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  5804. localtrans.set(_transaction);
  5805. }
  5806. else
  5807. localtrans.setown(new CDistributedFileTransaction(udesc, this));
  5808. // Make sure this file is in cache (reuse below)
  5809. localtrans->ensureFile(this);
  5810. // If recurring, traverse super-file subs (if super)
  5811. if (remcontents)
  5812. {
  5813. localtrans->descend();
  5814. CDfsLogicalFileName logicalname;
  5815. logicalname.set(subfile);
  5816. IDistributedFile *sub = querySubFileNamed(logicalname.get(),false);
  5817. if (!sub)
  5818. return false;
  5819. IDistributedSuperFile *sfile = sub->querySuperFile();
  5820. if (sfile)
  5821. {
  5822. Owned<IDistributedFileIterator> iter = sfile->getSubFileIterator(true);
  5823. bool ret = true;
  5824. StringArray toremove;
  5825. ForEach(*iter)
  5826. toremove.append(iter->query().queryLogicalName());
  5827. iter.clear();
  5828. ForEachItemIn(i,toremove)
  5829. {
  5830. if (!sfile->removeSubFile(toremove.item(i),remsub,false,localtrans))
  5831. ret = false;
  5832. }
  5833. if (!ret||!remsub)
  5834. return ret;
  5835. }
  5836. localtrans->ascend();
  5837. }
  5838. cRemoveSubFileAction *action = new cRemoveSubFileAction(queryLogicalName(),subfile,remsub);
  5839. localtrans->addAction(action); // takes ownership
  5840. localtrans->autoCommit();
  5841. // MORE - auto-commit will throw an exception, change this to void
  5842. return true;
  5843. }
  5844. virtual bool removeOwnedSubFiles(bool remsub, // if true removes subfiles from DFS
  5845. IDistributedFileTransaction *transaction) override
  5846. {
  5847. CriticalBlock block (sect);
  5848. checkModify("removeOwnedSubFiles");
  5849. partscache.kill();
  5850. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  5851. Linked<IDistributedFileTransactionExt> localtrans;
  5852. if (transaction)
  5853. {
  5854. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  5855. localtrans.set(_transaction);
  5856. }
  5857. else
  5858. localtrans.setown(new CDistributedFileTransaction(udesc, this));
  5859. // Make sure this file is in cache (reuse below)
  5860. localtrans->addFile(this);
  5861. cRemoveOwnedSubFilesAction *action = new cRemoveOwnedSubFilesAction(localtrans, queryLogicalName(), remsub);
  5862. localtrans->addAction(action); // takes ownership
  5863. localtrans->autoCommit();
  5864. // MORE - auto-commit will throw an exception, change this to void
  5865. return true;
  5866. }
  5867. virtual bool swapSuperFile( IDistributedSuperFile *_file,
  5868. IDistributedFileTransaction *transaction) override
  5869. {
  5870. CriticalBlock block (sect);
  5871. if (!_file)
  5872. return false;
  5873. checkModify("swapSuperFile");
  5874. partscache.kill();
  5875. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  5876. Linked<IDistributedFileTransactionExt> localtrans;
  5877. if (transaction)
  5878. {
  5879. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  5880. localtrans.set(_transaction);
  5881. }
  5882. else
  5883. localtrans.setown(new CDistributedFileTransaction(udesc, this));
  5884. // Make sure this file is in cache
  5885. localtrans->ensureFile(this);
  5886. cSwapFileAction *action = new cSwapFileAction(queryLogicalName(),_file->queryLogicalName());
  5887. localtrans->addAction(action); // takes ownership
  5888. localtrans->autoCommit();
  5889. return true;
  5890. }
  5891. virtual void savePartsAttr(bool force) override
  5892. {
  5893. }
  5894. void fillClustersCache()
  5895. {
  5896. if (clusterscache.ordinality()==0) {
  5897. StringBuffer name;
  5898. ForEachItemIn(i,subfiles) {
  5899. StringArray clusters;
  5900. IDistributedFile &f=subfiles.item(i);
  5901. unsigned nc = f.numClusters();
  5902. for(unsigned j=0;j<nc;j++) {
  5903. f.getClusterName(j,name.clear());
  5904. if (clusterscache.find(name.str())==NotFound) {
  5905. IClusterInfo &cluster = *createClusterInfo(name.str(),f.queryClusterGroup(j),f.queryPartDiskMapping(j),&queryNamedGroupStore());
  5906. clusterscache.append(cluster);
  5907. }
  5908. }
  5909. }
  5910. }
  5911. }
  5912. virtual unsigned getClusterNames(StringArray &clusters) override
  5913. {
  5914. CriticalBlock block (sect);
  5915. fillClustersCache();
  5916. return clusterscache.getNames(clusters);
  5917. }
  5918. virtual unsigned numClusters() override
  5919. {
  5920. CriticalBlock block (sect);
  5921. fillClustersCache();
  5922. return clusterscache.ordinality();
  5923. }
  5924. virtual unsigned findCluster(const char *clustername) override
  5925. {
  5926. CriticalBlock block (sect);
  5927. fillClustersCache();
  5928. return clusterscache.find(clustername);
  5929. }
  5930. virtual ClusterPartDiskMapSpec &queryPartDiskMapping(unsigned clusternum) override
  5931. {
  5932. CriticalBlock block (sect);
  5933. fillClustersCache();
  5934. return clusterscache.queryPartDiskMapping(clusternum);
  5935. }
  5936. virtual void updatePartDiskMapping(const char *clustername,const ClusterPartDiskMapSpec &spec) override
  5937. {
  5938. if (!clustername||!*clustername)
  5939. return;
  5940. CriticalBlock block (sect);
  5941. fillClustersCache();
  5942. ForEachItemIn(i,subfiles) {
  5943. IDistributedFile &f=subfiles.item(i);
  5944. f.updatePartDiskMapping(clustername,spec);
  5945. }
  5946. }
  5947. virtual IGroup *queryClusterGroup(unsigned clusternum) override
  5948. {
  5949. CriticalBlock block (sect);
  5950. fillClustersCache();
  5951. return clusterscache.queryGroup(clusternum);
  5952. }
  5953. virtual StringBuffer &getClusterGroupName(unsigned clusternum, StringBuffer &name) override
  5954. {
  5955. CriticalBlock block (sect);
  5956. fillClustersCache();
  5957. return clusterscache.item(clusternum).getGroupName(name, &queryNamedGroupStore());
  5958. }
  5959. virtual void addCluster(const char *clustername,const ClusterPartDiskMapSpec &mspec) override
  5960. {
  5961. if (!clustername||!*clustername)
  5962. return;
  5963. CriticalBlock block (sect);
  5964. clusterscache.clear();
  5965. subfiles.item(0).addCluster(clustername,mspec);
  5966. }
  5967. virtual bool removeCluster(const char *clustername) override
  5968. {
  5969. bool clusterRemoved=false;
  5970. CriticalBlock block (sect);
  5971. clusterscache.clear();
  5972. ForEachItemIn(i,subfiles) {
  5973. IDistributedFile &f=subfiles.item(i);
  5974. clusterRemoved |= f.removeCluster(clustername);
  5975. }
  5976. return clusterRemoved;
  5977. }
  5978. virtual void setPreferredClusters(const char *clusters) override
  5979. {
  5980. CriticalBlock block (sect);
  5981. clusterscache.clear();
  5982. ForEachItemIn(i,subfiles) {
  5983. IDistributedFile &f=subfiles.item(i);
  5984. f.setPreferredClusters(clusters);
  5985. }
  5986. }
  5987. virtual bool checkClusterCompatible(IFileDescriptor &fdesc, StringBuffer &err) override
  5988. {
  5989. CriticalBlock block (sect);
  5990. if (subfiles.ordinality()!=1) {
  5991. err.append("only singleton superfiles allowed");
  5992. return false;
  5993. }
  5994. ForEachItemIn(i,subfiles) {
  5995. IDistributedFile &f=subfiles.item(i);
  5996. if (!f.checkClusterCompatible(fdesc,err))
  5997. return false;
  5998. }
  5999. return true;
  6000. }
  6001. virtual void setSingleClusterOnly() override
  6002. {
  6003. CriticalBlock block (sect);
  6004. ForEachItemIn(i,subfiles) {
  6005. IDistributedFile &f=subfiles.item(i);
  6006. f.setSingleClusterOnly();
  6007. }
  6008. }
  6009. virtual void enqueueReplicate() override
  6010. {
  6011. CriticalBlock block (sect);
  6012. ForEachItemIn(i,subfiles) {
  6013. IDistributedFile &f=subfiles.item(i);
  6014. f.enqueueReplicate();
  6015. }
  6016. }
  6017. virtual bool getAccessedTime(CDateTime &dt) override
  6018. {
  6019. bool set=false;
  6020. CriticalBlock block (sect);
  6021. ForEachItemIn(i,subfiles) {
  6022. IDistributedFile &f=subfiles.item(i);
  6023. if (!set)
  6024. set = f.getAccessedTime(dt);
  6025. else {
  6026. CDateTime cmp;
  6027. if (f.getAccessedTime(cmp)) {
  6028. if (cmp.compare(dt)>0)
  6029. dt.set(cmp);
  6030. }
  6031. }
  6032. }
  6033. return set;
  6034. }
  6035. virtual void setAccessedTime(const CDateTime &dt) override
  6036. {
  6037. {
  6038. CriticalBlock block (sect);
  6039. ForEachItemIn(i,subfiles) {
  6040. IDistributedFile &f=subfiles.item(i);
  6041. f.setAccessedTime(dt);
  6042. }
  6043. }
  6044. }
  6045. };
  6046. // --------------------------------------------------------
  6047. void CDistributedFileTransaction::validateAddSubFile(IDistributedSuperFile *super, IDistributedFile *sub, const char *subName)
  6048. {
  6049. CTransactionFile *trackedSuper = lookupTrackedFile(super);
  6050. if (!trackedSuper)
  6051. return;
  6052. const char *superName = trackedSuper->queryName();
  6053. if (strcmp(subName, superName)==0)
  6054. throw MakeStringException(-1,"addSubFile: Cannot add file %s to itself", superName);
  6055. if (trackedSuper->numSubFiles())
  6056. {
  6057. CDistributedSuperFile *sf = dynamic_cast<CDistributedSuperFile *>(super);
  6058. sf->checkFormatAttr(sub, "addSubFile");
  6059. if (trackedSuper->find(subName, false))
  6060. throw MakeStringException(-1,"addSubFile: File %s is already a subfile of %s", subName, superName);
  6061. }
  6062. }
  6063. // --------------------------------------------------------
  6064. CDistributedFilePart::CDistributedFilePart(CDistributedFile &_parent,unsigned _part,IPartDescriptor *pd)
  6065. : parent(_parent)
  6066. {
  6067. partIndex = _part;
  6068. dirty = false;
  6069. if (pd) {
  6070. if (pd->isMulti())
  6071. IERRLOG("Multi filenames not supported in Dali DFS Part %d of %s",_part+1,_parent.queryLogicalName());
  6072. overridename.set(pd->queryOverrideName());
  6073. setAttr(*pd->getProperties());
  6074. }
  6075. else
  6076. IERRLOG("CDistributedFilePart::CDistributedFilePart no IPartDescriptor for part");
  6077. }
  6078. void CDistributedFilePart::Link(void) const
  6079. {
  6080. parent.Link();
  6081. CInterface::Link();
  6082. }
  6083. bool CDistributedFilePart::Release(void) const
  6084. {
  6085. parent.Release();
  6086. return CInterface::Release();
  6087. }
  6088. offset_t CDistributedFilePart::getSize(bool checkCompressed)
  6089. {
  6090. offset_t ret = (offset_t)-1;
  6091. StringBuffer firstname;
  6092. bool compressed = ::isCompressed(parent.queryAttributes());
  6093. unsigned nc=parent.numCopies(partIndex);
  6094. for (unsigned copy=0;copy<nc;copy++)
  6095. {
  6096. RemoteFilename rfn;
  6097. try
  6098. {
  6099. Owned<IFile> partfile = createIFile(getFilename(rfn,copy));
  6100. if (checkCompressed && compressed)
  6101. {
  6102. Owned<ICompressedFileIO> compressedIO = createCompressedFileReader(partfile);
  6103. if (compressedIO)
  6104. ret = compressedIO->size();
  6105. }
  6106. else
  6107. ret = partfile->size();
  6108. if (ret!=(offset_t)-1)
  6109. return ret;
  6110. }
  6111. catch (IException *e)
  6112. {
  6113. StringBuffer s("CDistributedFilePart::getSize ");
  6114. rfn.getRemotePath(s);
  6115. EXCLOG(e, s.str());
  6116. e->Release();
  6117. }
  6118. if (copy==0)
  6119. rfn.getRemotePath(firstname);
  6120. }
  6121. throw new CDFS_Exception(DFSERR_CannotFindPartFileSize,firstname.str());;
  6122. }
  6123. StringBuffer & CDistributedFilePart::getPartName(StringBuffer &partname)
  6124. {
  6125. if (!overridename.isEmpty()) {
  6126. if (isSpecialPath(overridename)) {
  6127. // bit of a kludge
  6128. if (isPathSepChar(*overridename)&&partname.length()&&isPathSepChar(partname.charAt(partname.length()-1)))
  6129. partname.setLength(partname.length()-1);
  6130. return partname.append(overridename);
  6131. }
  6132. return partname.append(pathTail(overridename));
  6133. }
  6134. const char *mask=parent.queryPartMask();
  6135. if (!mask||!*mask) {
  6136. const char *err ="CDistributedFilePart::getPartName cannot determine part name (no mask)";
  6137. IERRLOG("%s", err);
  6138. throw MakeStringExceptionDirect(-1, err);
  6139. }
  6140. expandMask(partname,mask,partIndex,parent.numParts());
  6141. return partname;
  6142. }
  6143. unsigned CDistributedFilePart::bestCopyNum(const IpAddress &ip,unsigned rel)
  6144. {
  6145. unsigned n = numCopies();
  6146. unsigned *dist = new unsigned[n];
  6147. unsigned *idx = new unsigned[n];
  6148. for (unsigned c=0;c<n;c++) {
  6149. dist[c] = ip.ipdistance(queryNode(c)->endpoint());
  6150. idx[c] = c;
  6151. }
  6152. if (rel>=n)
  6153. rel = n-1;
  6154. // do bubble sort as not that many!
  6155. for (unsigned i=0; i<n-1; i++)
  6156. for (unsigned j=0; j<n-1-i; j++)
  6157. if (dist[idx[j+1]] < dist[idx[j]]) {
  6158. unsigned t = idx[j];
  6159. idx[j] = idx[j+1];
  6160. idx[j+1] = t;
  6161. }
  6162. unsigned ret = idx[rel];
  6163. delete [] idx;
  6164. delete [] dist;
  6165. return ret;
  6166. }
  6167. unsigned CDistributedFilePart::copyClusterNum(unsigned copy,unsigned *replicate)
  6168. {
  6169. return parent.copyClusterNum(partIndex,copy,replicate);
  6170. }
  6171. StringBuffer &CDistributedFilePart::getPartDirectory(StringBuffer &ret,unsigned copy)
  6172. {
  6173. const char *defdir = parent.queryDefaultDir();
  6174. StringBuffer dir;
  6175. const char *pn;
  6176. if (overridename.isEmpty())
  6177. pn = parent.queryPartMask();
  6178. else {
  6179. pn = overridename.get();
  6180. if (isSpecialPath(pn)) // its a query
  6181. return ret; // ret.append('/'); // not sure if really need '/' here
  6182. }
  6183. if (pn&&*pn) {
  6184. StringBuffer odir;
  6185. splitDirTail(pn,odir);
  6186. if (odir.length()) {
  6187. if (isAbsolutePath(pn))
  6188. dir.append(odir);
  6189. else if (defdir&&*defdir)
  6190. addPathSepChar(dir.append(defdir)).append(odir);
  6191. }
  6192. else
  6193. dir.append(defdir);
  6194. }
  6195. if (dir.length()==0)
  6196. IERRLOG("IDistributedFilePart::getPartDirectory unable to determine part directory");
  6197. else {
  6198. parent.adjustClusterDir(partIndex,copy,dir);
  6199. ret.append(dir);
  6200. }
  6201. return ret;
  6202. }
  6203. unsigned CDistributedFilePart::numCopies()
  6204. {
  6205. return parent.numCopies(partIndex);
  6206. }
  6207. INode *CDistributedFilePart::queryNode(unsigned copy)
  6208. {
  6209. return parent.queryNode(partIndex,copy);
  6210. }
  6211. unsigned CDistributedFilePart::queryDrive(unsigned copy)
  6212. {
  6213. return parent.queryDrive(partIndex,copy,parent.directory);
  6214. }
  6215. bool CDistributedFilePart::isHost(unsigned copy)
  6216. {
  6217. return (queryNode(copy)->isHost());
  6218. }
  6219. IPropertyTree &CDistributedFilePart::queryAttributes()
  6220. {
  6221. CriticalBlock block (sect); // avoid nested blocks
  6222. if (attr)
  6223. return *attr;
  6224. DBGLOG("CDistributedFilePart::queryAttributes missing part attributes");
  6225. attr.setown(getEmptyAttr());
  6226. return *attr;
  6227. }
  6228. RemoteFilename &CDistributedFilePart::getFilename(RemoteFilename &ret,unsigned copy)
  6229. {
  6230. // this is probably not as efficient as could be
  6231. StringBuffer fullpath;
  6232. getPartDirectory(fullpath,copy);
  6233. addPathSepChar(fullpath);
  6234. getPartName(fullpath);
  6235. SocketEndpoint ep;
  6236. INode *node=queryNode(copy);
  6237. if (node)
  6238. ep = node->endpoint();
  6239. ret.setPath(ep,fullpath.str());
  6240. return ret;
  6241. }
  6242. bool CDistributedFilePart::getCrc(unsigned &crc)
  6243. {
  6244. return getCrcFromPartProps(parent.queryAttributes(),queryAttributes(), crc);
  6245. }
  6246. unsigned CDistributedFilePart::getPhysicalCrc()
  6247. {
  6248. StringBuffer firstname;
  6249. unsigned nc=parent.numCopies(partIndex);
  6250. for (unsigned copy=0;copy<nc;copy++) {
  6251. RemoteFilename rfn;
  6252. try {
  6253. Owned<IFile> partfile = createIFile(getFilename(rfn,copy));
  6254. if (partfile&&partfile->exists())
  6255. return partfile->getCRC();
  6256. }
  6257. catch (IException *e)
  6258. {
  6259. StringBuffer s("CDistributedFilePart::getPhysicalCrc ");
  6260. rfn.getRemotePath(s);
  6261. EXCLOG(e, s.str());
  6262. e->Release();
  6263. }
  6264. if (copy==0)
  6265. rfn.getRemotePath(firstname);
  6266. }
  6267. IDFS_Exception *e = new CDFS_Exception(DFSERR_CannotFindPartFileCrc,firstname.str());
  6268. throw e;
  6269. }
  6270. // TODO: Create DistributedFilePropertyLock for parts
  6271. bool CDistributedFilePart::lockProperties(unsigned timeoutms)
  6272. {
  6273. dirty = true;
  6274. return parent.lockProperties(timeoutms);
  6275. }
  6276. // TODO: Create DistributedFilePropertyLock for parts
  6277. void CDistributedFilePart::unlockProperties(DFTransactionState state=TAS_NONE)
  6278. {
  6279. parent.unlockProperties(state);
  6280. }
  6281. offset_t CDistributedFilePart::getFileSize(bool allowphysical,bool forcephysical)
  6282. {
  6283. offset_t ret = (offset_t)((forcephysical&&allowphysical)?-1:queryAttributes().getPropInt64("@size", -1));
  6284. if (allowphysical&&(ret==(offset_t)-1))
  6285. ret = getSize(true);
  6286. return ret;
  6287. }
  6288. offset_t CDistributedFilePart::getDiskSize(bool allowphysical,bool forcephysical)
  6289. {
  6290. if (!::isCompressed(parent.queryAttributes()))
  6291. return getFileSize(allowphysical, forcephysical);
  6292. if (forcephysical && allowphysical)
  6293. return getSize(false); // i.e. only if force, because all compressed should have @compressedSize attribute
  6294. // NB: compressSize is disk size
  6295. return queryAttributes().getPropInt64("@compressedSize", -1);
  6296. }
  6297. bool CDistributedFilePart::getModifiedTime(bool allowphysical,bool forcephysical, CDateTime &dt)
  6298. {
  6299. StringBuffer s;
  6300. if (!forcephysical&&queryAttributes().getProp("@modified", s)) {
  6301. dt.setString(s.str());
  6302. if (!dt.isNull())
  6303. return true;
  6304. }
  6305. if (allowphysical) {
  6306. unsigned nc=parent.numCopies(partIndex);
  6307. for (unsigned copy=0;copy<nc;copy++) {
  6308. RemoteFilename rfn;
  6309. try {
  6310. Owned<IFile> partfile = createIFile(getFilename(rfn,copy));
  6311. if (partfile->getTime(NULL,&dt,NULL))
  6312. return true;
  6313. }
  6314. catch (IException *e)
  6315. {
  6316. StringBuffer s("CDistributedFilePart::getFileTime ");
  6317. rfn.getRemotePath(s);
  6318. EXCLOG(e, s.str());
  6319. e->Release();
  6320. }
  6321. }
  6322. }
  6323. return false;
  6324. }
  6325. unsigned getSuperFileSubs(IDistributedSuperFile *super, IArrayOf<IDistributedFile> &subFiles, bool superSub)
  6326. {
  6327. unsigned numSubs = super->numSubFiles(superSub);
  6328. for (unsigned s=0; s<numSubs; s++)
  6329. {
  6330. IDistributedFile &subFile = super->querySubFile(s, superSub);
  6331. subFiles.append(*LINK(&subFile));
  6332. }
  6333. return numSubs;
  6334. }
  6335. // --------------------------------------------------------
  6336. class CNamedGroupIterator: implements INamedGroupIterator, public CInterface
  6337. {
  6338. Owned<IPropertyTreeIterator> pe;
  6339. Linked<IRemoteConnection> conn;
  6340. Linked<IGroup> matchgroup;
  6341. bool exactmatch;
  6342. bool match();
  6343. public:
  6344. IMPLEMENT_IINTERFACE;
  6345. CNamedGroupIterator(IRemoteConnection *_conn,IGroup *_matchgroup=NULL,bool _exactmatch=false)
  6346. : conn(_conn), matchgroup(_matchgroup)
  6347. {
  6348. exactmatch = _exactmatch;
  6349. if (matchgroup.get()) {
  6350. StringBuffer query;
  6351. query.append("Group[Node/@ip=\"");
  6352. matchgroup->queryNode(0).endpoint().getUrlStr(query);
  6353. query.append("\"]");
  6354. pe.setown(conn->getElements(query.str()));
  6355. }
  6356. else
  6357. pe.setown(conn->queryRoot()->getElements("Group"));
  6358. }
  6359. bool first()
  6360. {
  6361. if (!pe->first())
  6362. return false;
  6363. if (match())
  6364. return true;
  6365. return next();
  6366. }
  6367. bool next()
  6368. {
  6369. while (pe->next())
  6370. if (match())
  6371. return true;
  6372. return false;
  6373. }
  6374. bool isValid()
  6375. {
  6376. return pe->isValid();
  6377. }
  6378. StringBuffer &get(StringBuffer &name)
  6379. {
  6380. pe->query().getProp("@name",name);
  6381. return name;
  6382. }
  6383. StringBuffer &getdir(StringBuffer &dir)
  6384. {
  6385. pe->query().getProp("@dir",dir);
  6386. return dir;
  6387. }
  6388. bool isCluster()
  6389. {
  6390. return pe->query().getPropBool("@cluster");
  6391. }
  6392. };
  6393. // --------------------------------------------------------
  6394. #define GROUP_CACHE_INTERVAL (1000*60)
  6395. #define GROUP_EXCEPTION_CACHE_INTERVAL (1000*60*10)
  6396. static GroupType translateGroupType(const char *groupType)
  6397. {
  6398. if (!groupType)
  6399. return grp_unknown;
  6400. if (strieq(groupType, "Thor"))
  6401. return grp_thor;
  6402. else if (strieq(groupType, "Roxie"))
  6403. return grp_roxie;
  6404. else if (strieq(groupType, "hthor"))
  6405. return grp_hthor;
  6406. else
  6407. return grp_unknown;
  6408. }
  6409. class CNamedGroupCacheEntry: public CInterface
  6410. {
  6411. public:
  6412. Linked<IGroup> group;
  6413. StringAttr name;
  6414. StringAttr groupDir;
  6415. GroupType groupType;
  6416. Linked<IException> exception;
  6417. CNamedGroupCacheEntry(IGroup *_group, const char *_name, const char *_dir, GroupType _groupType)
  6418. : group(_group), name(_name), groupDir(_dir), groupType(_groupType)
  6419. {
  6420. cachedtime = msTick();
  6421. }
  6422. CNamedGroupCacheEntry(IException *_exception, const char *_name)
  6423. : exception(_exception), name(_name), groupType(grp_unknown)
  6424. {
  6425. cachedtime = msTick();
  6426. }
  6427. bool expired(unsigned timeNow)
  6428. {
  6429. if (exception)
  6430. return timeNow-cachedtime > GROUP_EXCEPTION_CACHE_INTERVAL;
  6431. else
  6432. return timeNow-cachedtime > GROUP_CACHE_INTERVAL;
  6433. }
  6434. protected:
  6435. unsigned cachedtime;
  6436. };
  6437. class CNamedGroupStore: implements INamedGroupStore, public CInterface
  6438. {
  6439. CriticalSection cachesect;
  6440. CIArrayOf<CNamedGroupCacheEntry> cache;
  6441. unsigned defaultTimeout;
  6442. unsigned defaultRemoteTimeout;
  6443. public:
  6444. IMPLEMENT_IINTERFACE;
  6445. CNamedGroupStore()
  6446. {
  6447. defaultTimeout = INFINITE;
  6448. defaultRemoteTimeout = FOREIGN_DALI_TIMEOUT;
  6449. }
  6450. IGroup *dolookup(const char *logicalgroupname,IRemoteConnection *conn, StringBuffer *dirret, GroupType &groupType)
  6451. {
  6452. SocketEndpointArray epa;
  6453. StringBuffer gname(logicalgroupname);
  6454. gname.trim();
  6455. groupType = grp_unknown;
  6456. if (!gname.length())
  6457. return nullptr;
  6458. gname.toLowerCase();
  6459. logicalgroupname = gname.str();
  6460. bool isiprange = (*logicalgroupname!=0);
  6461. for (const char *s1=logicalgroupname;*s1;s1++)
  6462. if (isalpha(*s1)) {
  6463. isiprange = false;
  6464. break;
  6465. }
  6466. if (isiprange) {
  6467. // allow IP or IP list instead of group name
  6468. // I don't think this is a security problem as groups not checked
  6469. // NB ports not allowed here
  6470. char *buf = strdup(logicalgroupname);
  6471. char *s = buf;
  6472. while (*s) {
  6473. char *next = strchr(s,',');
  6474. if (next)
  6475. *next = 0;
  6476. SocketEndpoint ep;
  6477. unsigned n = ep.ipsetrange(s);
  6478. for (unsigned i=0;i<n;i++) {
  6479. if (ep.isNull()) { // failed
  6480. epa.kill();
  6481. break;
  6482. }
  6483. epa.append(ep);
  6484. ep.ipincrement(1);
  6485. }
  6486. if (!next)
  6487. break;
  6488. s = next+1;
  6489. }
  6490. free(buf);
  6491. if (epa.ordinality())
  6492. return createIGroup(epa);
  6493. }
  6494. StringBuffer range;
  6495. StringBuffer parent;
  6496. if (decodeChildGroupName(gname.str(),parent,range)) {
  6497. gname.clear().append(parent);
  6498. logicalgroupname = gname.str();
  6499. }
  6500. StringAttr groupdir;
  6501. GroupType type = grp_unknown;
  6502. bool cached = false;
  6503. unsigned timeNow = msTick();
  6504. {
  6505. CriticalBlock block(cachesect);
  6506. ForEachItemInRev(idx, cache)
  6507. {
  6508. CNamedGroupCacheEntry &entry = cache.item(idx);
  6509. if (entry.expired(timeNow))
  6510. {
  6511. cache.remove(idx);
  6512. }
  6513. else if (strcmp(gname.str(),entry.name.get())==0)
  6514. {
  6515. cached = true;
  6516. if (entry.exception)
  6517. throw LINK(entry.exception);
  6518. if (!entry.group) //cache entry of a deleted groupname
  6519. return nullptr;
  6520. if (range.length()==0)
  6521. {
  6522. if (dirret)
  6523. dirret->append(entry.groupDir);
  6524. groupType = entry.groupType;
  6525. return entry.group.getLink();
  6526. }
  6527. // there is a range so copy to epa
  6528. entry.group->getSocketEndpoints(epa);
  6529. groupdir.set(entry.groupDir);
  6530. type = entry.groupType;
  6531. break;
  6532. }
  6533. }
  6534. }
  6535. try
  6536. {
  6537. if ((gname.length()>9)&&(memcmp(logicalgroupname,"foreign::",9)==0))
  6538. {
  6539. StringBuffer eps;
  6540. const char *s = logicalgroupname+9;
  6541. while (*s&&((*s!=':')||(s[1]!=':')))
  6542. eps.append(*(s++));
  6543. if (*s)
  6544. {
  6545. s+=2;
  6546. if (*s)
  6547. {
  6548. Owned<INode> dali = createINode(eps.str());
  6549. if (!dali || !getRemoteGroup(dali, s, defaultRemoteTimeout, groupdir, type, epa))
  6550. {
  6551. if (!cached)
  6552. {
  6553. CriticalBlock block(cachesect);
  6554. cache.append(*new CNamedGroupCacheEntry(NULL, gname, NULL, grp_unknown));
  6555. }
  6556. return nullptr;
  6557. }
  6558. }
  6559. }
  6560. }
  6561. else if (epa.ordinality()==0) {
  6562. struct sLock
  6563. {
  6564. sLock() { lock = NULL; };
  6565. ~sLock() { delete lock; };
  6566. CConnectLock *lock;
  6567. } slock;
  6568. if (!conn)
  6569. {
  6570. slock.lock = new CConnectLock("CNamedGroup::lookup", SDS_GROUPSTORE_ROOT, false, false, false, defaultTimeout);
  6571. conn = slock.lock->conn;
  6572. if (!conn)
  6573. {
  6574. if (!cached)
  6575. {
  6576. CriticalBlock block(cachesect);
  6577. cache.append(*new CNamedGroupCacheEntry(NULL, gname, NULL, grp_unknown));
  6578. }
  6579. return nullptr;
  6580. }
  6581. }
  6582. Owned<IPropertyTree> pt = getNamedPropTree(conn->queryRoot(),"Group","@name",gname.str(),true);
  6583. if (!pt)
  6584. return nullptr;
  6585. type = translateGroupType(pt->queryProp("@kind"));
  6586. groupdir.set(pt->queryProp("@dir"));
  6587. if (groupdir.isEmpty())
  6588. groupdir.set(queryBaseDirectory(type));
  6589. Owned<IPropertyTreeIterator> pe2 = pt->getElements("Node");
  6590. ForEach(*pe2)
  6591. {
  6592. SocketEndpoint ep(pe2->query().queryProp("@ip"));
  6593. epa.append(ep);
  6594. }
  6595. }
  6596. }
  6597. catch (IException *E)
  6598. {
  6599. // cache the exception
  6600. CriticalBlock block(cachesect);
  6601. cache.append(*new CNamedGroupCacheEntry(E, gname));
  6602. throw;
  6603. }
  6604. Owned<IGroup> ret = createIGroup(epa);
  6605. if (!cached)
  6606. {
  6607. CriticalBlock block(cachesect);
  6608. cache.append(*new CNamedGroupCacheEntry(ret, gname, groupdir, type));
  6609. }
  6610. if (range.length())
  6611. {
  6612. SocketEndpointArray epar;
  6613. const char *s = range.str();
  6614. while (*s)
  6615. {
  6616. unsigned start = 0;
  6617. while (isdigit(*s))
  6618. {
  6619. start = start*10+*s-'0';
  6620. s++;
  6621. }
  6622. if (!start)
  6623. break;
  6624. unsigned end;
  6625. if (*s=='-')
  6626. {
  6627. s++;
  6628. end = 0;
  6629. while (isdigit(*s))
  6630. {
  6631. end = end*10+*s-'0';
  6632. s++;
  6633. }
  6634. if (!end)
  6635. end = epa.ordinality();
  6636. }
  6637. else
  6638. end = start;
  6639. if ((start>epa.ordinality())||(end>epa.ordinality()))
  6640. {
  6641. s = range.str();
  6642. break;
  6643. }
  6644. if (*s==',')
  6645. s++;
  6646. unsigned i=start-1;
  6647. do { // allow 400-1 etc
  6648. i++;
  6649. if (i>epa.ordinality())
  6650. i = 1;
  6651. epar.append(epa.item(i-1));
  6652. } while (i!=end);
  6653. }
  6654. if (*s)
  6655. throw MakeStringException(-1,"Invalid group range %s",range.str());
  6656. ret.setown(createIGroup(epar));
  6657. }
  6658. if (dirret)
  6659. dirret->append(groupdir);
  6660. groupType = type;
  6661. return ret.getClear();
  6662. }
  6663. IGroup *lookup(const char *logicalgroupname)
  6664. {
  6665. GroupType dummy;
  6666. return dolookup(logicalgroupname, NULL, NULL, dummy);
  6667. }
  6668. IGroup *lookup(const char *logicalgroupname, StringBuffer &dir, GroupType &groupType)
  6669. {
  6670. return dolookup(logicalgroupname, NULL, &dir, groupType);
  6671. }
  6672. INamedGroupIterator *getIterator()
  6673. {
  6674. CConnectLock connlock("CNamedGroup::getIterator", SDS_GROUPSTORE_ROOT, false, true, false, defaultTimeout);
  6675. return new CNamedGroupIterator(connlock.conn); // links connection
  6676. }
  6677. INamedGroupIterator *getIterator(IGroup *match,bool exact)
  6678. {
  6679. CConnectLock connlock("CNamedGroup::getIterator", SDS_GROUPSTORE_ROOT, false, false, false, defaultTimeout);
  6680. return new CNamedGroupIterator(connlock.conn,match,exact); // links connection
  6681. }
  6682. void doadd(CConnectLock &connlock,const char *name,IGroup *group,bool cluster,const char *dir)
  6683. {
  6684. if (!group)
  6685. return;
  6686. IPropertyTree *val = createPTree("Group");
  6687. val->setProp("@name",name);
  6688. if (cluster)
  6689. val->setPropBool("@cluster", true);
  6690. if (dir)
  6691. val->setProp("@dir",dir);
  6692. INodeIterator &gi = *group->getIterator();
  6693. StringBuffer str;
  6694. ForEach(gi) {
  6695. IPropertyTree *n = createPTree("Node");
  6696. n = val->addPropTree("Node",n);
  6697. gi.query().endpoint().getIpText(str.clear());
  6698. n->setProp("@ip",str.str());
  6699. }
  6700. gi.Release();
  6701. connlock.conn->queryRoot()->addPropTree("Group",val);
  6702. }
  6703. void addUnique(IGroup *group,StringBuffer &lname, const char *dir)
  6704. {
  6705. if (group->ordinality()==1)
  6706. {
  6707. group->getText(lname);
  6708. return;
  6709. }
  6710. CConnectLock connlock("CNamedGroup::addUnique", SDS_GROUPSTORE_ROOT, true, false, false, defaultTimeout);
  6711. StringBuffer name;
  6712. StringBuffer prop;
  6713. unsigned scale = 16;
  6714. for (;;) {
  6715. name.clear();
  6716. if (lname.length()) { // try suggested name
  6717. name.append(lname);
  6718. name.toLowerCase();
  6719. lname.clear();
  6720. }
  6721. else
  6722. name.append("__anon").append(getRandom()%scale);
  6723. prop.clear().appendf("Group[@name=\"%s\"]",name.str());
  6724. if (!connlock.conn->queryRoot()->hasProp(prop.str()))
  6725. break;
  6726. scale*=2;
  6727. }
  6728. doadd(connlock,name.str(),group,false,dir);
  6729. lname.append(name);
  6730. }
  6731. void add(const char *logicalgroupname, IGroup *group, bool cluster, const char *dir, GroupType groupType)
  6732. {
  6733. StringBuffer name(logicalgroupname);
  6734. name.toLowerCase();
  6735. name.trim();
  6736. StringBuffer prop;
  6737. prop.appendf("Group[@name=\"%s\"]",name.str());
  6738. CConnectLock connlock("CNamedGroup::add", SDS_GROUPSTORE_ROOT, true, false, false, defaultTimeout);
  6739. connlock.conn->queryRoot()->removeProp(prop.str());
  6740. doadd(connlock,name.str(),group,cluster,dir);
  6741. {
  6742. CriticalBlock block(cachesect);
  6743. cache.kill();
  6744. if (group)
  6745. cache.append(*new CNamedGroupCacheEntry(group, name.str(), dir, groupType));
  6746. }
  6747. }
  6748. void remove(const char *logicalgroupname)
  6749. {
  6750. add(logicalgroupname, NULL, false, NULL, grp_unknown);
  6751. }
  6752. bool find(IGroup *grp, StringBuffer &gname, bool add)
  6753. {
  6754. // gname on entry is suggested name for add if set
  6755. unsigned n = grp->ordinality();
  6756. if (!grp||!n)
  6757. return false;
  6758. Owned<INamedGroupIterator> iter=getIterator(grp,(n==1)); // one node clusters must be exact match
  6759. StringAttr bestname;
  6760. StringBuffer name;
  6761. ForEach(*iter) {
  6762. bool iscluster = iter->isCluster();
  6763. if (iscluster||(bestname.isEmpty())) {
  6764. iter->get(name.clear());
  6765. if (name.length()) {
  6766. bestname.set(name);
  6767. if (iscluster)
  6768. break;
  6769. }
  6770. }
  6771. }
  6772. iter.clear();
  6773. if (bestname.isEmpty()) {
  6774. if (add||(n==1)) // single-nodes always have implicit group of IP
  6775. addUnique(grp,gname,NULL);
  6776. return false;
  6777. }
  6778. gname.clear().append(bestname);
  6779. return true;
  6780. }
  6781. void swapNode(const IpAddress &from, const IpAddress &to)
  6782. {
  6783. if (from.ipequals(to))
  6784. return;
  6785. CConnectLock connlock("CNamedGroup::swapNode", SDS_GROUPSTORE_ROOT, true, false, false, defaultTimeout);
  6786. StringBuffer froms;
  6787. from.getIpText(froms);
  6788. StringBuffer tos;
  6789. to.getIpText(tos);
  6790. Owned<IPropertyTreeIterator> pe = connlock.conn->queryRoot()->getElements("Group");
  6791. ForEach(*pe) {
  6792. IPropertyTree &group = pe->query();
  6793. const char *kind = group.queryProp("@kind");
  6794. if (kind && streq("Spare", kind))
  6795. continue;
  6796. StringBuffer name;
  6797. group.getProp("@name",name);
  6798. StringBuffer xpath("Node[@ip = \"");
  6799. xpath.append(froms).append("\"]");
  6800. for (unsigned guard=0; guard<1000; guard++) {
  6801. Owned<IPropertyTreeIterator> ne = group.getElements(xpath.str());
  6802. if (!ne->first())
  6803. break;
  6804. ne->query().setProp("@ip",tos.str());
  6805. PROGLOG("swapNode swapping %s for %s in group %s",froms.str(),tos.str(),name.str());
  6806. unsigned nodesSwapped = group.getPropInt("@nodesSwapped");
  6807. group.setPropInt("@nodesSwapped", nodesSwapped+1);
  6808. }
  6809. }
  6810. CriticalBlock block(cachesect);
  6811. cache.kill();
  6812. }
  6813. unsigned setDefaultTimeout(unsigned timems)
  6814. {
  6815. unsigned ret = defaultTimeout;
  6816. defaultTimeout = timems;
  6817. return ret;
  6818. }
  6819. unsigned setRemoteTimeout(unsigned timems)
  6820. {
  6821. unsigned ret = defaultRemoteTimeout;
  6822. defaultRemoteTimeout = timems;
  6823. return ret;
  6824. }
  6825. void resetCache()
  6826. {
  6827. CriticalBlock block(cachesect);
  6828. cache.kill();
  6829. }
  6830. private:
  6831. bool getRemoteGroup(const INode *foreigndali, const char *gname, unsigned foreigndalitimeout,
  6832. StringAttr &groupdir, GroupType &type, SocketEndpointArray &epa)
  6833. {
  6834. StringBuffer lcname(gname);
  6835. gname = lcname.trim().toLowerCase().str();
  6836. CMessageBuffer mb;
  6837. mb.append((int)MDFS_GET_GROUP_TREE).append(gname);
  6838. size32_t mbsz = mb.length();
  6839. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  6840. checkDfsReplyException(mb);
  6841. if (mb.length()==0)
  6842. return false;
  6843. byte ok;
  6844. mb.read(ok);
  6845. if (ok!=1) {
  6846. // kludge for prev bug
  6847. if ((ok==(byte)MDFS_GET_GROUP_TREE)&&mb.length()>mbsz) {
  6848. mb.skip(mbsz-1);
  6849. mb.read(ok);
  6850. if (ok!=1)
  6851. return false;
  6852. }
  6853. else
  6854. return false;
  6855. }
  6856. Owned<IPropertyTree> pt = createPTree(mb);
  6857. Owned<IPropertyTreeIterator> pe = pt->getElements("Node");
  6858. groupdir.set(pt->queryProp("@dir"));
  6859. type = translateGroupType(pt->queryProp("@kind"));
  6860. ForEach(*pe) {
  6861. SocketEndpoint ep(pe->query().queryProp("@ip"));
  6862. epa.append(ep);
  6863. }
  6864. return epa.ordinality() > 0;
  6865. }
  6866. };
  6867. static CNamedGroupStore *groupStore = NULL;
  6868. static CriticalSection groupsect;
  6869. bool CNamedGroupIterator::match()
  6870. {
  6871. if (conn.get()) {
  6872. if (matchgroup.get()) {
  6873. if (!groupStore)
  6874. return false;
  6875. const char *name = pe->query().queryProp("@name");
  6876. if (!name||!*name)
  6877. return false;
  6878. GroupType dummy;
  6879. Owned<IGroup> lgrp = groupStore->dolookup(name, conn, NULL, dummy);
  6880. if (lgrp) {
  6881. if (exactmatch)
  6882. return lgrp->equals(matchgroup);
  6883. GroupRelation gr = matchgroup->compare(lgrp);
  6884. return (gr==GRidentical)||(gr==GRbasesubset)||(gr==GRwrappedsuperset);
  6885. }
  6886. }
  6887. else
  6888. return true;
  6889. }
  6890. return false;
  6891. }
  6892. INamedGroupStore &queryNamedGroupStore()
  6893. {
  6894. if (!groupStore) {
  6895. CriticalBlock block(groupsect);
  6896. if (!groupStore)
  6897. groupStore = new CNamedGroupStore();
  6898. }
  6899. return *groupStore;
  6900. }
  6901. // --------------------------------------------------------
  6902. IDistributedFile *CDistributedFileDirectory::lookup(const char *_logicalname, IUserDescriptor *user, bool writeattr, bool hold, bool lockSuperOwner, IDistributedFileTransaction *transaction, unsigned timeout)
  6903. {
  6904. CDfsLogicalFileName logicalname;
  6905. logicalname.set(_logicalname);
  6906. return lookup(logicalname, user, writeattr, hold, lockSuperOwner, transaction, timeout);
  6907. }
  6908. IDistributedFile *CDistributedFileDirectory::dolookup(CDfsLogicalFileName &_logicalname, IUserDescriptor *user, bool writeattr, bool hold, bool lockSuperOwner, IDistributedFileTransaction *transaction, unsigned timeout)
  6909. {
  6910. CDfsLogicalFileName *logicalname = &_logicalname;
  6911. if (logicalname->isMulti())
  6912. // don't bother checking because the sub file creation will
  6913. return new CDistributedSuperFile(this,*logicalname,user,transaction); // temp superfile
  6914. if (strchr(logicalname->get(), '*')) // '*' only wildcard supported. NB: This is a temporary fix (See: HPCC-12523)
  6915. throw MakeStringException(-1, "Invalid filename lookup: %s", logicalname->get());
  6916. Owned<IDfsLogicalFileNameIterator> redmatch;
  6917. for (;;)
  6918. {
  6919. checkLogicalName(*logicalname,user,true,writeattr,true,NULL);
  6920. if (logicalname->isExternal()) {
  6921. Owned<IFileDescriptor> fDesc = getExternalFileDescriptor(logicalname->get());
  6922. if (!fDesc)
  6923. return NULL;
  6924. return queryDistributedFileDirectory().createExternal(fDesc, logicalname->get());
  6925. }
  6926. if (logicalname->isForeign()) {
  6927. IDistributedFile * ret = getFile(logicalname->get(),user,NULL);
  6928. if (ret)
  6929. return ret;
  6930. }
  6931. else {
  6932. unsigned start = 0;
  6933. for (;;) {
  6934. CFileLock fcl;
  6935. unsigned mode = RTM_LOCK_READ | RTM_SUB;
  6936. if (hold) mode |= RTM_LOCK_HOLD;
  6937. CTimeMon tm(timeout);
  6938. if (!fcl.init(*logicalname, mode, timeout, "CDistributedFileDirectory::lookup"))
  6939. break;
  6940. CFileSuperOwnerLock superOwnerLock;
  6941. if (lockSuperOwner)
  6942. {
  6943. unsigned remaining;
  6944. tm.timedout(&remaining);
  6945. verifyex(superOwnerLock.initWithFileLock(*logicalname, remaining, "CDistributedFileDirectory::dolookup(SuperOwnerLock)", fcl, mode));
  6946. }
  6947. if (fcl.getKind() == DXB_File)
  6948. {
  6949. StringBuffer cname;
  6950. if (logicalname->getCluster(cname).length())
  6951. {
  6952. IPropertyTree *froot=fcl.queryRoot();
  6953. if (froot)
  6954. {
  6955. StringBuffer query;
  6956. query.appendf("Cluster[@name=\"%s\"]",cname.str());
  6957. if (!froot->hasProp(query.str()))
  6958. break;
  6959. }
  6960. }
  6961. CDistributedFile *ret = new CDistributedFile(this,fcl.detach(),*logicalname,user); // found
  6962. ret->setSuperOwnerLock(superOwnerLock.detach());
  6963. return ret;
  6964. }
  6965. // now super file
  6966. if (fcl.getKind() != DXB_SuperFile)
  6967. break;
  6968. if (start==0)
  6969. start = msTick();
  6970. unsigned elapsed;
  6971. try
  6972. {
  6973. CDistributedSuperFile *ret = new CDistributedSuperFile(this,fcl.detach(),*logicalname,user,transaction,SDS_SUB_LOCK_TIMEOUT);
  6974. ret->setSuperOwnerLock(superOwnerLock.detach());
  6975. return ret;
  6976. }
  6977. catch (ISDSException *e)
  6978. {
  6979. elapsed = msTick()-start;
  6980. if ((e->errorCode()!=SDSExcpt_LockTimeout)||(elapsed>((timeout==INFINITE)?SDS_CONNECT_TIMEOUT:timeout)))
  6981. throw;
  6982. EXCLOG(e,"Superfile lookup");
  6983. e->Release();
  6984. }
  6985. PROGLOG("CDistributedSuperFile connect timeout (%dms) pausing",elapsed);
  6986. Sleep(SDS_TRANSACTION_RETRY/2+(getRandom()%SDS_TRANSACTION_RETRY));
  6987. }
  6988. }
  6989. if (redmatch.get()) {
  6990. if (!redmatch->next())
  6991. break;
  6992. }
  6993. else {
  6994. redmatch.setown(queryRedirection().getMatch(logicalname->get()));
  6995. if (!redmatch.get())
  6996. break;
  6997. if (!redmatch->first())
  6998. break;
  6999. }
  7000. logicalname = &redmatch->query();
  7001. }
  7002. return NULL;
  7003. }
  7004. IDistributedFile *CDistributedFileDirectory::lookup(CDfsLogicalFileName &logicalname, IUserDescriptor *user, bool writeattr, bool hold, bool lockSuperOwner, IDistributedFileTransaction *transaction, unsigned timeout)
  7005. {
  7006. return dolookup(logicalname, user, writeattr, hold, lockSuperOwner, transaction, timeout);
  7007. }
  7008. IDistributedSuperFile *CDistributedFileDirectory::lookupSuperFile(const char *_logicalname,IUserDescriptor *user,IDistributedFileTransaction *transaction, unsigned timeout)
  7009. {
  7010. CDfsLogicalFileName logicalname;
  7011. logicalname.set(_logicalname);
  7012. IDistributedFile *file = dolookup(logicalname, user, false, false, false, transaction, timeout);
  7013. if (file) {
  7014. IDistributedSuperFile *sf = file->querySuperFile();
  7015. if (sf)
  7016. return sf;
  7017. file->Release();
  7018. }
  7019. return NULL;
  7020. }
  7021. bool CDistributedFileDirectory::isSuperFile( const char *logicalname,
  7022. IUserDescriptor *user,
  7023. INode *foreigndali,
  7024. unsigned timeout)
  7025. {
  7026. Owned<IPropertyTree> tree = getFileTree(logicalname, user, foreigndali,timeout, false);
  7027. return tree.get()&&(strcmp(tree->queryName(),queryDfsXmlBranchName(DXB_SuperFile))==0);
  7028. }
  7029. bool CDistributedFileDirectory::exists(const char *_logicalname,IUserDescriptor *user,bool notsuper,bool superonly)
  7030. {
  7031. // (currently) no check on scope permissions for exists
  7032. bool external;
  7033. bool foreign;
  7034. CDfsLogicalFileName dlfn;
  7035. dlfn.set(_logicalname);
  7036. const char *logicalname = dlfn.get();
  7037. external = dlfn.isExternal();
  7038. foreign = dlfn.isForeign();
  7039. if (foreign) {
  7040. Owned<IDistributedFile> file = lookup(_logicalname, user, false, false, false, NULL, defaultTimeout);
  7041. if (file.get()==NULL)
  7042. return false;
  7043. if (file->querySuperFile()) {
  7044. if (notsuper)
  7045. return false;
  7046. }
  7047. else
  7048. if (superonly)
  7049. return false;
  7050. }
  7051. else if (external) {
  7052. if (!existsPhysical(_logicalname,user))
  7053. return false;
  7054. }
  7055. else {
  7056. StringBuffer str;
  7057. if (!superonly) {
  7058. dlfn.makeFullnameQuery(str,DXB_File,true);
  7059. CConnectLock connlockfile("CDistributedFileDirectory::exists",str.str(),false,false,false,defaultTimeout);
  7060. if (connlockfile.conn.get())
  7061. return true;
  7062. }
  7063. if (notsuper)
  7064. return false;
  7065. dlfn.makeFullnameQuery(str.clear(),DXB_SuperFile,true);
  7066. CConnectLock connlocksuper("CDistributedFileDirectory::exists",str.str(),false,false,false,defaultTimeout);
  7067. if (!connlocksuper.conn.get())
  7068. return false;
  7069. }
  7070. return true;
  7071. }
  7072. bool CDistributedFileDirectory::existsPhysical(const char *_logicalname, IUserDescriptor *user)
  7073. {
  7074. Owned<IDistributedFile> file = lookup(_logicalname, user, false, false, false, NULL, defaultTimeout);
  7075. if (!file)
  7076. return false;
  7077. return file->existsPhysicalPartFiles(0);
  7078. }
  7079. IDistributedFile *CDistributedFileDirectory::createNew(IFileDescriptor *fdesc)
  7080. {
  7081. return new CDistributedFile(this, fdesc, NULL, false);
  7082. }
  7083. IDistributedFile *CDistributedFileDirectory::createExternal(IFileDescriptor *fdesc, const char *name)
  7084. {
  7085. CDistributedFile *dFile = new CDistributedFile(this, fdesc, NULL, true);
  7086. dFile->setLogicalName(name);
  7087. return dFile;
  7088. }
  7089. ////////////////////////////////////
  7090. class DistributedFilePropertyLockFree
  7091. {
  7092. unsigned lockedCount;
  7093. CDistributedFile *file;
  7094. CDistributedSuperFile *sfile;
  7095. public:
  7096. DistributedFilePropertyLockFree(IDistributedFile *_file)
  7097. {
  7098. file = dynamic_cast<CDistributedFile *>(_file);
  7099. sfile = NULL;
  7100. if (file)
  7101. lockedCount = file->setPropLockCount(0);
  7102. else
  7103. {
  7104. sfile = dynamic_cast<CDistributedSuperFile *>(_file);
  7105. lockedCount = sfile->setPropLockCount(0);
  7106. }
  7107. }
  7108. ~DistributedFilePropertyLockFree()
  7109. {
  7110. if (file)
  7111. verifyex(0 == file->setPropLockCount(lockedCount));
  7112. else if (sfile)
  7113. verifyex(0 == sfile->setPropLockCount(lockedCount));
  7114. }
  7115. };
  7116. /**
  7117. * Creates a super-file within a transaction.
  7118. */
  7119. class CCreateSuperFileAction: public CDFAction
  7120. {
  7121. CDfsLogicalFileName logicalname;
  7122. CDistributedFileDirectory *parent;
  7123. Linked<IDistributedSuperFile> super;
  7124. IUserDescriptor *user;
  7125. bool interleaved, created;
  7126. void clearSuper()
  7127. {
  7128. if (created)
  7129. {
  7130. created = false;
  7131. super->detach();
  7132. }
  7133. super.clear();
  7134. }
  7135. public:
  7136. CCreateSuperFileAction(CDistributedFileDirectory *_parent,
  7137. IUserDescriptor *_user,
  7138. const char *_flname,
  7139. bool _interleaved)
  7140. : parent(_parent), user(_user), created(false), interleaved(_interleaved)
  7141. {
  7142. logicalname.set(_flname);
  7143. }
  7144. IDistributedSuperFile *getSuper()
  7145. {
  7146. if (!super)
  7147. {
  7148. Owned<IDistributedSuperFile> _super = transaction->lookupSuperFile(logicalname.get(), SDS_SUB_LOCK_TIMEOUT);
  7149. if (_super)
  7150. super.setown(_super.getClear());
  7151. else
  7152. {
  7153. /* No super, create one if necessary.
  7154. * This really shouldn't have to work this way, looking up super early, or creating super stub now,
  7155. * because other super file transactions are based on
  7156. * TBD: There should be a way to obtain lock independently of actually attaching.
  7157. */
  7158. Owned<IPropertyTree> root = createPTree();
  7159. root->setPropInt("@interleaved",interleaved?2:0); // this is ill placed
  7160. super.setown(new CDistributedSuperFile(parent, root, logicalname, user));
  7161. created = true;
  7162. transaction->addFile(super);
  7163. }
  7164. }
  7165. return super.getLink();
  7166. }
  7167. bool prepare()
  7168. {
  7169. Owned<IDistributedFile> _super = getSuper();
  7170. // Attach the file to DFS, if wasn't there already
  7171. if (created)
  7172. super->attach(logicalname.get(), user);
  7173. addFileLock(super);
  7174. if (lock())
  7175. return true;
  7176. unlock();
  7177. return false;
  7178. }
  7179. void run()
  7180. {
  7181. // Do nothing, file is already created
  7182. }
  7183. void retry()
  7184. {
  7185. // on retry, we need to remove the file so next lock doesn't fail
  7186. clearSuper();
  7187. CDFAction::retry();
  7188. }
  7189. void rollback()
  7190. {
  7191. state = TAS_FAILURE;
  7192. clearSuper();
  7193. CDFAction::rollback();
  7194. }
  7195. };
  7196. /**
  7197. * Removes a super-file within a transaction.
  7198. */
  7199. class CRemoveSuperFileAction: public CDFAction
  7200. {
  7201. CDfsLogicalFileName logicalname;
  7202. Linked<IDistributedSuperFile> super;
  7203. IUserDescriptor *user;
  7204. bool delSub;
  7205. Owned<IDistributedFileTransactionExt> nestedTransaction;
  7206. class CNestedTransaction : public CDistributedFileTransaction
  7207. {
  7208. IDistributedFileTransactionExt *transaction;
  7209. CIArrayOf<CDFAction> actions;
  7210. public:
  7211. CNestedTransaction(IDistributedFileTransactionExt *_transaction, IUserDescriptor *user)
  7212. : CDistributedFileTransaction(user), transaction(_transaction)
  7213. {
  7214. if (transaction->active())
  7215. start();
  7216. }
  7217. // wrap rest of calls into parent transaction calls
  7218. virtual IDistributedFile *lookupFile(const char *lfn,unsigned timeout=INFINITE)
  7219. {
  7220. return transaction->lookupFile(lfn, timeout);
  7221. }
  7222. virtual IDistributedSuperFile *lookupSuperFile(const char *slfn,unsigned timeout=INFINITE)
  7223. {
  7224. return transaction->lookupSuperFile(slfn, timeout);
  7225. }
  7226. virtual IUserDescriptor *queryUser() { return transaction->queryUser(); }
  7227. virtual void descend() { transaction->descend(); }
  7228. virtual void ascend() { transaction->ascend(); }
  7229. virtual void addFile(IDistributedFile *file) { transaction->addFile(file); }
  7230. virtual void ensureFile(IDistributedFile *file) { transaction->ensureFile(file); }
  7231. virtual void clearFile(IDistributedFile *file) { transaction->clearFile(file); }
  7232. virtual void noteAddSubFile(IDistributedSuperFile *super, const char *superName, IDistributedFile *sub)
  7233. {
  7234. transaction->noteAddSubFile(super, superName, sub);
  7235. }
  7236. virtual void noteRemoveSubFile(IDistributedSuperFile *super, IDistributedFile *sub)
  7237. {
  7238. transaction->noteRemoveSubFile(super, sub);
  7239. }
  7240. virtual void noteSuperSwap(IDistributedSuperFile *super1, IDistributedSuperFile *super2)
  7241. {
  7242. transaction->noteSuperSwap(super1, super2);
  7243. }
  7244. virtual void clearSubFiles(IDistributedSuperFile *super)
  7245. {
  7246. transaction->clearSubFiles(super);
  7247. }
  7248. virtual void noteRename(IDistributedFile *file, const char *newName)
  7249. {
  7250. transaction->noteRename(file, newName);
  7251. }
  7252. virtual void validateAddSubFile(IDistributedSuperFile *super, IDistributedFile *sub, const char *subName)
  7253. {
  7254. transaction->validateAddSubFile(super, sub, subName);
  7255. }
  7256. virtual bool isSubFile(IDistributedSuperFile *super, const char *subFile, bool sub)
  7257. {
  7258. return transaction->isSubFile(super, subFile, sub);
  7259. }
  7260. virtual bool addDelayedDelete(CDfsLogicalFileName &lfn,unsigned timeoutms=INFINITE)
  7261. {
  7262. return transaction->addDelayedDelete(lfn, timeoutms);
  7263. }
  7264. };
  7265. public:
  7266. CRemoveSuperFileAction(IUserDescriptor *_user,
  7267. const char *_flname,
  7268. bool _delSub)
  7269. : user(_user), delSub(_delSub)
  7270. {
  7271. logicalname.set(_flname);
  7272. }
  7273. virtual bool prepare()
  7274. {
  7275. // We *have* to make sure the file exists here
  7276. super.setown(transaction->lookupSuperFile(logicalname.get(), SDS_SUB_LOCK_TIMEOUT));
  7277. if (!super)
  7278. ThrowStringException(-1, "Super File %s doesn't exist in the file system", logicalname.get());
  7279. addFileLock(super);
  7280. // Adds actions to transactions before this one and gets executed only on commit
  7281. if (delSub)
  7282. {
  7283. // As 'delSub' means additional actions, handle them in their own transaction context
  7284. // Wrap lookups and record of removed/added subs to parent transaction, for common cache purposes
  7285. nestedTransaction.setown(new CNestedTransaction(transaction, user));
  7286. super->removeSubFile(NULL, true, false, nestedTransaction);
  7287. }
  7288. if (lock())
  7289. {
  7290. if (nestedTransaction)
  7291. {
  7292. if (nestedTransaction->prepareActions())
  7293. return true;
  7294. }
  7295. else
  7296. return true;
  7297. }
  7298. unlock();
  7299. super.clear();
  7300. return false;
  7301. }
  7302. virtual void retry()
  7303. {
  7304. super.clear();
  7305. if (nestedTransaction)
  7306. nestedTransaction->retryActions();
  7307. CDFAction::retry();
  7308. }
  7309. virtual void run()
  7310. {
  7311. if (nestedTransaction)
  7312. nestedTransaction->runActions();
  7313. super->detach(INFINITE, transaction->queryCodeContext());
  7314. }
  7315. virtual void commit()
  7316. {
  7317. if (nestedTransaction)
  7318. nestedTransaction->commitAndClearup();
  7319. CDFAction::commit();
  7320. }
  7321. };
  7322. /**
  7323. * Renames a file within a transaction.
  7324. */
  7325. class CRenameFileAction: public CDFAction
  7326. {
  7327. CDfsLogicalFileName fromName, toName;
  7328. CDistributedFileDirectory *parent;
  7329. Linked<IDistributedFile> file;
  7330. IUserDescriptor *user;
  7331. bool renamed;
  7332. enum RenameAction { ra_regular, ra_splitfrom, ra_mergeinto } ra;
  7333. public:
  7334. CRenameFileAction(CDistributedFileDirectory *_parent,
  7335. IUserDescriptor *_user,
  7336. const char *_flname,
  7337. const char *_newname)
  7338. : user(_user), parent(_parent)
  7339. {
  7340. fromName.set(_flname);
  7341. // Basic consistency checking
  7342. toName.set(_newname);
  7343. if (fromName.isExternal() || toName.isExternal())
  7344. throw MakeStringException(-1,"rename: cannot rename external files"); // JCSMORE perhaps you should be able to?
  7345. if (fromName.isForeign() || toName.isForeign())
  7346. throw MakeStringException(-1,"rename: cannot rename foreign files");
  7347. // Make sure files are not the same
  7348. if (0 == strcmp(fromName.get(), toName.get()))
  7349. ThrowStringException(-1, "rename: cannot rename file %s to itself", toName.get());
  7350. ra = ra_regular;
  7351. renamed = false;
  7352. }
  7353. virtual bool prepare()
  7354. {
  7355. // We *have* to make sure the source file exists and can be renamed
  7356. file.setown(transaction->lookupFile(fromName.get(), SDS_SUB_LOCK_TIMEOUT));
  7357. if (!file)
  7358. ThrowStringException(-1, "rename: file %s doesn't exist in the file system", fromName.get());
  7359. if (file->querySuperFile())
  7360. ThrowStringException(-1,"rename: cannot rename file %s as is SuperFile", fromName.get()); // Why not
  7361. StringBuffer reason;
  7362. if (!file->canRemove(reason))
  7363. ThrowStringException(-1,"rename: %s",reason.str());
  7364. addFileLock(file);
  7365. renamed = false;
  7366. if (lock())
  7367. {
  7368. StringBuffer oldcluster, newcluster;
  7369. fromName.getCluster(oldcluster);
  7370. toName.getCluster(newcluster);
  7371. Owned<IDistributedFile> newFile = transaction->lookupFile(toName.get(), SDS_SUB_LOCK_TIMEOUT);
  7372. if (newFile)
  7373. {
  7374. if (newcluster.length())
  7375. {
  7376. if (oldcluster.length())
  7377. ThrowStringException(-1,"rename: cannot specify both source and destination clusters on rename");
  7378. if (newFile->findCluster(newcluster.str())!=NotFound)
  7379. ThrowStringException(-1,"rename: cluster %s already part of file %s",newcluster.str(),toName.get());
  7380. if (file->numClusters()!=1)
  7381. ThrowStringException(-1,"rename: source file %s has more than one cluster",fromName.get());
  7382. // check compatible here ** TBD
  7383. ra = ra_mergeinto;
  7384. }
  7385. else
  7386. ThrowStringException(-1, "rename: file %s already exist in the file system", toName.get());
  7387. }
  7388. else if (oldcluster.length())
  7389. {
  7390. if (newcluster.length())
  7391. ThrowStringException(-1,"rename: cannot specify both source and destination clusters on rename");
  7392. if (file->numClusters()==1)
  7393. ThrowStringException(-1,"rename: cannot rename sole cluster %s",oldcluster.str());
  7394. if (file->findCluster(oldcluster.str())==NotFound)
  7395. ThrowStringException(-1,"rename: cannot find cluster %s",oldcluster.str());
  7396. ra = ra_splitfrom;
  7397. }
  7398. else
  7399. {
  7400. // TODO: something should check that file being renamed is not a subfile of a super where both created in transaction
  7401. transaction->noteRename(file, toName.get());
  7402. ra = ra_regular;
  7403. }
  7404. return true;
  7405. }
  7406. unlock();
  7407. file.clear();
  7408. return false;
  7409. }
  7410. virtual void run()
  7411. {
  7412. doRename(fromName, toName, ra);
  7413. renamed = true;
  7414. }
  7415. virtual void retry()
  7416. {
  7417. file.clear();
  7418. CDFAction::retry();
  7419. }
  7420. virtual void rollback()
  7421. {
  7422. // Only roll back if already renamed
  7423. if (renamed)
  7424. {
  7425. switch (ra)
  7426. {
  7427. case ra_regular:
  7428. doRename(toName, fromName, ra_regular);
  7429. break;
  7430. case ra_splitfrom:
  7431. doRename(toName, fromName, ra_mergeinto);
  7432. break;
  7433. case ra_mergeinto:
  7434. doRename(toName, fromName, ra_splitfrom);
  7435. break;
  7436. default:
  7437. throwUnexpected();
  7438. }
  7439. renamed = false;
  7440. }
  7441. CDFAction::rollback();
  7442. }
  7443. private:
  7444. void doRename(CDfsLogicalFileName &from, CDfsLogicalFileName &to, RenameAction ra)
  7445. {
  7446. CriticalBlock block(physicalChange);
  7447. StringBuffer oldcluster, newcluster;
  7448. fromName.getCluster(oldcluster);
  7449. toName.getCluster(newcluster);
  7450. Owned<IDistributedFile> oldfile;
  7451. if (ra_splitfrom == ra)
  7452. {
  7453. oldfile.setown(file.getClear());
  7454. Owned<IFileDescriptor> newdesc = oldfile->getFileDescriptor(oldcluster.str());
  7455. file.setown(parent->createNew(newdesc));
  7456. }
  7457. // Physical Rename
  7458. Owned<IMultiException> exceptions = MakeMultiException();
  7459. if (!file->renamePhysicalPartFiles(to.get(),newcluster,exceptions))
  7460. {
  7461. unlock();
  7462. StringBuffer errors;
  7463. exceptions->errorMessage(errors);
  7464. ThrowStringException(-1, "rename: could not rename logical file %s to %s: %s", fromName.get(), to.get(), errors.str());
  7465. }
  7466. // Logical rename and cleanup
  7467. switch (ra)
  7468. {
  7469. case ra_splitfrom:
  7470. {
  7471. unlock();
  7472. oldfile->removeCluster(oldcluster.str());
  7473. file->attach(to.get(), user);
  7474. lock();
  7475. break;
  7476. }
  7477. case ra_mergeinto:
  7478. {
  7479. Owned<IDistributedFile> newFile = transaction->lookupFile(to.get(), SDS_SUB_LOCK_TIMEOUT);
  7480. ClusterPartDiskMapSpec mspec = file->queryPartDiskMapping(0);
  7481. // Unlock the old file
  7482. unlock();
  7483. CDistributedFile *_file = dynamic_cast<CDistributedFile *>(file.get());
  7484. _file->detachLogical(INFINITE); // don't delete physicals, now used by newFile
  7485. transaction->clearFile(file); // no long used in transaction
  7486. newFile->addCluster(newcluster.str(),mspec);
  7487. parent->fixDates(newFile);
  7488. // need to clear and re-lookup as changed outside of transaction
  7489. // TBD: Allow 'addCluster' 'fixDates' etc. to be delayed/work inside transaction
  7490. transaction->clearFile(newFile);
  7491. newFile.clear();
  7492. file.setown(transaction->lookupFile(to.get(), SDS_SUB_LOCK_TIMEOUT));
  7493. addFileLock(file);
  7494. lock();
  7495. break;
  7496. }
  7497. case ra_regular:
  7498. {
  7499. /* It is not enough to unlock this actions locks on the file being renamed,
  7500. * because other actions, before and after may hold locks to the same file.
  7501. * For now, IDistributeFile::rename, needs to work on a lock free instance.
  7502. * TBD: Allow IDistributedFile::rename to work properly within transaction.
  7503. */
  7504. DistributedFilePropertyLockFree unlock(file);
  7505. file->rename(to.get(), user);
  7506. break;
  7507. }
  7508. default:
  7509. throwUnexpected();
  7510. }
  7511. // MORE: If the logical rename fails, we should roll back the physical renaming
  7512. // What if the physical renaming-back fails?!
  7513. // For now, leaving as it was, since physical renaming is more prone to errors than logical
  7514. // And checks were made earlier to make sure it was safe to rename
  7515. }
  7516. };
  7517. // MORE: This should be implemented in DFSAccess later on
  7518. IDistributedSuperFile *CDistributedFileDirectory::createSuperFile(const char *_logicalname,IUserDescriptor *user, bool _interleaved,bool ifdoesnotexist,IDistributedFileTransaction *transaction)
  7519. {
  7520. CDfsLogicalFileName logicalname;
  7521. logicalname.set(_logicalname);
  7522. checkLogicalName(logicalname,user,true,true,false,"have a superfile with");
  7523. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  7524. Linked<IDistributedFileTransactionExt> localtrans;
  7525. if (transaction)
  7526. {
  7527. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  7528. localtrans.set(_transaction);
  7529. }
  7530. else
  7531. localtrans.setown(new CDistributedFileTransaction(user));
  7532. IDistributedSuperFile *sfile = localtrans->lookupSuperFile(logicalname.get());
  7533. if (sfile)
  7534. {
  7535. if (ifdoesnotexist)
  7536. return sfile;
  7537. else
  7538. throw MakeStringException(-1,"createSuperFile: SuperFile %s already exists",logicalname.get());
  7539. }
  7540. Owned<CCreateSuperFileAction> action = new CCreateSuperFileAction(this,user,_logicalname,_interleaved);
  7541. localtrans->addAction(action.getLink()); // takes ownership
  7542. localtrans->autoCommit();
  7543. return action->getSuper();
  7544. }
  7545. // MORE: This should be implemented in DFSAccess later on
  7546. IDistributedSuperFile *CDistributedFileDirectory::createNewSuperFile(IPropertyTree *tree, const char *optionalName)
  7547. {
  7548. return new CDistributedSuperFile(this, tree, optionalName);
  7549. }
  7550. // MORE: This should be implemented in DFSAccess later on
  7551. void CDistributedFileDirectory::removeSuperFile(const char *_logicalname, bool delSubs, IUserDescriptor *user, IDistributedFileTransaction *transaction)
  7552. {
  7553. CDfsLogicalFileName logicalname;
  7554. logicalname.set(_logicalname);
  7555. checkLogicalName(logicalname,user,true,true,false,"have a superfile with");
  7556. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  7557. Linked<IDistributedFileTransactionExt> localtrans;
  7558. if (transaction)
  7559. {
  7560. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  7561. localtrans.set(_transaction);
  7562. }
  7563. else
  7564. localtrans.setown(new CDistributedFileTransaction(user));
  7565. CRemoveSuperFileAction *action = new CRemoveSuperFileAction(user, _logicalname, delSubs);
  7566. localtrans->addAction(action); // takes ownership
  7567. localtrans->autoCommit();
  7568. }
  7569. bool CDistributedFileDirectory::removeEntry(const char *name, IUserDescriptor *user, IDistributedFileTransaction *transaction, unsigned timeoutms, bool throwException)
  7570. {
  7571. CDfsLogicalFileName logicalname;
  7572. logicalname.set(name);
  7573. if (!logicalname.isExternal())
  7574. checkLogicalName(logicalname,user,true,true,false,"delete");
  7575. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  7576. Linked<IDistributedFileTransactionExt> localtrans;
  7577. if (transaction)
  7578. {
  7579. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  7580. localtrans.set(_transaction);
  7581. }
  7582. else
  7583. localtrans.setown(new CDistributedFileTransaction(user));
  7584. // Action will be executed at the end of the transaction (commit)
  7585. localtrans->addDelayedDelete(logicalname, timeoutms);
  7586. try
  7587. {
  7588. localtrans->autoCommit();
  7589. }
  7590. catch (IException *e)
  7591. {
  7592. // TODO: Transform removeEntry into void
  7593. StringBuffer msg(logicalname.get());
  7594. msg.append(" - cause: ");
  7595. e->errorMessage(msg);
  7596. IERRLOG("%s", msg.str());
  7597. if (throwException)
  7598. throw new CDFS_Exception(DFSERR_FailedToDeleteFile, msg.str());
  7599. e->Release();
  7600. return false;
  7601. }
  7602. return true;
  7603. }
  7604. void CDistributedFileDirectory::removeEmptyScope(const char *scope)
  7605. {
  7606. if (scope&&*scope) {
  7607. StringBuffer fn(scope);
  7608. fn.append("::x");
  7609. CDfsLogicalFileName dlfn;
  7610. dlfn.set(fn.str());
  7611. removeFileEmptyScope(dlfn,defaultTimeout);
  7612. }
  7613. }
  7614. void CDistributedFileDirectory::renamePhysical(const char *oldname,const char *newname,IUserDescriptor *user,IDistributedFileTransaction *transaction)
  7615. {
  7616. if (!user)
  7617. {
  7618. #ifdef NULL_DALIUSER_STACKTRACE
  7619. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp CDistributedFileDirectory::renamePhysical %d",__LINE__);
  7620. //following debug code to be removed
  7621. PrintStackReport();
  7622. #endif
  7623. user = defaultudesc.get();
  7624. }
  7625. CDfsLogicalFileName oldlogicalname;
  7626. oldlogicalname.set(oldname);
  7627. checkLogicalName(oldlogicalname,user,true,true,false,"rename");
  7628. // Create a local transaction that will be destroyed (MORE: make transaction compulsory)
  7629. Linked<IDistributedFileTransactionExt> localtrans;
  7630. if (transaction)
  7631. {
  7632. IDistributedFileTransactionExt *_transaction = dynamic_cast<IDistributedFileTransactionExt *>(transaction);
  7633. localtrans.set(_transaction);
  7634. }
  7635. else
  7636. localtrans.setown(new CDistributedFileTransaction(user));
  7637. CRenameFileAction *action = new CRenameFileAction(this, user, oldname, newname);
  7638. localtrans->addAction(action); // takes ownership
  7639. localtrans->autoCommit();
  7640. }
  7641. void CDistributedFileDirectory::fixDates(IDistributedFile *file)
  7642. {
  7643. // should do in parallel
  7644. unsigned width = file->numParts();
  7645. CriticalSection crit;
  7646. class casyncfor: public CAsyncFor
  7647. {
  7648. IDistributedFile *file;
  7649. CriticalSection &crit;
  7650. unsigned width;
  7651. public:
  7652. bool ok;
  7653. casyncfor(IDistributedFile *_file,unsigned _width,CriticalSection &_errcrit)
  7654. : crit(_errcrit)
  7655. {
  7656. file = _file;
  7657. ok = true;
  7658. width = _width;
  7659. ok = true;
  7660. }
  7661. void Do(unsigned i)
  7662. {
  7663. CriticalBlock block(crit);
  7664. Owned<IDistributedFilePart> part = file->getPart(i);
  7665. CDateTime dt;
  7666. if (!part->getModifiedTime(false,false,dt))
  7667. return;
  7668. unsigned nc = part->numCopies();
  7669. for (unsigned copy = 0; copy < nc; copy++) {
  7670. RemoteFilename rfn;
  7671. part->getFilename(rfn,copy);
  7672. Owned<IFile> partfile = createIFile(rfn);
  7673. try {
  7674. CriticalUnblock unblock(crit);
  7675. CDateTime dt2;
  7676. if (partfile->getTime(NULL,&dt2,NULL)) {
  7677. if (!dt.equals(dt2)) {
  7678. partfile->setTime(NULL,&dt,NULL);
  7679. }
  7680. }
  7681. }
  7682. catch (IException *e) {
  7683. CriticalBlock block(crit);
  7684. StringBuffer s("Failed to find file part ");
  7685. s.append(partfile->queryFilename()).append(" on ");
  7686. rfn.queryEndpoint().getUrlStr(s);
  7687. EXCLOG(e, s.str());
  7688. e->Release();
  7689. }
  7690. }
  7691. }
  7692. } afor(file,width,crit);
  7693. afor.For(width,10,false,true);
  7694. }
  7695. void CDistributedFileDirectory::addEntry(CDfsLogicalFileName &dlfn,IPropertyTree *root,bool superfile, bool ignoreexists)
  7696. {
  7697. // add bit awkward
  7698. bool external;
  7699. bool foreign;
  7700. external = dlfn.isExternal();
  7701. foreign = dlfn.isForeign();
  7702. if (external) {
  7703. root->Release();
  7704. return; // ignore attempts to add external
  7705. }
  7706. CScopeConnectLock sconnlock("CDistributedFileDirectory::addEntry", dlfn, true, false, false, defaultTimeout);
  7707. if (!sconnlock.conn()) {// warn?
  7708. root->Release();
  7709. return;
  7710. }
  7711. IPropertyTree* sroot = sconnlock.conn()->queryRoot();
  7712. StringBuffer tail;
  7713. dlfn.getTail(tail);
  7714. IPropertyTree *prev = getNamedPropTree(sroot,superfile?queryDfsXmlBranchName(DXB_SuperFile):queryDfsXmlBranchName(DXB_File),"@name",tail.str(),false);
  7715. if (!prev) // check super/file doesn't exist
  7716. prev = getNamedPropTree(sroot,superfile?queryDfsXmlBranchName(DXB_File):queryDfsXmlBranchName(DXB_SuperFile),"@name",tail.str(),false);
  7717. if (prev!=nullptr)
  7718. {
  7719. prev->Release();
  7720. root->Release();
  7721. if (ignoreexists)
  7722. return;
  7723. throw new CDFS_Exception(DFSERR_LogicalNameAlreadyExists,dlfn.get());
  7724. }
  7725. root->setProp("@name",tail.str());
  7726. root->setProp("OrigName",dlfn.get());
  7727. if (superfile)
  7728. sroot->addPropTree(queryDfsXmlBranchName(DXB_SuperFile), root); // now owns root
  7729. else
  7730. {
  7731. IPropertyTree *file = sroot->addPropTree(queryDfsXmlBranchName(DXB_File), root); // now owns root
  7732. file->setPropTree("ClusterLock", createPTree());
  7733. }
  7734. }
  7735. IDistributedFileIterator *CDistributedFileDirectory::getIterator(const char *wildname, bool includesuper, IUserDescriptor *user)
  7736. {
  7737. return new CDistributedFileIterator(this,wildname,includesuper,user);
  7738. }
  7739. GetFileClusterNamesType CDistributedFileDirectory::getFileClusterNames(const char *_logicalname,StringArray &out)
  7740. {
  7741. CDfsLogicalFileName logicalname;
  7742. logicalname.set(_logicalname);
  7743. if (logicalname.isForeign())
  7744. return GFCN_Foreign;
  7745. if (logicalname.isExternal())
  7746. return GFCN_External;
  7747. CScopeConnectLock sconnlock("CDistributedFileDirectory::getFileClusterList", logicalname, false, false, false, defaultTimeout);
  7748. DfsXmlBranchKind bkind;
  7749. IPropertyTree *froot = sconnlock.queryFileRoot(logicalname,bkind);
  7750. if (froot) {
  7751. if (bkind==DXB_File) {
  7752. getFileGroups(froot,out);
  7753. return GFCN_Normal;
  7754. }
  7755. if (bkind==DXB_SuperFile)
  7756. return GFCN_Super;
  7757. }
  7758. return GFCN_NotFound;
  7759. }
  7760. // --------------------------------------------------------
  7761. static CDistributedFileDirectory *DFdir = NULL;
  7762. static CriticalSection dfdirCrit;
  7763. /**
  7764. * Public method to control DistributedFileDirectory access
  7765. * as a singleton. This is the only way to get directories,
  7766. * files, super-files and logic-files.
  7767. */
  7768. IDistributedFileDirectory &queryDistributedFileDirectory()
  7769. {
  7770. if (!DFdir) {
  7771. CriticalBlock block(dfdirCrit);
  7772. if (!DFdir)
  7773. DFdir = new CDistributedFileDirectory();
  7774. }
  7775. return *DFdir;
  7776. }
  7777. /**
  7778. * Shutdown distributed file system (root directory).
  7779. */
  7780. void closedownDFS() // called by dacoven
  7781. {
  7782. CriticalBlock block(dfdirCrit);
  7783. try {
  7784. delete DFdir;
  7785. }
  7786. catch (IMP_Exception *e) {
  7787. if (e->errorCode()!=MPERR_link_closed)
  7788. throw;
  7789. PrintExceptionLog(e,"closedownDFS");
  7790. e->Release();
  7791. }
  7792. catch (IDaliClient_Exception *e) {
  7793. if (e->errorCode()!=DCERR_server_closed)
  7794. throw;
  7795. e->Release();
  7796. }
  7797. DFdir = NULL;
  7798. CriticalBlock block2(groupsect);
  7799. ::Release(groupStore);
  7800. groupStore = NULL;
  7801. }
  7802. class CDFPartFilter : implements IDFPartFilter, public CInterface
  7803. {
  7804. protected:
  7805. bool *partincluded;
  7806. unsigned max;
  7807. public:
  7808. IMPLEMENT_IINTERFACE;
  7809. CDFPartFilter(const char *filter)
  7810. {
  7811. max = 0;
  7812. partincluded = NULL;
  7813. unsigned pn=0;
  7814. const char *s=filter;
  7815. if (!s)
  7816. return;
  7817. while (*s) {
  7818. if (isdigit(*s)) {
  7819. pn = pn*10+(*s-'0');
  7820. if (pn>max)
  7821. max = pn;
  7822. }
  7823. else
  7824. pn = 0;
  7825. s++;
  7826. }
  7827. if (max==0)
  7828. return;
  7829. partincluded = new bool[max];
  7830. unsigned i;
  7831. for (i=0;i<max;i++)
  7832. partincluded[i] = false;
  7833. pn=0;
  7834. s=filter;
  7835. unsigned start=0;
  7836. for (;;) {
  7837. if ((*s==0)||(*s==',')||isspace(*s)) {
  7838. if (start) {
  7839. for (i=start-1;i<pn;i++)
  7840. partincluded[i] = true;
  7841. start = 0;
  7842. }
  7843. else
  7844. partincluded[pn-1] = true;
  7845. if (*s==0)
  7846. break;
  7847. pn = 0;
  7848. }
  7849. else if (isdigit(*s)) {
  7850. pn = pn*10+(*s-'0');
  7851. if (pn>max)
  7852. max = pn;
  7853. if (s[1]=='-') {
  7854. s++;
  7855. start = pn;
  7856. pn = 0;
  7857. }
  7858. }
  7859. s++;
  7860. }
  7861. }
  7862. ~CDFPartFilter()
  7863. {
  7864. delete [] partincluded;
  7865. }
  7866. bool includePart(unsigned part)
  7867. {
  7868. if (max==0)
  7869. return true;
  7870. if (part>=max)
  7871. return false;
  7872. return partincluded[part];
  7873. };
  7874. };
  7875. IDFPartFilter *createPartFilter(const char *filter)
  7876. {
  7877. return new CDFPartFilter(filter);
  7878. }
  7879. //=====================================================================================
  7880. // Server Side Support
  7881. class CFileMatch : public CInterface
  7882. {
  7883. StringAttr name;
  7884. Linked<IPropertyTree> tree;
  7885. bool isSuper;
  7886. public:
  7887. CFileMatch(const char *_name, IPropertyTree *_tree, bool _isSuper) : name(_name), tree(_tree), isSuper(_isSuper)
  7888. {
  7889. }
  7890. IPropertyTree &queryFileTree() const { return *tree; }
  7891. const char *queryName() const { return name; }
  7892. bool queryIsSuper() const { return isSuper; }
  7893. };
  7894. typedef CIArrayOf<CFileMatch> CFileMatchArray;
  7895. class CScope : public CInterface
  7896. {
  7897. StringAttr name;
  7898. CIArrayOf<CFileMatch> files; // matches
  7899. CIArrayOf<CScope> subScopes;
  7900. public:
  7901. CScope(const char *_name) : name(_name)
  7902. {
  7903. }
  7904. const char *getName() const { return name; }
  7905. void addMatch(const char *name, IPropertyTree &fileTree, bool isSuper)
  7906. {
  7907. files.append(*new CFileMatch(name, &fileTree, isSuper));
  7908. }
  7909. CScope *addScope(const char *scope)
  7910. {
  7911. CScope *subScope = new CScope(scope);
  7912. subScopes.append(*subScope);
  7913. return subScope;
  7914. }
  7915. void popLastScope()
  7916. {
  7917. subScopes.pop();
  7918. }
  7919. CIArrayOf<CScope> &querySubScopes() { return subScopes; }
  7920. CFileMatchArray &queryFiles() { return files; }
  7921. };
  7922. typedef CIArrayOf<CScope> CScopeArray;
  7923. const char* DFUQFilterFieldNames[] = { "", "@description", "@directory", "@group", "@modified", "@name", "@numclusters", "@numparts",
  7924. "@partmask", "@OrigName", "Attr", "Attr/@job", "Attr/@owner", "Attr/@recordCount", "Attr/@recordSize", "Attr/@size",
  7925. "Attr/@compressedsize", "Attr/@workunit", "Cluster", "Cluster/@defaultBaseDir", "Cluster/@defaultReplDir", "Cluster/@mapFlags",
  7926. "Cluster/@name", "Part", "Part/@name", "Part/@num", "Part/@size", "SuperOwner", "SuperOwner/@name",
  7927. "SubFile", "SubFile/@name", "SubFile/@num", "Attr/@kind" };
  7928. extern da_decl const char* getDFUQFilterFieldName(DFUQFilterField feild)
  7929. {
  7930. return DFUQFilterFieldNames[feild];
  7931. }
  7932. class CDFUSFFilter : public CInterface
  7933. {
  7934. DFUQFilterType filterType;
  7935. StringAttr attrPath;
  7936. bool hasFilter;
  7937. bool hasFilterHigh;
  7938. StringAttr filterValue;
  7939. StringAttr filterValueHigh;
  7940. int filterValueInt;
  7941. int filterValueHighInt;
  7942. __int64 filterValueInt64;
  7943. __int64 filterValueHighInt64;
  7944. bool filterValueBoolean;
  7945. StringAttr sep;
  7946. StringArray filterArray;
  7947. public:
  7948. CDFUSFFilter(DFUQFilterType _filterType, const char *_attrPath, const char *_filterValue, const char *_filterValueHigh)
  7949. : filterType(_filterType), attrPath(_attrPath), filterValue(_filterValue), filterValueHigh(_filterValueHigh) {};
  7950. CDFUSFFilter(DFUQFilterType _filterType, const char *_attrPath, bool _hasFilter, const int _filterValue, bool _hasFilterHigh, const int _filterValueHigh)
  7951. : filterType(_filterType), attrPath(_attrPath), hasFilter(_hasFilter), filterValueInt(_filterValue), hasFilterHigh(_hasFilterHigh), filterValueHighInt(_filterValueHigh) {};
  7952. CDFUSFFilter(DFUQFilterType _filterType, const char *_attrPath, bool _hasFilter, const __int64 _filterValue, bool _hasFilterHigh, const __int64 _filterValueHigh)
  7953. : filterType(_filterType), attrPath(_attrPath), hasFilter(_hasFilter), filterValueInt64(_filterValue), hasFilterHigh(_hasFilterHigh), filterValueHighInt64(_filterValueHigh) {};
  7954. CDFUSFFilter(DFUQFilterType _filterType, const char *_attrPath, bool _filterValue)
  7955. : filterType(_filterType), attrPath(_attrPath), filterValueBoolean(_filterValue) {};
  7956. CDFUSFFilter(DFUQFilterType _filterType, const char *_attrPath, const char *_filterValue, const char *_sep, StringArray& _filterArray)
  7957. : filterType(_filterType), attrPath(_attrPath), filterValue(_filterValue), sep(_sep)
  7958. {
  7959. ForEachItemIn(i,_filterArray)
  7960. {
  7961. const char* filter = _filterArray.item(i);
  7962. if (filter && *filter)
  7963. filterArray.append(filter);
  7964. }
  7965. };
  7966. DFUQFilterType getFilterType() { return filterType;}
  7967. const char * getAttrPath() { return attrPath.get();}
  7968. const char * getFilterValue() { return filterValue.get();}
  7969. const char * getFilterValueHigh() { return filterValueHigh.get();}
  7970. const int getFilterValueInt() { return filterValueInt;}
  7971. const int getFilterValueHighInt() { return filterValueHighInt;}
  7972. const __int64 getFilterValueInt64() { return filterValueInt64;}
  7973. const __int64 getFilterValueHighInt64() { return filterValueHighInt64;}
  7974. const bool getFilterValueBoolean() { return filterValueBoolean;}
  7975. const char * getSep() { return sep.get();}
  7976. void getFilterArray(StringArray &filters)
  7977. {
  7978. ForEachItemIn(c, filterArray)
  7979. filters.append(filterArray.item(c));
  7980. }
  7981. bool checkFilter(IPropertyTree &file)
  7982. {
  7983. bool match = true;
  7984. switch(filterType)
  7985. {
  7986. case DFUQFTwildcardMatch:
  7987. match = doWildMatch(file);
  7988. break;
  7989. case DFUQFTbooleanMatch:
  7990. match = doBooleanMatch(file);
  7991. break;
  7992. case DFUQFThasProp:
  7993. match = checkHasPropFilter(file);
  7994. break;
  7995. case DFUQFTcontainString:
  7996. match = checkContainStringFilter(file);
  7997. break;
  7998. case DFUQFTstringRange:
  7999. match = checkStringRangeFilter(file);
  8000. break;
  8001. case DFUQFTintegerRange:
  8002. match = checkIntegerRangeFilter(file);
  8003. break;
  8004. case DFUQFTinteger64Range:
  8005. match = checkInteger64RangeFilter(file);
  8006. break;
  8007. }
  8008. return match;
  8009. }
  8010. bool doWildMatch(IPropertyTree &file)
  8011. {
  8012. const char* filter = filterValue.get();
  8013. if (!attrPath.get() || !filter || !*filter || streq(filter, "*"))
  8014. return true;
  8015. const char* prop = file.queryProp(attrPath.get());
  8016. if (prop && WildMatch(prop, filter, true))
  8017. return true;
  8018. return false;
  8019. }
  8020. bool doBooleanMatch(IPropertyTree &file)
  8021. {
  8022. if (!attrPath.get())
  8023. return true;
  8024. return filterValueBoolean == file.getPropBool(attrPath.get(), true);
  8025. }
  8026. bool checkHasPropFilter(IPropertyTree &file)
  8027. {
  8028. if (!attrPath.get())
  8029. return true;
  8030. return filterValueBoolean == file.hasProp(attrPath.get());
  8031. }
  8032. bool checkContainStringFilter(IPropertyTree &file)
  8033. {
  8034. if (!attrPath.get())
  8035. return true;
  8036. const char* prop = file.queryProp(attrPath.get());
  8037. if (!prop || !*prop)
  8038. return false;
  8039. bool found = false;
  8040. if (!sep.get())
  8041. {
  8042. if (filterArray.find(prop) != NotFound) //Match with one of values in the filter
  8043. found = true;
  8044. return found;
  8045. }
  8046. StringArray propArray;
  8047. propArray.appendListUniq(prop, sep.get());
  8048. ForEachItemIn(i,propArray)
  8049. {
  8050. const char* value = propArray.item(i);
  8051. if (!value || !*value)
  8052. continue;
  8053. if (filterArray.find(value) != NotFound) //Match with one of values in the filter
  8054. {
  8055. found = true;
  8056. break;
  8057. }
  8058. }
  8059. return found;
  8060. }
  8061. bool checkStringRangeFilter(IPropertyTree &file)
  8062. {
  8063. if (!attrPath.get())
  8064. return true;
  8065. const char* prop = file.queryProp(attrPath.get());
  8066. if (!prop || !*prop)
  8067. return false;
  8068. if (filterValue && (strcmp(filterValue, prop) > 0))
  8069. return false;
  8070. if (filterValueHigh && (strcmp(filterValueHigh, prop) < 0))
  8071. return false;
  8072. return true;
  8073. }
  8074. bool checkIntegerRangeFilter(IPropertyTree &file)
  8075. {
  8076. if (!attrPath.get())
  8077. return true;
  8078. int prop = file.getPropInt(attrPath.get());
  8079. if (hasFilter && (prop < filterValueInt))
  8080. return false;
  8081. if (hasFilterHigh && (prop > filterValueHighInt))
  8082. return false;
  8083. return true;
  8084. }
  8085. bool checkInteger64RangeFilter(IPropertyTree &file)
  8086. {
  8087. if (!attrPath.get())
  8088. return true;
  8089. __int64 prop = file.getPropInt64(attrPath.get());
  8090. if (hasFilter && (prop < filterValueInt64))
  8091. return false;
  8092. if (hasFilterHigh && (prop > filterValueHighInt64))
  8093. return false;
  8094. return true;
  8095. }
  8096. };
  8097. typedef CIArrayOf<CDFUSFFilter> CDFUSFFilterArray;
  8098. class CIterateFileFilterContainer : public CInterface
  8099. {
  8100. StringAttr filterBuf; //Hold original filter string just in case
  8101. StringAttr wildNameFilter;
  8102. unsigned maxFilesFilter;
  8103. DFUQFileTypeFilter fileTypeFilter;
  8104. CIArrayOf<CDFUSFFilter> filters;
  8105. //The 'filters' contains the file scan filters other than wildNameFilter and fileTypeFilter. Those filters are used for
  8106. //filtering the files using File Attributes tree and CDFUSFFilter::checkFilter(). The wildNameFilter and fileTypeFilter need
  8107. //special code to filter the files.
  8108. SerializeFileAttrOptions options;
  8109. bool isValidInteger(const char *s)
  8110. {
  8111. if (!s || !*s)
  8112. return false;
  8113. while (*s)
  8114. {
  8115. if ((*s != '-') && !isdigit(*s))
  8116. return false;
  8117. s++;
  8118. }
  8119. return true;
  8120. }
  8121. void addOption(const char* optionStr)
  8122. {
  8123. if (!optionStr || !*optionStr || !isdigit(*optionStr))
  8124. return;
  8125. DFUQSerializeFileAttrOption option = (DFUQSerializeFileAttrOption) atoi(optionStr);
  8126. switch(option)
  8127. {
  8128. case DFUQSFAOincludeSuperOwner:
  8129. options.includeSuperOwner = true;
  8130. break;
  8131. //Add more when needed
  8132. }
  8133. }
  8134. void addFilter(DFUQFilterType filterType, const char* attr, const char* value, const char* valueHigh)
  8135. {
  8136. if (!attr || !*attr)
  8137. return;
  8138. if ((DFUQFTwildcardMatch == filterType) || (DFUQFTstringRange == filterType))
  8139. {
  8140. filters.append(*new CDFUSFFilter(filterType, attr, value, valueHigh));
  8141. return;
  8142. }
  8143. if ((DFUQFTbooleanMatch == filterType) || (DFUQFThasProp == filterType))
  8144. {
  8145. bool filter = true;
  8146. if (value && (streq(value, "0") || strieq(value, "false")))
  8147. filter = false;
  8148. filters.append(*new CDFUSFFilter(filterType, attr, filter));
  8149. return;
  8150. }
  8151. if ((DFUQFTintegerRange == filterType) || (DFUQFTinteger64Range == filterType))
  8152. {
  8153. bool hasFilter = false;
  8154. bool hasFilterHigh = false;
  8155. if (value && isValidInteger(value))
  8156. hasFilter = true;
  8157. if (valueHigh && isValidInteger(valueHigh))
  8158. hasFilterHigh = true;
  8159. if (!hasFilter && !hasFilterHigh)
  8160. return;
  8161. if (DFUQFTintegerRange == filterType)
  8162. filters.append(*new CDFUSFFilter(filterType, attr, hasFilter, atoi(value), hasFilterHigh, atoi(valueHigh)));
  8163. else
  8164. filters.append(*new CDFUSFFilter(filterType, attr, hasFilter, (__int64) atol(value), hasFilterHigh, (__int64) atol(valueHigh)));
  8165. return;
  8166. }
  8167. }
  8168. void addFilterArray(DFUQFilterType filterType, const char* attr, const char* value, const char* sep)
  8169. {
  8170. if (!attr || !*attr || !value || !*value)
  8171. return;
  8172. StringArray filterArray;
  8173. filterArray.appendListUniq(value, sep);
  8174. filters.append(*new CDFUSFFilter(filterType, attr, value, sep, filterArray));
  8175. }
  8176. void addSpecialFilter(const char* attr, const char* value)
  8177. {
  8178. if (!attr || !*attr || !value || !*value)
  8179. return;
  8180. if (!isdigit(*attr))
  8181. {
  8182. PROGLOG("Unsupported Special Filter: %s", attr);
  8183. return;
  8184. }
  8185. DFUQSpecialFilter filterName = (DFUQSpecialFilter) atoi(attr);
  8186. switch(filterName)
  8187. {
  8188. case DFUQSFFileNameWithPrefix:
  8189. wildNameFilter.set(value);
  8190. break;
  8191. case DFUQSFFileType:
  8192. if (isdigit(*value))
  8193. fileTypeFilter = (DFUQFileTypeFilter) atoi(value);
  8194. else
  8195. PROGLOG("Unsupported Special Filter: %s, value %s", attr, value);
  8196. break;
  8197. case DFUQSFMaxFiles:
  8198. if (isdigit(*value))
  8199. maxFilesFilter = atoi(value);
  8200. else
  8201. PROGLOG("Unsupported Special Filter: %s, value %s", attr, value);
  8202. break;
  8203. default:
  8204. PROGLOG("Unsupported Special Filter: %d", filterName);
  8205. break;
  8206. }
  8207. }
  8208. bool doWildMatch(const char* filter, const char* value)
  8209. {
  8210. if (!filter || !*filter || streq(filter, "*") || (value && WildMatch(value, filter, true)))
  8211. return true;
  8212. return false;
  8213. }
  8214. public:
  8215. CIterateFileFilterContainer()
  8216. {
  8217. maxFilesFilter = ITERATE_FILTEREDFILES_LIMIT;
  8218. fileTypeFilter = DFUQFFTall;
  8219. wildNameFilter.set("*");
  8220. filterBuf.clear();
  8221. };
  8222. void readFilters(const char *filterStr)
  8223. {
  8224. if (!filterStr || !*filterStr)
  8225. return;
  8226. filterBuf.set(filterStr);
  8227. StringArray filterStringArray;
  8228. char sep[] = { DFUQFilterSeparator, '\0' };
  8229. filterStringArray.appendList(filterStr, sep);
  8230. unsigned filterFieldsToRead = filterStringArray.length();
  8231. ForEachItemIn(i,filterStringArray)
  8232. {
  8233. const char* filterTypeStr = filterStringArray.item(i);
  8234. if (!filterTypeStr || !*filterTypeStr)
  8235. continue;
  8236. if (!isdigit(*filterTypeStr))
  8237. continue;
  8238. unsigned filterSize = 4;
  8239. DFUQFilterType filterType = (DFUQFilterType) atoi(filterTypeStr);
  8240. switch(filterType)
  8241. {
  8242. case DFUQFTcontainString:
  8243. if (filterFieldsToRead >= filterSize) //DFUQFilterType | filter name | separator | filter value separated by the separator
  8244. addFilterArray(DFUQFTcontainString, filterStringArray.item(i+1), (const char*)filterStringArray.item(i+2), (const char*)filterStringArray.item(i+3));
  8245. break;
  8246. case DFUQFThasProp:
  8247. case DFUQFTbooleanMatch:
  8248. case DFUQFTwildcardMatch:
  8249. filterSize = 3;
  8250. if (filterFieldsToRead >= filterSize) //DFUQFilterType | filter name | filter value
  8251. addFilter(filterType, filterStringArray.item(i+1), (const char*)filterStringArray.item(i+2), NULL);
  8252. break;
  8253. case DFUQFTstringRange:
  8254. case DFUQFTintegerRange:
  8255. case DFUQFTinteger64Range:
  8256. if (filterFieldsToRead >= filterSize) //DFUQFilterType | filter name | from filter | to filter
  8257. addFilter(filterType, filterStringArray.item(i+1), (const char*)filterStringArray.item(i+2), (const char*)filterStringArray.item(i+3));
  8258. break;
  8259. case DFUQFTincludeFileAttr:
  8260. filterSize = 2;
  8261. if (filterFieldsToRead >= filterSize) //DFUQFilterType | filter
  8262. addOption(filterStringArray.item(i+1));
  8263. break;
  8264. case DFUQFTspecial:
  8265. filterSize = 3;
  8266. if (filterFieldsToRead >= filterSize) //DFUQFilterType | filter name | filter value
  8267. addSpecialFilter(filterStringArray.item(i+1), (const char*)filterStringArray.item(i+2));
  8268. break;
  8269. }
  8270. filterFieldsToRead -= filterSize;
  8271. i += (filterSize - 1);
  8272. }
  8273. }
  8274. bool matchFileScanFilter(const char* name, IPropertyTree &file)
  8275. {
  8276. if (!doWildMatch(wildNameFilter.get(), name))
  8277. return false;
  8278. if (!filters.length())
  8279. return true;
  8280. ForEachItemIn(i,filters)
  8281. {
  8282. CDFUSFFilter &filter = filters.item(i);
  8283. const char* attrPath = filter.getAttrPath();
  8284. try
  8285. {
  8286. if (!filter.checkFilter(file))
  8287. return false;
  8288. }
  8289. catch (IException *e)
  8290. {
  8291. VStringBuffer msg("Failed to check filter %s for %s: ", attrPath, name);
  8292. int code = e->errorCode();
  8293. e->errorMessage(msg);
  8294. e->Release();
  8295. throw MakeStringException(code, "%s", msg.str());
  8296. }
  8297. }
  8298. return true;
  8299. }
  8300. DFUQFileTypeFilter getFileTypeFilter() { return fileTypeFilter; }
  8301. unsigned getMaxFilesFilter() { return maxFilesFilter; }
  8302. void setFileTypeFilter(DFUQFileTypeFilter _fileType)
  8303. {
  8304. fileTypeFilter = _fileType;
  8305. }
  8306. const char* getNameFilter() { return wildNameFilter.get(); }
  8307. void setNameFilter(const char* _wildName)
  8308. {
  8309. if (!_wildName || !*_wildName)
  8310. return;
  8311. wildNameFilter.set(_wildName);
  8312. }
  8313. SerializeFileAttrOptions& getSerializeFileAttrOptions() { return options; }
  8314. };
  8315. class CFileScanner
  8316. {
  8317. bool recursive;
  8318. bool includesuper;
  8319. StringAttr wildname;
  8320. Owned<CScope> topLevelScope;
  8321. CScope *currentScope;
  8322. Owned<CIterateFileFilterContainer> iterateFileFilterContainer;
  8323. bool scopeMatch(const char *name)
  8324. { // name has trailing '::'
  8325. if (!name || !*name)
  8326. return true;
  8327. const char *s1 = NULL;
  8328. if (!iterateFileFilterContainer)
  8329. s1 = wildname.get();
  8330. else
  8331. s1 = iterateFileFilterContainer->getNameFilter();
  8332. if (!s1 || !*s1)
  8333. return true;
  8334. const char *s2 = name;
  8335. while (*s2) {
  8336. if (*s1=='*') {
  8337. if (recursive)
  8338. return true;
  8339. if (*s2==':')
  8340. return false;
  8341. // '*' can only come at end of scope in non-recursive
  8342. while (*s1&&(*s1!=':'))
  8343. s1++;
  8344. while (*s2&&(*s2!=':'))
  8345. s2++;
  8346. }
  8347. else if ((*s1==*s2)||(*s1=='?')) {
  8348. s1++;
  8349. s2++;
  8350. }
  8351. else
  8352. return false;
  8353. }
  8354. return true;
  8355. }
  8356. bool processScopes(IPropertyTree &root,StringBuffer &name)
  8357. {
  8358. bool ret = false;
  8359. CScope *parentScope = currentScope;
  8360. if (parentScope)
  8361. currentScope = parentScope->addScope(name);
  8362. else
  8363. { // once only
  8364. topLevelScope.setown(new CScope(""));
  8365. currentScope = topLevelScope;
  8366. }
  8367. size32_t ns = name.length();
  8368. if (ns)
  8369. name.append("::");
  8370. size32_t ns2 = name.length();
  8371. if (scopeMatch(name.str())) {
  8372. Owned<IPropertyTreeIterator> iter = root.getElements(queryDfsXmlBranchName(DXB_Scope));
  8373. if (iter->first()) {
  8374. do {
  8375. IPropertyTree &scope = iter->query();
  8376. if (scope.hasChildren()) {
  8377. name.append(scope.queryProp("@name"));
  8378. ret |= processScopes(scope, name);
  8379. name.setLength(ns2);
  8380. }
  8381. } while (iter->next());
  8382. }
  8383. if (!iterateFileFilterContainer)
  8384. ret |= processFiles(root,name);
  8385. else
  8386. ret |= processFilesWithFilters(root,name);
  8387. }
  8388. if (!ret && parentScope)
  8389. parentScope->popLastScope(); // discard scopes where no matches
  8390. currentScope = parentScope;
  8391. name.setLength(ns);
  8392. return ret;
  8393. }
  8394. bool processFiles(IPropertyTree &root,StringBuffer &name)
  8395. {
  8396. bool ret = false;
  8397. const char *s1 = wildname.get();
  8398. size32_t ns = name.length();
  8399. Owned<IPropertyTreeIterator> iter = root.getElements(queryDfsXmlBranchName(DXB_File));
  8400. if (iter->first()) {
  8401. IPropertyTree &scope = iter->query();
  8402. do {
  8403. IPropertyTree &file = iter->query();
  8404. name.append(file.queryProp("@name"));
  8405. if (!s1||WildMatch(name.str(),s1,true)) {
  8406. currentScope->addMatch(name,file,false);
  8407. ret = true;
  8408. }
  8409. name.setLength(ns);
  8410. } while (iter->next());
  8411. }
  8412. if (includesuper) {
  8413. iter.setown(root.getElements(queryDfsXmlBranchName(DXB_SuperFile)));
  8414. if (iter->first()) {
  8415. do {
  8416. IPropertyTree &file = iter->query();
  8417. name.append(file.queryProp("@name"));
  8418. if (!s1||WildMatch(name.str(),s1,true)) {
  8419. currentScope->addMatch(name,file,true);
  8420. ret = true;
  8421. }
  8422. name.setLength(ns);
  8423. } while (iter->next());
  8424. }
  8425. }
  8426. return ret;
  8427. }
  8428. bool processFilesWithFilters(IPropertyTree &root, StringBuffer &name)
  8429. {
  8430. bool ret = false;
  8431. size32_t ns = name.length();
  8432. DFUQFileTypeFilter fileTypeFilter = iterateFileFilterContainer->getFileTypeFilter();
  8433. if (fileTypeFilter != DFUQFFTsuperfileonly)
  8434. addMatchedFiles(root.getElements(queryDfsXmlBranchName(DXB_File)), false, name, ns, ret);
  8435. if ((fileTypeFilter == DFUQFFTall) || (fileTypeFilter == DFUQFFTsuperfileonly))
  8436. addMatchedFiles(root.getElements(queryDfsXmlBranchName(DXB_SuperFile)), true, name, ns, ret);
  8437. return ret;
  8438. }
  8439. void addMatchedFiles(IPropertyTreeIterator* files, bool isSuper, StringBuffer &name, size32_t ns, bool& ret)
  8440. {
  8441. Owned<IPropertyTreeIterator> iter = files;
  8442. ForEach(*iter)
  8443. {
  8444. IPropertyTree &file = iter->query();
  8445. name.append(file.queryProp("@name"));
  8446. if (iterateFileFilterContainer->matchFileScanFilter(name.str(), file))
  8447. {
  8448. currentScope->addMatch(name,file,isSuper);
  8449. ret = true;
  8450. }
  8451. name.setLength(ns);
  8452. }
  8453. }
  8454. public:
  8455. void scan(IPropertyTree *sroot, const char *_wildname,bool _recursive,bool _includesuper)
  8456. {
  8457. if (_wildname)
  8458. wildname.set(_wildname);
  8459. else
  8460. wildname.clear();
  8461. recursive = _recursive;
  8462. includesuper = _includesuper;
  8463. StringBuffer name;
  8464. topLevelScope.clear();
  8465. currentScope = NULL;
  8466. processScopes(*sroot->queryPropTree(querySdsFilesRoot()),name);
  8467. }
  8468. void scan(IPropertyTree *sroot, CIterateFileFilterContainer* _iterateFileFilterContainer, bool _recursive)
  8469. {
  8470. iterateFileFilterContainer.setown(_iterateFileFilterContainer);
  8471. recursive = _recursive;
  8472. StringBuffer name;
  8473. topLevelScope.clear();
  8474. currentScope = NULL;
  8475. processScopes(*sroot->queryPropTree(querySdsFilesRoot()),name);
  8476. }
  8477. void _getResults(bool auth, IUserDescriptor *user, CScope &scope, CFileMatchArray &matchingFiles, StringArray &authScopes,
  8478. unsigned &count, bool checkFileCount)
  8479. {
  8480. if (auth)
  8481. {
  8482. SecAccessFlags perm = getScopePermissions(scope.getName(),user,0); // don't audit
  8483. if (!HASREADPERMISSION(perm))
  8484. return;
  8485. authScopes.append(scope.getName());
  8486. }
  8487. CFileMatchArray &files = scope.queryFiles();
  8488. ForEachItemIn(f, files)
  8489. {
  8490. if (checkFileCount && (count == iterateFileFilterContainer->getMaxFilesFilter()))
  8491. throw MakeStringException(DFSERR_PassIterateFilesLimit, "CFileScanner::_getResults() found >%d files.",
  8492. iterateFileFilterContainer->getMaxFilesFilter());
  8493. CFileMatch *match = &files.item(f);
  8494. matchingFiles.append(*LINK(match));
  8495. ++count;
  8496. }
  8497. CScopeArray &subScopes = scope.querySubScopes();
  8498. ForEachItemIn(s, subScopes)
  8499. {
  8500. CScope &subScope = subScopes.item(s);
  8501. _getResults(auth, user, subScope, matchingFiles, authScopes, count, checkFileCount);
  8502. }
  8503. }
  8504. unsigned getResults(bool auth, IUserDescriptor *user, CFileMatchArray &matchingFiles, StringArray &authScopes, unsigned &count, bool checkFileCount)
  8505. {
  8506. _getResults(auth, user, *topLevelScope, matchingFiles, authScopes, count, checkFileCount);
  8507. return count;
  8508. }
  8509. };
  8510. struct CMachineEntry: public CInterface
  8511. {
  8512. CMachineEntry(const char *_mname,SocketEndpoint _ep)
  8513. : mname(_mname),ep(_ep)
  8514. {
  8515. }
  8516. StringAttr mname;
  8517. SocketEndpoint ep;
  8518. };
  8519. typedef CMachineEntry *CMachineEntryPtr;
  8520. typedef MapStringTo<CMachineEntryPtr> CMachineEntryMap;
  8521. StringBuffer &getClusterGroupName(IPropertyTree &cluster, StringBuffer &groupName)
  8522. {
  8523. const char *name = cluster.queryProp("@name");
  8524. const char *nodeGroupName = cluster.queryProp("@nodeGroup");
  8525. if (nodeGroupName && *nodeGroupName)
  8526. name = nodeGroupName;
  8527. groupName.append(name);
  8528. return groupName.trim().toLowerCase();
  8529. }
  8530. StringBuffer &getClusterSpareGroupName(IPropertyTree &cluster, StringBuffer &groupName)
  8531. {
  8532. return getClusterGroupName(cluster, groupName).append("_spares");
  8533. }
  8534. // JCSMORE - dfs group handling may be clearer if in own module
  8535. class CInitGroups
  8536. {
  8537. CMachineEntryMap machinemap;
  8538. CIArrayOf<CMachineEntry> machinelist;
  8539. CConnectLock groupsconnlock;
  8540. StringArray clusternames;
  8541. unsigned defaultTimeout;
  8542. bool machinesLoaded;
  8543. GroupType getGroupType(const char *type)
  8544. {
  8545. if (0 == strcmp("ThorCluster", type))
  8546. return grp_thor;
  8547. else if (0 == strcmp("RoxieCluster", type))
  8548. return grp_roxie;
  8549. else
  8550. throwUnexpected();
  8551. }
  8552. bool clusterGroupCompare(IPropertyTree *newClusterGroup, IPropertyTree *oldClusterGroup)
  8553. {
  8554. if (!newClusterGroup && !oldClusterGroup)
  8555. return true; // i.e. both missing, so match
  8556. else if (!newClusterGroup || !oldClusterGroup)
  8557. return false; // i.e. one of them (not both) missing, so mismatch
  8558. // else // neither missing
  8559. // see if identical
  8560. const char *oldKind = oldClusterGroup->queryProp("@kind");
  8561. const char *oldDir = oldClusterGroup->queryProp("@dir");
  8562. const char *newKind = newClusterGroup->queryProp("@kind");
  8563. const char *newDir = newClusterGroup->queryProp("@dir");
  8564. if (oldKind) {
  8565. if (newKind) {
  8566. if (!streq(newKind, newKind))
  8567. return false;
  8568. }
  8569. else
  8570. return false;
  8571. }
  8572. else if (newKind)
  8573. return false;
  8574. if (oldDir) {
  8575. if (newDir) {
  8576. if (!streq(newDir,oldDir))
  8577. return false;
  8578. }
  8579. else
  8580. return false;
  8581. }
  8582. else if (NULL!=newDir)
  8583. return false;
  8584. unsigned oldGroupCount = oldClusterGroup->getCount("Node");
  8585. unsigned newGroupCount = newClusterGroup->getCount("Node");
  8586. if (oldGroupCount != newGroupCount)
  8587. return false;
  8588. if (0 == newGroupCount)
  8589. return true;
  8590. Owned<IPropertyTreeIterator> newIter = newClusterGroup->getElements("Node");
  8591. Owned<IPropertyTreeIterator> oldIter = oldClusterGroup->getElements("Node");
  8592. if (newIter->first() && oldIter->first()) {
  8593. for (;;) {
  8594. const char *oldIp = oldIter->query().queryProp("@ip");
  8595. const char *newIp = newIter->query().queryProp("@ip");
  8596. if (!streq(oldIp, newIp))
  8597. return false;
  8598. if (!oldIter->next() || !newIter->next())
  8599. break;
  8600. }
  8601. }
  8602. return true;
  8603. }
  8604. void addClusterGroup(const char *name, IPropertyTree *newClusterGroup, bool realCluster)
  8605. {
  8606. VStringBuffer prop("Group[@name=\"%s\"]", name);
  8607. IPropertyTree *root = groupsconnlock.conn->queryRoot();
  8608. IPropertyTree *old = root->queryPropTree(prop.str());
  8609. if (old) {
  8610. // JCSMORE
  8611. // clone
  8612. // iterate through files and point to clone
  8613. // i) if change is minor, worth swapping to new group anyway?
  8614. // ii) if old group has machines that are no longer in new environment, mark file bad?
  8615. root->removeTree(old);
  8616. }
  8617. if (!newClusterGroup)
  8618. return;
  8619. if (realCluster)
  8620. clusternames.append(name);
  8621. IPropertyTree *grp = root->addPropTree("Group", newClusterGroup);
  8622. grp->setProp("@name", name);
  8623. }
  8624. IGroup *getGroupFromCluster(GroupType groupType, IPropertyTree &cluster, bool expand)
  8625. {
  8626. SocketEndpointArray eps;
  8627. const char *processName=NULL;
  8628. switch (groupType)
  8629. {
  8630. case grp_thor:
  8631. processName = "ThorSlaveProcess";
  8632. break;
  8633. case grp_thorspares:
  8634. processName = "ThorSpareProcess";
  8635. break;
  8636. case grp_roxie:
  8637. processName = "RoxieServerProcess";
  8638. break;
  8639. default:
  8640. throwUnexpected();
  8641. }
  8642. SocketEndpoint nullep;
  8643. Owned<IPropertyTreeIterator> nodes = cluster.getElements(processName);
  8644. ForEach(*nodes)
  8645. {
  8646. IPropertyTree &node = nodes->query();
  8647. SocketEndpoint ep;
  8648. const char *computer = node.queryProp("@computer");
  8649. const char *netAddress = node.queryProp("@netAddress");
  8650. if (computer && *computer)
  8651. {
  8652. CMachineEntryPtr *m = machinemap.getValue(computer);
  8653. if (!m)
  8654. {
  8655. OERRLOG("Cannot construct %s, computer name %s not found\n", cluster.queryProp("@name"), computer);
  8656. return NULL;
  8657. }
  8658. ep.set((*m)->ep);
  8659. }
  8660. else if (netAddress && *netAddress)
  8661. {
  8662. ep.set(netAddress, 0);
  8663. }
  8664. else
  8665. {
  8666. OERRLOG("Cannot construct %s, missing computer spec on node\n", cluster.queryProp("@name"));
  8667. return NULL;
  8668. }
  8669. switch (groupType)
  8670. {
  8671. case grp_roxie:
  8672. // Redundant copies are located via the flags.
  8673. // Old environments may contain duplicated sever information for multiple ports
  8674. eps.appendUniq(ep);
  8675. break;
  8676. case grp_thor:
  8677. case grp_thorspares:
  8678. eps.append(ep);
  8679. break;
  8680. default:
  8681. throwUnexpected();
  8682. }
  8683. }
  8684. if (!eps.ordinality())
  8685. return NULL;
  8686. Owned<IGroup> grp;
  8687. if (grp_thor != groupType)
  8688. expand = false;
  8689. if (expand)
  8690. {
  8691. unsigned slavesPerNode = cluster.getPropInt("@slavesPerNode", 1);
  8692. unsigned channelsPerSlave = cluster.getPropInt("@channelsPerSlave", 1);
  8693. SocketEndpointArray msEps;
  8694. for (unsigned s=0; s<(slavesPerNode*channelsPerSlave); s++)
  8695. {
  8696. ForEachItemIn(e, eps)
  8697. msEps.append(eps.item(e));
  8698. }
  8699. grp.setown(createIGroup(msEps));
  8700. }
  8701. else
  8702. grp.setown(createIGroup(eps));
  8703. return grp.getClear();
  8704. }
  8705. bool loadMachineMap()
  8706. {
  8707. if (machinesLoaded)
  8708. return true;
  8709. //GH->JCS This can't be changed to use getEnvironmentFactory() unless that moved inside dalibase;
  8710. Owned<IRemoteConnection> conn = querySDS().connect("/Environment/Hardware", myProcessSession(), RTM_LOCK_READ, SDS_CONNECT_TIMEOUT);
  8711. if (!conn) {
  8712. IWARNLOG("Cannot connect to /Environment/Hardware");
  8713. return false;
  8714. }
  8715. IPropertyTree* root = conn->queryRoot();
  8716. Owned<IPropertyTreeIterator> machines= root->getElements("Computer");
  8717. ForEach(*machines) {
  8718. IPropertyTree &machine = machines->query();
  8719. SocketEndpoint ep(machine.queryProp("@netAddress"));
  8720. const char *name = machine.queryProp("@name");
  8721. CMachineEntry *entry = new CMachineEntry(name,ep);
  8722. machinemap.setValue(name, entry);
  8723. machinelist.append(*entry);
  8724. }
  8725. machinesLoaded = true;
  8726. return true;
  8727. }
  8728. IPropertyTree *createClusterGroup(GroupType groupType, IGroup *group, const char *dir, bool realCluster)
  8729. {
  8730. Owned<IPropertyTree> cluster = createPTree("Group");
  8731. if (realCluster)
  8732. cluster->setPropBool("@cluster", true);
  8733. const char *kind=NULL;
  8734. switch (groupType) {
  8735. case grp_thor:
  8736. kind = "Thor";
  8737. break;
  8738. case grp_roxie:
  8739. kind = "Roxie";
  8740. break;
  8741. case grp_hthor:
  8742. kind = "hthor";
  8743. break;
  8744. }
  8745. if (kind)
  8746. cluster->setProp("@kind",kind);
  8747. if (dir)
  8748. cluster->setProp("@dir",dir);
  8749. Owned<INodeIterator> iter = group->getIterator();
  8750. StringBuffer str;
  8751. ForEach(*iter) {
  8752. iter->query().endpoint().getIpText(str.clear());
  8753. IPropertyTree *n = createPTree("Node");
  8754. n->setProp("@ip",str.str());
  8755. cluster->addPropTree("Node", n);
  8756. }
  8757. return cluster.getClear();
  8758. }
  8759. IPropertyTree *createClusterGroupFromEnvCluster(GroupType groupType, IPropertyTree &cluster, const char *dir, bool realCluster)
  8760. {
  8761. Owned<IGroup> group = getGroupFromCluster(groupType, cluster, true);
  8762. if (!group)
  8763. return NULL;
  8764. return createClusterGroup(groupType, group, dir, realCluster);
  8765. }
  8766. bool constructGroup(IPropertyTree &cluster, const char *altName, IPropertyTree *oldEnvCluster, GroupType groupType, bool force, StringBuffer &messages)
  8767. {
  8768. /* a 'realCluster' is a cluster who's name matches it's nodeGroup
  8769. * if the nodeGroup differs it implies it's sharing the nodeGroup with other thor instance(s).
  8770. */
  8771. bool realCluster = true;
  8772. bool oldRealCluster = true;
  8773. StringBuffer gname, oldGname;
  8774. const char *defDir = NULL;
  8775. switch (groupType)
  8776. {
  8777. case grp_thor:
  8778. getClusterGroupName(cluster, gname);
  8779. if (!streq(cluster.queryProp("@name"), gname.str()))
  8780. realCluster = false;
  8781. if (oldEnvCluster)
  8782. {
  8783. getClusterGroupName(*oldEnvCluster, oldGname);
  8784. if (!streq(oldEnvCluster->queryProp("@name"), oldGname.str()))
  8785. oldRealCluster = false;
  8786. }
  8787. break;
  8788. case grp_thorspares:
  8789. getClusterSpareGroupName(cluster, gname);
  8790. oldRealCluster = realCluster = false;
  8791. break;
  8792. case grp_roxie:
  8793. gname.append(cluster.queryProp("@name"));
  8794. break;
  8795. default:
  8796. throwUnexpected();
  8797. }
  8798. if (altName)
  8799. gname.clear().append(altName).toLowerCase();
  8800. VStringBuffer xpath("Group[@name=\"%s\"]", gname.str());
  8801. IPropertyTree *existingClusterGroup = groupsconnlock.conn->queryRoot()->queryPropTree(xpath.str()); // 'live' cluster group
  8802. bool matchOldEnv = false;
  8803. Owned<IPropertyTree> newClusterGroup = createClusterGroupFromEnvCluster(groupType, cluster, defDir, realCluster);
  8804. bool matchExisting = clusterGroupCompare(newClusterGroup, existingClusterGroup);
  8805. if (oldEnvCluster)
  8806. {
  8807. // new matches old, only if neither has changed it's name to mismatch it's nodeGroup name
  8808. if (realCluster == oldRealCluster)
  8809. {
  8810. Owned<IPropertyTree> oldClusterGroup = createClusterGroupFromEnvCluster(groupType, *oldEnvCluster, defDir, oldRealCluster);
  8811. matchOldEnv = clusterGroupCompare(newClusterGroup, oldClusterGroup);
  8812. }
  8813. else
  8814. matchOldEnv = false;
  8815. }
  8816. if (!matchExisting)
  8817. {
  8818. if (force)
  8819. {
  8820. VStringBuffer msg("Forcing new group layout for %s [ matched active = false, matched old environment = %s ]", gname.str(), matchOldEnv?"true":"false");
  8821. UWARNLOG("%s", msg.str());
  8822. messages.append(msg).newline();
  8823. matchOldEnv = false;
  8824. }
  8825. else
  8826. {
  8827. VStringBuffer msg("Active cluster '%s' group layout does not match environment [matched old environment=%s]", gname.str(), matchOldEnv?"true":"false");
  8828. UWARNLOG("%s", msg.str()); \
  8829. messages.append(msg).newline();
  8830. if (existingClusterGroup)
  8831. {
  8832. // NB: not used at moment, but may help spot clusters that have swapped nodes
  8833. existingClusterGroup->setPropBool("@mismatched", true);
  8834. }
  8835. }
  8836. }
  8837. if ((!existingClusterGroup && (grp_thorspares != groupType)) || (!matchExisting && !matchOldEnv))
  8838. {
  8839. VStringBuffer msg("New cluster layout for cluster %s", gname.str());
  8840. UWARNLOG("%s", msg.str());
  8841. messages.append(msg).newline();
  8842. addClusterGroup(gname.str(), newClusterGroup.getClear(), realCluster);
  8843. return true;
  8844. }
  8845. return false;
  8846. }
  8847. void constructHThorGroups(IPropertyTree &cluster)
  8848. {
  8849. const char *groupname = cluster.queryProp("@name");
  8850. if (!groupname || !*groupname)
  8851. return;
  8852. unsigned ins = 0;
  8853. Owned<IPropertyTreeIterator> insts = cluster.getElements("Instance");
  8854. ForEach(*insts) {
  8855. const char *na = insts->query().queryProp("@netAddress");
  8856. if (na&&*na) {
  8857. SocketEndpoint ep(na);
  8858. if (!ep.isNull()) {
  8859. ins++;
  8860. VStringBuffer gname("hthor__%s", groupname);
  8861. if (ins>1)
  8862. gname.append('_').append(ins);
  8863. Owned<IGroup> group = createIGroup(1, &ep);
  8864. Owned<IPropertyTree> clusterGroup = createClusterGroup(grp_hthor, group, NULL, true);
  8865. addClusterGroup(gname.str(), clusterGroup.getClear(), true);
  8866. }
  8867. }
  8868. }
  8869. }
  8870. enum CgCmd { cg_null, cg_reset, cg_add, cg_remove };
  8871. public:
  8872. CInitGroups(unsigned _defaultTimeout)
  8873. : groupsconnlock("constructGroup",SDS_GROUPSTORE_ROOT,true,false,false,_defaultTimeout)
  8874. {
  8875. defaultTimeout = _defaultTimeout;
  8876. machinesLoaded = false;
  8877. }
  8878. bool doClusterGroup(CgCmd cmd, const char *_clusterName, const char *type, bool spares, SocketEndpointArray *eps, StringBuffer &messages)
  8879. {
  8880. Owned<IRemoteConnection> conn = querySDS().connect("/Environment/Software", myProcessSession(), RTM_LOCK_READ, SDS_CONNECT_TIMEOUT);
  8881. if (!conn)
  8882. return false;
  8883. if (!_clusterName || !*_clusterName)
  8884. return false;
  8885. StringAttr clusterName = _clusterName;
  8886. clusterName.toLowerCase();
  8887. if (!type || !*type)
  8888. return false;
  8889. bool ret = true;
  8890. IPropertyTree* root = conn->queryRoot();
  8891. Owned<IPropertyTreeIterator> clusters;
  8892. StringBuffer errMsg;
  8893. const char *clusterType = type;
  8894. if (loadMachineMap()) {
  8895. VStringBuffer xpath("%s[@name=\"%s\"]", type, clusterName.get());
  8896. clusters.setown(root->getElements(xpath.str()));
  8897. if (!clusters || !clusters->first()) {
  8898. VStringBuffer errMsg("Could not find type %s, %s cluster", type, clusterName.get());
  8899. UWARNLOG("%s", errMsg.str());
  8900. messages.append(errMsg).newline();
  8901. ret = false;
  8902. }
  8903. else {
  8904. if (!streq("ThorCluster", type))
  8905. return false; // currently only Thor supported here.
  8906. IPropertyTree &cluster = clusters->query();
  8907. switch (cmd) {
  8908. case cg_reset:
  8909. {
  8910. if (spares) {
  8911. if (!constructGroup(cluster,NULL,NULL,grp_thorspares,true,messages))
  8912. ret = false;
  8913. }
  8914. else {
  8915. if (!constructGroup(cluster,NULL,NULL,grp_thor,true,messages))
  8916. ret = false;
  8917. }
  8918. break;
  8919. }
  8920. case cg_add:
  8921. {
  8922. assertex(eps);
  8923. StringBuffer groupName;
  8924. getClusterSpareGroupName(cluster, groupName);
  8925. IPropertyTree *root = groupsconnlock.conn->queryRoot();
  8926. VStringBuffer xpath("Group[@name=\"%s\"]",groupName.str());
  8927. IPropertyTree *existing = root->queryPropTree(xpath.str());
  8928. if (existing) {
  8929. Owned<IPropertyTreeIterator> iter = existing->getElements("Node");
  8930. ForEach(*iter) {
  8931. SocketEndpoint ep(iter->query().queryProp("@ip"));
  8932. if (eps->zap(ep)) {
  8933. StringBuffer epStr;
  8934. VStringBuffer errMsg("addSpares: not adding: %s, already in spares", ep.getUrlStr(epStr).str());
  8935. UWARNLOG("%s", errMsg.str());
  8936. messages.append(errMsg).newline();
  8937. while (eps->zap(ep)); // delete any other duplicates
  8938. }
  8939. }
  8940. }
  8941. else {
  8942. existing = createPTree();
  8943. existing->setProp("@name", groupName.str());
  8944. existing = root->addPropTree("Group", existing);
  8945. }
  8946. // add remaining
  8947. ForEachItemIn(e, *eps) {
  8948. const SocketEndpoint &ep = eps->item(e);
  8949. StringBuffer ipStr;
  8950. ep.getIpText(ipStr);
  8951. IPropertyTree *node = createPTree();
  8952. node->setProp("@ip", ipStr.str());
  8953. existing->addPropTree("Node", node);
  8954. }
  8955. break;
  8956. }
  8957. case cg_remove:
  8958. {
  8959. assertex(eps);
  8960. StringBuffer groupName;
  8961. getClusterSpareGroupName(cluster, groupName);
  8962. IPropertyTree *root = groupsconnlock.conn->queryRoot();
  8963. VStringBuffer xpath("Group[@name=\"%s\"]", groupName.str());
  8964. IPropertyTree *existing = root->queryPropTree(xpath.str());
  8965. if (existing) {
  8966. ForEachItemIn(e, *eps) {
  8967. const SocketEndpoint &ep = eps->item(e);
  8968. StringBuffer ipStr;
  8969. ep.getIpText(ipStr);
  8970. VStringBuffer xpath("Node[@ip=\"%s\"]", ipStr.str());
  8971. if (!existing->removeProp(xpath.str())) {
  8972. VStringBuffer errMsg("removeSpares: %s not found in spares", ipStr.str());
  8973. UWARNLOG("%s", errMsg.str());
  8974. messages.append(errMsg).newline();
  8975. while (eps->zap(ep)); // delete any other duplicates
  8976. }
  8977. else
  8978. while (existing->removeProp(xpath.str())); // remove any others, shouldn't be any
  8979. }
  8980. }
  8981. break;
  8982. }
  8983. }
  8984. if (clusters->next()) {
  8985. VStringBuffer errMsg("resetThorGroup: more than one cluster named: %s", clusterName.get());
  8986. UWARNLOG("%s", errMsg.str());
  8987. messages.append(errMsg).newline();
  8988. ret = false;
  8989. }
  8990. }
  8991. }
  8992. return ret;
  8993. }
  8994. bool resetClusterGroup(const char *clusterName, const char *type, bool spares, StringBuffer &messages)
  8995. {
  8996. return doClusterGroup(cg_reset, clusterName, type, spares, NULL, messages);
  8997. }
  8998. bool addSpares(const char *clusterName, const char *type, SocketEndpointArray &eps, StringBuffer &messages)
  8999. {
  9000. return doClusterGroup(cg_add, clusterName, type, true, &eps, messages);
  9001. }
  9002. bool removeSpares(const char *clusterName, const char *type, SocketEndpointArray &eps, StringBuffer &messages)
  9003. {
  9004. return doClusterGroup(cg_remove, clusterName, type, true, &eps, messages);
  9005. }
  9006. void constructGroups(bool force, StringBuffer &messages, IPropertyTree *oldEnvironment)
  9007. {
  9008. Owned<IRemoteConnection> conn = querySDS().connect("/Environment/Software", myProcessSession(), RTM_LOCK_READ, SDS_CONNECT_TIMEOUT);
  9009. if (!conn)
  9010. return;
  9011. clusternames.kill();
  9012. IPropertyTree* root = conn->queryRoot();
  9013. Owned<IPropertyTreeIterator> clusters;
  9014. if (loadMachineMap()) {
  9015. clusters.setown(root->getElements("ThorCluster"));
  9016. ForEach(*clusters) {
  9017. IPropertyTree &cluster = clusters->query();
  9018. IPropertyTree *oldCluster = NULL;
  9019. if (oldEnvironment) {
  9020. VStringBuffer xpath("Software/ThorCluster[@name=\"%s\"]", cluster.queryProp("@name"));
  9021. oldCluster = oldEnvironment->queryPropTree(xpath.str());
  9022. }
  9023. constructGroup(cluster,NULL,oldCluster,grp_thor,force,messages);
  9024. constructGroup(cluster,NULL,oldCluster,grp_thorspares,force,messages);
  9025. }
  9026. clusters.setown(root->getElements("RoxieCluster"));
  9027. ForEach(*clusters) {
  9028. IPropertyTree &cluster = clusters->query();
  9029. IPropertyTree *oldCluster = NULL;
  9030. if (oldEnvironment) {
  9031. VStringBuffer xpath("Software/RoxieCluster[@name=\"%s\"]", cluster.queryProp("@name"));
  9032. oldCluster = oldEnvironment->queryPropTree(xpath.str());
  9033. }
  9034. constructGroup(cluster,NULL,oldCluster,grp_roxie,force,messages);
  9035. }
  9036. clusters.setown(root->getElements("EclAgentProcess"));
  9037. ForEach(*clusters) {
  9038. IPropertyTree &cluster = clusters->query();
  9039. constructHThorGroups(cluster);
  9040. }
  9041. // correct cluster flags
  9042. // JCSMORE - why was this necessary, may well be legacy..
  9043. Owned<IPropertyTreeIterator> grps = groupsconnlock.conn->queryRoot()->getElements("Group");
  9044. ForEach(*grps) {
  9045. IPropertyTree &grp = grps->query();
  9046. const char *name = grp.queryProp("@name");
  9047. bool iscluster = NotFound != clusternames.find(name);
  9048. if (iscluster!=grp.getPropBool("@cluster"))
  9049. {
  9050. if (iscluster)
  9051. grp.setPropBool("@cluster", true);
  9052. else
  9053. grp.removeProp("@cluster");
  9054. }
  9055. }
  9056. }
  9057. }
  9058. IGroup *getGroupFromCluster(const char *type, IPropertyTree &cluster, bool expand)
  9059. {
  9060. loadMachineMap();
  9061. GroupType gt = getGroupType(type);
  9062. return getGroupFromCluster(gt, cluster, expand);
  9063. }
  9064. IPropertyTree *queryRawGroup(const char *name)
  9065. {
  9066. VStringBuffer xpath("Group[@name=\"%s\"]", name);
  9067. return groupsconnlock.conn->queryRoot()->queryPropTree(xpath.str());
  9068. }
  9069. };
  9070. void initClusterGroups(bool force, StringBuffer &response, IPropertyTree *oldEnvironment, unsigned timems)
  9071. {
  9072. CInitGroups init(timems);
  9073. init.constructGroups(force, response, oldEnvironment);
  9074. }
  9075. bool resetClusterGroup(const char *clusterName, const char *type, bool spares, StringBuffer &response, unsigned timems)
  9076. {
  9077. CInitGroups init(timems);
  9078. return init.resetClusterGroup(clusterName, type, spares, response);
  9079. }
  9080. bool addClusterSpares(const char *clusterName, const char *type, SocketEndpointArray &eps, StringBuffer &response, unsigned timems)
  9081. {
  9082. CInitGroups init(timems);
  9083. return init.addSpares(clusterName, type, eps, response);
  9084. }
  9085. bool removeClusterSpares(const char *clusterName, const char *type, SocketEndpointArray &eps, StringBuffer &response, unsigned timems)
  9086. {
  9087. CInitGroups init(timems);
  9088. return init.removeSpares(clusterName, type, eps, response);
  9089. }
  9090. static IGroup *getClusterNodeGroup(const char *clusterName, const char *type, bool processGroup, unsigned timems)
  9091. {
  9092. VStringBuffer clusterPath("/Environment/Software/%s[@name=\"%s\"]", type, clusterName);
  9093. Owned<IRemoteConnection> conn = querySDS().connect(clusterPath.str(), myProcessSession(), RTM_LOCK_READ, SDS_CONNECT_TIMEOUT);
  9094. if (!conn)
  9095. return NULL;
  9096. IPropertyTree &cluster = *conn->queryRoot();
  9097. StringBuffer nodeGroupName;
  9098. getClusterGroupName(cluster, nodeGroupName);
  9099. if (0 == nodeGroupName.length())
  9100. throwUnexpected();
  9101. /* NB: Due to the way node groups and swapNode work, we need to return the IP's from the node group corresponding to the cluster
  9102. * which may no longer match the cluster IP's due to node swapping.
  9103. * As the node group is an expanded form of the cluster group (with a IP per partition/slave), with the cluster group repeated
  9104. * N times, where N is slavesPerNode*channelsPerSlave, return the first M (cluster group width) IP's of the node group.
  9105. * Ideally the node group representation would change to match the cluster group definition, but that require a lot of changes
  9106. * to DFS and elsewhere.
  9107. */
  9108. Owned<IGroup> nodeGroup = queryNamedGroupStore().lookup(nodeGroupName);
  9109. CInitGroups init(timems);
  9110. Owned<IGroup> expandedClusterGroup = init.getGroupFromCluster(type, cluster, true);
  9111. if (!expandedClusterGroup)
  9112. throwStringExceptionV(0, "Failed to get group for '%s' cluster '%s'", type, clusterName);
  9113. if (!expandedClusterGroup->equals(nodeGroup))
  9114. {
  9115. IPropertyTree *rawGroup = init.queryRawGroup(nodeGroupName);
  9116. if (!rawGroup)
  9117. throwUnexpectedX("missing node group");
  9118. unsigned nodesSwapped = rawGroup->getPropInt("@nodesSwapped");
  9119. if (nodesSwapped)
  9120. {
  9121. unsigned rawGroupSize = rawGroup->getCount("Node");
  9122. if (rawGroupSize != expandedClusterGroup->ordinality())
  9123. throwStringExceptionV(0, "DFS cluster topology for '%s', does not match existing DFS group size for group '%s' [Environment cluster group size = %u, Dali group size = %u]",
  9124. clusterName, nodeGroupName.str(), expandedClusterGroup->ordinality(), rawGroupSize);
  9125. VStringBuffer msg("DFS cluster topology for '%s' using group '%s', does not match environment due to previously swapped nodes", clusterName, nodeGroupName.str());
  9126. WARNLOG("%s", msg.str());
  9127. }
  9128. else
  9129. throwStringExceptionV(0, "DFS cluster topology for '%s', does not match existing DFS group layout for group '%s'", clusterName, nodeGroupName.str());
  9130. }
  9131. Owned<IGroup> clusterGroup = init.getGroupFromCluster(type, cluster, false);
  9132. ICopyArrayOf<INode> nodes;
  9133. unsigned l=processGroup?cluster.getPropInt("@slavesPerNode", 1):1; // if process group requested, repeat clusterGroup slavesPerNode times.
  9134. for (unsigned t=0; t<l; t++)
  9135. {
  9136. for (unsigned n=0; n<clusterGroup->ordinality(); n++)
  9137. nodes.append(nodeGroup->queryNode(n));
  9138. }
  9139. return createIGroup(nodes.ordinality(), nodes.getArray());
  9140. }
  9141. IGroup *getClusterNodeGroup(const char *clusterName, const char *type, unsigned timems)
  9142. {
  9143. return getClusterNodeGroup(clusterName, type, false, timems);
  9144. }
  9145. IGroup *getClusterProcessNodeGroup(const char *clusterName, const char *type, unsigned timems)
  9146. {
  9147. return getClusterNodeGroup(clusterName, type, true, timems);
  9148. }
  9149. class CDaliDFSServer: public Thread, public CTransactionLogTracker, implements IDaliServer, implements IExceptionHandler
  9150. { // Coven size
  9151. bool stopped;
  9152. unsigned defaultTimeout;
  9153. unsigned numThreads;
  9154. public:
  9155. IMPLEMENT_IINTERFACE;
  9156. CDaliDFSServer(IPropertyTree *config)
  9157. : Thread("CDaliDFSServer"), CTransactionLogTracker(MDFS_MAX)
  9158. {
  9159. stopped = true;
  9160. defaultTimeout = INFINITE; // server uses default
  9161. numThreads = config->getPropInt("DFS/@numThreads", DEFAULT_NUM_DFS_THREADS);
  9162. PROGLOG("DFS Server: numThreads=%d", numThreads);
  9163. }
  9164. ~CDaliDFSServer()
  9165. {
  9166. }
  9167. void start()
  9168. {
  9169. Thread::start();
  9170. }
  9171. void ready()
  9172. {
  9173. }
  9174. void suspend()
  9175. {
  9176. }
  9177. void stop()
  9178. {
  9179. if (!stopped) {
  9180. stopped = true;
  9181. queryCoven().cancel(RANK_ALL,MPTAG_DFS_REQUEST);
  9182. }
  9183. join();
  9184. }
  9185. int run()
  9186. {
  9187. ICoven &coven=queryCoven();
  9188. CMessageHandler<CDaliDFSServer> handler("CDaliDFSServer", this, &CDaliDFSServer::processMessage, this, numThreads, TIMEOUT_ON_CLOSEDOWN, INFINITE);
  9189. CMessageBuffer mb;
  9190. stopped = false;
  9191. while (!stopped)
  9192. {
  9193. try
  9194. {
  9195. mb.clear();
  9196. if (coven.recv(mb,RANK_ALL,MPTAG_DFS_REQUEST,NULL))
  9197. {
  9198. handler.handleMessage(mb);
  9199. mb.clear(); // ^ has copied mb
  9200. }
  9201. else
  9202. stopped = true;
  9203. }
  9204. catch (IException *e)
  9205. {
  9206. EXCLOG(e, "CDaliDFSServer");
  9207. e->Release();
  9208. }
  9209. }
  9210. return 0;
  9211. }
  9212. void iterateFiles(CMessageBuffer &mb,StringBuffer &trc)
  9213. {
  9214. TransactionLog transactionLog(*this, MDFS_ITERATE_FILES, mb.getSender());
  9215. StringAttr wildname;
  9216. bool recursive;
  9217. bool includesuper = false;
  9218. StringAttr attr;
  9219. mb.read(wildname).read(recursive).read(attr);
  9220. trc.appendf("iterateFiles(%s,%s,%s)",wildname.str(),recursive?"recursive":"",attr.str());
  9221. if (queryTransactionLogging())
  9222. transactionLog.log("%s", trc.str());
  9223. Owned<IUserDescriptor> udesc;
  9224. if (mb.getPos()<mb.length()) {
  9225. mb.read(includesuper);
  9226. if (mb.getPos()<mb.length()) {
  9227. udesc.setown(createUserDescriptor());
  9228. udesc->deserialize(mb);
  9229. }
  9230. }
  9231. mb.clear();
  9232. unsigned count=0;
  9233. mb.append(count);
  9234. CFileScanner scanner;
  9235. CSDSServerLockBlock sdsLock; // lock sds while scanning
  9236. unsigned start = msTick();
  9237. scanner.scan(sdsLock, wildname.get(),recursive,includesuper);
  9238. unsigned tookMs = msTick()-start;
  9239. if (tookMs>100)
  9240. PROGLOG("TIMING(filescan): %s: took %dms",trc.str(), tookMs);
  9241. sdsLock.unlock(); // unlock to perform authentification
  9242. bool auth = scopePermissionsAvail && querySessionManager().checkScopeScansLDAP();
  9243. StringArray authScopes;
  9244. CIArrayOf<CFileMatch> matchingFiles;
  9245. start = msTick();
  9246. scanner.getResults(auth, udesc, matchingFiles, authScopes, count, false);
  9247. tookMs = msTick()-start;
  9248. if (tookMs>100)
  9249. PROGLOG("TIMING(LDAP): %s: took %dms, %d lookups, file matches = %d", trc.str(), tookMs, authScopes.ordinality(), count);
  9250. sdsLock.lock(); // re-lock sds while serializing
  9251. start = msTick();
  9252. SerializeFileAttrOptions options; //The options is needed for the serializeFileAttributes()
  9253. ForEachItemIn(m, matchingFiles)
  9254. {
  9255. CFileMatch &fileMatch = matchingFiles.item(m);
  9256. CDFAttributeIterator::serializeFileAttributes(mb, fileMatch.queryFileTree(), fileMatch.queryName(), fileMatch.queryIsSuper(), options);
  9257. }
  9258. tookMs = msTick()-start;
  9259. if (tookMs>100)
  9260. PROGLOG("TIMING(filescan-serialization): %s: took %dms, %d files",trc.str(), tookMs, count);
  9261. mb.writeDirect(0,sizeof(count),&count);
  9262. }
  9263. void iterateFilteredFiles(TransactionLog &transactionLog, CMessageBuffer &mb,StringBuffer &trc, bool returnAllFilesFlag)
  9264. {
  9265. Owned<IUserDescriptor> udesc;
  9266. StringAttr filters;
  9267. bool recursive;
  9268. mb.read(filters).read(recursive);
  9269. trc.appendf("iterateFilteredFiles(%s,%s)",filters.str(),recursive?"recursive":"");
  9270. if (queryTransactionLogging())
  9271. transactionLog.log("%s", trc.str());
  9272. if (mb.getPos()<mb.length())
  9273. {
  9274. udesc.setown(createUserDescriptor());
  9275. udesc->deserialize(mb);
  9276. }
  9277. mb.clear();
  9278. unsigned count=0;
  9279. mb.append(count);
  9280. Owned<CIterateFileFilterContainer> iterateFileFilterContainer = new CIterateFileFilterContainer();
  9281. iterateFileFilterContainer->readFilters(filters);
  9282. CFileScanner scanner;
  9283. CSDSServerLockBlock sdsLock; // lock sds while scanning
  9284. unsigned start = msTick();
  9285. scanner.scan(sdsLock, iterateFileFilterContainer.getLink(), recursive);
  9286. unsigned tookMs = msTick()-start;
  9287. if (tookMs>100)
  9288. PROGLOG("TIMING(filescan): %s: took %dms",trc.str(), tookMs);
  9289. sdsLock.unlock(); // unlock to perform authentification
  9290. bool auth = scopePermissionsAvail && querySessionManager().checkScopeScansLDAP();
  9291. StringArray authScopes;
  9292. CIArrayOf<CFileMatch> matchingFiles;
  9293. start = msTick();
  9294. bool returnAllMatchingFiles = true;
  9295. try
  9296. {
  9297. scanner.getResults(auth, udesc, matchingFiles, authScopes, count, true);
  9298. }
  9299. catch(IException *e)
  9300. {
  9301. if (DFSERR_PassIterateFilesLimit != e->errorCode())
  9302. throw;
  9303. e->Release();
  9304. returnAllMatchingFiles = false;
  9305. }
  9306. if (returnAllFilesFlag)
  9307. mb.append(returnAllMatchingFiles);
  9308. tookMs = msTick()-start;
  9309. if (tookMs>100)
  9310. PROGLOG("TIMING(LDAP): %s: took %dms, %d lookups, file matches = %d", trc.str(), tookMs, authScopes.ordinality(), count);
  9311. sdsLock.lock(); // re-lock sds while serializing
  9312. start = msTick();
  9313. ForEachItemIn(m, matchingFiles)
  9314. {
  9315. CFileMatch &fileMatch = matchingFiles.item(m);
  9316. unsigned pos = mb.length();
  9317. try
  9318. {
  9319. CDFAttributeIterator::serializeFileAttributes(mb, fileMatch.queryFileTree(), fileMatch.queryName(), fileMatch.queryIsSuper(), iterateFileFilterContainer->getSerializeFileAttrOptions());
  9320. }
  9321. catch (IException *e)
  9322. {
  9323. StringBuffer errMsg("Failed to serialize properties for file: ");
  9324. LOG(MCuserWarning, e, errMsg.append(fileMatch.queryName()));
  9325. e->Release();
  9326. mb.setLength(pos);
  9327. --count;
  9328. }
  9329. }
  9330. tookMs = msTick()-start;
  9331. if (tookMs>100)
  9332. PROGLOG("TIMING(filescan-serialization): %s: took %dms, %d files",trc.str(), tookMs, count);
  9333. mb.writeDirect(0,sizeof(count),&count);
  9334. }
  9335. void iterateFilteredFiles(CMessageBuffer &mb,StringBuffer &trc)
  9336. {
  9337. TransactionLog transactionLog(*this, MDFS_ITERATE_FILTEREDFILES, mb.getSender());
  9338. iterateFilteredFiles(transactionLog, mb, trc, false);
  9339. }
  9340. void iterateFilteredFiles2(CMessageBuffer &mb,StringBuffer &trc)
  9341. {
  9342. TransactionLog transactionLog(*this, MDFS_ITERATE_FILTEREDFILES2, mb.getSender());
  9343. iterateFilteredFiles(transactionLog, mb, trc, true);
  9344. }
  9345. void iterateRelationships(CMessageBuffer &mb,StringBuffer &trc)
  9346. {
  9347. TransactionLog transactionLog(*this, MDFS_ITERATE_RELATIONSHIPS, mb.getSender());
  9348. StringAttr primary;
  9349. StringAttr secondary;
  9350. StringAttr primflds;
  9351. StringAttr secflds;
  9352. StringAttr kind;
  9353. StringAttr cardinality;
  9354. byte payloadb;
  9355. mb.read(primary).read(secondary).read(primflds).read(secflds).read(kind).read(cardinality).read(payloadb);
  9356. mb.clear();
  9357. bool payload = (payloadb==1);
  9358. trc.appendf("iterateRelationships(%s,%s,%s,%s,%s,%s,%d)",primary.str(),secondary.str(),primflds.str(),secflds.str(),kind.str(),cardinality.str(),(int)payloadb);
  9359. if (queryTransactionLogging())
  9360. transactionLog.log("%s", trc.str());
  9361. unsigned start = msTick();
  9362. unsigned count=0;
  9363. CSDSServerLockBlock sdsLock; // lock sds while scanning
  9364. StringBuffer xpath;
  9365. CDistributedFileDirectory::getFileRelationshipXPath(xpath,primary,secondary,primflds,secflds,kind,cardinality,((payloadb==0)||(payloadb==1))?&payload:NULL);
  9366. IPropertyTree *root = sdsLock->queryPropTree(querySdsRelationshipsRoot());
  9367. Owned<IPropertyTreeIterator> iter = root?root->getElements(xpath.str()):NULL;
  9368. mb.append(count);
  9369. // save as sequence of branches
  9370. if (iter) {
  9371. ForEach(*iter.get()) {
  9372. iter->query().serialize(mb);
  9373. count++;
  9374. }
  9375. }
  9376. if (msTick()-start>100) {
  9377. PROGLOG("TIMING(relationshipscan): %s: took %dms, %d relations",trc.str(),msTick()-start,count);
  9378. }
  9379. mb.writeDirect(0,sizeof(count),&count);
  9380. }
  9381. void setFileAccessed(CMessageBuffer &mb,StringBuffer &trc)
  9382. {
  9383. TransactionLog transactionLog(*this, MDFS_SET_FILE_ACCESSED, mb.getSender());
  9384. StringAttr lname;
  9385. mb.read(lname);
  9386. CDateTime dt;
  9387. dt.deserialize(mb);
  9388. trc.appendf("setFileAccessed(%s)",lname.str());
  9389. Owned<IUserDescriptor> udesc;
  9390. if (mb.getPos()<mb.length()) {
  9391. udesc.setown(createUserDescriptor());
  9392. udesc->deserialize(mb);
  9393. }
  9394. if (queryTransactionLogging())
  9395. transactionLog.log("%s", trc.str());
  9396. mb.clear();
  9397. StringBuffer tail;
  9398. CDfsLogicalFileName dlfn;
  9399. dlfn.set(lname);
  9400. if (!checkLogicalName(dlfn,udesc,true,false,true,"setFileAccessed on"))
  9401. return;
  9402. CScopeConnectLock sconnlock("setFileAccessed", dlfn, false, false, false, defaultTimeout);
  9403. IPropertyTree* sroot = sconnlock.conn()?sconnlock.conn()->queryRoot():NULL;
  9404. dlfn.getTail(tail);
  9405. Owned<IPropertyTree> tree = getNamedPropTree(sroot,queryDfsXmlBranchName(DXB_File),"@name",tail.str(),false);
  9406. if (tree) {
  9407. StringBuffer str;
  9408. tree->setProp("@accessed",dt.getString(str).str());
  9409. }
  9410. }
  9411. void setFileProtect(CMessageBuffer &mb,StringBuffer &trc)
  9412. {
  9413. TransactionLog transactionLog(*this, MDFS_SET_FILE_PROTECT, mb.getSender());
  9414. StringAttr lname;
  9415. StringAttr owner;
  9416. bool set;
  9417. mb.read(lname).read(owner).read(set);
  9418. trc.appendf("setFileProtect(%s,%s,%s)",lname.str(),owner.str(),set?"true":"false");
  9419. if (queryTransactionLogging())
  9420. transactionLog.log("%s", trc.str());
  9421. Owned<IUserDescriptor> udesc;
  9422. if (mb.getPos()<mb.length()) {
  9423. udesc.setown(createUserDescriptor());
  9424. udesc->deserialize(mb);
  9425. }
  9426. mb.clear();
  9427. StringBuffer tail;
  9428. CDfsLogicalFileName dlfn;
  9429. dlfn.set(lname);
  9430. if (!checkLogicalName(dlfn,udesc,true,false,true,"setFileProtect"))
  9431. return;
  9432. CScopeConnectLock sconnlock("setFileProtect", dlfn, false, false, false, defaultTimeout);
  9433. IPropertyTree* sroot = sconnlock.conn()?sconnlock.conn()->queryRoot():NULL;
  9434. dlfn.getTail(tail);
  9435. Owned<IPropertyTree> tree = getNamedPropTree(sroot,queryDfsXmlBranchName(DXB_File),"@name",tail.str(),false);
  9436. if (!tree)
  9437. tree.setown(getNamedPropTree(sroot,queryDfsXmlBranchName(DXB_SuperFile),"@name",tail.str(),false));
  9438. if (tree) {
  9439. IPropertyTree *pt = tree->queryPropTree("Attr");
  9440. if (pt)
  9441. setFileProtectTree(*pt,*owner?owner:owner,set);
  9442. }
  9443. }
  9444. void getFileTree(CMessageBuffer &mb,StringBuffer &trc)
  9445. {
  9446. TransactionLog transactionLog(*this, MDFS_GET_FILE_TREE, mb.getSender());
  9447. StringAttr lname;
  9448. mb.read(lname);
  9449. unsigned ver;
  9450. if (mb.length()<mb.getPos()+sizeof(unsigned))
  9451. ver = 0;
  9452. else {
  9453. mb.read(ver);
  9454. // this is a bit of a mess - for backward compatibility where user descriptor specified
  9455. if (ver>MDFS_GET_FILE_TREE_V2) {
  9456. mb.reset(mb.getPos()-sizeof(unsigned));
  9457. ver = 0;
  9458. }
  9459. }
  9460. trc.appendf("getFileTree(%s,%d)",lname.str(),ver);
  9461. if (queryTransactionLogging())
  9462. transactionLog.log("%s", trc.str());
  9463. Owned<IUserDescriptor> udesc;
  9464. if (mb.getPos()<mb.length()) {
  9465. udesc.setown(createUserDescriptor());
  9466. udesc->deserialize(mb);
  9467. }
  9468. mb.clear();
  9469. CDfsLogicalFileName dlfn;
  9470. dlfn.set(lname);
  9471. CDfsLogicalFileName *logicalname=&dlfn;
  9472. Owned<IDfsLogicalFileNameIterator> redmatch;
  9473. for (;;) {
  9474. StringBuffer tail;
  9475. checkLogicalName(*logicalname,udesc,true,false,true,"getFileTree on");
  9476. CScopeConnectLock sconnlock("getFileTree", *logicalname, false, false, false, defaultTimeout);
  9477. IPropertyTree* sroot = sconnlock.conn()?sconnlock.conn()->queryRoot():NULL;
  9478. logicalname->getTail(tail);
  9479. Owned<IPropertyTree> tree = getNamedPropTree(sroot,queryDfsXmlBranchName(DXB_File),"@name",tail.str(),false);
  9480. if (tree) {
  9481. if (ver>=MDFS_GET_FILE_TREE_V2) {
  9482. Owned<IFileDescriptor> fdesc = deserializeFileDescriptorTree(tree,&queryNamedGroupStore(),IFDSF_EXCLUDE_CLUSTERNAMES);
  9483. if (fdesc) {
  9484. ver = MDFS_GET_FILE_TREE_V2;
  9485. mb.append((int)-2).append(ver);
  9486. fdesc->serialize(mb);
  9487. StringBuffer dts;
  9488. if (tree->getProp("@modified",dts)) {
  9489. CDateTime dt;
  9490. dt.setString(dts.str());
  9491. dt.serialize(mb);
  9492. }
  9493. }
  9494. else
  9495. ver = 0;
  9496. }
  9497. if (ver==0) {
  9498. tree.setown(createPTreeFromIPT(tree));
  9499. StringBuffer cname;
  9500. logicalname->getCluster(cname);
  9501. expandFileTree(tree,true,cname.str()); // resolve @node values that may not be set
  9502. tree->serialize(mb);
  9503. }
  9504. break;
  9505. }
  9506. else {
  9507. tree.setown(getNamedPropTree(sroot,queryDfsXmlBranchName(DXB_SuperFile),"@name",tail.str(),false));
  9508. if (tree) {
  9509. tree->serialize(mb);
  9510. break;
  9511. }
  9512. }
  9513. if (redmatch.get()) {
  9514. if (!redmatch->next())
  9515. break;
  9516. }
  9517. else {
  9518. redmatch.setown(queryDistributedFileDirectory().queryRedirection().getMatch(logicalname->get()));
  9519. if (!redmatch.get())
  9520. break;
  9521. if (!redmatch->first())
  9522. break;
  9523. }
  9524. logicalname = &redmatch->query();
  9525. }
  9526. }
  9527. void getGroupTree(CMessageBuffer &mb,StringBuffer &trc)
  9528. {
  9529. TransactionLog transactionLog(*this, MDFS_GET_GROUP_TREE, mb.getSender());
  9530. StringAttr gname;
  9531. mb.read(gname);
  9532. mb.clear();
  9533. trc.appendf("getGroupTree(%s)",gname.str());
  9534. if (queryTransactionLogging())
  9535. transactionLog.log("%s", trc.str());
  9536. byte ok;
  9537. CConnectLock connlock("getGroupTree",SDS_GROUPSTORE_ROOT,false,false,false,defaultTimeout);
  9538. Owned<IPropertyTree> pt = getNamedPropTree(connlock.conn->queryRoot(),"Group","@name",gname.get(),true);
  9539. if (pt) {
  9540. ok = 1;
  9541. mb.append(ok);
  9542. pt->serialize(mb);
  9543. }
  9544. else {
  9545. ok = 0;
  9546. mb.append(ok);
  9547. }
  9548. }
  9549. void processMessage(CMessageBuffer &mb)
  9550. {
  9551. CheckTime block0("CDaliDFSServer::processMessage ");
  9552. ICoven &coven=queryCoven();
  9553. StringBuffer trc;
  9554. int fn;
  9555. mb.read(fn);
  9556. try
  9557. {
  9558. switch (fn)
  9559. {
  9560. case MDFS_ITERATE_FILES:
  9561. {
  9562. iterateFiles(mb, trc);
  9563. break;
  9564. }
  9565. case MDFS_ITERATE_FILTEREDFILES: // legacy, newer clients will send MDFS_ITERATE_FILTEREDFILES2
  9566. {
  9567. iterateFilteredFiles(mb, trc);
  9568. break;
  9569. }
  9570. case MDFS_ITERATE_FILTEREDFILES2:
  9571. {
  9572. iterateFilteredFiles2(mb, trc);
  9573. break;
  9574. }
  9575. case MDFS_ITERATE_RELATIONSHIPS:
  9576. {
  9577. iterateRelationships(mb, trc);
  9578. break;
  9579. }
  9580. case MDFS_GET_FILE_TREE:
  9581. {
  9582. getFileTree(mb, trc);
  9583. break;
  9584. }
  9585. case MDFS_GET_GROUP_TREE:
  9586. {
  9587. getGroupTree(mb, trc);
  9588. break;
  9589. }
  9590. case MDFS_SET_FILE_ACCESSED:
  9591. {
  9592. setFileAccessed(mb, trc);
  9593. break;
  9594. }
  9595. case MDFS_SET_FILE_PROTECT:
  9596. {
  9597. setFileProtect(mb, trc);
  9598. break;
  9599. }
  9600. default:
  9601. {
  9602. mb.clear();
  9603. break;
  9604. }
  9605. }
  9606. }
  9607. catch (IException *e)
  9608. {
  9609. int err=-1; // exception marker
  9610. mb.clear().append(err);
  9611. serializeException(e, mb);
  9612. e->Release();
  9613. }
  9614. coven.reply(mb);
  9615. if (block0.slow())
  9616. {
  9617. SocketEndpoint ep = mb.getSender();
  9618. ep.getUrlStr(block0.appendMsg(trc).append(" from "));
  9619. }
  9620. }
  9621. void nodeDown(rank_t rank)
  9622. {
  9623. assertex(!"TBD");
  9624. }
  9625. // CTransactionLogTracker
  9626. virtual StringBuffer &getCmdText(unsigned cmd, StringBuffer &ret) const
  9627. {
  9628. switch (cmd)
  9629. {
  9630. case MDFS_ITERATE_FILES:
  9631. return ret.append("MDFS_ITERATE_FILES");
  9632. case MDFS_ITERATE_FILTEREDFILES:
  9633. return ret.append("MDFS_ITERATE_FILTEREDFILES");
  9634. case MDFS_ITERATE_FILTEREDFILES2:
  9635. return ret.append("MDFS_ITERATE_FILTEREDFILES2");
  9636. case MDFS_ITERATE_RELATIONSHIPS:
  9637. return ret.append("MDFS_ITERATE_RELATIONSHIPS");
  9638. case MDFS_GET_FILE_TREE:
  9639. return ret.append("MDFS_GET_FILE_TREE");
  9640. case MDFS_GET_GROUP_TREE:
  9641. return ret.append("MDFS_GET_GROUP_TREE");
  9642. case MDFS_SET_FILE_ACCESSED:
  9643. return ret.append("MDFS_SET_FILE_ACCESSED");
  9644. case MDFS_SET_FILE_PROTECT:
  9645. return ret.append("MDFS_SET_FILE_PROTECT");
  9646. default:
  9647. return ret.append("UNKNOWN");
  9648. }
  9649. }
  9650. // IExceptionHandler impl.
  9651. virtual bool fireException(IException *e)
  9652. {
  9653. EXCLOG(e, "CDaliDFSServer exception");
  9654. return true;
  9655. }
  9656. } *daliDFSServer = NULL;
  9657. IDFAttributesIterator *CDistributedFileDirectory::getDFAttributesIterator(const char *wildname, IUserDescriptor *user, bool recursive, bool includesuper,INode *foreigndali,unsigned foreigndalitimeout)
  9658. {
  9659. if (!wildname||!*wildname||(strcmp(wildname,"*")==0)) {
  9660. recursive = true;
  9661. }
  9662. CMessageBuffer mb;
  9663. mb.append((int)MDFS_ITERATE_FILES).append(wildname).append(recursive).append("").append(includesuper); // "" is legacy
  9664. if (user)
  9665. {
  9666. user->serializeWithoutPassword(mb);
  9667. }
  9668. #ifdef NULL_DALIUSER_STACKTRACE
  9669. else
  9670. {
  9671. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp getDFAttributesIterator() line %d",__LINE__);
  9672. PrintStackReport();
  9673. }
  9674. #endif
  9675. if (foreigndali)
  9676. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  9677. else
  9678. queryCoven().sendRecv(mb,RANK_RANDOM,MPTAG_DFS_REQUEST);
  9679. checkDfsReplyException(mb);
  9680. return new CDFAttributeIterator(mb);
  9681. }
  9682. IDFScopeIterator *CDistributedFileDirectory::getScopeIterator(IUserDescriptor *user, const char *basescope, bool recursive,bool includeempty)
  9683. {
  9684. return new CDFScopeIterator(this,basescope,recursive,includeempty,defaultTimeout);
  9685. }
  9686. static bool isValidLFN(const char *lfn)
  9687. { // bit OTT
  9688. if (!lfn||!*lfn||(strcmp(lfn,".")==0))
  9689. return false;
  9690. StringBuffer tmp(".::");
  9691. tmp.append(lfn);
  9692. CDfsLogicalFileName dlfn;
  9693. return dlfn.setValidate(tmp.str());
  9694. }
  9695. bool CDistributedFileDirectory::loadScopeContents(const char *scopelfn,
  9696. StringArray *scopes,
  9697. StringArray *supers,
  9698. StringArray *files,
  9699. bool includeemptyscopes
  9700. )
  9701. {
  9702. StringBuffer baseq;
  9703. if (scopelfn&&*scopelfn) {
  9704. if (memcmp(scopelfn,".::",3)==0) // scopes not in .
  9705. scopelfn += 3;
  9706. StringBuffer tmp(scopelfn);
  9707. if (tmp.trim().length()) {
  9708. tmp.append("::.");
  9709. CDfsLogicalFileName dlfn;
  9710. if (!dlfn.setValidate(tmp.str()))
  9711. return false;
  9712. dlfn.makeScopeQuery(baseq,false);
  9713. }
  9714. }
  9715. CConnectLock connlock("CDistributedFileDirectory::loadScopeContents",querySdsFilesRoot(),false,false,false,defaultTimeout);
  9716. if (!connlock.conn)
  9717. return false;
  9718. IPropertyTree *root = connlock.conn->queryRoot();
  9719. if (!root)
  9720. return false;
  9721. if (baseq.length()) {
  9722. root = root->queryPropTree(baseq.str());
  9723. if (!root)
  9724. return false;
  9725. }
  9726. Owned<IPropertyTreeIterator> iter;
  9727. if (scopes) {
  9728. iter.setown(root->getElements(queryDfsXmlBranchName(DXB_Scope)));
  9729. ForEach(*iter) {
  9730. IPropertyTree &ct = iter->query();
  9731. if (includeemptyscopes||!recursiveCheckEmptyScope(ct)) {
  9732. StringBuffer name;
  9733. if (ct.getProp("@name",name)&&name.trim().length()&&isValidLFN(name.str()))
  9734. scopes->append(name.str());
  9735. }
  9736. }
  9737. }
  9738. if (!supers&&!files)
  9739. return true;
  9740. if (baseq.length()==0) { // bit odd but top level files are in '.'
  9741. CDfsLogicalFileName dlfn;
  9742. dlfn.set(".",".");
  9743. dlfn.makeScopeQuery(baseq,false);
  9744. root = root->queryPropTree(baseq.str());
  9745. if (!root)
  9746. return true;
  9747. }
  9748. if (supers) {
  9749. iter.setown(root->getElements(queryDfsXmlBranchName(DXB_SuperFile)));
  9750. ForEach(*iter) {
  9751. IPropertyTree &ct = iter->query();
  9752. StringBuffer name;
  9753. if (ct.getProp("@name",name)&&name.trim().length()&&isValidLFN(name.str()))
  9754. supers->append(name.str());
  9755. }
  9756. }
  9757. if (files) {
  9758. iter.setown(root->getElements(queryDfsXmlBranchName(DXB_File)));
  9759. ForEach(*iter) {
  9760. StringBuffer name;
  9761. IPropertyTree &ct = iter->query();
  9762. if (ct.getProp("@name",name)&&name.trim().length()&&isValidLFN(name.str()))
  9763. files->append(name.str());
  9764. }
  9765. }
  9766. return true;
  9767. }
  9768. void CDistributedFileDirectory::setFileAccessed(CDfsLogicalFileName &dlfn,IUserDescriptor *user, const CDateTime &dt, const INode *foreigndali,unsigned foreigndalitimeout)
  9769. {
  9770. // this accepts either a foreign dali node or a foreign lfn
  9771. Owned<INode> fnode;
  9772. SocketEndpoint ep;
  9773. const char *lname;
  9774. if (dlfn.isForeign()) {
  9775. if (!dlfn.getEp(ep))
  9776. throw MakeStringException(-1,"cannot resolve dali ip in foreign file name (%s)",dlfn.get());
  9777. fnode.setown(createINode(ep));
  9778. foreigndali = fnode;
  9779. lname = dlfn.get(true);
  9780. }
  9781. else if (dlfn.isExternal())
  9782. return;
  9783. else
  9784. lname = dlfn.get();
  9785. if (isLocalDali(foreigndali))
  9786. foreigndali = NULL;
  9787. CMessageBuffer mb;
  9788. mb.append((int)MDFS_SET_FILE_ACCESSED).append(lname);
  9789. dt.serialize(mb);
  9790. if (user)
  9791. {
  9792. user->serializeWithoutPassword(mb);
  9793. }
  9794. #ifdef NULL_DALIUSER_STACKTRACE
  9795. else
  9796. {
  9797. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp setFileAccessed() line %d",__LINE__);
  9798. PrintStackReport();
  9799. }
  9800. #endif
  9801. if (foreigndali)
  9802. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  9803. else
  9804. queryCoven().sendRecv(mb,RANK_RANDOM,MPTAG_DFS_REQUEST);
  9805. checkDfsReplyException(mb);
  9806. }
  9807. void CDistributedFileDirectory::setFileProtect(CDfsLogicalFileName &dlfn,IUserDescriptor *user, const char *owner, bool set, const INode *foreigndali,unsigned foreigndalitimeout)
  9808. {
  9809. // this accepts either a foreign dali node or a foreign lfn
  9810. Owned<INode> fnode;
  9811. SocketEndpoint ep;
  9812. const char *lname;
  9813. if (dlfn.isForeign()) {
  9814. if (!dlfn.getEp(ep))
  9815. throw MakeStringException(-1,"cannot resolve dali ip in foreign file name (%s)",dlfn.get());
  9816. fnode.setown(createINode(ep));
  9817. foreigndali = fnode;
  9818. lname = dlfn.get(true);
  9819. }
  9820. else if (dlfn.isExternal())
  9821. return;
  9822. else
  9823. lname = dlfn.get();
  9824. if (isLocalDali(foreigndali))
  9825. foreigndali = NULL;
  9826. CMessageBuffer mb;
  9827. if (!owner)
  9828. owner = "";
  9829. mb.append((int)MDFS_SET_FILE_PROTECT).append(lname).append(owner).append(set);
  9830. if (user)
  9831. {
  9832. user->serializeWithoutPassword(mb);
  9833. }
  9834. #ifdef NULL_DALIUSER_STACKTRACE
  9835. else
  9836. {
  9837. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp setFileProtect() line %d",__LINE__);
  9838. PrintStackReport();
  9839. }
  9840. #endif
  9841. if (foreigndali)
  9842. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  9843. else
  9844. queryCoven().sendRecv(mb,RANK_RANDOM,MPTAG_DFS_REQUEST);
  9845. checkDfsReplyException(mb);
  9846. }
  9847. IPropertyTree *CDistributedFileDirectory::getFileTree(const char *lname, IUserDescriptor *user, const INode *foreigndali,unsigned foreigndalitimeout, bool expandnodes, bool appendForeign)
  9848. {
  9849. // this accepts either a foreign dali node or a foreign lfn
  9850. Owned<INode> fnode;
  9851. CDfsLogicalFileName dlfn;
  9852. SocketEndpoint ep;
  9853. dlfn.set(lname);
  9854. if (dlfn.isForeign()) {
  9855. if (!dlfn.getEp(ep))
  9856. throw MakeStringException(-1,"cannot resolve dali ip in foreign file name (%s)",lname);
  9857. fnode.setown(createINode(ep));
  9858. foreigndali = fnode;
  9859. lname = dlfn.get(true);
  9860. }
  9861. if (isLocalDali(foreigndali))
  9862. foreigndali = NULL;
  9863. CMessageBuffer mb;
  9864. mb.append((int)MDFS_GET_FILE_TREE).append(lname);
  9865. mb.append(MDFS_GET_FILE_TREE_V2);
  9866. if (user)
  9867. {
  9868. user->serializeWithoutPassword(mb);
  9869. }
  9870. #ifdef NULL_DALIUSER_STACKTRACE
  9871. else
  9872. {
  9873. DBGLOG("UNEXPECTED USER (NULL) in dadfs.cpp getFileTree() line %d",__LINE__);
  9874. PrintStackReport();
  9875. }
  9876. #endif
  9877. if (foreigndali)
  9878. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  9879. else
  9880. queryCoven().sendRecv(mb,RANK_RANDOM,MPTAG_DFS_REQUEST);
  9881. checkDfsReplyException(mb);
  9882. if (mb.length()==0)
  9883. return NULL;
  9884. unsigned ver = 0;
  9885. if ((mb.length()>=sizeof(int))&&(*(int *)mb.bufferBase()) == -2) { // version indicator
  9886. int i;
  9887. mb.read(i);
  9888. mb.read(ver);
  9889. }
  9890. Owned<IPropertyTree> ret;
  9891. if (ver==0)
  9892. ret.setown(createPTree(mb));
  9893. else {
  9894. Owned<IFileDescriptor> fdesc;
  9895. CDateTime modified;
  9896. if (ver==MDFS_GET_FILE_TREE_V2) { // no longer in use but support for back compatibility
  9897. fdesc.setown(deserializeFileDescriptor(mb));
  9898. if (mb.remaining()>0)
  9899. modified.deserialize(mb);
  9900. }
  9901. else
  9902. throw MakeStringException(-1,"Unknown GetFileTree serialization version %d",ver);
  9903. ret.setown(createPTree(queryDfsXmlBranchName(DXB_File)));
  9904. fdesc->serializeTree(*ret,expandnodes?0:CPDMSF_packParts);
  9905. if (!modified.isNull()) {
  9906. StringBuffer dts;
  9907. ret->setProp("@modified",modified.getString(dts).str());
  9908. }
  9909. }
  9910. if (expandnodes) {
  9911. StringBuffer cname;
  9912. dlfn.getCluster(cname);
  9913. expandFileTree(ret,true,cname.str());
  9914. CDfsLogicalFileName dlfn2;
  9915. dlfn2.set(dlfn);
  9916. if (foreigndali)
  9917. dlfn2.setForeign(foreigndali->endpoint(),false);
  9918. ret->setProp("OrigName",dlfn.get());
  9919. }
  9920. if (foreigndali && appendForeign)
  9921. resolveForeignFiles(ret,foreigndali);
  9922. return ret.getClear();
  9923. }
  9924. IFileDescriptor *CDistributedFileDirectory::getFileDescriptor(const char *lname,IUserDescriptor *user,const INode *foreigndali,unsigned foreigndalitimeout)
  9925. {
  9926. Owned<IPropertyTree> tree = getFileTree(lname,user,foreigndali,foreigndalitimeout,false);
  9927. if (!tree)
  9928. return NULL;
  9929. if (strcmp(tree->queryName(),queryDfsXmlBranchName(DXB_SuperFile))==0) {
  9930. CDfsLogicalFileName dlfn;
  9931. dlfn.set(lname);
  9932. Owned<CDistributedSuperFile> sfile = new CDistributedSuperFile(this,tree, dlfn, user);
  9933. return sfile->getFileDescriptor(NULL);
  9934. }
  9935. if (strcmp(tree->queryName(),queryDfsXmlBranchName(DXB_File))!=0)
  9936. return NULL; // what is it?
  9937. IFileDescriptor * fdesc = deserializeFileDescriptorTree(tree,&queryNamedGroupStore(),0);
  9938. if (fdesc)
  9939. fdesc->setTraceName(lname);
  9940. return fdesc;
  9941. }
  9942. IDistributedFile *CDistributedFileDirectory::getFile(const char *lname,IUserDescriptor *user,const INode *foreigndali,unsigned foreigndalitimeout)
  9943. {
  9944. Owned<IPropertyTree> tree = getFileTree(lname,user,foreigndali,foreigndalitimeout,false);
  9945. if (!tree)
  9946. return NULL;
  9947. if (strcmp(tree->queryName(),queryDfsXmlBranchName(DXB_SuperFile))==0) {
  9948. CDfsLogicalFileName dlfn;
  9949. dlfn.set(lname);
  9950. return new CDistributedSuperFile(this,tree, dlfn, user);
  9951. }
  9952. if (strcmp(tree->queryName(),queryDfsXmlBranchName(DXB_File))!=0)
  9953. return NULL; // what is it?
  9954. Owned<IFileDescriptor> fdesc = deserializeFileDescriptorTree(tree,&queryNamedGroupStore(),IFDSF_FOREIGN_GROUP);
  9955. if (!fdesc)
  9956. return NULL;
  9957. fdesc->setTraceName(lname);
  9958. CDistributedFile *ret = new CDistributedFile(this, fdesc, user, false);
  9959. ret->setLogicalName(lname);
  9960. const char *date = tree->queryProp("@modified");
  9961. if (ret) {
  9962. CDateTime dt;
  9963. if (date&&*date)
  9964. dt.setString(date);
  9965. ret->setModificationTime(dt);
  9966. }
  9967. return ret;
  9968. }
  9969. static void addForeignName(IPropertyTree &t,const INode *foreigndali,const char *attr)
  9970. {
  9971. StringBuffer sb;
  9972. const char *name = t.queryProp(attr);
  9973. if (!name||!*name)
  9974. return;
  9975. CDfsLogicalFileName logicalname;
  9976. logicalname.set(name);
  9977. if (logicalname.isExternal()||logicalname.isQuery())
  9978. return; // how did that get in here?
  9979. if (logicalname.isForeign()) {
  9980. SocketEndpoint ep;
  9981. Owned<INode> fd = createINode(ep);
  9982. if (logicalname.getEp(ep)&&isLocalDali(fd)) { // see if pointing back at self
  9983. logicalname.clearForeign();
  9984. t.setProp(attr,logicalname.get());
  9985. }
  9986. }
  9987. else if (foreigndali) {
  9988. logicalname.setForeign(foreigndali->endpoint(),false);
  9989. t.setProp(attr,logicalname.get());
  9990. }
  9991. }
  9992. void CDistributedFileDirectory::resolveForeignFiles(IPropertyTree *tree,const INode *foreigndali)
  9993. {
  9994. if (!tree||!foreigndali)
  9995. return;
  9996. // now add to all sub files
  9997. Owned<IPropertyTreeIterator> pe = tree->getElements("SubFile");
  9998. ForEach(*pe)
  9999. addForeignName(pe->query(),foreigndali,"@name");
  10000. pe.setown(tree->getElements("SuperOwner"));
  10001. ForEach(*pe)
  10002. addForeignName(pe->query(),foreigndali,"@name");
  10003. // do origname?
  10004. }
  10005. SecAccessFlags CDistributedFileDirectory::getFilePermissions(const char *lname,IUserDescriptor *user,unsigned auditflags)
  10006. {
  10007. CDfsLogicalFileName dlfn;
  10008. dlfn.set(lname);
  10009. StringBuffer scopes;
  10010. dlfn.getScopes(scopes);
  10011. return getScopePermissions(scopes.str(),user,auditflags);
  10012. }
  10013. SecAccessFlags CDistributedFileDirectory::getNodePermissions(const IpAddress &ip,IUserDescriptor *user,unsigned auditflags)
  10014. {
  10015. if (ip.isNull())
  10016. return SecAccess_None;
  10017. CDfsLogicalFileName dlfn;
  10018. SocketEndpoint ep(0,ip);
  10019. dlfn.setExternal(ep,"/x");
  10020. StringBuffer scopes;
  10021. dlfn.getScopes(scopes,true);
  10022. return getScopePermissions(scopes.str(),user,auditflags);
  10023. }
  10024. SecAccessFlags CDistributedFileDirectory::getFDescPermissions(IFileDescriptor *fdesc,IUserDescriptor *user,unsigned auditflags)
  10025. {
  10026. // this checks have access to the nodes in the file descriptor
  10027. SecAccessFlags retPerms = SecAccess_Full;
  10028. unsigned np = fdesc->numParts();
  10029. for (unsigned i=0;i<np;i++) {
  10030. INode *node = fdesc->queryNode(i);
  10031. if (node) {
  10032. bool multi = false;
  10033. RemoteMultiFilename mfn;
  10034. unsigned n = 1;
  10035. if (fdesc->isMulti()) {
  10036. fdesc->getMultiFilename(i,0,mfn);
  10037. multi = true;
  10038. n = mfn.ordinality();
  10039. }
  10040. for (unsigned j = 0;j<n;j++) {
  10041. RemoteFilename rfn;
  10042. if (multi) {
  10043. rfn.set(mfn.item(j));
  10044. }
  10045. else
  10046. fdesc->getFilename(i,0,rfn);
  10047. StringBuffer localpath;
  10048. rfn.getLocalPath(localpath);
  10049. // translate wild cards
  10050. for (unsigned k=0;k<localpath.length();k++)
  10051. if ((localpath.charAt(k)=='?')||(localpath.charAt(k)=='*'))
  10052. localpath.setCharAt(k,'_');
  10053. CDfsLogicalFileName dlfn;
  10054. dlfn.setExternal(rfn.queryEndpoint(),localpath.str());
  10055. StringBuffer scopes;
  10056. dlfn.getScopes(scopes);
  10057. SecAccessFlags perm = getScopePermissions(scopes.str(),user,auditflags);
  10058. if (perm < retPerms) {
  10059. retPerms = perm;
  10060. if (retPerms == SecAccess_None)
  10061. return SecAccess_None;
  10062. }
  10063. }
  10064. }
  10065. }
  10066. return retPerms;
  10067. }
  10068. void CDistributedFileDirectory::setDefaultUser(IUserDescriptor *user)
  10069. {
  10070. if (user)
  10071. defaultudesc.set(user);
  10072. else
  10073. defaultudesc.setown(createUserDescriptor());
  10074. }
  10075. IUserDescriptor* CDistributedFileDirectory::queryDefaultUser()
  10076. {
  10077. return defaultudesc.get();
  10078. }
  10079. void CDistributedFileDirectory::setDefaultPreferredClusters(const char *clusters)
  10080. {
  10081. defprefclusters.set(clusters);
  10082. }
  10083. bool removePhysicalFiles(IGroup *grp,const char *_filemask,unsigned short port,ClusterPartDiskMapSpec &mspec,IMultiException *mexcept)
  10084. {
  10085. // TBD this won't remove repeated parts
  10086. PROGLOG("removePhysicalFiles(%s)",_filemask);
  10087. if (!isAbsolutePath(_filemask))
  10088. throw MakeStringException(-1,"removePhysicalFiles: Filename %s must be complete path",_filemask);
  10089. size32_t l = strlen(_filemask);
  10090. while (l&&isdigit(_filemask[l-1]))
  10091. l--;
  10092. unsigned width=0;
  10093. if (l&&(_filemask[l-1]=='_'))
  10094. width = atoi(_filemask+l);
  10095. if (!width)
  10096. width = grp->ordinality();
  10097. CriticalSection errcrit;
  10098. class casyncfor: public CAsyncFor
  10099. {
  10100. unsigned short port;
  10101. CriticalSection &errcrit;
  10102. IMultiException *mexcept;
  10103. unsigned width;
  10104. StringAttr filemask;
  10105. IGroup *grp;
  10106. ClusterPartDiskMapSpec &mspec;
  10107. public:
  10108. bool ok;
  10109. casyncfor(IGroup *_grp,const char *_filemask,unsigned _width,unsigned short _port,ClusterPartDiskMapSpec &_mspec,IMultiException *_mexcept,CriticalSection &_errcrit)
  10110. : mspec(_mspec),filemask(_filemask),errcrit(_errcrit)
  10111. {
  10112. grp = _grp;
  10113. port = _port;
  10114. ok = true;
  10115. mexcept = _mexcept;
  10116. width = _width;
  10117. }
  10118. void Do(unsigned i)
  10119. {
  10120. for (unsigned copy = 0; copy < 2; copy++) // ** TBD
  10121. {
  10122. RemoteFilename rfn;
  10123. constructPartFilename(grp,i+1,width,NULL,filemask,"",copy>0,mspec,rfn);
  10124. if (port)
  10125. rfn.setPort(port); // if daliservix
  10126. Owned<IFile> partfile = createIFile(rfn);
  10127. StringBuffer eps;
  10128. try
  10129. {
  10130. unsigned start = msTick();
  10131. #if 1
  10132. if (partfile->remove()) {
  10133. PROGLOG("Removed '%s'",partfile->queryFilename());
  10134. unsigned t = msTick()-start;
  10135. if (t>5*1000)
  10136. DBGLOG("Removing %s from %s took %ds", partfile->queryFilename(), rfn.queryEndpoint().getUrlStr(eps).str(), t/1000);
  10137. }
  10138. else
  10139. IWARNLOG("Failed to remove file part %s from %s", partfile->queryFilename(),rfn.queryEndpoint().getUrlStr(eps).str());
  10140. #else
  10141. if (partfile->exists())
  10142. PROGLOG("Would remove '%s'",partfile->queryFilename());
  10143. #endif
  10144. }
  10145. catch (IException *e)
  10146. {
  10147. CriticalBlock block(errcrit);
  10148. if (mexcept)
  10149. mexcept->append(*e);
  10150. else {
  10151. StringBuffer s("Failed to remove file part ");
  10152. s.append(partfile->queryFilename()).append(" from ");
  10153. rfn.queryEndpoint().getUrlStr(s);
  10154. EXCLOG(e, s.str());
  10155. e->Release();
  10156. }
  10157. ok = false;
  10158. }
  10159. }
  10160. }
  10161. } afor(grp,_filemask,width,port,mspec,mexcept,errcrit);
  10162. afor.For(width,10,false,true);
  10163. return afor.ok;
  10164. }
  10165. IDaliServer *createDaliDFSServer(IPropertyTree *config)
  10166. {
  10167. assertex(!daliDFSServer); // initialization problem
  10168. daliDFSServer = new CDaliDFSServer(config);
  10169. return daliDFSServer;
  10170. }
  10171. IDistributedFileTransaction *createDistributedFileTransaction(IUserDescriptor *user, ICodeContext *ctx)
  10172. {
  10173. return new CDistributedFileTransaction(user, NULL, ctx);
  10174. }
  10175. static void encodeCompareResult(DistributedFileCompareResult &ret,bool differs,CDateTime &newestdt1,CDateTime &newestdt2)
  10176. {
  10177. if (ret!=DFS_COMPARE_RESULT_FAILURE) {
  10178. int cmp = 0;
  10179. if (!newestdt1.isNull()) {
  10180. if (!newestdt2.isNull()) {
  10181. int cmp = newestdt1.compare(newestdt2,false);
  10182. if (cmp>=0)
  10183. ret = DFS_COMPARE_RESULT_SAME_NEWER;
  10184. else
  10185. ret = DFS_COMPARE_RESULT_SAME_OLDER;
  10186. }
  10187. else
  10188. ret = DFS_COMPARE_RESULT_SAME_NEWER;
  10189. }
  10190. else if (!newestdt2.isNull())
  10191. ret = DFS_COMPARE_RESULT_SAME_OLDER;
  10192. if (differs) {
  10193. if (ret==DFS_COMPARE_RESULT_SAME_OLDER) // ok they could be same but seems rather unlikely!
  10194. ret = DFS_COMPARE_RESULT_DIFFER_OLDER;
  10195. else
  10196. ret = DFS_COMPARE_RESULT_DIFFER_NEWER;
  10197. }
  10198. }
  10199. }
  10200. DistributedFileCompareResult CDistributedFileDirectory::fileCompare(const char *lfn1,const char *lfn2,DistributedFileCompareMode mode,StringBuffer &errstr,IUserDescriptor *user)
  10201. {
  10202. DistributedFileCompareResult ret = DFS_COMPARE_RESULT_SAME;
  10203. StringBuffer msg;
  10204. try
  10205. {
  10206. Owned<IDistributedFile> file1 = lookup(lfn1, user, false, false, false, NULL, defaultTimeout);
  10207. Owned<IDistributedFile> file2 = lookup(lfn2, user, false, false, false, NULL, defaultTimeout);
  10208. if (!file1)
  10209. {
  10210. errstr.appendf("File %s not found",lfn1);
  10211. ret = DFS_COMPARE_RESULT_FAILURE;
  10212. }
  10213. else if (!file2)
  10214. {
  10215. errstr.appendf("File %s not found",lfn2);
  10216. ret = DFS_COMPARE_RESULT_FAILURE;
  10217. }
  10218. else
  10219. {
  10220. unsigned np = file1->numParts();
  10221. if (np!=file2->numParts())
  10222. {
  10223. errstr.appendf("Files %s and %s have differing number of parts",lfn1,lfn2);
  10224. ret = DFS_COMPARE_RESULT_FAILURE;
  10225. }
  10226. else
  10227. {
  10228. CDateTime newestdt1;
  10229. CDateTime newestdt2;
  10230. bool differs = false;
  10231. class casyncfor: public CAsyncFor
  10232. {
  10233. CriticalSection crit;
  10234. DistributedFileCompareResult &ret;
  10235. IDistributedFile *file1;
  10236. IDistributedFile *file2;
  10237. const char *lfn1;
  10238. const char *lfn2;
  10239. StringBuffer &errstr;
  10240. DistributedFileCompareMode mode;
  10241. bool physdatesize;
  10242. CDateTime &newestdt1;
  10243. CDateTime &newestdt2;
  10244. bool &differs;
  10245. public:
  10246. casyncfor(const char *_lfn1,const char *_lfn2,IDistributedFile *_file1,IDistributedFile *_file2,DistributedFileCompareMode _mode,DistributedFileCompareResult &_ret,StringBuffer &_errstr,
  10247. CDateTime &_newestdt1,CDateTime &_newestdt2,bool &_differs)
  10248. : ret(_ret), errstr(_errstr),newestdt1(_newestdt1),newestdt2(_newestdt2),differs(_differs)
  10249. {
  10250. lfn1 = _lfn1;
  10251. lfn2 = _lfn2;
  10252. file1 = _file1;
  10253. file2 = _file2;
  10254. mode = _mode;
  10255. physdatesize = (mode==DFS_COMPARE_FILES_PHYSICAL)||(mode==DFS_COMPARE_FILES_PHYSICAL_CRCS);
  10256. }
  10257. void Do(unsigned p)
  10258. {
  10259. CriticalBlock block (crit);
  10260. StringBuffer msg;
  10261. Owned<IDistributedFilePart> part1 = file1->getPart(p);
  10262. Owned<IDistributedFilePart> part2 = file2->getPart(p);
  10263. CDateTime dt1;
  10264. RemoteFilename rfn;
  10265. bool ok;
  10266. {
  10267. CriticalUnblock unblock(crit);
  10268. ok = part1->getModifiedTime(true,physdatesize,dt1);
  10269. }
  10270. if (!ok) {
  10271. if (errstr.length()==0) {
  10272. errstr.append("Could not find ");
  10273. part1->getFilename(rfn);
  10274. rfn.getPath(errstr);
  10275. }
  10276. ret = DFS_COMPARE_RESULT_FAILURE;
  10277. }
  10278. CDateTime dt2;
  10279. {
  10280. CriticalUnblock unblock(crit);
  10281. ok = part2->getModifiedTime(true,physdatesize,dt2);
  10282. }
  10283. if (!ok) {
  10284. if (errstr.length()==0) {
  10285. errstr.append("Could not find ");
  10286. part2->getFilename(rfn);
  10287. rfn.getPath(errstr);
  10288. }
  10289. ret = DFS_COMPARE_RESULT_FAILURE;
  10290. }
  10291. if (ret!=DFS_COMPARE_RESULT_FAILURE) {
  10292. int cmp = dt1.compare(dt2,false);
  10293. if (cmp>0) {
  10294. if (newestdt1.isNull()||(dt1.compare(newestdt1,false)>0))
  10295. newestdt1.set(dt1);
  10296. }
  10297. else if (cmp<0) {
  10298. if (newestdt2.isNull()||(dt2.compare(newestdt2,false)>0))
  10299. newestdt2.set(dt2);
  10300. }
  10301. }
  10302. if ((ret!=DFS_COMPARE_RESULT_FAILURE)&&!differs) {
  10303. offset_t sz1;
  10304. offset_t sz2;
  10305. {
  10306. CriticalUnblock unblock(crit);
  10307. sz1 = part1->getFileSize(true,physdatesize);
  10308. sz2 = part2->getFileSize(true,physdatesize);
  10309. }
  10310. if (sz1!=sz2)
  10311. differs = true;
  10312. }
  10313. if ((ret!=DFS_COMPARE_RESULT_FAILURE)&&!differs) {
  10314. unsigned crc1;
  10315. unsigned crc2;
  10316. if (mode==DFS_COMPARE_FILES_PHYSICAL_CRCS) {
  10317. {
  10318. CriticalUnblock unblock(crit);
  10319. crc1 = part1->getPhysicalCrc();
  10320. crc2 = part2->getPhysicalCrc();
  10321. }
  10322. }
  10323. else {
  10324. if (!part1->getCrc(crc1))
  10325. return;
  10326. if (!part2->getCrc(crc2))
  10327. return;
  10328. }
  10329. if (crc1!=crc2)
  10330. differs = true;
  10331. }
  10332. }
  10333. } afor(lfn1,lfn2,file1,file2,mode,ret,errstr,newestdt1,newestdt2,differs);
  10334. afor.For(np,20,false,false);
  10335. encodeCompareResult(ret,differs,newestdt1,newestdt2);
  10336. }
  10337. }
  10338. }
  10339. catch (IException *e) {
  10340. if (errstr.length()==0)
  10341. e->errorMessage(errstr);
  10342. else
  10343. EXCLOG(e,"CDistributedFileDirectory::fileCompare");
  10344. e->Release();
  10345. ret = DFS_COMPARE_RESULT_FAILURE;
  10346. }
  10347. return ret;
  10348. }
  10349. bool CDistributedFileDirectory::filePhysicalVerify(const char *lfn, IUserDescriptor *user, bool includecrc, StringBuffer &errstr)
  10350. {
  10351. bool differs = false;
  10352. Owned<IDistributedFile> file = lookup(lfn, user, false, false, false, NULL, defaultTimeout);
  10353. if (!file)
  10354. {
  10355. errstr.appendf("Could not find file: %s",lfn);
  10356. return false;
  10357. }
  10358. try
  10359. {
  10360. unsigned np = file->numParts();
  10361. class casyncfor: public CAsyncFor
  10362. {
  10363. CriticalSection crit;
  10364. IDistributedFile *file;
  10365. const char *lfn;
  10366. StringBuffer &errstr;
  10367. bool includecrc;
  10368. bool &differs;
  10369. unsigned defaultTimeout;
  10370. public:
  10371. casyncfor(const char *_lfn,IDistributedFile *_file,StringBuffer &_errstr, bool _includecrc,
  10372. bool &_differs, unsigned _defaultTimeout)
  10373. : errstr(_errstr), differs(_differs)
  10374. {
  10375. lfn = _lfn;
  10376. file = _file;
  10377. includecrc = _includecrc;
  10378. defaultTimeout = _defaultTimeout;
  10379. }
  10380. void Do(unsigned p)
  10381. {
  10382. CriticalBlock block (crit);
  10383. StringBuffer msg;
  10384. Owned<IDistributedFilePart> part = file->getPart(p);
  10385. CDateTime dt1; // logical
  10386. CDateTime dt2; // physical
  10387. RemoteFilename rfn;
  10388. bool ok;
  10389. bool nological = !part->getModifiedTime(false,false,dt1);
  10390. {
  10391. CriticalUnblock unblock(crit);
  10392. ok = part->getModifiedTime(true,true,dt2);
  10393. }
  10394. if (!ok) {
  10395. if (errstr.length()==0) {
  10396. errstr.append("Could not find part file: ");
  10397. part->getFilename(rfn);
  10398. rfn.getPath(errstr);
  10399. }
  10400. differs = true;
  10401. }
  10402. if (!differs&&!includecrc) {
  10403. if (nological) {
  10404. StringBuffer str;
  10405. // TODO: Create DistributedFilePropertyLock for parts
  10406. part->lockProperties(defaultTimeout);
  10407. part->queryAttributes().setProp("@modified",dt2.getString(str).str());
  10408. part->unlockProperties();
  10409. }
  10410. else {
  10411. if (dt1.compare(dt2,false)!=0) {
  10412. if (errstr.length()==0) {
  10413. errstr.append("Modified time differs for: ");
  10414. part->getFilename(rfn);
  10415. rfn.getPath(errstr);
  10416. }
  10417. differs = true;
  10418. }
  10419. }
  10420. }
  10421. if (!differs) {
  10422. offset_t sz1;
  10423. offset_t sz2;
  10424. {
  10425. CriticalUnblock unblock(crit);
  10426. sz1 = part->getFileSize(false,false);
  10427. sz2 = part->getFileSize(true,true);
  10428. }
  10429. if (sz1!=sz2) {
  10430. if (sz1==(offset_t)-1) {
  10431. // TODO: Create DistributedFilePropertyLock for parts
  10432. part->lockProperties(defaultTimeout);
  10433. part->queryAttributes().setPropInt64("@size",sz2);
  10434. part->unlockProperties();
  10435. }
  10436. else if (sz2!=(offset_t)-1) {
  10437. if (errstr.length()==0) {
  10438. errstr.append("File size differs for: ");
  10439. part->getFilename(rfn);
  10440. rfn.getPath(errstr);
  10441. }
  10442. differs = true;
  10443. }
  10444. }
  10445. }
  10446. if (!differs&&includecrc) {
  10447. unsigned crc1;
  10448. unsigned crc2;
  10449. {
  10450. CriticalUnblock unblock(crit);
  10451. crc2 = part->getPhysicalCrc();
  10452. }
  10453. if (!part->getCrc(crc1)) {
  10454. // TODO: Create DistributedFilePropertyLock for parts
  10455. part->lockProperties(defaultTimeout);
  10456. part->queryAttributes().setPropInt64("@fileCrc",(unsigned)crc2);
  10457. part->unlockProperties();
  10458. }
  10459. else if (crc1!=crc2) {
  10460. if (errstr.length()==0) {
  10461. errstr.append("File CRC differs for: ");
  10462. part->getFilename(rfn);
  10463. rfn.getPath(errstr);
  10464. }
  10465. differs = true;
  10466. }
  10467. }
  10468. }
  10469. } afor(lfn,file,errstr,includecrc,differs,defaultTimeout);
  10470. afor.For(np,10,false,false);
  10471. }
  10472. catch (IException *e) {
  10473. if (errstr.length()==0)
  10474. e->errorMessage(errstr);
  10475. else
  10476. EXCLOG(e,"CDistributedFileDirectory::fileCompare");
  10477. e->Release();
  10478. differs = true;
  10479. }
  10480. return !differs;
  10481. }
  10482. typedef MapStringTo<bool> SubfileSet;
  10483. class CFilterAttrIterator: implements IDFAttributesIterator, public CInterface
  10484. {
  10485. Owned<IDFAttributesIterator> iter;
  10486. Linked<IUserDescriptor> user;
  10487. SubfileSet sfset;
  10488. bool includesub;
  10489. public:
  10490. IMPLEMENT_IINTERFACE;
  10491. CFilterAttrIterator(IDFAttributesIterator *_iter,IUserDescriptor* _user,bool _includesub,unsigned timeoutms)
  10492. : iter(_iter), user(_user)
  10493. {
  10494. includesub = _includesub;
  10495. CDfsLogicalFileName lfn;
  10496. StringBuffer query;
  10497. Owned<IDFScopeIterator> siter = queryDistributedFileDirectory().getScopeIterator(user,NULL,true,false);
  10498. ForEach(*siter) {
  10499. lfn.set(siter->query(),"X");
  10500. lfn.makeScopeQuery(query.clear());
  10501. Owned<IRemoteConnection> conn = querySDS().connect(query.str(),myProcessSession(),0, timeoutms);
  10502. if (conn) {
  10503. IPropertyTree *t = conn->queryRoot();
  10504. Owned<IPropertyTreeIterator> iter = t->getElements("SuperFile/SubFile");
  10505. ForEach(*iter) {
  10506. const char *name = iter->query().queryProp("@name");
  10507. if (!sfset.getValue(name))
  10508. sfset.setValue(name, true);
  10509. }
  10510. }
  10511. }
  10512. }
  10513. inline bool match()
  10514. {
  10515. const char *name = iter->query().queryProp("@name");
  10516. return ((sfset.getValue(name)!=NULL)==includesub);
  10517. }
  10518. bool first()
  10519. {
  10520. if (!iter->first())
  10521. return false;
  10522. while (!match())
  10523. if (!iter->next())
  10524. return false;
  10525. return true;
  10526. }
  10527. bool next()
  10528. {
  10529. do {
  10530. if (!iter->next())
  10531. return false;
  10532. } while (!match());
  10533. return true;
  10534. }
  10535. bool isValid() { return iter->isValid(); }
  10536. IPropertyTree & query() { return iter->query(); }
  10537. };
  10538. IDFAttributesIterator *createSubFileFilter(IDFAttributesIterator *_iter,IUserDescriptor* _user, bool includesub, unsigned timeoutms)
  10539. {
  10540. return new CFilterAttrIterator(_iter,_user,includesub,timeoutms);
  10541. }
  10542. bool decodeChildGroupName(const char *gname,StringBuffer &parentname, StringBuffer &range)
  10543. {
  10544. if (!gname||!*gname)
  10545. return false;
  10546. size32_t l = strlen(gname);
  10547. if (gname[l-1]!=']')
  10548. return false;
  10549. const char *ss = strchr(gname,'[');
  10550. if (!ss||(ss==gname))
  10551. return false;
  10552. range.append(l-(ss-gname)-2,ss+1);
  10553. range.trim();
  10554. if (!range.length())
  10555. return false;
  10556. parentname.append(ss-gname,gname);
  10557. return true;
  10558. }
  10559. /* given a list of group offsets (positions), create a compact representation of the range
  10560. * compatible with the group range syntax, e.g. mygroup[1-5,8-10] or mygroup[1,5,10]
  10561. */
  10562. StringBuffer &encodeChildGroupRange(UnsignedArray &positions, StringBuffer &rangeText)
  10563. {
  10564. unsigned items = positions.ordinality();
  10565. if (0 == items)
  10566. return rangeText;
  10567. unsigned start = positions.item(0);
  10568. unsigned last = start;
  10569. rangeText.append('[');
  10570. unsigned p=1;
  10571. while (true)
  10572. {
  10573. unsigned pos = p==items ? NotFound : positions.item(p++);
  10574. if ((pos != last+1))
  10575. {
  10576. if (last-start>0)
  10577. rangeText.append(start).append('-').append(last);
  10578. else
  10579. rangeText.append(last);
  10580. if (NotFound == pos)
  10581. break;
  10582. rangeText.append(',');
  10583. start = pos;
  10584. }
  10585. last = pos;
  10586. }
  10587. return rangeText.append(']');
  10588. }
  10589. class CLightWeightSuperFileConn: implements ISimpleSuperFileEnquiry, public CInterface
  10590. {
  10591. CFileLock lock;
  10592. bool readonly;
  10593. IArrayOf<IRemoteConnection> children;
  10594. unsigned defaultTimeout;
  10595. Owned<IUserDescriptor> udesc;
  10596. static StringBuffer &getSubPath(StringBuffer &path,unsigned idx)
  10597. {
  10598. return path.append("SubFile[@num=\"").append(idx+1).append("\"]");
  10599. }
  10600. void migrateProp(const char *name, unsigned num,IPropertyTree *from,IPropertyTree *to,IPropertyTree *newt, bool allowunchanged)
  10601. {
  10602. StringBuffer aname("Attr/");
  10603. aname.append(name);
  10604. StringBuffer s;
  10605. StringBuffer o;
  10606. if (from->getProp(aname.str(),s))
  10607. if ((num==1)||(allowunchanged&&to->getProp(aname.str(),o)&&(strcmp(s.str(),o.str())==0)))
  10608. newt->setProp(name,s.str());
  10609. }
  10610. void migrateAttr(IPropertyTree *from,IPropertyTree *to)
  10611. {
  10612. // this tries hard to set what it knows but avoids sibling traversal
  10613. if (!to)
  10614. return;
  10615. const char *desc = to->queryProp("Attr/@description");
  10616. IPropertyTree* newt = getEmptyAttr();
  10617. if (desc)
  10618. newt->setProp("@description",desc);
  10619. if (from) {
  10620. unsigned num=to->getPropInt("@numsubfiles");
  10621. migrateProp("@size",num,from,to,newt,false);
  10622. migrateProp("@checkSum",num,from,to,newt,true);
  10623. migrateProp("@formatCrc",num,from,to,newt,true);
  10624. migrateProp("@recordSize",num,from,to,newt,true);
  10625. MemoryBuffer mb;
  10626. MemoryBuffer mbo;
  10627. const char *aname = "Attr/_record_layout";
  10628. if (from->getPropBin(aname,mb))
  10629. if ((num==1)||(to->getPropBin(aname,mbo)&&
  10630. (mb.length()==mbo.length())&&
  10631. (memcmp(mb.bufferBase(),mbo.bufferBase(),mb.length())==0)))
  10632. newt->setPropBin("_record_layout", mb.length(), mb.bufferBase());
  10633. }
  10634. to->setPropTree("Attr",newt);
  10635. }
  10636. void migrateSuperOwnersAttr(IPropertyTree *from)
  10637. {
  10638. if (!from)
  10639. return;
  10640. Owned<IPropertyTreeIterator> iter = from->getElements("SuperOwner");
  10641. StringBuffer pname;
  10642. StringBuffer query;
  10643. ForEach(*iter) {
  10644. if (iter->query().getProp("@name",pname.clear())) {
  10645. CDfsLogicalFileName lfn;
  10646. lfn.set(pname.str());
  10647. lfn.makeFullnameQuery(query.clear(),DXB_SuperFile,true);
  10648. Owned<IRemoteConnection> conn;
  10649. try {
  10650. conn.setown(querySDS().connect(query.str(),myProcessSession(),RTM_LOCK_WRITE,1000*60*5));
  10651. }
  10652. catch (ISDSException *e) {
  10653. if (SDSExcpt_LockTimeout != e->errorCode())
  10654. throw;
  10655. e->Release();
  10656. IWARNLOG("migrateSuperOwnersAttr: Could not lock parent %s",query.str());
  10657. conn.setown(querySDS().connect(query.str(),myProcessSession(),0,defaultTimeout));
  10658. }
  10659. if (conn) {
  10660. migrateAttr(from,conn->queryRoot());
  10661. migrateSuperOwnersAttr(conn->queryRoot());
  10662. }
  10663. else
  10664. IWARNLOG("migrateSuperOwnersAttr could not connect to parent superfile %s",lfn.get());
  10665. }
  10666. }
  10667. }
  10668. public:
  10669. IMPLEMENT_IINTERFACE;
  10670. CLightWeightSuperFileConn(unsigned _defaultTimeout, IUserDescriptor *_udesc)
  10671. {
  10672. defaultTimeout = _defaultTimeout;
  10673. readonly = false;
  10674. udesc.set(_udesc);
  10675. }
  10676. bool connect(CDistributedFileDirectory *parent,const char *title, const char *name, bool _readonly, bool *autocreate, unsigned timeout)
  10677. {
  10678. if (autocreate)
  10679. *autocreate = false;
  10680. readonly = _readonly;
  10681. disconnect(false);
  10682. CDfsLogicalFileName lfn;
  10683. if (!lfn.setValidate(name))
  10684. throw MakeStringException(-1,"%s: Invalid superfile name '%s'",title,name);
  10685. if (lfn.isMulti()||lfn.isExternal()||lfn.isForeign())
  10686. return false;
  10687. unsigned mode = RTM_SUB | (readonly ? RTM_LOCK_READ : RTM_LOCK_WRITE);
  10688. if (!lock.init(lfn, DXB_SuperFile, mode, timeout, title))
  10689. {
  10690. if (!autocreate) // NB not !*autocreate here !
  10691. return false;
  10692. IPropertyTree *root = createPTree();
  10693. root->setPropInt("@interleaved",2);
  10694. root->setPropInt("@numsubfiles",0);
  10695. root->setPropTree("Attr",getEmptyAttr());
  10696. parent->addEntry(lfn,root,true,false);
  10697. mode = RTM_SUB | RTM_LOCK_WRITE;
  10698. if (!lock.init(lfn, DXB_SuperFile, mode, timeout, title))
  10699. throw MakeStringException(-1,"%s: Cannot create superfile '%s'",title,name);
  10700. if (autocreate)
  10701. *autocreate = true;
  10702. }
  10703. StringBuffer reason;
  10704. if (!readonly&&checkProtectAttr(name,lock.queryRoot(),reason))
  10705. throw MakeStringException(-1,"CDistributedSuperFile::%s %s",title,reason.str());
  10706. return true;
  10707. }
  10708. void disconnect(bool commit)
  10709. {
  10710. if (lock.queryConnection()&&!readonly) {
  10711. if (commit) {
  10712. migrateSuperOwnersAttr(lock.queryRoot());
  10713. CDateTime dt;
  10714. dt.setNow();
  10715. StringBuffer s;
  10716. lock.queryRoot()->setProp("@modified",dt.getString(s).str());
  10717. }
  10718. else {
  10719. ForEachItemIn(i,children)
  10720. children.item(i).rollback();
  10721. lock.queryConnection()->rollback();
  10722. }
  10723. }
  10724. lock.clear();
  10725. children.kill();
  10726. }
  10727. unsigned numSubFiles() const
  10728. {
  10729. return (unsigned)lock.queryRoot()->getPropInt("@numsubfiles");
  10730. }
  10731. bool getSubFileName(unsigned num,StringBuffer &name) const
  10732. {
  10733. if ((unsigned)lock.queryRoot()->getPropInt("@numsubfiles")<=num)
  10734. return false;
  10735. StringBuffer xpath;
  10736. getSubPath(xpath,num);
  10737. IPropertyTree *sub = lock.queryRoot()->queryPropTree(xpath.str());
  10738. if (!sub)
  10739. return false;
  10740. name.append(sub->queryProp("@name"));
  10741. return true;
  10742. }
  10743. unsigned findSubName(const char *subname) const
  10744. {
  10745. unsigned n = findSubFileOrd(subname);
  10746. if (n!=NotFound)
  10747. return n;
  10748. StringBuffer lfn;
  10749. normalizeLFN(subname,lfn);
  10750. Owned<IPropertyTreeIterator> iter = lock.queryRoot()->getElements("SubFile");
  10751. ForEach(*iter) {
  10752. if (stricmp(iter->query().queryProp("@name"),lfn.str())==0) {
  10753. unsigned ret=iter->query().getPropInt("@num");
  10754. if (ret&&((unsigned)lock.queryRoot()->getPropInt("@numsubfiles")>=ret))
  10755. return ret-1;
  10756. }
  10757. }
  10758. return NotFound;
  10759. }
  10760. unsigned getContents(StringArray &contents) const
  10761. {
  10762. // slightly inefficient
  10763. unsigned n = lock.queryRoot()->getPropInt("@numsubfiles");
  10764. StringBuffer xpath;
  10765. for (unsigned sni=0;sni<n;sni++) {
  10766. getSubPath(xpath.clear(),sni);
  10767. IPropertyTree *sub = lock.queryRoot()->queryPropTree(xpath.str());
  10768. if (!sub)
  10769. break;
  10770. contents.append(sub->queryProp("@name"));
  10771. }
  10772. return contents.ordinality();
  10773. }
  10774. };
  10775. // Contention never expected for this function!
  10776. #define PROMOTE_CONN_TIMEOUT (60*1000) // how long to wait for a single superfile
  10777. #define PROMOTE_DELAY (30*1000)
  10778. // Check files don't share subfiles (MORE - make this part of swap files action?)
  10779. static int hasCommonSubChildren(IDistributedSuperFile *orig, IDistributedSuperFile *dest)
  10780. {
  10781. unsigned origSubs = orig->numSubFiles();
  10782. unsigned destSubs = dest->numSubFiles();
  10783. if (origSubs == 0)
  10784. return NotFound;
  10785. for (unsigned j=0; j<origSubs; j++) {
  10786. for (unsigned k=0; k<destSubs; k++) {
  10787. if (strcmp(orig->querySubFile(j).queryLogicalName(), dest->querySubFile(k).queryLogicalName())==0)
  10788. return j;
  10789. }
  10790. }
  10791. return NotFound;
  10792. }
  10793. // MORE - use string arrays, rather than char* arrays or comma-separated strings
  10794. void CDistributedFileDirectory::promoteSuperFiles(unsigned numsf,const char **sfnames,const char *addsubnames,bool delsub,bool createonlyonesuperfile,IUserDescriptor *user,unsigned timeout,StringArray &outunlinked)
  10795. {
  10796. if (!numsf)
  10797. return;
  10798. // Create a local transaction that will be destroyed
  10799. Owned<IDistributedFileTransactionExt> transaction = new CDistributedFileTransaction(user);
  10800. transaction->start();
  10801. // Lookup all files (keep them in transaction's cache)
  10802. bool created = false;
  10803. unsigned files = numsf;
  10804. for (unsigned i=0; i<numsf; i++) {
  10805. Owned<IDistributedSuperFile> super = transaction->lookupSuperFile(sfnames[i]);
  10806. if (!super.get()) {
  10807. if (created && createonlyonesuperfile) {
  10808. files = i;
  10809. break;
  10810. }
  10811. Owned<IDistributedSuperFile> sfile = createSuperFile(sfnames[i],user,true,false,transaction);
  10812. created = true;
  10813. }
  10814. }
  10815. // If last file had sub-files, clean and fill outlinked
  10816. Owned<IDistributedSuperFile> last = transaction->lookupSuperFile(sfnames[files-1]);
  10817. assertex(last.get());
  10818. unsigned lastSubs = last->numSubFiles();
  10819. if (files == numsf && lastSubs > 0) {
  10820. for (unsigned i=0; i<lastSubs; i++) {
  10821. outunlinked.append(last->querySubFile(i).queryLogicalName());
  10822. }
  10823. last->removeSubFile(NULL,false,false,transaction);
  10824. }
  10825. last.clear();
  10826. // Move up, starting from last
  10827. for (unsigned i=files-1; i; i--) {
  10828. Owned<IDistributedSuperFile> orig = transaction->lookupSuperFile(sfnames[i-1]);
  10829. Owned<IDistributedSuperFile> dest = transaction->lookupSuperFile(sfnames[i]);
  10830. assertex(orig.get());
  10831. assertex(dest.get());
  10832. int common = hasCommonSubChildren(orig, dest);
  10833. if (common != NotFound) {
  10834. throw MakeStringException(-1,"promoteSuperFiles: superfiles %s and %s share same subfile %s",
  10835. orig->queryLogicalName(), dest->queryLogicalName(), orig->querySubFile(common).queryLogicalName());
  10836. }
  10837. orig->swapSuperFile(dest, transaction);
  10838. }
  10839. // Move new subs to first super, if any
  10840. Owned<IDistributedSuperFile> first = transaction->lookupSuperFile(sfnames[0]);
  10841. assertex(first.get());
  10842. StringArray toadd;
  10843. toadd.appendListUniq(addsubnames, ",");
  10844. ForEachItemIn(i,toadd) {
  10845. CDfsLogicalFileName lfn;
  10846. if (!lfn.setValidate(toadd.item(i)))
  10847. throw MakeStringException(-1,"promoteSuperFiles: invalid logical name to add: %s",toadd.item(i));
  10848. first->addSubFile(toadd.item(i),false,NULL,false,transaction);
  10849. }
  10850. first.clear();
  10851. transaction->commit();
  10852. // MORE - once deletion of logic files are also in transaction we can move this up (and allow promote within transactions)
  10853. if (delsub) {
  10854. ForEachItemIn(j,outunlinked)
  10855. removeEntry(outunlinked.item(j),user,transaction,timeout);
  10856. }
  10857. }
  10858. ISimpleSuperFileEnquiry * CDistributedFileDirectory::getSimpleSuperFileEnquiry(const char *logicalname,const char *title,IUserDescriptor *udesc,unsigned timeout)
  10859. {
  10860. Owned<CLightWeightSuperFileConn> ret = new CLightWeightSuperFileConn(defaultTimeout,udesc);
  10861. if (ret->connect(this,title,logicalname,true,NULL,timeout))
  10862. return ret.getClear();
  10863. return NULL;
  10864. }
  10865. bool CDistributedFileDirectory::getFileSuperOwners(const char *logicalname, StringArray &owners)
  10866. {
  10867. CFileLock lock;
  10868. CDfsLogicalFileName lfn;
  10869. if (!lfn.setValidate(logicalname))
  10870. throw MakeStringException(-1,"CDistributedFileDirectory::getFileSuperOwners: Invalid file name '%s'",logicalname);
  10871. if (lfn.isMulti()||lfn.isExternal()||lfn.isForeign())
  10872. return false;
  10873. CTimeMon tm(defaultTimeout);
  10874. if (!lock.init(lfn, RTM_LOCK_READ, defaultTimeout, "CDistributedFileDirectory::getFileSuperOwners"))
  10875. return false;
  10876. CFileSuperOwnerLock superOwnerLock;
  10877. unsigned remaining;
  10878. tm.timedout(&remaining);
  10879. verifyex(superOwnerLock.initWithFileLock(lfn, remaining, "CDistributedFileDirectory::getFileSuperOwners(SuperOwnerLock)", lock, RTM_LOCK_READ));
  10880. Owned<IPropertyTreeIterator> iter = lock.queryRoot()->getElements("SuperOwner");
  10881. StringBuffer pname;
  10882. ForEach(*iter) {
  10883. iter->query().getProp("@name",pname.clear());
  10884. if (pname.length())
  10885. owners.append(pname.str());
  10886. }
  10887. return true;
  10888. }
  10889. class CFileRelationship: implements IFileRelationship, public CInterface
  10890. {
  10891. Linked<IPropertyTree> pt;
  10892. const char *queryProp(const char *name)
  10893. {
  10894. if (pt.get()) {
  10895. const char *ret = pt->queryProp(name);
  10896. if (ret)
  10897. return ret;
  10898. }
  10899. return "";
  10900. }
  10901. public:
  10902. IMPLEMENT_IINTERFACE;
  10903. CFileRelationship(IPropertyTree *_pt)
  10904. : pt(_pt)
  10905. {
  10906. }
  10907. virtual const char *queryKind() { return queryProp("@kind"); }
  10908. virtual const char *queryPrimaryFilename() { return queryProp("@primary"); }
  10909. virtual const char *querySecondaryFilename() { return queryProp("@secondary"); }
  10910. virtual const char *queryPrimaryFields() { return queryProp("@primflds"); }
  10911. virtual const char *querySecondaryFields() { return queryProp("@secflds"); }
  10912. virtual const char *queryCardinality() { return queryProp("@cardinality"); }
  10913. virtual bool isPayload() { return pt->getPropBool("@payload"); }
  10914. virtual const char *queryDescription() { return queryProp("Description"); }
  10915. virtual IPropertyTree *queryTree() { return pt.get(); }
  10916. };
  10917. class CFileRelationshipIterator: implements IFileRelationshipIterator, public CInterface
  10918. {
  10919. unsigned num;
  10920. unsigned idx;
  10921. CMessageBuffer mb;
  10922. Owned<CFileRelationship> r;
  10923. Owned<IPropertyTree> pt;
  10924. Linked<INode> foreigndali;
  10925. unsigned defaultTimeout;
  10926. bool setPT()
  10927. {
  10928. if (idx<num) {
  10929. pt.setown(createPTree(mb));
  10930. addForeignName(*pt,foreigndali,"@primary");
  10931. addForeignName(*pt,foreigndali,"@secondary");
  10932. }
  10933. return pt.get()!=NULL;
  10934. }
  10935. public:
  10936. IMPLEMENT_IINTERFACE;
  10937. CFileRelationshipIterator(unsigned timems)
  10938. {
  10939. num = 0;
  10940. idx = 0;
  10941. mb.append(num);
  10942. defaultTimeout = timems;
  10943. }
  10944. void init(
  10945. INode *_foreigndali,
  10946. unsigned foreigndalitimeout,
  10947. const char *primary,
  10948. const char *secondary,
  10949. const char *primflds,
  10950. const char *secflds,
  10951. const char *kind,
  10952. const char *cardinality,
  10953. const bool *payload )
  10954. {
  10955. foreigndali.set(_foreigndali);
  10956. if (isLocalDali(foreigndali)) {
  10957. CConnectLock connlock("lookupFileRelationships",querySdsRelationshipsRoot(),false,false,false,defaultTimeout);
  10958. StringBuffer xpath;
  10959. CDistributedFileDirectory::getFileRelationshipXPath(xpath,primary,secondary,primflds,secflds,kind,cardinality,payload);
  10960. Owned<IPropertyTreeIterator> iter = connlock.conn?connlock.conn->getElements(xpath.str()):NULL;
  10961. mb.clear();
  10962. unsigned count = 0;
  10963. mb.append(count);
  10964. // save as sequence of branches
  10965. if (iter) {
  10966. ForEach(*iter.get()) {
  10967. iter->query().serialize(mb);
  10968. count++;
  10969. }
  10970. mb.writeDirect(0,sizeof(count),&count);
  10971. }
  10972. }
  10973. else {
  10974. byte payloadb = 255;
  10975. if (payload)
  10976. payloadb = *payload?1:0;
  10977. mb.clear().append((int)MDFS_ITERATE_RELATIONSHIPS).append(primary).append(secondary).append(primflds).append(secflds).append(kind).append(cardinality).append(payloadb);
  10978. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  10979. checkDfsReplyException(mb);
  10980. if (mb.length()<sizeof(unsigned))
  10981. mb.clear().append((unsigned)0);
  10982. }
  10983. }
  10984. void initall(const char *filename)
  10985. {
  10986. StringBuffer xpath;
  10987. Owned<IPropertyTreeIterator> iter;
  10988. mb.clear();
  10989. unsigned count = 0;
  10990. mb.append(count);
  10991. {
  10992. CConnectLock connlock("lookupFileRelationships",querySdsRelationshipsRoot(),false,false,false,defaultTimeout);
  10993. CDistributedFileDirectory::getFileRelationshipXPath(xpath,filename,NULL,NULL,NULL,NULL,NULL,NULL);
  10994. // save as sequence of branches
  10995. iter.setown(connlock.conn?connlock.conn->getElements(xpath.str()):NULL);
  10996. if (iter) {
  10997. ForEach(*iter.get()) {
  10998. iter->query().serialize(mb);
  10999. count++;
  11000. }
  11001. }
  11002. }
  11003. { // Kludge - seems to be a bug in getElements without second conn lock
  11004. CConnectLock connlock("lookupFileRelationships",querySdsRelationshipsRoot(),false,false,false,defaultTimeout);
  11005. xpath.clear();
  11006. CDistributedFileDirectory::getFileRelationshipXPath(xpath,NULL,filename,NULL,NULL,NULL,NULL,NULL);
  11007. iter.clear();
  11008. iter.setown(connlock.conn?connlock.conn->getElements(xpath.str()):NULL);
  11009. if (iter) {
  11010. ForEach(*iter.get()) {
  11011. IPropertyTree &it = iter->query();
  11012. const char *fn1 = it.queryProp("@primary");
  11013. if (!fn1||(strcmp(fn1,filename)!=0)) { // see if already done
  11014. it.serialize(mb);
  11015. count++;
  11016. }
  11017. }
  11018. }
  11019. }
  11020. mb.writeDirect(0,sizeof(count),&count);
  11021. }
  11022. bool first()
  11023. {
  11024. r.clear();
  11025. pt.clear();
  11026. idx = 0;
  11027. mb.reset().read(num);
  11028. return setPT();
  11029. }
  11030. bool next()
  11031. {
  11032. r.clear();
  11033. pt.clear();
  11034. idx++;
  11035. return setPT();
  11036. }
  11037. bool isValid()
  11038. {
  11039. return pt.get()!=NULL;
  11040. }
  11041. IFileRelationship & query()
  11042. {
  11043. if (!r)
  11044. r.setown(new CFileRelationship(pt));
  11045. return *r;
  11046. }
  11047. };
  11048. static bool isWild(const char *path,bool emptydefault=false)
  11049. {
  11050. if (!path||!*path)
  11051. return emptydefault;
  11052. return ((strchr(path,'?')||strchr(path,'*')));
  11053. }
  11054. static void addRelationCondition(StringBuffer &xpath,const char *fld,const char *mask)
  11055. {
  11056. if (!mask||!*mask||((*mask=='*')&&(!mask[1])))
  11057. return;
  11058. xpath.append('[').append(fld).append('=');
  11059. if (isWild(mask))
  11060. xpath.append('~');
  11061. xpath.append('"').append(mask).append("\"]");
  11062. }
  11063. static void addRelationBoolCondition(StringBuffer &xpath,const char *fld,const bool *mask)
  11064. {
  11065. if (!mask)
  11066. return;
  11067. xpath.append('[').append(fld).append("=\"");
  11068. if (*mask)
  11069. xpath.append("1\"]");
  11070. else
  11071. xpath.append("0\"]");
  11072. }
  11073. static const char *normLFN(const char *name,CDfsLogicalFileName &logicalname,const char *title)
  11074. {
  11075. if (isWild(name,true))
  11076. return name;
  11077. if (!logicalname.setValidate(name))
  11078. throw MakeStringException(-1,"%s: invalid logical file name '%s'",title,name);
  11079. if (logicalname.isForeign()) {
  11080. SocketEndpoint ep;
  11081. Owned<INode> fd = createINode(ep);
  11082. if (logicalname.getEp(ep)&&isLocalDali(fd)) // see if pointing back at self
  11083. logicalname.clearForeign();
  11084. }
  11085. return logicalname.get();
  11086. }
  11087. StringBuffer &CDistributedFileDirectory::getFileRelationshipXPath(
  11088. StringBuffer &xpath,
  11089. const char *primary,
  11090. const char *secondary,
  11091. const char *primflds,
  11092. const char *secflds,
  11093. const char *kind,
  11094. const char *cardinality,
  11095. const bool *payload
  11096. )
  11097. {
  11098. xpath.append("Relationship");
  11099. CDfsLogicalFileName lfn;
  11100. addRelationCondition(xpath,"@kind",kind);
  11101. addRelationCondition(xpath,"@primary",normLFN(primary,lfn,"findFileRelationship(primary)"));
  11102. addRelationCondition(xpath,"@secondary",normLFN(secondary,lfn,"findFileRelationship(secondary)"));
  11103. addRelationCondition(xpath,"@primflds",primflds);
  11104. addRelationCondition(xpath,"@secflds",secflds);
  11105. addRelationCondition(xpath,"@cardinality",cardinality);
  11106. addRelationBoolCondition(xpath,"@payload",payload);
  11107. return xpath;
  11108. }
  11109. void CDistributedFileDirectory::doRemoveFileRelationship(
  11110. IRemoteConnection *conn,
  11111. const char *primary,
  11112. const char *secondary,
  11113. const char *primflds,
  11114. const char *secflds,
  11115. const char *kind
  11116. )
  11117. {
  11118. if (!conn)
  11119. return;
  11120. StringBuffer xpath;
  11121. CDistributedFileDirectory::getFileRelationshipXPath(xpath,primary,secondary,primflds,secflds,kind,NULL,NULL);
  11122. Owned<IPropertyTreeIterator> iter = conn->getElements(xpath.str());
  11123. IArrayOf<IPropertyTree> toremove;
  11124. ForEach(*iter) {
  11125. IPropertyTree &t = iter->query();
  11126. toremove.append(*LINK(&t));
  11127. }
  11128. ForEachItemIn(i, toremove) {
  11129. conn->queryRoot()->removeTree(&toremove.item(i));
  11130. }
  11131. }
  11132. void CDistributedFileDirectory::addFileRelationship(
  11133. const char *primary,
  11134. const char *secondary,
  11135. const char *primflds,
  11136. const char *secflds,
  11137. const char *kind,
  11138. const char *cardinality,
  11139. bool payload,
  11140. IUserDescriptor *user,
  11141. const char *description=NULL
  11142. )
  11143. {
  11144. if (!kind||!*kind)
  11145. kind = S_LINK_RELATIONSHIP_KIND;
  11146. Owned<IPropertyTree> pt = createPTree("Relationship");
  11147. if (isWild(primary,true)||isWild(secondary,true)||isWild(primflds,false)||isWild(secflds,false)||isWild(cardinality,false))
  11148. throw MakeStringException(-1,"Wildcard not allowed in addFileRelation");
  11149. CDfsLogicalFileName pfn;
  11150. if (!pfn.setValidate(primary))
  11151. throw MakeStringException(-1,"addFileRelationship invalid primary name '%s'",primary);
  11152. if (pfn.isExternal()||pfn.isForeign()||pfn.isQuery())
  11153. throw MakeStringException(-1,"addFileRelationship primary %s not allowed",pfn.get());
  11154. primary = pfn.get();
  11155. if (!exists(primary,user))
  11156. throw MakeStringException(-1,"addFileRelationship primary %s does not exist",primary);
  11157. CDfsLogicalFileName sfn;
  11158. if (!sfn.setValidate(secondary))
  11159. throw MakeStringException(-1,"addFileRelationship invalid secondary name '%s'",secondary);
  11160. if (sfn.isExternal()||sfn.isForeign()||sfn.isQuery())
  11161. throw MakeStringException(-1,"addFileRelationship secondary %s not allowed",sfn.get());
  11162. secondary = sfn.get();
  11163. if (!exists(secondary,user))
  11164. throw MakeStringException(-1,"addFileRelationship secondary %s does not exist",secondary);
  11165. if (cardinality&&*cardinality&&!strchr(cardinality,':'))
  11166. throw MakeStringException(-1,"addFileRelationship cardinality %s invalid",cardinality);
  11167. pt->setProp("@kind",kind);
  11168. pt->setProp("@primary",primary);
  11169. pt->setProp("@secondary",secondary);
  11170. pt->setProp("@cardinality",cardinality);
  11171. pt->setProp("@primflds",primflds);
  11172. pt->setProp("@secflds",secflds);
  11173. pt->setPropBool("@payload",payload);
  11174. if (description&&*description)
  11175. pt->setProp("Description",description);
  11176. StringBuffer xpath(querySdsFilesRoot());
  11177. for (unsigned i=0;i<2;i++) {
  11178. CConnectLock connlock("addFileRelation",querySdsRelationshipsRoot(),true,false,false,defaultTimeout);
  11179. if (!connlock.conn) {
  11180. CConnectLock connlock2("addFileRelation.2",querySdsFilesRoot(),true,false,false,defaultTimeout);
  11181. if (!connlock2.conn)
  11182. return;
  11183. Owned<IPropertyTree> ptr = createPTree("Relationships");
  11184. connlock2.conn->queryRoot()->addPropTree("Relationships",ptr.getClear());
  11185. continue;
  11186. }
  11187. StringBuffer query;
  11188. doRemoveFileRelationship(connlock.conn,primary,secondary,primflds,secflds,kind);
  11189. connlock.conn->queryRoot()->addPropTree("Relationship",pt.getClear());
  11190. break;
  11191. }
  11192. }
  11193. void CDistributedFileDirectory::removeFileRelationships(
  11194. const char *primary,
  11195. const char *secondary,
  11196. const char *primflds,
  11197. const char *secflds,
  11198. const char *kind
  11199. )
  11200. {
  11201. if ((!primary||!*primary||(strcmp(primary,"*")==0))&&
  11202. (!secondary||!*secondary||(strcmp(secondary,"*")==0)))
  11203. throw MakeStringException(-1,"removeFileRelationships primary and secondary cannot both be wild");
  11204. CConnectLock connlock("removeFileRelation",querySdsRelationshipsRoot(),true,false,false,defaultTimeout);
  11205. doRemoveFileRelationship(connlock.conn,primary,secondary,primflds,secflds,kind);
  11206. }
  11207. IFileRelationshipIterator *CDistributedFileDirectory::lookupFileRelationships(
  11208. const char *primary,
  11209. const char *secondary,
  11210. const char *primflds,
  11211. const char *secflds,
  11212. const char *kind,
  11213. const char *cardinality,
  11214. const bool *payload,
  11215. const char *foreigndali,
  11216. unsigned foreigndalitimeout
  11217. )
  11218. {
  11219. Owned<INode> foreign;
  11220. if (foreigndali&&*foreigndali) {
  11221. SocketEndpoint ep(foreigndali);
  11222. if (ep.isNull())
  11223. throw MakeStringException(-1,"lookupFileRelationships::Cannot resolve foreign dali %s",foreigndali);
  11224. foreign.setown(createINode(ep));
  11225. }
  11226. Owned<CFileRelationshipIterator> ret = new CFileRelationshipIterator(defaultTimeout);
  11227. ret->init(foreign,foreigndalitimeout,primary,secondary,primflds,secflds,kind,cardinality,payload);
  11228. return ret.getClear();
  11229. }
  11230. void CDistributedFileDirectory::removeAllFileRelationships(const char *filename)
  11231. {
  11232. if (!filename||!*filename||(strcmp(filename,"*")==0))
  11233. throw MakeStringException(-1,"removeAllFileRelationships filename cannot be wild");
  11234. {
  11235. CConnectLock connlock("removeFileRelation",querySdsRelationshipsRoot(),true,false,false,defaultTimeout);
  11236. doRemoveFileRelationship(connlock.conn,filename,NULL,NULL,NULL,NULL);
  11237. }
  11238. { // kludge bug in getElements if connection used twice
  11239. CConnectLock connlock("removeFileRelation",querySdsRelationshipsRoot(),true,false,false,defaultTimeout);
  11240. doRemoveFileRelationship(connlock.conn,NULL,filename,NULL,NULL,NULL);
  11241. }
  11242. }
  11243. IFileRelationshipIterator *CDistributedFileDirectory::lookupAllFileRelationships(
  11244. const char *filename)
  11245. {
  11246. if (isWild(filename,true))
  11247. throw MakeStringException(-1,"Wildcard filename not allowed in lookupAllFileRelationships");
  11248. CDfsLogicalFileName lfn;
  11249. normLFN(filename,lfn,"lookupAllFileRelationships");
  11250. Owned<CFileRelationshipIterator> ret = new CFileRelationshipIterator(defaultTimeout);
  11251. ret->initall(lfn.get());
  11252. return ret.getClear();
  11253. }
  11254. void CDistributedFileDirectory::renameFileRelationships(const char *oldname,const char *newname,IFileRelationshipIterator *reliter,IUserDescriptor*user)
  11255. {
  11256. CDfsLogicalFileName oldlfn;
  11257. normLFN(oldname,oldlfn,"renameFileRelationships(old name)");
  11258. CDfsLogicalFileName newlfn;
  11259. normLFN(newname,newlfn,"renameFileRelationships(new name)");
  11260. ForEach(*reliter) {
  11261. try {
  11262. IFileRelationship &r = reliter->query();
  11263. bool adj = false;
  11264. const char *pf = r.queryPrimaryFilename();
  11265. if (!pf)
  11266. continue;
  11267. if (strcmp(pf,oldlfn.get())==0) {
  11268. adj = true;
  11269. pf = newlfn.get();
  11270. }
  11271. const char *sf = r.querySecondaryFilename();
  11272. if (!sf)
  11273. continue;
  11274. if (strcmp(sf,oldlfn.get())==0) {
  11275. adj = true;
  11276. sf = newlfn.get();
  11277. }
  11278. if (adj)
  11279. addFileRelationship(pf,sf,r.queryPrimaryFields(),r.querySecondaryFields(),r.queryKind(),r.queryCardinality(),r.isPayload(),user,r.queryDescription());
  11280. }
  11281. catch (IException *e)
  11282. {
  11283. EXCLOG(e,"renameFileRelationships");
  11284. e->Release();
  11285. }
  11286. }
  11287. }
  11288. // JCSMORE what was this for, not called by anything afaics
  11289. bool CDistributedFileDirectory::publishMetaFileXML(const CDfsLogicalFileName &logicalname,IUserDescriptor *user)
  11290. {
  11291. if (logicalname.isExternal()||logicalname.isForeign()||logicalname.isQuery())
  11292. return false;
  11293. Owned<IPropertyTree> file = getFileTree(logicalname.get(),user,NULL,FOREIGN_DALI_TIMEOUT,true);
  11294. if (!file.get())
  11295. return false;
  11296. if (strcmp(file->queryName(),queryDfsXmlBranchName(DXB_SuperFile))==0)
  11297. return false;
  11298. unsigned max = file->getPropInt("@numparts");
  11299. SocketEndpointArray ips;
  11300. StringBuffer xpath;
  11301. StringBuffer ipstr;
  11302. for (unsigned i=0;i<max;i++) { // probably could be done better
  11303. xpath.clear().append("Part[@num=\"").append(i+1).append("\"]");
  11304. Owned<IPropertyTree> child = file->getPropTree(xpath.str());
  11305. SocketEndpoint ep;
  11306. if (child.get()&&child->getProp("@node",ipstr.clear()))
  11307. ep.ipset(ipstr.str());
  11308. ips.append(ep);
  11309. }
  11310. Owned<IException> exc;
  11311. CriticalSection errcrit;
  11312. class casyncfor: public CAsyncFor
  11313. {
  11314. IPropertyTree* file;
  11315. CriticalSection &errcrit;
  11316. Owned<IException> &exc;
  11317. SocketEndpointArray &ips;
  11318. public:
  11319. casyncfor(IPropertyTree* _file,SocketEndpointArray &_ips,Owned<IException> &_exc,CriticalSection &_errcrit)
  11320. : ips(_ips), exc(_exc), errcrit(_errcrit)
  11321. {
  11322. file = _file;
  11323. }
  11324. void Do(unsigned i)
  11325. {
  11326. UnsignedArray parts;
  11327. const SocketEndpoint &ep = ips.item(i);
  11328. if (ep.isNull())
  11329. return;
  11330. ForEachItemIn(j,ips) {
  11331. if (j==i)
  11332. parts.append(i);
  11333. else if (ep.ipequals(ips.item(j))) {
  11334. if (j<i)
  11335. return; // already done
  11336. parts.append(j);
  11337. }
  11338. }
  11339. try {
  11340. StringBuffer path;
  11341. StringBuffer mask;
  11342. if (file->getProp("@directory",path)&&file->getProp("@partmask",mask)) {
  11343. addPathSepChar(path).append(mask);
  11344. StringBuffer outpath;
  11345. StringBuffer tail("META__");
  11346. splitFilename(path.str(), &outpath, &outpath, &tail, NULL);
  11347. outpath.append(tail).append(".xml");
  11348. Owned<IPropertyTree> pt = createPTreeFromIPT(file);
  11349. filterParts(pt,parts);
  11350. StringBuffer str;
  11351. toXML(pt, str);
  11352. RemoteFilename rfn;
  11353. rfn.setPath(ep,outpath.str());
  11354. Owned<IFile> out = createIFile(rfn);
  11355. Owned<IFileIO> outio = out->open(IFOcreate);
  11356. if (outio)
  11357. outio->write(0,str.length(),str.str());
  11358. }
  11359. }
  11360. catch(IException *e)
  11361. {
  11362. CriticalBlock block(errcrit);
  11363. EXCLOG(e,"publishMetaFileXML");
  11364. if (!exc.get())
  11365. exc.setown(e);
  11366. else
  11367. e->Release();
  11368. }
  11369. }
  11370. } afor(file,ips,exc,errcrit);
  11371. afor.For(max,20);
  11372. if (exc)
  11373. throw exc.getClear();
  11374. return true;
  11375. }
  11376. IFileDescriptor *CDistributedFileDirectory::createDescriptorFromMetaFile(const CDfsLogicalFileName &logicalname,IUserDescriptor *user)
  11377. {
  11378. return NULL; // TBD
  11379. }
  11380. // Overwrite protection
  11381. bool CDistributedFileDirectory::isProtectedFile(const CDfsLogicalFileName &logicalName, unsigned timeout)
  11382. {
  11383. CFileAttrLock attrLock;
  11384. if (!attrLock.init(logicalName, RTM_LOCK_READ, NULL, timeout?timeout:INFINITE, "CDistributedFileDirectory::isProtectedFile"))
  11385. return false; // timeout will raise exception
  11386. Owned<IPropertyTreeIterator> wpiter = attrLock.queryRoot()->getElements("Protect");
  11387. bool prot = false;
  11388. ForEach(*wpiter) {
  11389. IPropertyTree &t = wpiter->query();
  11390. if (t.getPropInt("@count")) {
  11391. prot = true;
  11392. break;
  11393. }
  11394. }
  11395. // timeout retry TBD
  11396. return prot;
  11397. }
  11398. unsigned CDistributedFileDirectory::queryProtectedCount(const CDfsLogicalFileName &logicalName, const char *owner)
  11399. {
  11400. CFileAttrLock attrLock;
  11401. if (!attrLock.init(logicalName, RTM_LOCK_READ, NULL, defaultTimeout, "CDistributedFileDirectory::queryProtectedCount"))
  11402. return 0; // timeout will raise exception
  11403. Owned<IPropertyTreeIterator> wpiter = attrLock.queryRoot()->getElements("Protect");
  11404. unsigned count = 0;
  11405. ForEach(*wpiter) {
  11406. IPropertyTree &t = wpiter->query();
  11407. const char *name = t.queryProp("@name");
  11408. if (!owner||!*owner||(name&&(strcmp(owner,name)==0)))
  11409. count += t.getPropInt("@count");
  11410. }
  11411. return count;
  11412. }
  11413. bool CDistributedFileDirectory::getProtectedInfo(const CDfsLogicalFileName &logicalName, StringArray &names, UnsignedArray &counts)
  11414. {
  11415. CFileAttrLock attrLock;
  11416. if (!attrLock.init(logicalName, RTM_LOCK_READ, NULL, defaultTimeout, "CDistributedFileDirectory::getProtectedInfo"))
  11417. return false; // timeout will raise exception
  11418. Owned<IPropertyTreeIterator> wpiter = attrLock.queryRoot()->getElements("Protect");
  11419. bool prot = false;
  11420. ForEach(*wpiter) {
  11421. IPropertyTree &t = wpiter->query();
  11422. const char *name = t.queryProp("@name");
  11423. names.append(name?name:"<Unknown>");
  11424. unsigned c = t.getPropInt("@count");
  11425. if (c)
  11426. prot = true;
  11427. counts.append(c);
  11428. }
  11429. return prot;
  11430. }
  11431. IDFProtectedIterator *CDistributedFileDirectory::lookupProtectedFiles(const char *owner,bool notsuper,bool superonly)
  11432. {
  11433. return new CDFProtectedIterator(owner,notsuper,superonly,defaultTimeout);
  11434. }
  11435. const char* DFUQResultFieldNames[] = { "@name", "@description", "@group", "@kind", "@modified", "@job", "@owner",
  11436. "@DFUSFrecordCount", "@recordCount", "@recordSize", "@DFUSFsize", "@size", "@workunit", "@DFUSFcluster", "@numsubfiles",
  11437. "@accessed", "@numparts", "@compressedSize", "@directory", "@partmask", "@superowners", "@persistent", "@protect", "@compressed" };
  11438. extern da_decl const char* getDFUQResultFieldName(DFUQResultField feild)
  11439. {
  11440. return DFUQResultFieldNames[feild];
  11441. }
  11442. IPropertyTreeIterator *deserializeFileAttrIterator(MemoryBuffer& mb, unsigned numFiles, DFUQResultField* localFilters, const char* localFilterBuf)
  11443. {
  11444. class CFileAttrIterator: implements IPropertyTreeIterator, public CInterface
  11445. {
  11446. size32_t fileDataStart;
  11447. Owned<IPropertyTree> cur;
  11448. StringArray fileNodeGroups;
  11449. void setFileNodeGroup(IPropertyTree *attr, const char* group, StringArray& nodeGroupFilter)
  11450. {
  11451. if (!group || !*group)
  11452. return;
  11453. //The group may contain multiple clusters and some of them may match with the clusterFilter.
  11454. if (nodeGroupFilter.length() == 1)
  11455. attr->setProp(getDFUQResultFieldName(DFUQRFnodegroup), nodeGroupFilter.item(0));//Filter has been handled on server side.
  11456. else
  11457. {
  11458. StringArray groups;
  11459. groups.appendListUniq(group, ",");
  11460. ForEachItemIn(i,groups)
  11461. {
  11462. //Add a group if no group filter or the group matches with group filter
  11463. const char* node = groups.item(i);
  11464. if (node && *node && ((!nodeGroupFilter.length()) || (nodeGroupFilter.find(node) != NotFound)))
  11465. fileNodeGroups.append(node);
  11466. }
  11467. if (fileNodeGroups.length())
  11468. {
  11469. //if this file exists on multiple groups, set one of the groups as the "@DFUSFnodegroup" prop for
  11470. //this attr, leaving the rest inside the fileNodeGroups array. Those groups will be used by the
  11471. //duplicateFileAttrOnOtherNodeGroup() to duplicate this file attr on other groups.
  11472. attr->setProp(getDFUQResultFieldName(DFUQRFnodegroup), fileNodeGroups.item(fileNodeGroups.length() -1));
  11473. fileNodeGroups.pop();
  11474. }
  11475. }
  11476. }
  11477. void setRecordCount(IPropertyTree* file)
  11478. {
  11479. __int64 recordCount = 0;
  11480. if (file->hasProp(getDFUQResultFieldName(DFUQRForigrecordcount)))
  11481. recordCount = file->getPropInt64(getDFUQResultFieldName(DFUQRForigrecordcount));
  11482. else
  11483. {
  11484. __int64 recordSize=file->getPropInt64(getDFUQResultFieldName(DFUQRFrecordsize),0);
  11485. if(recordSize)
  11486. {
  11487. __int64 size=file->getPropInt64(getDFUQResultFieldName(DFUQRForigsize),-1);
  11488. recordCount = size/recordSize;
  11489. }
  11490. }
  11491. file->setPropInt64(getDFUQResultFieldName(DFUQRFrecordcount),recordCount);
  11492. return;
  11493. }
  11494. void setIsCompressed(IPropertyTree* file)
  11495. {
  11496. if (isCompressed(*file) || isFileKey(*file))
  11497. file->setPropBool(getDFUQResultFieldName(DFUQRFiscompressed), true);
  11498. }
  11499. IPropertyTree *deserializeFileAttr(MemoryBuffer &mb, StringArray& nodeGroupFilter)
  11500. {
  11501. IPropertyTree *attr = getEmptyAttr();
  11502. StringAttr val;
  11503. unsigned n;
  11504. mb.read(val);
  11505. attr->setProp(getDFUQResultFieldName(DFUQRFname),val.get());
  11506. mb.read(val);
  11507. if (strieq(val,"!SF"))
  11508. {
  11509. mb.read(n);
  11510. attr->setPropInt(getDFUQResultFieldName(DFUQRFnumsubfiles),n);
  11511. mb.read(val); // not used currently
  11512. }
  11513. else
  11514. {
  11515. attr->setProp(getDFUQResultFieldName(DFUQRFdirectory),val.get());
  11516. mb.read(n);
  11517. attr->setPropInt(getDFUQResultFieldName(DFUQRFnumparts),n);
  11518. mb.read(val);
  11519. attr->setProp(getDFUQResultFieldName(DFUQRFpartmask),val.get());
  11520. }
  11521. mb.read(val);
  11522. attr->setProp(getDFUQResultFieldName(DFUQRFtimemodified),val.get());
  11523. unsigned count;
  11524. mb.read(count);
  11525. StringAttr at;
  11526. while (count--)
  11527. {
  11528. mb.read(at);
  11529. mb.read(val);
  11530. attr->setProp(at.get(),val.get());
  11531. if (strieq(at.get(), getDFUQResultFieldName(DFUQRFnodegroups)))
  11532. setFileNodeGroup(attr, val.get(), nodeGroupFilter);
  11533. }
  11534. attr->setPropInt64(getDFUQResultFieldName(DFUQRFsize), attr->getPropInt64(getDFUQResultFieldName(DFUQRForigsize), -1));//Sort the files with empty size to front
  11535. setRecordCount(attr);
  11536. setIsCompressed(attr);
  11537. return attr;
  11538. }
  11539. IPropertyTree *duplicateFileAttrOnOtherNodeGroup(IPropertyTree *previousAttr)
  11540. {
  11541. IPropertyTree *attr = getEmptyAttr();
  11542. Owned<IAttributeIterator> ai = previousAttr->getAttributes();
  11543. ForEach(*ai)
  11544. attr->setProp(ai->queryName(),ai->queryValue());
  11545. attr->setProp(getDFUQResultFieldName(DFUQRFnodegroup), fileNodeGroups.item(fileNodeGroups.length()-1));
  11546. fileNodeGroups.pop();
  11547. return attr;
  11548. }
  11549. public:
  11550. IMPLEMENT_IINTERFACE;
  11551. MemoryBuffer mb;
  11552. unsigned numfiles;
  11553. StringArray nodeGroupFilter;
  11554. CFileAttrIterator(MemoryBuffer &_mb, unsigned _numfiles) : numfiles(_numfiles)
  11555. {
  11556. /* not particuarly nice, but buffer contains extra meta info ahead of serialized file info
  11557. * record position to rewind to, if iterator reused.
  11558. */
  11559. fileDataStart = _mb.getPos();
  11560. mb.swapWith(_mb);
  11561. }
  11562. bool first()
  11563. {
  11564. mb.reset(fileDataStart);
  11565. return next();
  11566. }
  11567. bool next()
  11568. {
  11569. if (fileNodeGroups.length())
  11570. {
  11571. IPropertyTree *attr = duplicateFileAttrOnOtherNodeGroup(cur);
  11572. cur.clear();
  11573. cur.setown(attr);
  11574. return true;
  11575. }
  11576. cur.clear();
  11577. if (mb.getPos()>=mb.length())
  11578. return false;
  11579. cur.setown(deserializeFileAttr(mb, nodeGroupFilter));
  11580. return true;
  11581. }
  11582. bool isValid()
  11583. {
  11584. return cur.get()!=NULL;
  11585. }
  11586. IPropertyTree & query()
  11587. {
  11588. return *cur;
  11589. }
  11590. void setLocalFilters(DFUQResultField* localFilters, const char* localFilterBuf)
  11591. {
  11592. if (!localFilters || !localFilterBuf || !*localFilterBuf)
  11593. return;
  11594. const char *fv = localFilterBuf;
  11595. for (unsigned i=0;localFilters[i]!=DFUQRFterm;i++)
  11596. {
  11597. int fmt = localFilters[i];
  11598. int subfmt = (fmt&0xff);
  11599. if ((subfmt==DFUQRFnodegroup) && fv && *fv)
  11600. nodeGroupFilter.appendListUniq(fv, ",");
  11601. //Add more if needed
  11602. fv = fv + strlen(fv)+1;
  11603. }
  11604. }
  11605. } *fai = new CFileAttrIterator(mb, numFiles);
  11606. fai->setLocalFilters(localFilters, localFilterBuf);
  11607. return fai;
  11608. }
  11609. IPropertyTreeIterator *CDistributedFileDirectory::getDFAttributesTreeIterator(const char* filters, DFUQResultField* localFilters,
  11610. const char* localFilterBuf, IUserDescriptor* user, bool recursive, bool& allMatchingFilesReceived, INode* foreigndali, unsigned foreigndalitimeout)
  11611. {
  11612. CMessageBuffer mb;
  11613. CDaliVersion serverVersionNeeded("3.13");
  11614. bool legacy = (queryDaliServerVersion().compare(serverVersionNeeded) < 0);
  11615. if (legacy)
  11616. mb.append((int)MDFS_ITERATE_FILTEREDFILES);
  11617. else
  11618. mb.append((int)MDFS_ITERATE_FILTEREDFILES2);
  11619. mb.append(filters).append(recursive);
  11620. if (user)
  11621. {
  11622. user->serializeWithoutPassword(mb);
  11623. }
  11624. if (foreigndali)
  11625. foreignDaliSendRecv(foreigndali,mb,foreigndalitimeout);
  11626. else
  11627. queryCoven().sendRecv(mb,RANK_RANDOM,MPTAG_DFS_REQUEST);
  11628. checkDfsReplyException(mb);
  11629. unsigned numfiles;
  11630. mb.read(numfiles);
  11631. if (legacy)
  11632. allMatchingFilesReceived = true; // don't know any better
  11633. else
  11634. mb.read(allMatchingFilesReceived);
  11635. return deserializeFileAttrIterator(mb, numfiles, localFilters, localFilterBuf);
  11636. }
  11637. IDFAttributesIterator* CDistributedFileDirectory::getLogicalFiles(
  11638. IUserDescriptor* udesc,
  11639. DFUQResultField *sortOrder, // list of fields to sort by (terminated by DFUSFterm)
  11640. const void *filters, // (appended) string values for filters used by dali server
  11641. DFUQResultField *localFilters, //used for filtering query result received from dali server.
  11642. const void *localFilterBuf,
  11643. unsigned startOffset,
  11644. unsigned maxNum,
  11645. __int64 *cacheHint,
  11646. unsigned *total,
  11647. bool *allMatchingFiles,
  11648. bool recursive,
  11649. bool sorted)
  11650. {
  11651. class CDFUPager : implements IElementsPager, public CSimpleInterface
  11652. {
  11653. IUserDescriptor* udesc;
  11654. //StringAttr clusterFilter;
  11655. StringAttr filters;
  11656. DFUQResultField *localFilters;
  11657. StringAttr localFilterBuf;
  11658. StringAttr sortOrder;
  11659. bool recursive, sorted;
  11660. bool allMatchingFilesReceived;
  11661. public:
  11662. IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
  11663. CDFUPager(IUserDescriptor* _udesc, const char*_filters, DFUQResultField*_localFilters, const char*_localFilterBuf,
  11664. const char*_sortOrder, bool _recursive, bool _sorted) : udesc(_udesc), filters(_filters), localFilters(_localFilters), localFilterBuf(_localFilterBuf),
  11665. sortOrder(_sortOrder), recursive(_recursive), sorted(_sorted)
  11666. {
  11667. allMatchingFilesReceived = true;
  11668. }
  11669. virtual IRemoteConnection* getElements(IArrayOf<IPropertyTree> &elements)
  11670. {
  11671. Owned<IPropertyTreeIterator> fi = queryDistributedFileDirectory().getDFAttributesTreeIterator(filters.get(),
  11672. localFilters, localFilterBuf.get(), udesc, recursive, allMatchingFilesReceived);
  11673. StringArray unknownAttributes;
  11674. sortElements(fi, sorted ? sortOrder.get() : NULL, NULL, NULL, unknownAttributes, elements);
  11675. return NULL;
  11676. }
  11677. virtual bool allMatchingElementsReceived() { return allMatchingFilesReceived; }
  11678. };
  11679. StringBuffer so;
  11680. if (sorted && sortOrder)
  11681. {
  11682. for (unsigned i=0;sortOrder[i]!=DFUQRFterm;i++)
  11683. {
  11684. if (so.length())
  11685. so.append(',');
  11686. int fmt = sortOrder[i];
  11687. if (fmt&DFUQRFreverse)
  11688. so.append('-');
  11689. if (fmt&DFUQRFnocase)
  11690. so.append('?');
  11691. if (fmt&DFUQRFnumeric)
  11692. so.append('#');
  11693. so.append(getDFUQResultFieldName((DFUQResultField) (fmt&0xff)));
  11694. }
  11695. }
  11696. IArrayOf<IPropertyTree> results;
  11697. Owned<IElementsPager> elementsPager = new CDFUPager(udesc, (const char*) filters, localFilters, (const char*) localFilterBuf,
  11698. so.length()?so.str():NULL, recursive, sorted);
  11699. Owned<IRemoteConnection> conn = getElementsPaged(elementsPager,startOffset,maxNum,NULL,"",cacheHint,results,total,allMatchingFiles,false);
  11700. return new CDFAttributeIterator(results);
  11701. }
  11702. IDFAttributesIterator* CDistributedFileDirectory::getLogicalFilesSorted(
  11703. IUserDescriptor* udesc,
  11704. DFUQResultField *sortOrder, // list of fields to sort by (terminated by DFUSFterm)
  11705. const void *filters, // (appended) string values for filters used by dali server
  11706. DFUQResultField *localFilters, //used for filtering query result received from dali server.
  11707. const void *localFilterBuf,
  11708. unsigned startOffset,
  11709. unsigned maxNum,
  11710. __int64 *cacheHint,
  11711. unsigned *total,
  11712. bool *allMatchingFiles)
  11713. {
  11714. return getLogicalFiles(udesc, sortOrder, filters, localFilters, localFilterBuf, startOffset, maxNum,
  11715. cacheHint, total, allMatchingFiles, true, true);
  11716. }
  11717. bool CDistributedFileDirectory::removePhysicalPartFiles(const char *logicalName, IFileDescriptor *fileDesc, IMultiException *mexcept, unsigned numParallelDeletes)
  11718. {
  11719. class casyncfor: public CAsyncFor
  11720. {
  11721. IFileDescriptor *fileDesc;
  11722. CriticalSection errcrit;
  11723. IMultiException *mexcept;
  11724. public:
  11725. bool ok;
  11726. bool islazy;
  11727. casyncfor(IFileDescriptor *_fileDesc, IMultiException *_mexcept)
  11728. {
  11729. fileDesc = _fileDesc;
  11730. ok = true;
  11731. islazy = false;
  11732. mexcept = _mexcept;
  11733. }
  11734. void Do(unsigned i)
  11735. {
  11736. IPartDescriptor *part = fileDesc->queryPart(i);
  11737. unsigned nc = part->numCopies();
  11738. for (unsigned copy = 0; copy < nc; copy++)
  11739. {
  11740. RemoteFilename rfn;
  11741. part->getFilename(copy, rfn);
  11742. Owned<IFile> partfile = createIFile(rfn);
  11743. StringBuffer eps;
  11744. try
  11745. {
  11746. unsigned start = msTick();
  11747. if (!partfile->remove()&&(copy==0)&&!islazy) // only warn about missing primary files
  11748. LOG(MCwarning, unknownJob, "Failed to remove file part %s from %s", partfile->queryFilename(),rfn.queryEndpoint().getUrlStr(eps).str());
  11749. else
  11750. {
  11751. unsigned t = msTick()-start;
  11752. if (t>5*1000)
  11753. LOG(MCwarning, unknownJob, "Removing %s from %s took %ds", partfile->queryFilename(), rfn.queryEndpoint().getUrlStr(eps).str(), t/1000);
  11754. }
  11755. }
  11756. catch (IException *e)
  11757. {
  11758. CriticalBlock block(errcrit);
  11759. if (mexcept)
  11760. mexcept->append(*e);
  11761. else
  11762. {
  11763. StringBuffer s("Failed to remove file part ");
  11764. s.append(partfile->queryFilename()).append(" from ");
  11765. rfn.queryEndpoint().getUrlStr(s);
  11766. EXCLOG(e, s.str());
  11767. e->Release();
  11768. }
  11769. ok = false;
  11770. }
  11771. }
  11772. }
  11773. } afor(fileDesc, mexcept);
  11774. afor.islazy = fileDesc->queryProperties().getPropBool("@lazy");
  11775. if (0 == numParallelDeletes)
  11776. numParallelDeletes = fileDesc->numParts();
  11777. if (numParallelDeletes > MAX_PHYSICAL_DELETE_THREADS)
  11778. {
  11779. WARNLOG("Limiting parallel physical delete threads to %d", MAX_PHYSICAL_DELETE_THREADS);
  11780. numParallelDeletes = MAX_PHYSICAL_DELETE_THREADS;
  11781. }
  11782. afor.For(fileDesc->numParts(),numParallelDeletes,false,true);
  11783. return afor.ok;
  11784. }
  11785. #ifdef _USE_CPPUNIT
  11786. /*
  11787. * This method removes files only logically. removeEntry() used to do that, but the only
  11788. * external use for logical-files only is this test-suite, so I'd rather hack the test
  11789. * suite than expose the behaviour to more viewers.
  11790. */
  11791. extern da_decl void removeLogical(const char *fname, IUserDescriptor *user) {
  11792. if (queryDistributedFileDirectory().exists(fname, user)) {
  11793. Owned<IDistributedFile> file = queryDistributedFileDirectory().lookup(fname, user, true);
  11794. CDistributedFile *f = QUERYINTERFACE(file.get(),CDistributedFile);
  11795. assert(f);
  11796. f->detachLogical();
  11797. }
  11798. }
  11799. #endif // _USE_CPPUNIT