daliadmin.cpp 129 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660
  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. #include "platform.h"
  14. #include "portlist.h"
  15. #include "jlib.hpp"
  16. #include "jmisc.hpp"
  17. #include "jptree.hpp"
  18. #include "jarray.hpp"
  19. #include "jencrypt.hpp"
  20. #include "jregexp.hpp"
  21. #include "jptree.hpp"
  22. #include "jlzw.hpp"
  23. #include "jexcept.hpp"
  24. #include "jset.hpp"
  25. #include "jprop.hpp"
  26. #include "mpbase.hpp"
  27. #include "mpcomm.hpp"
  28. #include "daclient.hpp"
  29. #include "dadiags.hpp"
  30. #include "danqs.hpp"
  31. #include "dadfs.hpp"
  32. #include "dasds.hpp"
  33. #include "dautils.hpp"
  34. #include "daaudit.hpp"
  35. #include "daft.hpp"
  36. #include "rmtfile.hpp"
  37. #include "workunit.hpp"
  38. #include "dllserver.hpp"
  39. #include "seclib.hpp"
  40. #ifdef _WIN32
  41. #include <conio.h>
  42. #else
  43. #define _getch getchar
  44. #define _putch putchar
  45. #endif
  46. #define DEFAULT_DALICONNECT_TIMEOUT 5 // seconds
  47. static unsigned daliConnectTimeoutMs = 5000;
  48. static bool noninteractive=false;
  49. void usage(const char *exe)
  50. {
  51. printf("Usage:\n");
  52. printf(" %s [<daliserver-ip>] <command> { <option> }\n", exe);
  53. printf("\n");
  54. printf("Data store commands:\n");
  55. printf(" export <branchxpath> <destfile>\n");
  56. printf(" import <branchxpath> <srcfile>\n");
  57. printf(" importadd <branchxpath> <srcfile>\n");
  58. printf(" delete <branchxpath> [nobackup] -- delete branch, 'nobackup' option suppresses writing copy of existing branch\n");
  59. printf(" set <xpath> <value> -- set single value\n");
  60. printf(" get <xpath> -- get single value\n");
  61. printf(" bget <xpath> <dest-file> -- binary property\n");
  62. printf(" xget <xpath> -- (multi-value tail can have commas)\n");
  63. printf(" wget <xpath> -- (gets all matching xpath)\n");
  64. printf(" add <xpath> [<value>] -- adds new xpath node with optional value\n");
  65. printf(" delv <xpath> -- deletes value\n");
  66. printf(" count <xpath> -- counts xpath matches\n");
  67. printf("\n");
  68. printf("Logical File meta information commands:\n");
  69. printf(" dfsfile <logicalname> -- get meta information for file\n");
  70. printf(" setdfspartattr <logicalname> <part> <attribute> [<value>] -- set attribute of a file part to value, or delete the attribute if not provided\n");
  71. printf(" dfspart <logicalname> <part> -- get meta information for part num\n");
  72. printf(" dfscheck -- verify dfs file information is valid\n");
  73. printf(" dfscsv <logicalnamemask> -- get csv info. for files matching mask\n");
  74. printf(" dfsgroup <logicalgroupname> [filename] -- get IPs for logical group (aka cluster). Written to optional filename if provided\n");
  75. printf(" clusternodes <clustername> [filename] -- get IPs for cluster group. Written to optional filename if provided\n");
  76. printf(" dfsls [<logicalname>] [options]-- get list of files within a scope (options=lrs)\n");
  77. printf(" dfsmap <logicalname> -- get part files (primary and replicates)\n");
  78. printf(" dfsexists <logicalname> -- sets return value to 0 if file exists\n");
  79. printf(" dfsparents <logicalname> -- list superfiles containing file\n");
  80. printf(" dfsunlink <logicalname> -- unlinks file from all super parents\n");
  81. printf(" dfsverify <logicalname> -- verifies parts exist, returns 0 if ok\n");
  82. printf(" setprotect <logicalname> <id> -- overwrite protects logical file\n");
  83. printf(" unprotect <logicalname> <id> -- unprotect (if id=* then clear all)\n");
  84. printf(" listprotect <logicalnamemask> <id-mask> -- list protected files\n");
  85. printf(" checksuperfile <superfilename> [fix=true|false] -- check superfile links consistent and optionally fix\n");
  86. printf(" checksubfile <subfilename> -- check subfile links to parent consistent\n");
  87. printf(" listexpires <logicalnamemask> -- lists logical files with expiry value\n");
  88. printf(" listrelationships <primary> <secondary>\n");
  89. printf(" dfsperm <logicalname> -- returns LDAP permission for file\n");
  90. printf(" dfscompratio <logicalname> -- returns compression ratio of file\n");
  91. printf(" dfsscopes <mask> -- lists logical scopes (mask = * for all)\n");
  92. printf(" cleanscopes -- remove empty scopes\n");
  93. printf(" normalizefilenames [<logicalnamemask>] -- normalize existing logical filenames that match, e.g. .::.::scope::.::name -> scope::name\n");
  94. printf(" dfsreplication <clustermask> <logicalnamemask> <redundancy-count> [dryrun] -- set redundancy for files matching mask, on specified clusters only\n");
  95. printf(" holdlock <logicalfile> <read|write> -- hold a lock to the logical-file until a key is pressed");
  96. printf("\n");
  97. printf("Workunit commands:\n");
  98. printf(" listworkunits [<prop>=<val> [<lower> [<upper>]]] -- list workunits that match prop=val in workunit name range lower to upper\n");
  99. printf(" listmatches <connection xpath> [<match xpath>=<val> [<property xpaths>]] -- <property xpaths> is comma separated list of xpaths\n");
  100. printf(" workunittimings <WUID>\n");
  101. printf("\n");
  102. printf("Other dali server and misc commands:\n");
  103. printf(" serverlist <mask> -- list server IPs (mask optional)\n");
  104. printf(" clusterlist <mask> -- list clusters (mask optional)\n");
  105. printf(" auditlog <fromdate> <todate> <match>\n");
  106. printf(" coalesce -- force transaction coalesce\n");
  107. printf(" mpping <server-ip> -- time MP connect\n");
  108. printf(" daliping [ <num> ] -- time dali server connect\n");
  109. printf(" getxref <destxmlfile> -- get all XREF information\n");
  110. printf(" dalilocks [ <ip-pattern> ] [ files ] -- get all locked files/xpaths\n");
  111. printf(" unlock <xpath or logicalfile> <[path|file]> -- unlocks either matching xpath(s) or matching logical file(s), can contain wildcards\n");
  112. printf(" validatestore [fix=<true|false>]\n"
  113. " [verbose=<true|false>]\n"
  114. " [deletefiles=<true|false>]-- perform some checks on dali meta data an optionally fix or remove redundant info \n");
  115. printf(" workunit <workunit> [true] -- dump workunit xml, if 2nd parameter equals true, will also include progress data\n");
  116. printf(" wuidcompress <wildcard> <type> -- scan workunits that match <wildcard> and compress resources of <type>\n");
  117. printf(" wuiddecompress <wildcard> <type> -- scan workunits that match <wildcard> and decompress resources of <type>\n");
  118. printf(" xmlsize <filename> [<percentage>] -- analyse size usage in xml file, display individual items above 'percentage' \n");
  119. printf(" migratefiles <src-group> <target-group> [<filemask>] [dryrun] [createmaps] [listonly] [verbose]\n");
  120. printf(" translatetoxpath logicalfile [File|SuperFile|Scope]\n");
  121. printf("\n");
  122. printf("Common options\n");
  123. printf(" server=<dali-server-ip> -- server ip\n");
  124. printf(" -- can be 1st param if numeric ip (or '.')\n");
  125. printf(" user=<username> -- for file operations\n");
  126. printf(" password=<password> -- for file operations\n");
  127. printf(" logfile=<filename> -- filename blank for no log\n");
  128. printf(" rawlog=0|1 -- if raw omits timestamps etc\n");
  129. printf(" timeout=<seconds> -- set dali connect timeout\n");
  130. }
  131. #define SDS_LOCK_TIMEOUT 60000
  132. static void outln(const char *ln)
  133. {
  134. PROGLOG("%s",ln);
  135. }
  136. #define OUTLOG PROGLOG
  137. static const char *remLeading(const char *s)
  138. {
  139. if (*s=='/')
  140. s++;
  141. return s;
  142. }
  143. static bool isWild(const char *path)
  144. {
  145. if (strchr(path,'?')||strchr(path,'*'))
  146. return true;
  147. return false;
  148. }
  149. static const char *splitpath(const char *path,StringBuffer &head,StringBuffer &tmp)
  150. {
  151. if (path[0]!='/')
  152. path = tmp.append('/').append(path).str();
  153. const char *tail = splitXPath(path, head);
  154. if (!tail)
  155. throw MakeStringException(0, "Expecting xpath tail node in: %s", path);
  156. return tail;
  157. }
  158. // NB: there's strtoll under Linux
  159. static unsigned __int64 hextoll(const char *str, bool &error)
  160. {
  161. unsigned len = strlen(str);
  162. if (!len)
  163. {
  164. error = true;
  165. return 0;
  166. }
  167. unsigned __int64 factor = 1;
  168. unsigned __int64 rolling = 0;
  169. char *ptr = (char *)str+len-1;
  170. for (;;) {
  171. char c = *ptr;
  172. unsigned v;
  173. if (isdigit(c))
  174. v = c-'0';
  175. else if (c>='A' && c<='F')
  176. v = 10+(c-'A');
  177. else if (c>='a' && c<='f')
  178. v = 10+(c-'a');
  179. else {
  180. error = true;
  181. return 0;
  182. }
  183. rolling += v * factor;
  184. factor <<= 4;
  185. if (ptr == str)
  186. break;
  187. --ptr;
  188. }
  189. error = false;
  190. return rolling;
  191. }
  192. static IRemoteConnection *connectXPathOrFile(const char *path,bool safe,StringBuffer &xpath)
  193. {
  194. CDfsLogicalFileName lfn;
  195. StringBuffer lfnpath;
  196. if ((strstr(path,"::")!=NULL)&&!strchr(path,'/')) {
  197. lfn.set(path);
  198. lfn.makeFullnameQuery(lfnpath,DXB_File);
  199. path = lfnpath.str();
  200. }
  201. else if (strchr(path+((*path=='/')?1:0),'/')==NULL)
  202. safe = true; // all root trees safe
  203. Owned<IRemoteConnection> conn = querySDS().connect(remLeading(path),myProcessSession(),safe?0:RTM_LOCK_READ, daliConnectTimeoutMs);
  204. if (!conn&&lfnpath.length()) {
  205. lfn.makeFullnameQuery(lfnpath.clear(),DXB_SuperFile);
  206. path = lfnpath.str();
  207. conn.setown(querySDS().connect(remLeading(path),myProcessSession(),safe?0:RTM_LOCK_READ, daliConnectTimeoutMs));
  208. }
  209. if (conn.get())
  210. xpath.append(path);
  211. return conn.getClear();
  212. }
  213. //=============================================================================
  214. static void _export_(const char *path,const char *dst,bool safe=false)
  215. {
  216. StringBuffer xpath;
  217. Owned<IRemoteConnection> conn = connectXPathOrFile(path,safe,xpath);
  218. if (!conn) {
  219. UERRLOG("Could not connect to %s",path);
  220. return;
  221. }
  222. Owned<IPropertyTree> root = conn->getRoot();
  223. Owned<IFile> f = createIFile(dst);
  224. Owned<IFileIO> io = f->open(IFOcreate);
  225. Owned<IFileIOStream> fstream = createBufferedIOStream(io);
  226. toXML(root, *fstream); // formatted (default)
  227. OUTLOG("Branch %s saved in '%s'",xpath.str(),dst);
  228. conn->close();
  229. }
  230. //==========================================================================================================
  231. static void import(const char *path,const char *src,bool add)
  232. {
  233. Owned<IFile> iFile = createIFile(src);
  234. Owned<IFileIO> iFileIO = iFile->open(IFOread);
  235. if (!iFileIO)
  236. {
  237. UERRLOG("Could not open to %s",src);
  238. return;
  239. }
  240. size32_t sz = (size32_t)iFile->size();
  241. StringBuffer xml;
  242. iFileIO->read(0, sz, xml.reserve(sz));
  243. Owned<IPropertyTree> branch = createPTreeFromXMLString(xml.str());
  244. StringBuffer head;
  245. StringBuffer tmp;
  246. const char *tail=splitpath(path,head,tmp);
  247. if (!add) {
  248. Owned<IRemoteConnection> bconn = querySDS().connect(remLeading(path),myProcessSession(),RTM_LOCK_READ|RTM_SUB, daliConnectTimeoutMs);
  249. if (bconn) {
  250. Owned<IPropertyTree> broot = bconn->getRoot();
  251. StringBuffer bakname;
  252. Owned<IFileIO> io = createUniqueFile(NULL, tail, "bak", bakname);
  253. OUTLOG("Saving backup of %s to %s",path,bakname.str());
  254. Owned<IFileIOStream> fstream = createBufferedIOStream(io);
  255. toXML(broot, *fstream); // formatted (default)
  256. }
  257. }
  258. Owned<IRemoteConnection> conn = querySDS().connect(head.str(),myProcessSession(),0, daliConnectTimeoutMs);
  259. if (!conn) {
  260. UERRLOG("Could not connect to %s",path);
  261. return;
  262. }
  263. StringAttr newtail; // must be declared outside the following if
  264. Owned<IPropertyTree> root = conn->getRoot();
  265. if (!add) {
  266. Owned<IPropertyTree> child = root->getPropTree(tail);
  267. root->removeTree(child);
  268. //If replacing a qualified branch then remove the qualifiers before calling addProp
  269. const char * qualifier = strchr(tail, '[');
  270. if (qualifier)
  271. {
  272. newtail.set(tail, qualifier-tail);
  273. tail = newtail;
  274. }
  275. }
  276. Owned<IPropertyTree> oldEnvironment;
  277. if (streq(path,"Environment"))
  278. oldEnvironment.setown(createPTreeFromIPT(conn->queryRoot()));
  279. root->addPropTree(tail,LINK(branch));
  280. conn->commit();
  281. OUTLOG("Branch %s loaded from '%s'",path,src);
  282. conn->close();
  283. if (*path=='/')
  284. path++;
  285. if (strcmp(path,"Environment")==0) {
  286. OUTLOG("Refreshing cluster groups from Environment");
  287. StringBuffer response;
  288. initClusterGroups(false, response, oldEnvironment);
  289. if (response.length())
  290. PROGLOG("updating Environment via import path=%s : %s", path, response.str());
  291. }
  292. }
  293. //=============================================================================
  294. static void _delete_(const char *path,bool backup)
  295. {
  296. StringBuffer head;
  297. StringBuffer tmp;
  298. const char *tail=splitpath(path,head,tmp);
  299. Owned<IRemoteConnection> conn = querySDS().connect(head.str(),myProcessSession(),RTM_LOCK_WRITE, daliConnectTimeoutMs);
  300. if (!conn) {
  301. UERRLOG("Could not connect to %s",path);
  302. return;
  303. }
  304. Owned<IPropertyTree> root = conn->getRoot();
  305. Owned<IPropertyTree> child = root->getPropTree(tail);
  306. if (!child) {
  307. UERRLOG("Couldn't find %s/%s",head.str(),tail);
  308. return;
  309. }
  310. if (backup) {
  311. StringBuffer bakname;
  312. Owned<IFileIO> io = createUniqueFile(NULL,"daliadmin", "bak", bakname);
  313. OUTLOG("Saving backup of %s/%s to %s",head.str(),tail,bakname.str());
  314. Owned<IFileIOStream> fstream = createBufferedIOStream(io);
  315. toXML(child, *fstream); // formatted (default)
  316. }
  317. root->removeTree(child);
  318. child.clear();
  319. root.clear();
  320. conn->commit();
  321. conn->close();
  322. }
  323. //=============================================================================
  324. static void set(const char *path,const char *val)
  325. {
  326. StringBuffer head;
  327. StringBuffer tmp;
  328. const char *tail=splitpath(path,head,tmp);
  329. Owned<IRemoteConnection> conn = querySDS().connect(head.str(),myProcessSession(),RTM_LOCK_WRITE, daliConnectTimeoutMs);
  330. if (!conn) {
  331. UERRLOG("Could not connect to %s",path);
  332. return;
  333. }
  334. Owned<IPropertyTree> root = conn->getRoot();
  335. StringBuffer oldv;
  336. StringBuffer newv;
  337. root->getProp(tail,oldv);
  338. root->setProp(tail,val);
  339. conn->commit();
  340. root->getProp(tail,newv);
  341. OUTLOG("Changed %s from '%s' to '%s'",path,oldv.str(),newv.str());
  342. conn->close();
  343. }
  344. //=============================================================================
  345. static void get(const char *path)
  346. {
  347. StringBuffer head;
  348. StringBuffer tmp;
  349. const char *tail=splitpath(path,head,tmp);
  350. Owned<IRemoteConnection> conn = querySDS().connect(head.str(),myProcessSession(),RTM_LOCK_READ, daliConnectTimeoutMs);
  351. if (!conn) {
  352. UERRLOG("Could not connect to %s",path);
  353. return;
  354. }
  355. Owned<IPropertyTree> root = conn->getRoot();
  356. StringBuffer val;
  357. root->getProp(tail,val);
  358. OUTLOG("Value of %s is: '%s'",path,val.str());
  359. conn->close();
  360. }
  361. //=============================================================================
  362. static void bget(const char *path,const char *outfn)
  363. {
  364. StringBuffer head;
  365. StringBuffer tmp;
  366. const char *tail=splitpath(path,head,tmp);
  367. Owned<IRemoteConnection> conn = querySDS().connect(head.str(),myProcessSession(),RTM_LOCK_READ, daliConnectTimeoutMs);
  368. if (!conn) {
  369. UERRLOG("Could not connect to %s",path);
  370. return;
  371. }
  372. Owned<IPropertyTree> root = conn->getRoot();
  373. MemoryBuffer val;
  374. root->getPropBin(tail,val);
  375. Owned<IFile> f = createIFile(outfn);
  376. Owned<IFileIO> io = f->open(IFOcreate);
  377. io->write(0,val.length(),val.toByteArray());
  378. conn->close();
  379. }
  380. //=============================================================================
  381. static void xget(const char *path)
  382. {
  383. if (!path||!*path)
  384. return;
  385. Owned<IRemoteConnection> conn = querySDS().connect("/",myProcessSession(),RTM_LOCK_READ, daliConnectTimeoutMs);
  386. if (!conn) {
  387. UERRLOG("Could not connect to /");
  388. return;
  389. }
  390. Owned<IPropertyTree> root = conn->getRoot();
  391. StringBuffer head;
  392. StringBuffer tmp;
  393. const char *props=splitpath(path,head,tmp);
  394. const char *s = head.str();
  395. if (*s=='/')
  396. s++;
  397. Owned<IPropertyTreeIterator> it = root->getElements(s);
  398. if (it->first()) {
  399. unsigned idx = 0;
  400. do {
  401. idx++;
  402. StringBuffer res;
  403. res.append(idx).append(',');
  404. s = props;
  405. for (;;) {
  406. const char *e = strchr(s,',');
  407. if (e&&e[1]) {
  408. StringBuffer prop(e-s,s);
  409. it->query().getProp(prop.str(),res);
  410. s = e+1;
  411. res.append(',');
  412. }
  413. else {
  414. it->query().getProp(s,res);
  415. break;
  416. }
  417. }
  418. outln(res.str());
  419. } while (it->next());
  420. }
  421. conn->close();
  422. }
  423. //=============================================================================
  424. static void wget(const char *path)
  425. {
  426. StringBuffer head;
  427. StringBuffer tmp;
  428. const char *tail=splitpath(path,head,tmp);
  429. Owned<IRemoteConnection> conn = querySDS().connect(head.str(),myProcessSession(),RTM_LOCK_READ, daliConnectTimeoutMs);
  430. if (!conn) {
  431. UERRLOG("Could not connect to %s",path);
  432. return;
  433. }
  434. Owned<IPropertyTreeIterator> iter = conn->queryRoot()->getElements(tail);
  435. unsigned n = 0;
  436. ForEach(*iter) {
  437. n++;
  438. const char *s = iter->query().queryName();
  439. OUTLOG("%d,%s",n,s);
  440. }
  441. conn->close();
  442. }
  443. //=============================================================================
  444. static void add(const char *path, const char *val)
  445. {
  446. if (!path || !*path)
  447. throw makeStringException(0, "Invalid xpath (empty)");
  448. if ('/' == path[strlen(path)-1])
  449. throw makeStringException(0, "Invalid xpath (no trailing xpath node provided)");
  450. Owned<IRemoteConnection> conn = querySDS().connect(path, myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_ADD, daliConnectTimeoutMs);
  451. if (!conn)
  452. {
  453. UERRLOG("Could not connect to %s", path);
  454. return;
  455. }
  456. VStringBuffer msg("Added %s", path);
  457. if (val)
  458. {
  459. conn->queryRoot()->setProp(NULL, val);
  460. msg.appendf(" (with value = '%s')", val);
  461. }
  462. OUTLOG("%s", msg.str());
  463. }
  464. //=============================================================================
  465. static void delv(const char *path)
  466. {
  467. StringBuffer head;
  468. StringBuffer tmp;
  469. const char *tail=splitpath(path,head,tmp);
  470. Owned<IRemoteConnection> conn = querySDS().connect(head.str(),myProcessSession(),RTM_LOCK_WRITE, daliConnectTimeoutMs);
  471. if (!conn) {
  472. UERRLOG("Could not connect to %s",path);
  473. return;
  474. }
  475. Owned<IPropertyTree> root = conn->getRoot();
  476. StringBuffer val;
  477. root->getProp(tail,val);
  478. root->removeProp(tail);
  479. OUTLOG("Value of %s was: '%s'",path,val.str());
  480. conn->close();
  481. }
  482. //=============================================================================
  483. static void count(const char *path)
  484. {
  485. unsigned result = querySDS().queryCount(path);
  486. OUTLOG("Count of %s is: %d", path, result);
  487. }
  488. //=============================================================================
  489. static void dfsfile(const char *lname,IUserDescriptor *userDesc, UnsignedArray *partslist=NULL)
  490. {
  491. StringBuffer str;
  492. CDfsLogicalFileName lfn;
  493. lfn.set(lname);
  494. if (!lfn.isExternal()) {
  495. Owned<IPropertyTree> tree = queryDistributedFileDirectory().getFileTree(lname,userDesc,NULL,daliConnectTimeoutMs,true); //,userDesc);
  496. if (partslist)
  497. filterParts(tree,*partslist);
  498. if (!tree) {
  499. UERRLOG("%s not found",lname);
  500. return;
  501. }
  502. toXML(tree, str);
  503. outln(str.str());
  504. }
  505. else {
  506. Owned<IDistributedFile> file = queryDistributedFileDirectory().lookup(lname,userDesc,false,false,false,nullptr,defaultPrivilegedUser);
  507. if (file) {
  508. Owned<IFileDescriptor> fdesc = file->getFileDescriptor();
  509. Owned<IPropertyTree> t = createPTree("File");
  510. fdesc->serializeTree(*t);
  511. filterParts(t,*partslist);
  512. toXML(t, str.clear());
  513. outln(str.str());
  514. }
  515. }
  516. }
  517. //=============================================================================
  518. static void dfspart(const char *lname,IUserDescriptor *userDesc, unsigned partnum)
  519. {
  520. UnsignedArray partslist;
  521. partslist.append(partnum);
  522. dfsfile(lname,userDesc,&partslist);
  523. }
  524. //=============================================================================
  525. static void setdfspartattr(const char *lname, unsigned partNum, const char *attr, const char *value, IUserDescriptor *userDesc)
  526. {
  527. StringBuffer str;
  528. CDfsLogicalFileName lfn;
  529. lfn.set(lname);
  530. if (lfn.isExternal())
  531. throw MakeStringException(0, "External file not supported");
  532. if (lfn.isForeign())
  533. throw MakeStringException(0, "Foreign file not supported");
  534. Owned<IDistributedFile> file = queryDistributedFileDirectory().lookup(lname, userDesc, false, false, false, nullptr, defaultPrivilegedUser);
  535. if (!file)
  536. throw MakeStringException(0, "Could not find file: '%s'", lname);
  537. if (file->querySuperFile())
  538. throw MakeStringException(0, "Cannot be used on a superfile");
  539. if (!partNum || partNum>file->numParts())
  540. throw MakeStringException(0, "Invalid part number, must be in the range 1 - %u", file->numParts());
  541. IDistributedFilePart &part = file->queryPart(partNum-1);
  542. StringBuffer attrProp("@");
  543. attrProp.append(attr);
  544. part.lockProperties(10000);
  545. StringBuffer oldValueSB;
  546. const char *oldValue = nullptr;
  547. if (part.queryAttributes().getProp(attrProp.str(), oldValueSB))
  548. oldValue = oldValueSB.str();
  549. if (value)
  550. {
  551. part.queryAttributes().setProp(attrProp.str(), value);
  552. PROGLOG("Set property '%s' to '%s' for file %s, part# %u", attrProp.str(), value, lname, partNum);
  553. }
  554. else
  555. {
  556. part.queryAttributes().removeProp(attrProp.str());
  557. PROGLOG("Removed property '%s' from file %s, part# %u", attrProp.str(), lname, partNum);
  558. }
  559. part.unlockProperties();
  560. if (oldValue)
  561. PROGLOG("Prev. value = '%s'", oldValue);
  562. }
  563. //=============================================================================
  564. void dfscsv(const char *dali,IUserDescriptor *udesc)
  565. {
  566. const char *fields[] = {
  567. "name","group","directory","partmask","modified","job","owner","workunit","numparts","size","recordCount","recordSize","compressedSize",NULL
  568. };
  569. Owned<INode> foreigndali;
  570. if (dali&&*dali&&(*dali!='*')) {
  571. SocketEndpoint ep(dali,DALI_SERVER_PORT);
  572. foreigndali.setown(createINode(ep));
  573. }
  574. unsigned start = msTick();
  575. IDFAttributesIterator *iter = queryDistributedFileDirectory().getDFAttributesIterator("*",udesc,true,false,foreigndali);
  576. StringBuffer ln;
  577. unsigned i;
  578. for (i=0;fields[i];i++) {
  579. if (i>0)
  580. ln.append(',');
  581. ln.append('"').append(fields[i]).append('"');
  582. }
  583. outln(ln.str());
  584. if (iter) {
  585. StringBuffer aname;
  586. StringBuffer vals;
  587. ForEach(*iter) {
  588. IPropertyTree &attr=iter->query();
  589. ln.clear();
  590. for (i=0;fields[i];i++) {
  591. aname.clear().append('@').append(fields[i]);
  592. const char *val = attr.queryProp(aname.str());
  593. if (i>0)
  594. ln.append(',');
  595. if (val)
  596. while (*val) {
  597. if (*val!=',')
  598. ln.append(*val);
  599. val++;
  600. }
  601. }
  602. outln(ln.str());
  603. }
  604. }
  605. }
  606. //=============================================================================
  607. static void writeGroup(IGroup *group, const char *name, const char *outputFilename)
  608. {
  609. Owned<IFileIOStream> io;
  610. if (outputFilename)
  611. {
  612. OwnedIFile iFile = createIFile(outputFilename);
  613. OwnedIFileIO iFileIO = iFile->open(IFOcreate);
  614. io.setown(createIOStream(iFileIO));
  615. }
  616. StringBuffer eps;
  617. for (unsigned i=0;i<group->ordinality();i++)
  618. {
  619. group->queryNode(i).endpoint().getUrlStr(eps.clear());
  620. if (io)
  621. {
  622. eps.newline();
  623. io->write(eps.length(), eps.str());
  624. }
  625. else
  626. OUTLOG("%s",eps.str());
  627. }
  628. }
  629. unsigned dfsCheck(StringBuffer & path, IPropertyTree * tree)
  630. {
  631. const char * name = tree->queryProp("@name");
  632. //MORE: What other consistency checks can be added here?
  633. if (tree->hasProp("Attr[2]"))
  634. {
  635. printf("%s%s - duplicate Attr tag\n", path.str(), name ? name : "");
  636. return 1;
  637. }
  638. unsigned issues = 0;
  639. unsigned prevLength = path.length();
  640. if (name)
  641. path.append(name).append("::");
  642. Owned<IPropertyTreeIterator> elems = tree->getElements("*");
  643. ForEach(*elems)
  644. {
  645. issues += dfsCheck(path, &elems->query());
  646. }
  647. path.setLength(prevLength);
  648. return issues;
  649. }
  650. void dfsCheck()
  651. {
  652. StringBuffer xpath;
  653. Owned<IRemoteConnection> conn = querySDS().connect("Files",myProcessSession(),0, daliConnectTimeoutMs);
  654. if (!conn)
  655. {
  656. UERRLOG("Could not connect to %s","/Files");
  657. return;
  658. }
  659. StringBuffer path;
  660. dfsCheck(path, conn->queryRoot());
  661. }
  662. static void dfsGroup(const char *name, const char *outputFilename)
  663. {
  664. Owned<IGroup> group = queryNamedGroupStore().lookup(name);
  665. if (!group)
  666. {
  667. UERRLOG("cannot find group %s",name);
  668. return;
  669. }
  670. writeGroup(group, name, outputFilename);
  671. }
  672. static int clusterGroup(const char *name, const char *outputFilename)
  673. {
  674. StringBuffer errStr;
  675. try
  676. {
  677. Owned<IGroup> group = getClusterNodeGroup(name, "ThorCluster");
  678. if (group)
  679. {
  680. writeGroup(group, name, outputFilename);
  681. return 0; // success
  682. }
  683. errStr.appendf("cannot find group %s", name);
  684. }
  685. catch (IException *e)
  686. {
  687. e->errorMessage(errStr);
  688. e->Release();
  689. }
  690. UERRLOG("%s", errStr.str());
  691. return 1;
  692. }
  693. static IPropertyTree * selectLevel(IPropertyTree * root, const char * name)
  694. {
  695. StringBuffer xpath;
  696. xpath.append("*[@name='").append(name).append("']");
  697. Owned<IPropertyTree> match = root->getPropTree(xpath);
  698. if (match)
  699. return match.getClear();
  700. UERRLOG("Path %s not found", name);
  701. return nullptr;
  702. }
  703. static IPropertyTree * selectPath(IPropertyTree * root, const char * path)
  704. {
  705. if (!path || !*path) // use / to refer to the root directory
  706. return LINK(root);
  707. const char * split = strstr(path, "::");
  708. if (split)
  709. {
  710. //Can use :: to refer to the root directory
  711. if (split == path)
  712. return selectPath(root, split + 2);
  713. StringAttr name(path, split - path);
  714. Owned<IPropertyTree> match = selectLevel(root, name);
  715. if (match)
  716. return selectPath(match, split + 2);
  717. return nullptr;
  718. }
  719. return selectLevel(root, path);
  720. }
  721. static void displayDirectory(IPropertyTree * directory, const char * options, unsigned depth)
  722. {
  723. Owned<IPropertyTreeIterator> elems = directory->getElements("*");
  724. ForEach(*elems)
  725. {
  726. IPropertyTree & cur = elems->query();
  727. const char * tag = cur.queryName();
  728. const char * name = cur.queryProp("@name");
  729. const char * modified = cur.queryProp("@modified");
  730. if (name && tag)
  731. {
  732. if (strieq(tag, "Scope"))
  733. {
  734. OUTLOG("%*sD %s", depth, "", name);
  735. if (options && strchr(options, 'r'))
  736. displayDirectory(&cur, options, depth+1);
  737. }
  738. else if (strieq(tag, "File"))
  739. {
  740. const char * group = cur.queryProp("@group");
  741. const char * size = cur.queryProp("Attr[1]/@size");
  742. if (options && strchr(options, 'l'))
  743. OUTLOG("%*s %-30s %12s %s %s", depth, "", name, size ? size : "", group ? group : "?", modified ? modified : "");
  744. else
  745. OUTLOG("%*s %s", depth, "", name);
  746. }
  747. else if (strieq(tag, "SuperFile"))
  748. {
  749. if (options && strchr(options, 'l'))
  750. OUTLOG("%*sS %s %s (%d)", depth, "", name, modified ? modified : "", cur.getPropInt("@numsubfiles"));
  751. else
  752. OUTLOG("%*sS %s", depth, "", name);
  753. if (options && strchr(options, 's'))
  754. {
  755. Owned<IPropertyTreeIterator> subs = cur.getElements("SubFile");
  756. ForEach(*subs)
  757. {
  758. OUTLOG("%*s->%s", depth, "", subs->query().queryProp("@name"));
  759. }
  760. }
  761. }
  762. else
  763. OUTLOG("? %s %s", name, tag);
  764. }
  765. }
  766. }
  767. static void dfsLs(const char *name, const char *options, bool safe = false)
  768. {
  769. StringBuffer xpath;
  770. Owned<IRemoteConnection> conn = querySDS().connect("Files",myProcessSession(),0, daliConnectTimeoutMs);
  771. if (!conn)
  772. {
  773. UERRLOG("Could not connect to %s","/Files");
  774. return;
  775. }
  776. {
  777. Owned<IPropertyTree> directory = selectPath(conn->queryRoot(), name);
  778. if (directory)
  779. displayDirectory(directory, options, 0);
  780. }
  781. }
  782. //=============================================================================
  783. static void dfsmap(const char *lname, IUserDescriptor *user)
  784. {
  785. Owned<IDistributedFile> file = queryDistributedFileDirectory().lookup(lname,user,false,false,false,nullptr,defaultPrivilegedUser);
  786. if (!file) {
  787. UERRLOG("File %s not found",lname);
  788. return;
  789. }
  790. Owned<IDistributedFilePartIterator> pi = file->getIterator();
  791. unsigned pn=1;
  792. StringBuffer ln;
  793. ForEach(*pi) {
  794. ln.clear().appendf("%d: ",pn);
  795. Owned<IDistributedFilePart> part = &pi->get();
  796. for (unsigned int i=0; i<part->numCopies(); i++) {
  797. RemoteFilename rfn;
  798. part->getFilename(rfn,i);
  799. if (i)
  800. ln.append(", ");
  801. rfn.getRemotePath(ln);
  802. }
  803. outln(ln.str());
  804. pn++;
  805. }
  806. }
  807. //=============================================================================
  808. static int dfsexists(const char *lname,IUserDescriptor *user)
  809. {
  810. return queryDistributedFileDirectory().exists(lname,user)?0:1;
  811. }
  812. //=============================================================================
  813. static void dfsparents(const char *lname, IUserDescriptor *user)
  814. {
  815. Owned<IDistributedFile> file = queryDistributedFileDirectory().lookup(lname,user,false,false,true,nullptr,defaultPrivilegedUser);
  816. if (file) {
  817. Owned<IDistributedSuperFileIterator> iter = file->getOwningSuperFiles();
  818. ForEach(*iter)
  819. OUTLOG("%s,%s",iter->query().queryLogicalName(),lname);
  820. }
  821. }
  822. //=============================================================================
  823. static void dfsunlink(const char *lname, IUserDescriptor *user)
  824. {
  825. for (;;)
  826. {
  827. Owned<IDistributedFile> file = queryDistributedFileDirectory().lookup(lname,user,false,false,true,nullptr,defaultPrivilegedUser);
  828. if (!file)
  829. {
  830. UERRLOG("File '%s' not found", lname);
  831. break;
  832. }
  833. Owned<IDistributedSuperFileIterator> iter = file->getOwningSuperFiles();
  834. if (!iter->first())
  835. break;
  836. file.clear();
  837. Owned<IDistributedSuperFile> sf = &iter->get();
  838. iter.clear();
  839. if (sf->removeSubFile(lname,false))
  840. OUTLOG("removed %s from %s",lname,sf->queryLogicalName());
  841. else
  842. UERRLOG("FAILED to remove %s from %s",lname,sf->queryLogicalName());
  843. }
  844. }
  845. //=============================================================================
  846. class CIpItem: public CInterface
  847. {
  848. public:
  849. bool ok;
  850. IpAddress ip;
  851. };
  852. class CIpTable: public SuperHashTableOf<CIpItem,IpAddress>
  853. {
  854. public:
  855. ~CIpTable()
  856. {
  857. _releaseAll();
  858. }
  859. void onAdd(void *)
  860. {
  861. // not used
  862. }
  863. void onRemove(void *e)
  864. {
  865. CIpItem &elem=*(CIpItem *)e;
  866. elem.Release();
  867. }
  868. unsigned getHashFromElement(const void *e) const
  869. {
  870. const CIpItem &elem=*(const CIpItem *)e;
  871. return elem.ip.iphash();
  872. }
  873. unsigned getHashFromFindParam(const void *fp) const
  874. {
  875. return ((const IpAddress *)fp)->iphash();
  876. }
  877. const void * getFindParam(const void *p) const
  878. {
  879. const CIpItem &elem=*(const CIpItem *)p;
  880. return &elem.ip;
  881. }
  882. bool matchesFindParam(const void * et, const void *fp, unsigned fphash) const
  883. {
  884. return ((CIpItem *)et)->ip.ipequals(*(IpAddress *)fp);
  885. }
  886. IMPLEMENT_SUPERHASHTABLEOF_REF_FIND(CIpItem,IpAddress);
  887. bool verifyDaliFileServer(IpAddress &ip)
  888. {
  889. CIpItem *item=find(ip);
  890. if (!item) {
  891. item = new CIpItem;
  892. item->ip.ipset(ip);
  893. item->ok = testDaliServixPresent(ip);
  894. add(*item);
  895. }
  896. return item->ok;
  897. }
  898. };
  899. class CFileCrcItem: public CInterface
  900. {
  901. public:
  902. RemoteFilename filename;
  903. unsigned requiredcrc;
  904. unsigned crc;
  905. unsigned partno;
  906. unsigned copy;
  907. bool ok;
  908. byte flags;
  909. CDateTime dt;
  910. };
  911. #define FLAG_ROW_COMPRESSED 1
  912. #define FLAG_NO_CRC 2
  913. class CFileList: public CIArrayOf<CFileCrcItem>
  914. {
  915. public:
  916. void add(RemoteFilename &filename,unsigned partno,unsigned copy,unsigned crc,byte flags)
  917. {
  918. CFileCrcItem *item = new CFileCrcItem();
  919. item->filename.set(filename);
  920. item->partno = partno;
  921. item->copy = copy;
  922. item->crc = crc;
  923. item->requiredcrc = crc;
  924. item->flags = flags;
  925. append(*item);
  926. }
  927. };
  928. static int dfsverify(const char *name,CDateTime *cutoff, IUserDescriptor *user)
  929. {
  930. static CIpTable dafilesrvips;
  931. Owned<IDistributedFile> file=queryDistributedFileDirectory().lookup(name,user,false,false,false,nullptr,defaultPrivilegedUser);
  932. if (!file) {
  933. UERRLOG("VERIFY: cannot find %s",name);
  934. return 1;
  935. }
  936. CDateTime filetime;
  937. if (file->getModificationTime(filetime)) {
  938. if (cutoff&&(filetime.compare(*cutoff)<=0))
  939. return 0;
  940. }
  941. IPropertyTree &fileprops = file->queryAttributes();
  942. bool blocked;
  943. bool rowcompressed = file->isCompressed(&blocked)&&!blocked;
  944. CFileList list;
  945. unsigned width = file->numParts();
  946. unsigned short port = getDaliServixPort();
  947. try {
  948. for (unsigned i=0;i<width;i++) {
  949. Owned<IDistributedFilePart> part = file->getPart(i);
  950. for (unsigned copy = 0; copy < part->numCopies(); copy++) {
  951. unsigned reqcrc;
  952. bool noreq = !part->getCrc(reqcrc);
  953. // if (reqcrc==(unsigned)-1)
  954. // continue;
  955. SocketEndpoint ep(part->queryNode()->endpoint());
  956. if (!dafilesrvips.verifyDaliFileServer(ep)) {
  957. StringBuffer ips;
  958. ep.getIpText(ips);
  959. UERRLOG("VERIFY: file %s, cannot run DAFILESRV on %s",name,ips.str());
  960. return 4;
  961. }
  962. RemoteFilename rfn;
  963. part->getFilename(rfn,copy);
  964. rfn.setPort(port);
  965. list.add(rfn,i,copy,reqcrc,rowcompressed?FLAG_ROW_COMPRESSED:(noreq?FLAG_NO_CRC:0));
  966. }
  967. }
  968. }
  969. catch (IException *e)
  970. {
  971. StringBuffer s;
  972. s.appendf("VERIFY: file %s",name);
  973. EXCLOG(e, s.str());
  974. e->Release();
  975. return 2;
  976. }
  977. if (list.ordinality()==0)
  978. return 0;
  979. OUTLOG("VERIFY: start file %s",name);
  980. file.clear();
  981. CriticalSection crit;
  982. class casyncfor: public CAsyncFor
  983. {
  984. CFileList &list;
  985. CriticalSection &crit;
  986. public:
  987. bool ok;
  988. casyncfor(CFileList &_list, CriticalSection &_crit)
  989. : list(_list), crit(_crit)
  990. {
  991. ok = true;
  992. }
  993. void Do(unsigned i)
  994. {
  995. CriticalBlock block(crit);
  996. CFileCrcItem &item = list.item(i);
  997. RemoteFilename &rfn = item.filename;
  998. Owned<IFile> partfile;
  999. StringBuffer eps;
  1000. try
  1001. {
  1002. partfile.setown(createIFile(rfn));
  1003. // OUTLOG("VERIFY: part %s on %s",partfile->queryFilename(),rfn.queryEndpoint().getUrlStr(eps).str());
  1004. if (partfile) {
  1005. CriticalUnblock unblock(crit);
  1006. item.crc = partfile->getCRC();
  1007. partfile->getTime(NULL,&item.dt,NULL);
  1008. if ((item.crc==0)&&!partfile->exists()) {
  1009. UERRLOG("VERIFY: does not exist part %s on %s",partfile->queryFilename(),rfn.queryEndpoint().getUrlStr(eps).str());
  1010. ok = false;
  1011. }
  1012. }
  1013. else
  1014. ok = false;
  1015. }
  1016. catch (IException *e)
  1017. {
  1018. StringBuffer s;
  1019. s.appendf("VERIFY: part %s on %s",partfile->queryFilename(),rfn.queryEndpoint().getUrlStr(eps).str());
  1020. EXCLOG(e, s.str());
  1021. e->Release();
  1022. ok = false;
  1023. }
  1024. }
  1025. } afor(list,crit);
  1026. afor.For(list.ordinality(),400,false,true);
  1027. StringBuffer outs;
  1028. ForEachItemIn(j,list) {
  1029. CFileCrcItem &item = list.item(j);
  1030. item.filename.setPort(0);
  1031. if (item.crc!=item.requiredcrc) {
  1032. StringBuffer rfs;
  1033. UERRLOG("VERIFY: FAILED %s (%x,%x) file %s",name,item.crc,item.requiredcrc,item.filename.getRemotePath(rfs).str());
  1034. afor.ok = false;
  1035. }
  1036. }
  1037. if (afor.ok) {
  1038. OUTLOG("VERIFY: OK file %s",name);
  1039. return 0;
  1040. }
  1041. return 3;
  1042. }
  1043. //=============================================================================
  1044. static void setprotect(const char *filename, const char *callerid, IUserDescriptor *user)
  1045. {
  1046. Owned<IDistributedFile> file = queryDistributedFileDirectory().lookup(filename,user,false,false,false,nullptr,defaultPrivilegedUser);
  1047. file->setProtect(callerid,true);
  1048. }
  1049. //=============================================================================
  1050. static void unprotect(const char *filename, const char *callerid, IUserDescriptor *user)
  1051. {
  1052. Owned<IDistributedFile> file = queryDistributedFileDirectory().lookup(filename,user,false,false,false,nullptr,defaultPrivilegedUser);
  1053. file->setProtect((strcmp(callerid,"*")==0)?NULL:callerid,false);
  1054. }
  1055. //=============================================================================
  1056. static void listprotect(const char *filename, const char *callerid)
  1057. {
  1058. Owned<IDFProtectedIterator> piter = queryDistributedFileDirectory().lookupProtectedFiles((strcmp(callerid,"*")==0)?NULL:callerid);
  1059. ForEach(*piter) {
  1060. if (WildMatch(piter->queryFilename(),filename))
  1061. OUTLOG("%s,%s,%s,%u",piter->isSuper()?"SuperFile":"File",piter->queryFilename(),piter->queryOwner(),piter->getCount());
  1062. }
  1063. }
  1064. //=============================================================================
  1065. static bool allyes = false;
  1066. static bool getResponse()
  1067. {
  1068. if (allyes)
  1069. return true;
  1070. int ch;
  1071. do
  1072. {
  1073. ch = toupper(ch = _getch());
  1074. } while (ch != 'Y' && ch != 'N' && ch != '*');
  1075. _putch(ch);
  1076. _putch('\n');
  1077. if (ch=='*') {
  1078. allyes = true;
  1079. return true;
  1080. }
  1081. return ch=='Y' ? true : false;
  1082. }
  1083. static bool doFix()
  1084. {
  1085. if (allyes)
  1086. return true;
  1087. printf("Fix? (Y/N/*):");
  1088. return getResponse();
  1089. }
  1090. static void checksuperfile(const char *lfn,bool fix=false)
  1091. {
  1092. if (strcmp(lfn,"*")==0) {
  1093. class csuperfilescan: public CSDSFileScanner
  1094. {
  1095. virtual bool checkScopeOk(const char *scopename)
  1096. {
  1097. OUTLOG("Processing scope %s",scopename);
  1098. return true;
  1099. }
  1100. void processSuperFile(IPropertyTree &superfile,StringBuffer &name)
  1101. {
  1102. try {
  1103. checksuperfile(name.str(),fix);
  1104. }
  1105. catch (IException *e) {
  1106. EXCLOG(e,"processSuperFiles");
  1107. e->Release();
  1108. }
  1109. }
  1110. public:
  1111. bool fix;
  1112. } superfilescan;
  1113. superfilescan.fix = fix;
  1114. Owned<IRemoteConnection> conn = querySDS().connect("/Files", myProcessSession(), 0, 100000);
  1115. superfilescan.scan(conn,false,true);
  1116. return;
  1117. }
  1118. bool fixed = false;
  1119. CDfsLogicalFileName lname;
  1120. lname.set(lfn);
  1121. StringBuffer query;
  1122. lname.makeFullnameQuery(query, DXB_SuperFile, true);
  1123. Owned<IRemoteConnection> conn = querySDS().connect(query.str(),myProcessSession(),fix?RTM_LOCK_WRITE:0, daliConnectTimeoutMs);
  1124. if (!conn) {
  1125. UERRLOG("Could not connect to %s",lfn);
  1126. UERRLOG("Superfile %s FAILED",lname.get());
  1127. return;
  1128. }
  1129. Owned<IPropertyTree> root = conn->getRoot();
  1130. unsigned n=root->getPropInt("@numsubfiles");
  1131. StringBuffer path;
  1132. StringBuffer subname;
  1133. unsigned subnum = 0;
  1134. unsigned i;
  1135. for (i=0;i<n;i++) {
  1136. for (;;) {
  1137. IPropertyTree *sub2 = root->queryPropTree(path.clear().appendf("SubFile[@num=\"%d\"][2]",i+1).str());
  1138. if (!sub2)
  1139. break;
  1140. StringBuffer s;
  1141. s.appendf("SuperFile %s: corrupt, subfile file part %d is duplicated",lname.get(),i+1);
  1142. UERRLOG("%s",s.str());
  1143. if (!fix||!doFix()) {
  1144. UERRLOG("Superfile %s FAILED",lname.get());
  1145. return;
  1146. }
  1147. root->removeProp(path.str());
  1148. }
  1149. IPropertyTree *sub = root->queryPropTree(path.clear().appendf("SubFile[@num=\"%d\"]",i+1).str());
  1150. if (!sub) {
  1151. StringBuffer s;
  1152. s.appendf("SuperFile %s: corrupt, subfile file part %d cannot be found",lname.get(),i+1);
  1153. UERRLOG("%s",s.str());
  1154. if (!fix||!doFix()) {
  1155. UERRLOG("Superfile %s FAILED",lname.get());
  1156. return;
  1157. }
  1158. fixed = true;
  1159. break;
  1160. }
  1161. sub->getProp("@name",subname.clear());
  1162. CDfsLogicalFileName sublname;
  1163. sublname.set(subname.str());
  1164. if (!sublname.isExternal()&&!sublname.isForeign()) {
  1165. StringBuffer subquery;
  1166. sublname.makeFullnameQuery(subquery, DXB_File, true);
  1167. Owned<IRemoteConnection> subconn = querySDS().connect(subquery.str(),myProcessSession(),fix?RTM_LOCK_WRITE:0, daliConnectTimeoutMs);
  1168. if (!subconn) {
  1169. sublname.makeFullnameQuery(subquery.clear(), DXB_SuperFile, true);
  1170. subconn.setown(querySDS().connect(subquery.str(),myProcessSession(),0, daliConnectTimeoutMs));
  1171. }
  1172. if (!subconn) {
  1173. UERRLOG("SuperFile %s is missing sub-file file %s",lname.get(),subname.str());
  1174. if (!fix||!doFix()) {
  1175. UERRLOG("Superfile %s FAILED",lname.get());
  1176. return;
  1177. }
  1178. root->removeTree(sub);
  1179. for (unsigned j=i+1;j<n; j++) {
  1180. sub = root->queryPropTree(path.clear().appendf("SubFile[@num=\"%d\"]",j+1).str());
  1181. if (sub)
  1182. sub->setPropInt("@num",j);
  1183. }
  1184. i--;
  1185. n--;
  1186. fixed = true;
  1187. continue;
  1188. }
  1189. subnum++;
  1190. Owned<IPropertyTree> subroot = subconn->getRoot();
  1191. Owned<IPropertyTreeIterator> iter = subroot->getElements("SuperOwner");
  1192. StringBuffer pname;
  1193. bool parentok=false;
  1194. ForEach(*iter) {
  1195. iter->query().getProp("@name",pname.clear());
  1196. if (strcmp(pname.str(),lname.get())==0)
  1197. parentok = true;
  1198. else {
  1199. CDfsLogicalFileName sdlname;
  1200. sdlname.set(pname.str());
  1201. StringBuffer sdquery;
  1202. sdlname.makeFullnameQuery(sdquery, DXB_SuperFile, true);
  1203. Owned<IRemoteConnection> sdconn = querySDS().connect(sdquery.str(),myProcessSession(),0, daliConnectTimeoutMs);
  1204. if (!conn) {
  1205. UWARNLOG("SubFile %s has missing owner superfile %s",sublname.get(),sdlname.get());
  1206. }
  1207. // make sure superfile exists
  1208. }
  1209. }
  1210. if (!parentok) {
  1211. UWARNLOG("SubFile %s is missing link to Superfile %s",sublname.get(),lname.get());
  1212. ForEach(*iter) {
  1213. iter->query().getProp("@name",pname.clear());
  1214. OUTLOG("Candidate %s",pname.str());
  1215. }
  1216. if (fix&&doFix()) {
  1217. Owned<IPropertyTree> t = createPTree("SuperOwner");
  1218. t->setProp("@name",lname.get());
  1219. subroot->addPropTree("SuperOwner",t.getClear());
  1220. }
  1221. }
  1222. }
  1223. else
  1224. subnum++;
  1225. }
  1226. if (fixed)
  1227. root->setPropInt("@numsubfiles",subnum);
  1228. i = 0;
  1229. byte fixstate = 0;
  1230. for (;;) {
  1231. bool err = false;
  1232. IPropertyTree *sub = root->queryPropTree(path.clear().appendf("SubFile[%d]",i+1).str());
  1233. if (sub) {
  1234. unsigned pn = sub->getPropInt("@num");
  1235. if (pn>subnum) {
  1236. UERRLOG("SuperFile %s: corrupt, subfile file part %d spurious",lname.get(),pn);
  1237. if (fixstate==0)
  1238. {
  1239. if (fix&&doFix())
  1240. fixstate = 1;
  1241. else
  1242. fixstate = 2;
  1243. }
  1244. if (fixstate==1) {
  1245. root->removeTree(sub);
  1246. fixed = true;
  1247. i--;
  1248. }
  1249. }
  1250. }
  1251. else
  1252. break;
  1253. i++;
  1254. }
  1255. if (n==0) {
  1256. IPropertyTree *sub = root->queryPropTree("Attr");
  1257. if (!isEmptyPTree(sub)&&!sub->queryProp("description")) {
  1258. if (fix) {
  1259. if (!fixed)
  1260. UERRLOG("FIX Empty Superfile %s contains non-empty Attr",lname.get());
  1261. root->removeTree(sub);
  1262. }
  1263. else if (sub->getPropInt64("@recordCount")||sub->getPropInt64("@size"))
  1264. UERRLOG("FAIL Empty Superfile %s contains non-empty Attr sz=%" I64F "d rc=%" I64F "d",lname.get(),sub->getPropInt64("@recordCount"),sub->getPropInt64("@size"));
  1265. }
  1266. }
  1267. if (fixed)
  1268. OUTLOG("Superfile %s FIXED - from %d to %d subfiles",lname.get(),n,subnum);
  1269. else
  1270. OUTLOG("Superfile %s OK - contains %d subfiles",lname.get(),n);
  1271. }
  1272. //=============================================================================
  1273. static void checksubfile(const char *lfn)
  1274. {
  1275. if (strcmp(lfn,"*")==0) {
  1276. class csubfilescan: public CSDSFileScanner
  1277. {
  1278. virtual bool checkFileOk(IPropertyTree &file,const char *filename)
  1279. {
  1280. return (file.hasProp("SuperOwner[1]"));
  1281. }
  1282. virtual bool checkSuperFileOk(IPropertyTree &file,const char *filename)
  1283. {
  1284. return (file.hasProp("SuperOwner[1]"));
  1285. }
  1286. virtual bool checkScopeOk(const char *scopename)
  1287. {
  1288. OUTLOG("Processing scope %s",scopename);
  1289. return true;
  1290. }
  1291. void processFile(IPropertyTree &root,StringBuffer &name)
  1292. {
  1293. try {
  1294. checksubfile(name.str());
  1295. }
  1296. catch (IException *e) {
  1297. EXCLOG(e,"processSuperFiles");
  1298. e->Release();
  1299. }
  1300. }
  1301. void processSuperFile(IPropertyTree &root,StringBuffer &name)
  1302. {
  1303. try {
  1304. checksubfile(name.str());
  1305. }
  1306. catch (IException *e) {
  1307. EXCLOG(e,"processSuperFiles");
  1308. e->Release();
  1309. }
  1310. }
  1311. public:
  1312. } subfilescan;
  1313. Owned<IRemoteConnection> conn = querySDS().connect("/Files", myProcessSession(), 0, 100000);
  1314. subfilescan.scan(conn,true,true);
  1315. return;
  1316. }
  1317. CDfsLogicalFileName lname;
  1318. lname.set(lfn);
  1319. StringBuffer query;
  1320. lname.makeFullnameQuery(query, DXB_File, true);
  1321. Owned<IRemoteConnection> conn = querySDS().connect(query.str(),myProcessSession(),0, daliConnectTimeoutMs);
  1322. if (!conn) {
  1323. lname.makeFullnameQuery(query.clear(), DXB_SuperFile, true);
  1324. conn.setown(querySDS().connect(query.str(),myProcessSession(),0, daliConnectTimeoutMs));
  1325. }
  1326. if (!conn) {
  1327. UERRLOG("Could not connect to %s",lfn);
  1328. UERRLOG("Subfile %s FAILED",lname.get());
  1329. return;
  1330. }
  1331. Owned<IPropertyTree> root = conn->getRoot();
  1332. Owned<IPropertyTreeIterator> iter = root->getElements("SuperOwner");
  1333. StringBuffer pname;
  1334. bool ok=true;
  1335. ForEach(*iter) {
  1336. iter->query().getProp("@name",pname.clear());
  1337. CDfsLogicalFileName sdlname;
  1338. sdlname.set(pname.str());
  1339. StringBuffer sdquery;
  1340. sdlname.makeFullnameQuery(sdquery, DXB_SuperFile, true);
  1341. Owned<IRemoteConnection> sdconn = querySDS().connect(sdquery.str(),myProcessSession(),0, daliConnectTimeoutMs);
  1342. if (!conn) {
  1343. UERRLOG("SubFile %s has missing owner superfile %s",lname.get(),sdlname.get());
  1344. ok = false;
  1345. }
  1346. else {
  1347. StringBuffer path;
  1348. IPropertyTree *sub = sdconn->queryRoot()->queryPropTree(path.clear().appendf("SubFile[@name=\"%s\"]",lname.get()).str());
  1349. if (!sub) {
  1350. UERRLOG("Superfile %s is not linked to %s",sdlname.get(),lname.get());
  1351. ok = false;
  1352. }
  1353. }
  1354. }
  1355. if (ok)
  1356. OUTLOG("SubFile %s OK",lname.get());
  1357. }
  1358. //=============================================================================
  1359. static void listexpires(const char * lfnmask, IUserDescriptor *user)
  1360. {
  1361. IDFAttributesIterator *iter = queryDistributedFileDirectory().getDFAttributesIterator(lfnmask,user,true,false);
  1362. ForEach(*iter) {
  1363. IPropertyTree &attr=iter->query();
  1364. if (attr.hasProp("@expireDays"))
  1365. {
  1366. unsigned expireDays = attr.getPropInt("@expireDays");
  1367. const char *name = attr.queryProp("@name");
  1368. const char *lastAccessed = attr.queryProp("@accessed");
  1369. if (lastAccessed && name&&*name) // NB: all files that have expireDays should have lastAccessed also
  1370. {
  1371. StringBuffer days;
  1372. if (0 == expireDays)
  1373. days.append("the sasha default number of days");
  1374. else
  1375. {
  1376. days.append(expireDays);
  1377. if (expireDays>1)
  1378. days.append(" days");
  1379. else
  1380. days.append(" day");
  1381. }
  1382. OUTLOG("%s, last accessed = %s, set to expire %s after last accessed", name, lastAccessed, days.str());
  1383. }
  1384. }
  1385. }
  1386. }
  1387. //=============================================================================
  1388. static void listrelationships(const char *primary,const char *secondary)
  1389. {
  1390. Owned<IFileRelationshipIterator> iter = queryDistributedFileDirectory().lookupFileRelationships(primary,secondary,NULL,NULL,S_LINK_RELATIONSHIP_KIND,NULL,NULL,NULL);
  1391. ForEach(*iter) {
  1392. OUTLOG("%s,%s,%s,%s,%s,%s,%s,%s",
  1393. iter->query().queryKind(),
  1394. iter->query().queryPrimaryFilename(),
  1395. iter->query().querySecondaryFilename(),
  1396. iter->query().queryPrimaryFields(),
  1397. iter->query().querySecondaryFields(),
  1398. iter->query().queryCardinality(),
  1399. iter->query().isPayload()?"payload":"",
  1400. iter->query().queryDescription());
  1401. }
  1402. }
  1403. //=============================================================================
  1404. int dfsperm(const char *obj,IUserDescriptor *user)
  1405. {
  1406. SecAccessFlags perm = SecAccess_None;
  1407. if (strchr(obj,'\\')||strchr(obj,'/')) {
  1408. Owned<IFileDescriptor> fd = createFileDescriptor();
  1409. RemoteFilename rfn;
  1410. rfn.setRemotePath(obj);
  1411. fd->setPart(0, rfn);
  1412. perm = queryDistributedFileDirectory().getFDescPermissions(fd,user,0);
  1413. }
  1414. else {
  1415. perm = queryDistributedFileDirectory().getFilePermissions(obj,user,0);
  1416. }
  1417. OUTLOG("perm %s = %d",obj,perm);
  1418. return perm;
  1419. }
  1420. //=============================================================================
  1421. static offset_t getCompressedSize(IDistributedFile *file)
  1422. { // this should be parallel! TBD
  1423. if (!file)
  1424. return (offset_t)-1;
  1425. offset_t ret = (offset_t)file->queryAttributes().getPropInt64("@compressedSize",-1);
  1426. if (ret==(offset_t)-1) {
  1427. try {
  1428. ret = 0;
  1429. Owned<IDistributedFilePartIterator> piter = file->getIterator();
  1430. ForEach(*piter) {
  1431. IDistributedFilePart &part = piter->query();
  1432. offset_t sz = (offset_t)-1;
  1433. for (unsigned c=0;c<part.numCopies();c++) {
  1434. RemoteFilename rfn;
  1435. part.getFilename(rfn,c);
  1436. try {
  1437. Owned<IFile> file = createIFile(rfn);
  1438. sz = file->size();
  1439. }
  1440. catch (IException *e) {
  1441. StringBuffer tmp("getCompressedSize(1): ");
  1442. rfn.getPath(tmp);
  1443. EXCLOG(e,tmp.str());
  1444. sz = (offset_t)-1;
  1445. e->Release();
  1446. }
  1447. if (sz!=(offset_t)-1)
  1448. break;
  1449. }
  1450. if (sz==(offset_t)-1) {
  1451. ret = (offset_t)-1;
  1452. break;
  1453. }
  1454. ret += sz;
  1455. }
  1456. }
  1457. catch (IException *e) {
  1458. EXCLOG(e,"getCompressedSize");
  1459. ret = (offset_t)-1;
  1460. e->Release();
  1461. }
  1462. }
  1463. return ret;
  1464. }
  1465. static void dfscompratio (const char *lname, IUserDescriptor *user)
  1466. {
  1467. Owned<IDistributedFile> file = queryDistributedFileDirectory().lookup(lname,user,false,false,false,nullptr,defaultPrivilegedUser);
  1468. StringBuffer out;
  1469. out.appendf("File %s ",lname);
  1470. if (file) {
  1471. bool compressed = file->isCompressed();
  1472. if (!compressed)
  1473. out.append("not ");
  1474. out.append("compressed, ");
  1475. offset_t size = file->getFileSize(true,false);
  1476. if (size==(offset_t)-1)
  1477. out.appendf("size not known");
  1478. else if (compressed) {
  1479. out.appendf("expanded size %" I64F "d, ",size);
  1480. offset_t csize = getCompressedSize(file);
  1481. if (csize==(offset_t)-1)
  1482. out.append("compressed size unknown");
  1483. else {
  1484. out.appendf("compressed size %" I64F "d",csize);
  1485. if (csize)
  1486. out.appendf(", Ratio %.2f:1 (%%%d)",(float)size/csize,(unsigned)(csize*100/size));
  1487. }
  1488. }
  1489. else
  1490. out.appendf("not compressed, size %" I64F "d",size);
  1491. }
  1492. else
  1493. out.appendf("File %s not found",lname);
  1494. outln(out.str());
  1495. }
  1496. //=============================================================================
  1497. static bool onlyNamePtree(IPropertyTree *t)
  1498. {
  1499. if (!t)
  1500. return true;
  1501. if (t->numUniq())
  1502. return false;
  1503. Owned<IAttributeIterator> ai = t->getAttributes();
  1504. if (ai->first()) {
  1505. if (strcmp(ai->queryName(),"@name")!=0)
  1506. return false;
  1507. if (ai->next())
  1508. return false;
  1509. }
  1510. const char *s = t->queryProp(NULL);
  1511. if (s&&*s)
  1512. return false;
  1513. return true;
  1514. }
  1515. static bool countScopeChildren(IPropertyTree *t,unsigned &files, unsigned &sfiles, unsigned &scopes, unsigned &other)
  1516. {
  1517. scopes = 0;
  1518. files = 0;
  1519. sfiles = 0;
  1520. other = 0;
  1521. if (!t)
  1522. return false;
  1523. Owned<IPropertyTreeIterator> it = t->getElements("*");
  1524. ForEach(*it) {
  1525. IPropertyTree *st = &it->query();
  1526. const char *s = st?st->queryName():NULL;
  1527. if (!s)
  1528. other++;
  1529. else if (stricmp(s,queryDfsXmlBranchName(DXB_File))==0)
  1530. files++;
  1531. else if (stricmp(s,queryDfsXmlBranchName(DXB_SuperFile))==0)
  1532. sfiles++;
  1533. else if (stricmp(s,queryDfsXmlBranchName(DXB_Scope))==0)
  1534. scopes++;
  1535. else
  1536. other++;
  1537. }
  1538. return (other!=0)||(files!=0)||(sfiles!=0)||(scopes!=0)||(!onlyNamePtree(t));
  1539. }
  1540. static void dfsscopes(const char *name, IUserDescriptor *user)
  1541. {
  1542. bool wild = isWild(name);
  1543. Owned<IDFScopeIterator> iter = queryDistributedFileDirectory().getScopeIterator(user,wild?NULL:name,true,true);
  1544. StringBuffer ln;
  1545. ForEach(*iter) {
  1546. CDfsLogicalFileName dlfn;
  1547. StringBuffer scope;
  1548. if (!wild&&name&&*name&&(strcmp(name,".")!=0))
  1549. scope.append(name).append("::");
  1550. scope.append(iter->query());
  1551. if (wild&&!WildMatch(scope.str(),name))
  1552. continue;
  1553. dlfn.set(scope.str(),"x");
  1554. StringBuffer s;
  1555. dlfn.makeScopeQuery(s,true);
  1556. ln.clear().append("SCOPE '").append(iter->query()).append('\'');
  1557. Owned<IRemoteConnection> conn = querySDS().connect(s.str(),myProcessSession(),RTM_LOCK_READ, daliConnectTimeoutMs);
  1558. if (!conn)
  1559. UERRLOG("%s - Could not connect using %s",ln.str(),s.str());
  1560. else {
  1561. unsigned files;
  1562. unsigned sfiles;
  1563. unsigned scopes;
  1564. unsigned other;
  1565. if (countScopeChildren(conn->queryRoot(),files,sfiles,scopes,other)) {
  1566. ln.appendf(" Files=%d SuperFiles=%d Scopes=%d",files,sfiles,scopes);
  1567. if (other)
  1568. ln.appendf(" others=%d",other);
  1569. OUTLOG("%s",ln.str());
  1570. }
  1571. else
  1572. OUTLOG("%s EMPTY",ln.str());
  1573. }
  1574. }
  1575. }
  1576. //=============================================================================
  1577. static bool recursiveCheckEmptyScope(IPropertyTree &ct)
  1578. {
  1579. Owned<IPropertyTreeIterator> iter = ct.getElements("*");
  1580. ForEach(*iter) {
  1581. IPropertyTree &item = iter->query();
  1582. const char *n = item.queryName();
  1583. if (!n||(strcmp(n,queryDfsXmlBranchName(DXB_Scope))!=0))
  1584. return false;
  1585. if (!recursiveCheckEmptyScope(item))
  1586. return false;
  1587. }
  1588. return true;
  1589. }
  1590. static void cleanscopes(IUserDescriptor *user)
  1591. {
  1592. Owned<IDFScopeIterator> iter = queryDistributedFileDirectory().getScopeIterator(user, NULL,true,true);
  1593. CDfsLogicalFileName dlfn;
  1594. StringBuffer s;
  1595. StringArray toremove;
  1596. ForEach(*iter) {
  1597. CDfsLogicalFileName dlfn;
  1598. StringBuffer scope;
  1599. scope.append(iter->query());
  1600. dlfn.set(scope.str(),"x");
  1601. dlfn.makeScopeQuery(s.clear(),true);
  1602. Owned<IRemoteConnection> conn = querySDS().connect(s.str(),myProcessSession(),RTM_LOCK_READ, daliConnectTimeoutMs);
  1603. if (!conn)
  1604. UWARNLOG("Could not connect to '%s' using %s",iter->query(),s.str());
  1605. else {
  1606. if (recursiveCheckEmptyScope(*conn->queryRoot())) {
  1607. toremove.append(iter->query());
  1608. PROGLOG("EMPTY %s, %s",iter->query(),s.str());
  1609. }
  1610. }
  1611. }
  1612. iter.clear();
  1613. ForEachItemIn(i,toremove) {
  1614. PROGLOG("REMOVE %s",toremove.item(i));
  1615. try {
  1616. queryDistributedFileDirectory().removeEmptyScope(toremove.item(i));
  1617. }
  1618. catch (IException *e) {
  1619. EXCLOG(e,"checkScopes");
  1620. e->Release();
  1621. }
  1622. }
  1623. }
  1624. static void normalizeFileNames(IUserDescriptor *user, const char *name)
  1625. {
  1626. if (!name)
  1627. name = "*";
  1628. Owned<IDFAttributesIterator> iter = queryDistributedFileDirectory().getDFAttributesIterator(name, user, true, true);
  1629. ForEach(*iter)
  1630. {
  1631. IPropertyTree &attr = iter->query();
  1632. const char *lfn = attr.queryProp("@name");
  1633. CDfsLogicalFileName dlfn;
  1634. dlfn.enableSelfScopeTranslation(false);
  1635. dlfn.set(lfn);
  1636. Owned<IDistributedFile> dFile;
  1637. try
  1638. {
  1639. dFile.setown(queryDistributedFileDirectory().lookup(dlfn, user, true, false, false, nullptr, defaultPrivilegedUser, 30000)); // 30 sec timeout
  1640. if (!dFile)
  1641. UWARNLOG("Could not find file lfn = %s", dlfn.get());
  1642. }
  1643. catch (IException *e)
  1644. {
  1645. if (SDSExcpt_LockTimeout != e->errorCode())
  1646. throw;
  1647. VStringBuffer msg("Connecting to '%s'", lfn);
  1648. EXCLOG(e, msg.str());
  1649. e->Release();
  1650. }
  1651. if (dFile)
  1652. {
  1653. CDfsLogicalFileName newDlfn;
  1654. newDlfn.set(lfn);
  1655. if (!streq(newDlfn.get(), dlfn.get()))
  1656. {
  1657. PROGLOG("File: '%s', renaming to: '%s'", dlfn.get(), newDlfn.get());
  1658. try
  1659. {
  1660. dFile->rename(newDlfn.get(), user);
  1661. }
  1662. catch (IException *e)
  1663. {
  1664. VStringBuffer msg("Failure to rename file '%s'", lfn);
  1665. EXCLOG(e, msg.str());
  1666. e->Release();
  1667. }
  1668. }
  1669. }
  1670. }
  1671. }
  1672. //=============================================================================
  1673. static void listworkunits(const char *test, const char *min, const char *max)
  1674. {
  1675. Owned<IRemoteConnection> conn = querySDS().connect("/", myProcessSession(), 0, daliConnectTimeoutMs);
  1676. Owned<IPropertyTreeIterator> iter = conn->queryRoot()->getElements("WorkUnits/*");
  1677. ForEach(*iter)
  1678. {
  1679. IPropertyTree &e=iter->query();
  1680. if (test&&*test) {
  1681. const char *tval = strchr(test,'=');
  1682. if (!tval)
  1683. {
  1684. UERRLOG("missing '=' in %s",test);
  1685. return;
  1686. }
  1687. StringBuffer prop;
  1688. if (*test!='@')
  1689. prop.append('@');
  1690. prop.append(tval-test,test);
  1691. tval++;
  1692. const char *val = e.queryProp(prop.str());
  1693. if (!val||(strcmp(val,tval)!=0))
  1694. continue;
  1695. if (min &&(strcmp(e.queryName(),min)<0))
  1696. continue;
  1697. if (max &&(strcmp(e.queryName(),max)>0))
  1698. continue;
  1699. }
  1700. outln(e.queryName());
  1701. }
  1702. }
  1703. //=============================================================================
  1704. static void listmatches(const char *path, const char *match, const char *pval)
  1705. {
  1706. Owned<IRemoteConnection> conn = querySDS().connect(path, myProcessSession(), 0, daliConnectTimeoutMs);
  1707. if (!conn)
  1708. {
  1709. PROGLOG("Failed to connect to %s", path);
  1710. return;
  1711. }
  1712. StringBuffer output("Listing matches for path=");
  1713. output.append(path);
  1714. if (match)
  1715. {
  1716. output.append(", match=").append(match);
  1717. if (pval)
  1718. output.append(", property value(s) = ").append(pval);
  1719. }
  1720. outln(output);
  1721. StringArray pvals;
  1722. if (pval)
  1723. pvals.appendList(pval, ",");
  1724. Owned<IPropertyTreeIterator> iter = conn->queryRoot()->getElements(match?match:"*", iptiter_remote);
  1725. ForEach(*iter)
  1726. {
  1727. IPropertyTree &e=iter->query();
  1728. output.clear().append(e.queryName());
  1729. bool first = true;
  1730. ForEachItemIn(pv, pvals)
  1731. {
  1732. const char *val = e.queryProp(pvals.item(pv));
  1733. if (val)
  1734. {
  1735. if (first)
  1736. {
  1737. first = false;
  1738. output.append(" = ").append(val);
  1739. }
  1740. else
  1741. output.append(',').append(val);
  1742. }
  1743. }
  1744. outln(output.str());
  1745. }
  1746. }
  1747. //=============================================================================
  1748. static void dfsreplication(const char *clusterMask, const char *lfnMask, unsigned redundancy, bool dryRun)
  1749. {
  1750. StringBuffer findXPath("//File");
  1751. if (clusterMask && !streq("*", clusterMask))
  1752. findXPath.appendf("[Cluster/@name=\"%s\"]", clusterMask);
  1753. if (lfnMask && !streq("*", lfnMask))
  1754. findXPath.appendf("[@name=\"%s\"]", lfnMask);
  1755. const char *basePath = "/Files";
  1756. const char *propToSet = "@redundancy";
  1757. const char *defVal = "1"; // default reduncancy value, attribute not set/stored if equal to default.
  1758. StringBuffer value;
  1759. value.append(redundancy);
  1760. StringBuffer clusterFilter("Cluster");
  1761. if (clusterMask && !streq("*", clusterMask))
  1762. clusterFilter.appendf("[@name=\"%s\"]", clusterMask);
  1763. Owned<IRemoteConnection> conn = querySDS().connect(basePath, myProcessSession(), 0, daliConnectTimeoutMs);
  1764. Owned<IPropertyTreeIterator> iter = conn->getElements(findXPath);
  1765. ForEach(*iter)
  1766. {
  1767. IPropertyTree &file = iter->query();
  1768. Owned<IPropertyTreeIterator> clusterIter = file.getElements(clusterFilter);
  1769. ForEach(*clusterIter)
  1770. {
  1771. IPropertyTree &cluster = clusterIter->query();
  1772. const char *oldValue = cluster.queryProp(propToSet);
  1773. if ((!oldValue && !streq(value, defVal)) || (oldValue && !streq(value, oldValue)))
  1774. {
  1775. const char *fileName = file.queryProp("OrigName");
  1776. const char *clusterName = cluster.queryProp("@name");
  1777. VStringBuffer msg("File=%s on cluster=%s - %s %s to %s", fileName, clusterName, dryRun?"Would set":"Setting", propToSet, value.str());
  1778. if (oldValue)
  1779. msg.appendf(" [old value = %s]", oldValue);
  1780. PROGLOG("%s", msg.str());
  1781. if (!dryRun)
  1782. {
  1783. if (!streq(value, defVal))
  1784. cluster.setProp(propToSet, value);
  1785. else
  1786. cluster.removeProp(propToSet);
  1787. }
  1788. }
  1789. }
  1790. }
  1791. }
  1792. static void holdlock(const char *logicalFile, const char *mode, IUserDescriptor *userDesc)
  1793. {
  1794. bool write;
  1795. if (strieq(mode, "read"))
  1796. write = false;
  1797. else if (strieq(mode, "write"))
  1798. write = true;
  1799. else
  1800. throw MakeStringException(0,"Invalid mode: %s", mode);
  1801. PROGLOG("Looking up file: %s, mode=%s", logicalFile, mode);
  1802. Owned<IDistributedFile> file = queryDistributedFileDirectory().lookup(logicalFile, userDesc, write, false, false, NULL, defaultPrivilegedUser, 5000);
  1803. if (!file)
  1804. {
  1805. UERRLOG("File not found: %s", logicalFile);
  1806. return;
  1807. }
  1808. OwnedPtr<DistributedFilePropertyLock> writeLock;
  1809. if (write)
  1810. writeLock.setown(new DistributedFilePropertyLock(file));
  1811. PROGLOG("File: %s, locked, mode=%s - press a key to release", logicalFile, mode);
  1812. getchar();
  1813. }
  1814. static const char *getNum(const char *s,unsigned &num)
  1815. {
  1816. while (*s&&!isdigit(*s))
  1817. s++;
  1818. num = 0;
  1819. while (isdigit(*s)) {
  1820. num = num*10+*s-'0';
  1821. s++;
  1822. }
  1823. return s;
  1824. }
  1825. static void displayGraphTiming(const char * name, unsigned time)
  1826. {
  1827. unsigned gn;
  1828. const char *s = getNum(name,gn);
  1829. unsigned sn;
  1830. s = getNum(s,sn);
  1831. if (gn&&sn) {
  1832. const char *gs = strchr(name,'(');
  1833. unsigned gid = 0;
  1834. if (gs)
  1835. getNum(gs+1,gid);
  1836. OUTLOG("\"%s\",%d,%d,%d,%d,%d",name,gn,sn,gid,time,(time/60000));
  1837. }
  1838. }
  1839. static void workunittimings(const char *wuid)
  1840. {
  1841. StringBuffer path;
  1842. path.append("/WorkUnits/").append(wuid);
  1843. Owned<IRemoteConnection> conn = querySDS().connect(path, myProcessSession(), 0, daliConnectTimeoutMs);
  1844. if (!conn) {
  1845. UERRLOG("WU %s not found",wuid);
  1846. return;
  1847. }
  1848. IPropertyTree *wu = conn->queryRoot();
  1849. StringBuffer name;
  1850. outln("Name,graph,sub,gid,time ms,time min");
  1851. if (wu->hasProp("Statistics"))
  1852. {
  1853. Owned<IPropertyTreeIterator> iter = wu->getElements("Statistics/Statistic");
  1854. ForEach(*iter)
  1855. {
  1856. if (iter->query().getProp("@desc",name.clear()))
  1857. {
  1858. if ((name.length()>11)&&(memcmp("Graph graph",name.str(),11)==0))
  1859. {
  1860. unsigned time = (unsigned)(iter->query().getPropInt64("@value") / 1000000);
  1861. displayGraphTiming(name.str(), time);
  1862. }
  1863. }
  1864. }
  1865. }
  1866. else
  1867. {
  1868. Owned<IPropertyTreeIterator> iter = wu->getElements("Timings/Timing");
  1869. ForEach(*iter)
  1870. {
  1871. if (iter->query().getProp("@name",name.clear()))
  1872. {
  1873. if ((name.length()>11)&&(memcmp("Graph graph",name.str(),11)==0))
  1874. {
  1875. unsigned time = iter->query().getPropInt("@duration");
  1876. displayGraphTiming(name.str(), time);
  1877. }
  1878. }
  1879. }
  1880. }
  1881. }
  1882. //=============================================================================
  1883. static void serverlist(const char *mask)
  1884. {
  1885. Owned<IRemoteConnection> conn = querySDS().connect( "/Environment/Software", myProcessSession(), RTM_LOCK_READ, SDS_LOCK_TIMEOUT);
  1886. if (!conn)
  1887. throw MakeStringException(0,"Failed to connect to Environment/Software");
  1888. IPropertyTree* root = conn->queryRoot();
  1889. Owned<IPropertyTreeIterator> services= root->getElements("*");
  1890. ForEach(*services) {
  1891. IPropertyTree& t = services->query();
  1892. const char *name = t.queryName();
  1893. if (name) {
  1894. if (!mask||!*mask||WildMatch(name,mask)) {
  1895. Owned<IPropertyTreeIterator> insts = t.getElements("Instance");
  1896. ForEach(*insts) {
  1897. StringBuffer ips;
  1898. insts->query().getProp("@netAddress",ips);
  1899. StringBuffer dir;
  1900. insts->query().getProp("@directory",dir);
  1901. OUTLOG("%s,%s,%s",name,ips.str(),dir.str());
  1902. }
  1903. }
  1904. }
  1905. }
  1906. }
  1907. //=============================================================================
  1908. static void clusterlist(const char *mask)
  1909. {
  1910. Owned<IRemoteConnection> conn = querySDS().connect("/Environment/Software", myProcessSession(), RTM_LOCK_READ, SDS_LOCK_TIMEOUT);
  1911. if (!conn)
  1912. throw MakeStringException(0,"Failed to connect to Environment/Software");
  1913. IPropertyTree* root = conn->queryRoot();
  1914. Owned<IPropertyTreeIterator> clusters;
  1915. clusters.setown(root->getElements("ThorCluster"));
  1916. ForEach(*clusters) {
  1917. }
  1918. clusters.setown(root->getElements("RoxieCluster"));
  1919. ForEach(*clusters) {
  1920. }
  1921. clusters.setown(root->getElements("EclAgentProcess"));
  1922. ForEach(*clusters) {
  1923. }
  1924. }
  1925. static unsigned clustersToGroups(IPropertyTree *envroot,const StringArray &cmplst,StringArray &cnames,StringArray &groups,bool *done)
  1926. {
  1927. if (!envroot)
  1928. return 0;
  1929. for (int roxie=0;roxie<2;roxie++) {
  1930. Owned<IPropertyTreeIterator> clusters= envroot->getElements(roxie?"RoxieCluster":"ThorCluster");
  1931. unsigned ret = 0;
  1932. ForEach(*clusters) {
  1933. IPropertyTree &cluster = clusters->query();
  1934. const char *name = cluster.queryProp("@name");
  1935. if (name&&*name) {
  1936. ForEachItemIn(i,cmplst) {
  1937. const char *s = cmplst.item(i);
  1938. assertex(s);
  1939. if ((strcmp(s,"*")==0)||WildMatch(name,s,true)) {
  1940. const char *group = cluster.queryProp("@nodeGroup");
  1941. if (!group||!*group)
  1942. group = name;
  1943. bool found = false;
  1944. ForEachItemIn(j,groups)
  1945. if (strcmp(groups.item(j),group)==0)
  1946. found = true;
  1947. if (!found) {
  1948. cnames.append(name);
  1949. groups.append(group);
  1950. if (done)
  1951. done[i] =true;
  1952. break;
  1953. }
  1954. }
  1955. }
  1956. }
  1957. }
  1958. }
  1959. return groups.ordinality();
  1960. }
  1961. static void clusterlist()
  1962. {
  1963. Owned<IRemoteConnection> conn = querySDS().connect("/Environment/Software", myProcessSession(), RTM_LOCK_READ, daliConnectTimeoutMs);
  1964. if (!conn) {
  1965. UERRLOG("Could not connect to /Environment/Software");
  1966. return;
  1967. }
  1968. StringArray list;
  1969. list.append("*");
  1970. StringArray groups;
  1971. StringArray cnames;
  1972. bool *done = (bool *)calloc(list.ordinality(),sizeof(bool));
  1973. clustersToGroups(conn->queryRoot(),list,cnames,groups,done);
  1974. free(done);
  1975. ForEachItemIn(i,cnames)
  1976. OUTLOG("%s,%s",cnames.item(i),groups.item(i));
  1977. }
  1978. //=============================================================================
  1979. static void auditlog(const char *froms, const char *tos, const char *matchs)
  1980. {
  1981. CDateTime from;
  1982. try {
  1983. from.setDateString(froms);
  1984. }
  1985. catch (IException *) {
  1986. UERRLOG("%s: invalid date (format YYYY-MM-DD)",froms);
  1987. throw;
  1988. }
  1989. CDateTime to;
  1990. try {
  1991. to.setDateString(tos);
  1992. }
  1993. catch (IException *) {
  1994. UERRLOG("%s: invalid date (format YYYY-MM-DD)",tos);
  1995. throw;
  1996. }
  1997. StringAttrArray res;
  1998. queryAuditLogs(from,to,matchs,res);
  1999. ForEachItemIn(i,res)
  2000. outln(res.item(i).text.get());
  2001. }
  2002. //=============================================================================
  2003. static void coalesce()
  2004. {
  2005. const char *daliDataPath = NULL;
  2006. const char *remoteBackupLocation = NULL;
  2007. Owned<IStoreHelper> iStoreHelper = createStoreHelper(NULL, daliDataPath, remoteBackupLocation, SH_External|SH_RecoverFromIncErrors);
  2008. unsigned baseEdition = iStoreHelper->queryCurrentEdition();
  2009. StringBuffer storeFilename(daliDataPath);
  2010. iStoreHelper->getCurrentStoreFilename(storeFilename);
  2011. OUTLOG("Loading store: %s", storeFilename.str());
  2012. Owned<IPropertyTree> root = createPTreeFromXMLFile(storeFilename.str());
  2013. OUTLOG("Loaded: %s", storeFilename.str());
  2014. if (baseEdition != iStoreHelper->queryCurrentEdition())
  2015. OUTLOG("Store was changed by another process prior to coalesce. Exiting.");
  2016. else
  2017. {
  2018. if (!iStoreHelper->loadDeltas(root))
  2019. OUTLOG("Nothing to coalesce");
  2020. else
  2021. iStoreHelper->saveStore(root, &baseEdition);
  2022. }
  2023. }
  2024. //=============================================================================
  2025. static void mpping(const char *eps)
  2026. {
  2027. SocketEndpoint ep(eps);
  2028. Owned<INode> node = createINode(ep);
  2029. Owned<IGroup> grp = createIGroup(1,&ep);
  2030. Owned<ICommunicator> comm = createCommunicator(grp,true);
  2031. unsigned start = msTick();
  2032. if (!comm->verifyConnection(0,60*1000))
  2033. UERRLOG("MPping %s failed",eps);
  2034. else
  2035. OUTLOG("MPping %s succeeded in %d",eps,msTick()-start);
  2036. }
  2037. //=============================================================================
  2038. static void daliping(const char *dalis,unsigned connecttime,unsigned n)
  2039. {
  2040. OUTLOG("Dali(%s) connect time: %d ms",dalis,connecttime);
  2041. if (!n)
  2042. return;
  2043. StringBuffer qname("TESTINGQ_");
  2044. SocketEndpoint ep;
  2045. ep.setLocalHost(0);
  2046. ep.getUrlStr(qname);
  2047. Owned<INamedQueueConnection> qconn;
  2048. qconn.setown(createNamedQueueConnection(0));
  2049. Owned<IQueueChannel> channel;
  2050. channel.setown(qconn->open(qname.str()));
  2051. MemoryBuffer mb;
  2052. while (channel->probe()) {
  2053. mb.clear();
  2054. channel->get(mb);
  2055. }
  2056. unsigned max = 0;
  2057. unsigned tot = 0;
  2058. for (unsigned i=0;i<=n;i++) {
  2059. mb.clear().append("Hello").append(i);
  2060. ep.serialize(mb);
  2061. unsigned start = msTick();
  2062. channel->put(mb);
  2063. channel->get(mb);
  2064. if (i) { // ignore first
  2065. unsigned t = msTick()-start;
  2066. if (t>max)
  2067. max = t;
  2068. tot += t;
  2069. OUTLOG("Dali(%s) ping %d ms",dalis,t);
  2070. if (i+1<n)
  2071. Sleep(1000);
  2072. }
  2073. }
  2074. OUTLOG("Dali(%s) ping avg = %d max = %d ms",dalis,tot/n,max);
  2075. }
  2076. //=============================================================================
  2077. static void convertBinBranch(IPropertyTree &cluster,const char *branch)
  2078. {
  2079. StringBuffer query(branch);
  2080. query.append("/data");
  2081. IPropertyTree *t;
  2082. MemoryBuffer buf;
  2083. cluster.getPropBin(query.str(),buf);
  2084. if (buf.length()) {
  2085. StringBuffer xml;
  2086. xml.append(buf.length(),buf.toByteArray());
  2087. t = createPTreeFromXMLString(xml.str());
  2088. cluster.removeProp(query.str());
  2089. cluster.addPropTree(query.str(),t);
  2090. }
  2091. }
  2092. static void getxref(const char *dst)
  2093. {
  2094. Owned<IRemoteConnection> conn = querySDS().connect("DFU/XREF",myProcessSession(),RTM_LOCK_READ, daliConnectTimeoutMs);
  2095. Owned<IPropertyTree> root = createPTreeFromIPT(conn->getRoot());
  2096. Owned<IPropertyTreeIterator> iter = root->getElements("Cluster");
  2097. ForEach(*iter) {
  2098. IPropertyTree &cluster = iter->query();
  2099. convertBinBranch(cluster,"Directories");
  2100. convertBinBranch(cluster,"Lost");
  2101. convertBinBranch(cluster,"Found");
  2102. convertBinBranch(cluster,"Orphans");
  2103. convertBinBranch(cluster,"Messages");
  2104. }
  2105. Owned<IFile> f = createIFile(dst);
  2106. Owned<IFileIO> io = f->open(IFOcreate);
  2107. Owned<IFileIOStream> fstream = createBufferedIOStream(io);
  2108. toXML(root, *fstream); // formatted (default)
  2109. OUTLOG("DFU/XREF saved in '%s'",dst);
  2110. conn->close();
  2111. }
  2112. struct CTreeItem : public CInterface
  2113. {
  2114. String *tail;
  2115. CTreeItem *parent;
  2116. unsigned index;
  2117. offset_t startOffset;
  2118. offset_t endOffset;
  2119. offset_t adjust;
  2120. bool supressidx;
  2121. CTreeItem(CTreeItem *_parent, String *_tail, unsigned _index, offset_t _startOffset)
  2122. {
  2123. parent = LINK(_parent);
  2124. startOffset = _startOffset;
  2125. endOffset = 0;
  2126. adjust = 0;
  2127. index = _index;
  2128. supressidx = true;
  2129. tail = _tail;
  2130. }
  2131. ~CTreeItem()
  2132. {
  2133. if (parent)
  2134. parent->Release();
  2135. ::Release(tail);
  2136. }
  2137. void getXPath(StringBuffer &xpath)
  2138. {
  2139. if (parent)
  2140. parent->getXPath(xpath);
  2141. xpath.append('/').append(tail->str());
  2142. if ((index!=0)||tail->IsShared())
  2143. xpath.append('[').append(index+1).append(']');
  2144. }
  2145. offset_t size() { return endOffset?(endOffset-startOffset):0; }
  2146. offset_t adjustedSize(bool &adjusted) { adjusted = (adjust!=0); return size()-adjust; }
  2147. };
  2148. class CXMLSizesParser : public CInterface
  2149. {
  2150. Owned<IPullPTreeReader> xmlReader;
  2151. PTreeReaderOptions xmlOptions;
  2152. double pc;
  2153. class CParse : implements IPTreeNotifyEvent, public CInterface
  2154. {
  2155. CIArrayOf<CTreeItem> stack;
  2156. String * levtail;
  2157. CIArrayOf<CTreeItem> arr;
  2158. unsigned limit;
  2159. __int64 totalSize;
  2160. static int _sortF(CInterface * const *_left, CInterface * const *_right)
  2161. {
  2162. CTreeItem **left = (CTreeItem **)_left;
  2163. CTreeItem **right = (CTreeItem **)_right;
  2164. offset_t leftSize = (*left)->size();
  2165. offset_t rightSize = (*right)->size();
  2166. if (rightSize > leftSize)
  2167. return +1;
  2168. else if (rightSize < leftSize)
  2169. return -1;
  2170. else
  2171. return 0;
  2172. }
  2173. public:
  2174. IMPLEMENT_IINTERFACE;
  2175. CParse(unsigned __int64 _totalSize, double limitpc) : totalSize(_totalSize)
  2176. {
  2177. levtail = NULL;
  2178. limit = (unsigned)((double)totalSize*limitpc/100.0);
  2179. }
  2180. void reset()
  2181. {
  2182. stack.kill();
  2183. }
  2184. // IPTreeNotifyEvent
  2185. virtual void beginNode(const char *tag, offset_t startOffset)
  2186. {
  2187. String *tail = levtail;
  2188. if (levtail&&(0 == strcmp(tag, levtail->str())))
  2189. tail->Link();
  2190. else
  2191. tail = new String(tag);
  2192. levtail = NULL; // opening new child
  2193. CTreeItem *parent = stack.empty()?NULL:&stack.tos();
  2194. CTreeItem *item = new CTreeItem(parent, tail, tail->getLinkCount(), startOffset);
  2195. stack.append(*item);
  2196. }
  2197. virtual void newAttribute(const char *tag, const char *value)
  2198. {
  2199. }
  2200. virtual void beginNodeContent(const char *tag)
  2201. {
  2202. }
  2203. virtual void endNode(const char *tag, unsigned length, const void *value, bool binary, offset_t endOffset)
  2204. {
  2205. CTreeItem *tos = &stack.tos();
  2206. assertex(tos);
  2207. tos->endOffset = endOffset;
  2208. bool adjusted;
  2209. offset_t sz = tos->adjustedSize(adjusted);
  2210. if (sz>=limit)
  2211. {
  2212. CTreeItem *parent = tos->parent;
  2213. while (parent) {
  2214. parent->adjust += sz;
  2215. parent = parent->parent;
  2216. }
  2217. tos->Link();
  2218. arr.append(*tos);
  2219. levtail = tos->tail;
  2220. }
  2221. else
  2222. levtail = NULL;
  2223. stack.pop();
  2224. }
  2225. void printFullResults()
  2226. {
  2227. arr.sort(_sortF);
  2228. ForEachItemIn(m, arr)
  2229. {
  2230. CTreeItem &match = arr.item(m);
  2231. StringBuffer xpath;
  2232. match.getXPath(xpath);
  2233. printf("xpath=%s, size=%" I64F "d\n", xpath.str(), match.size());
  2234. }
  2235. }
  2236. void printResultTree()
  2237. {
  2238. if (!totalSize)
  2239. return;
  2240. StringBuffer res;
  2241. ForEachItemIn(i, arr) {
  2242. CTreeItem &item = arr.item(i);
  2243. bool adjusted;
  2244. offset_t sz = item.adjustedSize(adjusted);
  2245. if (sz>=limit) {
  2246. res.clear();
  2247. item.getXPath(res);
  2248. if (adjusted)
  2249. res.append(" (rest)");
  2250. res.padTo(40);
  2251. res.appendf(" %10" I64F "d(%5.2f%%)",sz,((float)sz*100.0)/(float)totalSize);
  2252. printf("%s\n",res.str());
  2253. }
  2254. }
  2255. }
  2256. } *parser;
  2257. public:
  2258. CXMLSizesParser(const char *fName, PTreeReaderOptions _xmlOptions=ptr_none, double _pc=1.0) : xmlOptions(_xmlOptions), pc(_pc) { go(fName); }
  2259. ~CXMLSizesParser() { ::Release(parser); }
  2260. void go(const char *fName)
  2261. {
  2262. OwnedIFile ifile = createIFile(fName);
  2263. OwnedIFileIO ifileio = ifile->open(IFOread);
  2264. if (!ifileio)
  2265. throw MakeStringException(0, "Failed to open: %s", ifile->queryFilename());
  2266. parser = new CParse(ifileio->size(), pc);
  2267. Owned<IIOStream> stream = createIOStream(ifileio);
  2268. xmlReader.setown(createPullXMLStreamReader(*stream, *parser, xmlOptions));
  2269. }
  2270. void printResultTree()
  2271. {
  2272. parser->printResultTree();
  2273. }
  2274. virtual bool next()
  2275. {
  2276. return xmlReader->next();
  2277. }
  2278. virtual void reset()
  2279. {
  2280. parser->reset();
  2281. xmlReader->reset();
  2282. }
  2283. };
  2284. static void xmlSize(const char *filename, double pc)
  2285. {
  2286. try
  2287. {
  2288. OwnedIFile iFile = createIFile(filename);
  2289. if (!iFile->exists())
  2290. OUTLOG("File '%s' not found", filename);
  2291. else
  2292. {
  2293. Owned<CXMLSizesParser> parser = new CXMLSizesParser((filename&&*filename)?filename:"dalisds.xml", ptr_none, pc);
  2294. while (parser->next())
  2295. ;
  2296. parser->printResultTree();
  2297. }
  2298. }
  2299. catch (IException *e)
  2300. {
  2301. pexception("xmlSize", e);
  2302. e->Release();
  2303. }
  2304. }
  2305. static void translateToXpath(const char *logicalfile, DfsXmlBranchKind tailType=DXB_File)
  2306. {
  2307. CDfsLogicalFileName lfn;
  2308. lfn.set(logicalfile);
  2309. StringBuffer str;
  2310. OUTLOG("%s", lfn.makeFullnameQuery(str, tailType).str());
  2311. }
  2312. //=============================================================================
  2313. static bool begins(const char *&ln,const char *pat)
  2314. {
  2315. size32_t sz = strlen(pat);
  2316. if (memicmp(ln,pat,sz)==0) {
  2317. ln += sz;
  2318. return true;
  2319. }
  2320. return false;
  2321. }
  2322. static void dalilocks(const char *ipPattern, bool files)
  2323. {
  2324. Owned<ILockInfoCollection> lockInfoCollection = querySDS().getLocks(ipPattern, files ? "/Files/*" : NULL);
  2325. bool headers = true;
  2326. CDfsLogicalFileName dlfn;
  2327. for (unsigned l=0; l<lockInfoCollection->queryLocks(); l++)
  2328. {
  2329. ILockInfo &lockInfo = lockInfoCollection->queryLock(l);
  2330. if (files)
  2331. {
  2332. if (!dlfn.setFromXPath(lockInfo.queryXPath()))
  2333. continue;
  2334. }
  2335. if (0 == lockInfo.queryConnections())
  2336. continue;
  2337. StringBuffer lockFormat;
  2338. lockInfo.toString(lockFormat, 1, headers, files ? dlfn.get() : NULL);
  2339. headers = false;
  2340. PROGLOG("%s", lockFormat.str());
  2341. }
  2342. if (headers) // if still true, no locks matched
  2343. {
  2344. printf("No lock(s) found\n");
  2345. return;
  2346. }
  2347. }
  2348. //=============================================================================
  2349. static void unlock(const char *pattern, bool files)
  2350. {
  2351. Owned<ILockInfoCollection> lockInfoCollection = querySDS().getLocks(NULL, files ? "/Files/*" : pattern);
  2352. for (unsigned l=0; l<lockInfoCollection->queryLocks(); l++)
  2353. {
  2354. ILockInfo &lockInfo = lockInfoCollection->queryLock(l);
  2355. bool match = false;
  2356. if (files)
  2357. {
  2358. CDfsLogicalFileName dlfn;
  2359. dlfn.setAllowWild(true);
  2360. if (dlfn.setFromXPath(lockInfo.queryXPath()))
  2361. match = WildMatch(dlfn.get(), pattern);
  2362. }
  2363. else
  2364. match = WildMatch(lockInfo.queryXPath(), pattern);
  2365. if (match)
  2366. {
  2367. for (unsigned c=0; c<lockInfo.queryConnections(); c++)
  2368. {
  2369. ConnectionId connectionId = lockInfo.queryLockData(c).connectionId;
  2370. bool disconnect = false; // TBD?
  2371. MemoryBuffer mb;
  2372. mb.append("unlock").append(connectionId).append(disconnect);
  2373. getDaliDiagnosticValue(mb);
  2374. bool success;
  2375. mb.read(success);
  2376. if (!success)
  2377. PROGLOG("Lock %" I64F "x not found",connectionId);
  2378. else
  2379. {
  2380. StringBuffer connectionInfo;
  2381. mb.read(connectionInfo);
  2382. PROGLOG("Lock %" I64F "x successfully removed: %s", connectionId, connectionInfo.str());
  2383. }
  2384. }
  2385. }
  2386. }
  2387. }
  2388. static void dumpWorkunit(const char *wuid, bool includeProgress)
  2389. {
  2390. Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
  2391. Owned<IConstWorkUnit> workunit = factory->openWorkUnit(wuid);
  2392. exportWorkUnitToXMLFile(workunit, "stdout:", 0, true, includeProgress, true, false);
  2393. }
  2394. static void dumpProgress(const char *wuid, const char * graph)
  2395. {
  2396. Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
  2397. Owned<IConstWorkUnit> workunit = factory->openWorkUnit(wuid);
  2398. if (!workunit)
  2399. return;
  2400. Owned<IConstWUGraphProgress> progress = workunit->getGraphProgress(graph);
  2401. if (!progress)
  2402. return;
  2403. Owned<IPropertyTree> tree = progress->getProgressTree();
  2404. saveXML("stdout:", tree);
  2405. }
  2406. /* Callback used to output the different scope properties as xml */
  2407. class ScopeDumper : public IWuScopeVisitor
  2408. {
  2409. public:
  2410. virtual void noteStatistic(StatisticKind kind, unsigned __int64 value, IConstWUStatistic & cur) override
  2411. {
  2412. StringBuffer xml;
  2413. SCMStringBuffer curCreator;
  2414. SCMStringBuffer curDescription;
  2415. SCMStringBuffer curFormattedValue;
  2416. StatisticCreatorType curCreatorType = cur.getCreatorType();
  2417. StatisticScopeType curScopeType = cur.getScopeType();
  2418. StatisticMeasure curMeasure = cur.getMeasure();
  2419. unsigned __int64 count = cur.getCount();
  2420. unsigned __int64 max = cur.getMax();
  2421. unsigned __int64 ts = cur.getTimestamp();
  2422. const char * curScope = cur.queryScope();
  2423. cur.getCreator(curCreator);
  2424. cur.getDescription(curDescription, false);
  2425. cur.getFormattedValue(curFormattedValue);
  2426. if (kind != StKindNone)
  2427. xml.append(" kind='").append(queryStatisticName(kind)).append("'");
  2428. xml.append(" value='").append(value).append("'");
  2429. xml.append(" formatted='").append(curFormattedValue).append("'");
  2430. if (curMeasure != SMeasureNone)
  2431. xml.append(" unit='").append(queryMeasureName(curMeasure)).append("'");
  2432. if (curCreatorType != SCTnone)
  2433. xml.append(" ctype='").append(queryCreatorTypeName(curCreatorType)).append("'");
  2434. if (curCreator.length())
  2435. xml.append(" creator='").append(curCreator.str()).append("'");
  2436. if (count != 1)
  2437. xml.append(" count='").append(count).append("'");
  2438. if (max)
  2439. xml.append(" max='").append(value).append("'");
  2440. if (ts)
  2441. {
  2442. xml.append(" ts='");
  2443. formatStatistic(xml, ts, SMeasureTimestampUs);
  2444. xml.append("'");
  2445. }
  2446. if (curDescription.length())
  2447. xml.append(" desc='").append(curDescription.str()).append("'");
  2448. printf(" <attr%s/>\n", xml.str());
  2449. }
  2450. virtual void noteAttribute(WuAttr attr, const char * value)
  2451. {
  2452. StringBuffer xml;
  2453. xml.appendf("<attr kind='%s' value='", queryWuAttributeName(attr));
  2454. encodeXML(value, xml, ENCODE_NEWLINES, (unsigned)-1, true);
  2455. xml.append("'/>");
  2456. printf(" %s\n", xml.str());
  2457. }
  2458. virtual void noteHint(const char * kind, const char * value)
  2459. {
  2460. StringBuffer xml;
  2461. xml.appendf("<attr kind='hint:%s' value='%s'/>", kind, value);
  2462. printf(" %s\n", xml.str());
  2463. }
  2464. virtual void noteException(IConstWUException & exception) override
  2465. {
  2466. StringBuffer xml;
  2467. SCMStringBuffer source, message, timestamp, scope;
  2468. exception.getExceptionSource(source);
  2469. exception.getExceptionMessage(message);
  2470. exception.getTimeStamp(timestamp);
  2471. xml.appendf("<attr source='%s' message='%s' timestamp='%s' exceptionCode='%u' severity='%u' scope='%s' cost='%u'",
  2472. source.str(), message.str(), timestamp.str(),
  2473. exception.getExceptionCode(), exception.getSeverity(), exception.queryScope(), exception.getPriority());
  2474. xml.append("/>");
  2475. printf(" %s\n", xml.str());
  2476. }
  2477. };
  2478. static void dumpWorkunitAttr(IConstWorkUnit * workunit, const WuScopeFilter & filter)
  2479. {
  2480. ScopeDumper dumper;
  2481. printf("<Workunit wuid=\"%s\">\n", workunit->queryWuid());
  2482. Owned<IConstWUScopeIterator> iter = &workunit->getScopeIterator(filter);
  2483. ForEach(*iter)
  2484. {
  2485. printf("<scope scope='%s' type='%s'>\n", iter->queryScope(), queryScopeTypeName(iter->getScopeType()));
  2486. iter->playProperties(dumper);
  2487. printf("</scope>\n");
  2488. }
  2489. printf("</Workunit>\n");
  2490. }
  2491. static void dumpWorkunitAttr(const char *wuid, const char * userFilter)
  2492. {
  2493. WuScopeFilter filter(userFilter);
  2494. Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
  2495. const char * star = strchr(wuid, '*');
  2496. if (star)
  2497. {
  2498. WUSortField filters[2];
  2499. MemoryBuffer filterbuf;
  2500. filters[0] = WUSFwildwuid;
  2501. filterbuf.append(wuid);
  2502. filters[1] = WUSFterm;
  2503. Owned<IConstWorkUnitIterator> iter = factory->getWorkUnitsSorted((WUSortField) (WUSFwuid), filters, filterbuf.bufferBase(), 0, INT_MAX, NULL, NULL);
  2504. ForEach(*iter)
  2505. {
  2506. Owned<IConstWorkUnit> workunit = factory->openWorkUnit(iter->query().queryWuid());
  2507. if (workunit)
  2508. dumpWorkunitAttr(workunit, filter);
  2509. }
  2510. }
  2511. else
  2512. {
  2513. Owned<IConstWorkUnit> workunit = factory->openWorkUnit(wuid);
  2514. if (!workunit)
  2515. return;
  2516. dumpWorkunitAttr(workunit, filter);
  2517. }
  2518. }
  2519. static void wuidCompress(const char *match, const char *type, bool compress)
  2520. {
  2521. if (0 != stricmp("graph", type))
  2522. {
  2523. UWARNLOG("Currently, only type=='graph' supported.");
  2524. return;
  2525. }
  2526. Owned<IRemoteConnection> conn = querySDS().connect("/WorkUnits", myProcessSession(), 0, daliConnectTimeoutMs);
  2527. Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
  2528. Owned<IPropertyTreeIterator> iter = conn->queryRoot()->getElements(match?match:"*", iptiter_remote);
  2529. ForEach(*iter)
  2530. {
  2531. const char *wuid = iter->query().queryName();
  2532. IConstWorkUnit &wu = *factory->openWorkUnit(wuid);
  2533. StringArray graphNames;
  2534. Owned<IConstWUGraphIterator> graphIter = &wu.getGraphs(GraphTypeAny);
  2535. ForEach(*graphIter)
  2536. {
  2537. SCMStringBuffer graphName;
  2538. IConstWUGraph &graph = graphIter->query();
  2539. Owned<IPropertyTree> xgmml = graph.getXGMMLTreeRaw();
  2540. if (compress != xgmml->hasProp("graphBin"))
  2541. {
  2542. graph.getName(graphName);
  2543. graphNames.append(graphName.s.str());
  2544. }
  2545. }
  2546. }
  2547. }
  2548. static void validateStore(bool fix, bool deleteFiles, bool verbose)
  2549. {
  2550. /*
  2551. * Place holder for client-side dali store verification/validation. Currently performs:
  2552. * 1) validates GeneratedDll entries correspond to current workunits (see HPCC-9146)
  2553. */
  2554. CTimeMon totalTime, ts;
  2555. PROGLOG("Gathering list of workunits");
  2556. Owned<IRemoteConnection> conn = querySDS().connect("/WorkUnits", myProcessSession(), RTM_LOCK_READ, 10000);
  2557. if (!conn)
  2558. throw MakeStringException(0, "Failed to connect to /WorkUnits");
  2559. AtomRefTable wuids;
  2560. Owned<IPropertyTreeIterator> wuidIter = conn->queryRoot()->getElements("*");
  2561. ForEach(*wuidIter)
  2562. {
  2563. IPropertyTree &wuid = wuidIter->query();
  2564. wuids.queryCreate(wuid.queryName());
  2565. }
  2566. PROGLOG("%d workunits gathered. Took %d ms", wuids.count(), ts.elapsed());
  2567. ts.reset(0);
  2568. StringArray uidsToDelete;
  2569. UnsignedArray indexToDelete;
  2570. PROGLOG("Gathering associated files");
  2571. conn.setown(querySDS().connect("/GeneratedDlls", myProcessSession(), fix?RTM_LOCK_WRITE:RTM_LOCK_READ, 10000));
  2572. if (!conn)
  2573. {
  2574. PROGLOG("No generated DLLs associated with any workunit.\nExit. Took %d ms", ts.elapsed());
  2575. return;
  2576. }
  2577. IPropertyTree *root = conn->queryRoot()->queryBranch(NULL); // force all to download
  2578. Owned<IPropertyTreeIterator> gdIter = root->getElements("*");
  2579. RegExpr RE("^.*{W2[0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9]{-[0-9]+}?}{[^0-9].*|}$");
  2580. unsigned index=1;
  2581. ForEach(*gdIter)
  2582. {
  2583. IPropertyTree &gd = gdIter->query();
  2584. const char *name = gd.queryProp("@name");
  2585. if (name && *name)
  2586. {
  2587. if (RE.find(name))
  2588. {
  2589. StringBuffer wuid;
  2590. RE.substitute(wuid,"#1");
  2591. const char *w = wuid.str();
  2592. bool found = NULL != wuids.find(*w);
  2593. const char *uid = gd.queryProp("@uid");
  2594. if (!found)
  2595. {
  2596. uidsToDelete.append(uid);
  2597. indexToDelete.append(index);
  2598. }
  2599. }
  2600. }
  2601. ++index;
  2602. }
  2603. PROGLOG("%d out of %d workunit files not associated with any workunit. Took %d ms", indexToDelete.ordinality(), index, ts.elapsed());
  2604. ts.reset(0);
  2605. IArrayOf<IDllEntry> removedEntries;
  2606. unsigned numDeleted = 0;
  2607. ForEachItemInRev(d, indexToDelete)
  2608. {
  2609. const char *uid = uidsToDelete.item(d);
  2610. unsigned index = indexToDelete.item(d);
  2611. StringBuffer path("GeneratedDll[");
  2612. path.append(index).append("]");
  2613. IPropertyTree *gd = root->queryPropTree(path.str());
  2614. if (NULL == gd)
  2615. throwUnexpected();
  2616. const char *uidQuery = gd->queryProp("@uid");
  2617. if (0 != strcmp(uid, uidQuery))
  2618. throw MakeStringException(0, "Expecting uid=%s @ GeneratedDll[%d], but found uid=%s", uid, index, uidQuery);
  2619. if (verbose)
  2620. PROGLOG("Removing: %s, uid=%s", path.str(), uid);
  2621. if (fix)
  2622. {
  2623. Owned<IDllEntry> entry = queryDllServer().createEntry(root, gd);
  2624. entry->remove(false, false); // NB: This will remove child 'gd' element from root (GeneratedDlls)
  2625. if (deleteFiles) // delay until after meta info removed and /GeneratedDlls unlocked
  2626. removedEntries.append(*entry.getClear());
  2627. }
  2628. ++numDeleted;
  2629. }
  2630. if (fix)
  2631. {
  2632. conn->commit();
  2633. PROGLOG("Removed %d unassociated file entries. Took %d ms", numDeleted, ts.elapsed());
  2634. ts.reset(0);
  2635. if (deleteFiles)
  2636. {
  2637. PROGLOG("Deleting physical files..");
  2638. ForEachItemIn(r, removedEntries)
  2639. {
  2640. IDllEntry &entry = removedEntries.item(r);
  2641. PROGLOG("Removing files for: %s", entry.queryName());
  2642. entry.remove(true, false);
  2643. }
  2644. PROGLOG("Removed physical files. Took %d ms", ts.elapsed());
  2645. }
  2646. }
  2647. else
  2648. PROGLOG("%d unassociated file entries to remove - use 'fix=true'", numDeleted);
  2649. PROGLOG("Done time = %d secs", totalTime.elapsed()/1000);
  2650. }
  2651. //=============================================================================
  2652. static void migrateFiles(const char *srcGroup, const char *tgtGroup, const char *filemask, const char *_options)
  2653. {
  2654. if (strieq(srcGroup, tgtGroup))
  2655. throw makeStringExceptionV(0, "source and target cluster groups cannot be the same! cluster = %s", srcGroup);
  2656. enum class mg_options : unsigned { nop, createmaps=1, listonly=2, dryrun=4, verbose=8};
  2657. StringArray options;
  2658. options.appendList(_options, ",");
  2659. mg_options opts = mg_options::nop;
  2660. ForEachItemIn(o, options)
  2661. {
  2662. const char *opt = options.item(o);
  2663. if (strieq("CREATEMAPS", opt))
  2664. opts = (mg_options)((unsigned)opts | (unsigned)mg_options::createmaps);
  2665. else if (strieq("LISTONLY", opt))
  2666. opts = (mg_options)((unsigned)opts | (unsigned)mg_options::listonly);
  2667. else if (strieq("DRYRUN", opt))
  2668. opts = (mg_options)((unsigned)opts | (unsigned)mg_options::dryrun);
  2669. else if (strieq("VERBOSE", opt))
  2670. opts = (mg_options)((unsigned)opts | (unsigned)mg_options::verbose);
  2671. else
  2672. UWARNLOG("Unknown option: %s", opt);
  2673. }
  2674. /*
  2675. * CMatchScanner scans logical files, looking for files that are in the source group
  2676. * and matching against the logical file names against filemask.
  2677. * Then (depending on options) manipulates the meta data to point to new target group
  2678. * and outputs a file per node of the source group, with a list of all matching
  2679. * physical files in the format: srcIP,dstIP,physical file
  2680. */
  2681. class CMatchScanner : public CSDSFileScanner
  2682. {
  2683. StringAttr srcGroup, tgtGroup;
  2684. mg_options options;
  2685. StringBuffer tgtClusterGroupText;
  2686. Owned<IGroup> srcClusterGroup, tgtClusterGroup;
  2687. IPointerArrayOf<IFileIOStream> fileLists;
  2688. unsigned matchingFiles = 0;
  2689. Linked<IRemoteConnection> conn;
  2690. StringAttr filemask;
  2691. bool wild = false;
  2692. unsigned srcClusterSize = 0;
  2693. unsigned tgtClusterSize = 0;
  2694. bool mgOpt(mg_options o)
  2695. {
  2696. return ((unsigned)o & (unsigned)options);
  2697. }
  2698. IFileIOStream *getFileIOStream(unsigned p)
  2699. {
  2700. while (fileLists.ordinality()<=p)
  2701. fileLists.append(nullptr);
  2702. Linked<IFileIOStream> stream = fileLists.item(p);
  2703. if (nullptr == stream)
  2704. {
  2705. VStringBuffer filePartList("fileparts%u_%s_%u.lst", GetCurrentProcessId(), srcGroup.get(), p);
  2706. Owned<IFile> iFile = createIFile(filePartList);
  2707. Owned<IFileIO> iFileIO = iFile->open(IFOcreate);
  2708. if (!iFileIO)
  2709. throw makeStringExceptionV(0, "Failed to open: %s", filePartList.str());
  2710. stream.setown(createBufferedIOStream(iFileIO));
  2711. fileLists.replace(stream.getLink(), p);
  2712. }
  2713. return stream.getClear();
  2714. }
  2715. unsigned find(IGroup *group, const IpAddress &ip) const
  2716. {
  2717. unsigned c = group->ordinality();
  2718. for (unsigned i=0; i<c; i++)
  2719. {
  2720. const IpAddress &nodeIP = group->queryNode(i).endpoint();
  2721. if (ip.ipequals(nodeIP))
  2722. return i;
  2723. }
  2724. return NotFound;
  2725. }
  2726. public:
  2727. CMatchScanner(const char *_srcGroup, const char *_tgtGroup, mg_options _options) : srcGroup(_srcGroup), tgtGroup(_tgtGroup), options(_options)
  2728. {
  2729. srcClusterGroup.setown(queryNamedGroupStore().lookup(srcGroup));
  2730. if (!srcClusterGroup)
  2731. throw makeStringExceptionV(0, "Could not find source cluster group: %s", _srcGroup);
  2732. tgtClusterGroup.setown(queryNamedGroupStore().lookup(tgtGroup));
  2733. if (!tgtClusterGroup)
  2734. throw makeStringExceptionV(0, "Could not find target cluster group: %s", _tgtGroup);
  2735. srcClusterSize = srcClusterGroup->ordinality();
  2736. tgtClusterSize = tgtClusterGroup->ordinality();
  2737. if (tgtClusterSize>srcClusterSize)
  2738. throw makeStringExceptionV(0, "Unsupported - target cluster is wider than source (target size=%u, source size=%u", tgtClusterSize, srcClusterSize);
  2739. if (0 != (srcClusterSize%tgtClusterSize))
  2740. throw makeStringExceptionV(0, "Unsupported - target cluster must be a factor of source cluster size (target size=%u, source size=%u", tgtClusterSize, srcClusterSize);
  2741. tgtClusterGroup->getText(tgtClusterGroupText);
  2742. }
  2743. virtual bool checkFileOk(IPropertyTree &file, const char *filename) override
  2744. {
  2745. const char *group = file.queryProp("@group");
  2746. if (!group)
  2747. {
  2748. if (mgOpt(mg_options::verbose))
  2749. PROGLOG("No group defined - filename=%s, mask=%s, srcGroup=%s", filename, filemask.get(), srcGroup.get());
  2750. return false;
  2751. }
  2752. else if (nullptr == strstr(file.queryProp("@group"), srcGroup)) // crude match, could be rejected in processFile
  2753. {
  2754. if (mgOpt(mg_options::verbose))
  2755. PROGLOG("GROUP-MISMATCH - filename=%s, mask=%s, srcGroup=%s, file group=%s", filename, filemask.get(), srcGroup.get(), group);
  2756. return false;
  2757. }
  2758. else if (wild)
  2759. {
  2760. if (WildMatch(filename, filemask, false))
  2761. {
  2762. if (mgOpt(mg_options::verbose))
  2763. PROGLOG("WILD-MISMATCH - filename=%s, mask=%s, srcGroup=%s, file group=%s", filename, filemask.get(), srcGroup.get(), group);
  2764. return true;
  2765. }
  2766. }
  2767. else if (strieq(filename, filemask))
  2768. return true;
  2769. if (mgOpt(mg_options::verbose))
  2770. PROGLOG("EXACT-MISMATCH - filename=%s, mask=%s, srcGroup=%s, file group=%s", filename, filemask.get(), srcGroup.get(), group);
  2771. return false;
  2772. }
  2773. virtual bool checkScopeOk(const char *scopename) override
  2774. {
  2775. if (mgOpt(mg_options::verbose))
  2776. PROGLOG("Processing scope %s", scopename);
  2777. return true;
  2778. }
  2779. virtual void processFile(IPropertyTree &root, StringBuffer &name) override
  2780. {
  2781. try
  2782. {
  2783. bool doCommit = false;
  2784. StringBuffer _tgtClusterGroupText(tgtClusterGroupText);
  2785. Owned<IFileDescriptor> fileDesc = deserializeFileDescriptorTree(&root, &queryNamedGroupStore());
  2786. unsigned numClusters = fileDesc->numClusters();
  2787. for (unsigned clusterNum=0; clusterNum<numClusters; clusterNum++)
  2788. {
  2789. StringBuffer srcFileGroup;
  2790. fileDesc->getClusterGroupName(clusterNum, srcFileGroup);
  2791. StringBuffer srcFileGroupName, srcFileGroupRange;
  2792. if (!decodeChildGroupName(srcFileGroup, srcFileGroupName, srcFileGroupRange))
  2793. srcFileGroupName.append(srcFileGroup);
  2794. if (streq(srcFileGroupName, srcGroup))
  2795. {
  2796. IGroup *srcFileClusterGroup = fileDesc->queryClusterGroup(clusterNum);
  2797. unsigned srcFileClusterGroupWidth = srcFileClusterGroup->ordinality();
  2798. StringBuffer _tgtGroup(tgtGroup);
  2799. unsigned groupOffset = NotFound;
  2800. if (srcFileGroupRange.length())
  2801. {
  2802. SocketEndpointArray epas;
  2803. UnsignedArray dstPositions;
  2804. Owned<INodeIterator> nodeIter = srcFileClusterGroup->getIterator();
  2805. ForEach(*nodeIter)
  2806. {
  2807. const IpAddress &ip = nodeIter->query().endpoint();
  2808. unsigned srcRelPos = find(srcClusterGroup, ip);
  2809. if (NotFound == groupOffset)
  2810. groupOffset = srcRelPos;
  2811. unsigned dstRelPos = srcRelPos % tgtClusterSize;
  2812. dstPositions.append(dstRelPos+1);
  2813. }
  2814. StringBuffer rangeText;
  2815. encodeChildGroupRange(dstPositions, rangeText);
  2816. _tgtGroup.append(rangeText);
  2817. }
  2818. else
  2819. groupOffset = 0;
  2820. unsigned numParts = fileDesc->numParts();
  2821. PROGLOG("Processing file %s (width=%u), cluster group=%s (%u of %u), new group = %s", name.str(), numParts, srcFileGroup.str(), clusterNum+1, numClusters, _tgtGroup.str());
  2822. if (!mgOpt(mg_options::listonly))
  2823. {
  2824. if (!mgOpt(mg_options::dryrun))
  2825. {
  2826. doCommit = true;
  2827. VStringBuffer clusterXPath("Cluster[%u]", clusterNum+1);
  2828. IPropertyTree *cluster = root.queryPropTree(clusterXPath);
  2829. root.setProp("@group", _tgtGroup);
  2830. if (cluster)
  2831. cluster->setProp("@name", _tgtGroup);
  2832. else
  2833. UWARNLOG("No Cluster found for file: %s", name.str());
  2834. }
  2835. if (mgOpt(mg_options::createmaps))
  2836. {
  2837. for (unsigned partNum=0; partNum<numParts; partNum++)
  2838. {
  2839. unsigned r = partNum % srcFileClusterGroupWidth;
  2840. const SocketEndpoint &srcEp = srcFileClusterGroup->queryNode(r).endpoint();
  2841. unsigned relPos = find(srcClusterGroup, srcEp);
  2842. unsigned dstPos = (partNum+groupOffset) % tgtClusterSize;
  2843. const SocketEndpoint &tgtEp = tgtClusterGroup->queryNode(dstPos).endpoint();
  2844. // output srcIP, dstIP, path/file-part-name >> script<N>.lst
  2845. Owned<IFileIOStream> iFileIOStream = getFileIOStream(relPos+1);
  2846. StringBuffer outputLine;
  2847. srcEp.getIpText(outputLine);
  2848. outputLine.append(",");
  2849. tgtEp.getIpText(outputLine);
  2850. outputLine.append(",");
  2851. IPartDescriptor *part = fileDesc->queryPart(partNum);
  2852. StringBuffer filePath;
  2853. part->getPath(filePath);
  2854. outputLine.append(filePath);
  2855. outputLine.newline();
  2856. iFileIOStream->write(outputLine.length(), outputLine.str());
  2857. }
  2858. }
  2859. }
  2860. }
  2861. }
  2862. ++matchingFiles;
  2863. if (doCommit)
  2864. conn->commit(); // NB: the scanner rolls back any changes, mainly to reduce cost/exposure to previously lazy fetched scope branches
  2865. }
  2866. catch (IException *e)
  2867. {
  2868. VStringBuffer errorMsg("Failed to process file : %s", name.str());
  2869. EXCLOG(e, errorMsg.str());
  2870. e->Release();
  2871. }
  2872. }
  2873. unsigned scan(IRemoteConnection *_conn, const char *_filemask, bool includefiles=true, bool includesuper=false)
  2874. {
  2875. filemask.set(_filemask);
  2876. conn.set(_conn);
  2877. wild = containsWildcard(_filemask);
  2878. CSDSFileScanner::scan(_conn, includefiles, includesuper);
  2879. return matchingFiles;
  2880. }
  2881. } scanner(srcGroup, tgtGroup, opts);
  2882. IUserDescriptor *user = nullptr;
  2883. Owned<IRemoteConnection> conn = querySDS().connect("/Files", myProcessSession(), 0, 100000);
  2884. bool success=false;
  2885. unsigned matchingFiles=0;
  2886. try
  2887. {
  2888. matchingFiles = scanner.scan(conn, filemask, true, false);
  2889. success=true;
  2890. }
  2891. catch (IException *e)
  2892. {
  2893. EXCLOG(e, nullptr);
  2894. e->Release();
  2895. }
  2896. if (!success)
  2897. {
  2898. UWARNLOG("Failed to make changes");
  2899. conn->rollback();
  2900. }
  2901. else if ((unsigned)opts & (unsigned)mg_options::dryrun)
  2902. {
  2903. conn->rollback();
  2904. UWARNLOG("Dry-run, no changes committed. %u files matched", matchingFiles);
  2905. }
  2906. else
  2907. PROGLOG("Committed changes: %u files changed", matchingFiles);
  2908. }
  2909. //=============================================================================
  2910. void testThorRunningWUs()
  2911. {
  2912. Owned<IRemoteConnection> conn = querySDS().connect("/Status/Servers",myProcessSession(),RTM_LOCK_READ,30000);
  2913. if (conn.get())
  2914. {
  2915. Owned<IPropertyTreeIterator> it(conn->queryRoot()->getElements("Server"));
  2916. ForEach(*it) {
  2917. StringBuffer instance;
  2918. if(it->query().hasProp("@queue"))
  2919. {
  2920. const char* queue=it->query().queryProp("@queue");
  2921. if(strstr(queue,".thor")) {
  2922. Owned<IPropertyTreeIterator> wuids(it->query().getElements("WorkUnit"));
  2923. ForEach(*wuids) {
  2924. IPropertyTree &wu = wuids->query();
  2925. const char* wuid=wu.queryProp(NULL);
  2926. if (wuid&&*wuid) {
  2927. const char *prioclass = wu.queryProp("@priorityClass");
  2928. bool high = false;
  2929. if (prioclass&&(stricmp(prioclass,"high")==0))
  2930. high = true;
  2931. OUTLOG("%s running on queue %s",wuid,queue);
  2932. }
  2933. }
  2934. }
  2935. }
  2936. }
  2937. }
  2938. }
  2939. #define CHECKPARAMS(mn,mx) { if ((np<mn)||(np>mx)) throw MakeStringException(-1,"%s: incorrect number of parameters",cmd); }
  2940. int main(int argc, char* argv[])
  2941. {
  2942. int ret = 0;
  2943. InitModuleObjects();
  2944. EnableSEHtoExceptionMapping();
  2945. setDaliServixSocketCaching(true);
  2946. if (argc<2) {
  2947. usage(argv[0]);
  2948. return -1;
  2949. }
  2950. Owned<IProperties> props = createProperties("daliadmin.ini");
  2951. StringArray params;
  2952. SocketEndpoint ep;
  2953. StringBuffer tmps;
  2954. for (int i=1;i<argc;i++) {
  2955. const char *param = argv[i];
  2956. if ((memcmp(param,"server=",7)==0)||
  2957. (memcmp(param,"logfile=",8)==0)||
  2958. (memcmp(param,"rawlog=",7)==0)||
  2959. (memcmp(param,"user=",5)==0)||
  2960. (memcmp(param,"password=",9)==0) ||
  2961. (memcmp(param,"fix=",4)==0) ||
  2962. (memcmp(param,"verbose=",8)==0) ||
  2963. (memcmp(param,"deletefiles=",12)==0) ||
  2964. (memcmp(param,"timeout=",8)==0))
  2965. props->loadProp(param);
  2966. else if ((i==1)&&(isdigit(*param)||(*param=='.'))&&ep.set(((*param=='.')&&param[1])?(param+1):param,DALI_SERVER_PORT))
  2967. props->setProp("server",ep.getUrlStr(tmps.clear()).str());
  2968. else {
  2969. if ((strieq(param,"help")) || (strieq(param,"-help")) || (strieq(param,"--help"))) {
  2970. usage(argv[0]);
  2971. return -1;
  2972. }
  2973. params.append(param);
  2974. }
  2975. }
  2976. if (!params.ordinality()) {
  2977. usage(argv[0]);
  2978. return -1;
  2979. }
  2980. try {
  2981. StringBuffer logname;
  2982. StringBuffer aliasname;
  2983. bool rawlog = props->getPropBool("rawlog");
  2984. Owned<ILogMsgHandler> fileMsgHandler;
  2985. if (props->getProp("logfile",logname)) {
  2986. if (logname.length()) {
  2987. fileMsgHandler.setown(getFileLogMsgHandler(logname.str(), NULL, rawlog?MSGFIELD_prefix:MSGFIELD_STANDARD, false, false, true));
  2988. queryLogMsgManager()->addMonitorOwn(fileMsgHandler.getClear(), getCategoryLogMsgFilter(MSGAUD_all, MSGCLS_all, TopDetail));
  2989. }
  2990. }
  2991. // set stdout
  2992. attachStandardHandleLogMsgMonitor(stdout,0,MSGAUD_all,MSGCLS_all&~(MSGCLS_disaster|MSGCLS_error|MSGCLS_warning));
  2993. Owned<ILogMsgFilter> filter = getCategoryLogMsgFilter(MSGAUD_user, MSGCLS_error|MSGCLS_warning);
  2994. queryLogMsgManager()->changeMonitorFilter(queryStderrLogMsgHandler(), filter);
  2995. queryStderrLogMsgHandler()->setMessageFields(MSGFIELD_prefix);
  2996. }
  2997. catch (IException *e) {
  2998. pexception("daliadmin",e);
  2999. e->Release();
  3000. ret = 255;
  3001. }
  3002. unsigned daliconnectelapsed;
  3003. StringBuffer daliserv;
  3004. if (!ret) {
  3005. const char *cmd = params.item(0);
  3006. unsigned np = params.ordinality()-1;
  3007. if (!props->getProp("server",daliserv.clear()))
  3008. {
  3009. // external commands
  3010. try
  3011. {
  3012. if (strieq(cmd,"xmlsize"))
  3013. {
  3014. CHECKPARAMS(1,2);
  3015. xmlSize(params.item(1), np>1?atof(params.item(2)):1.0);
  3016. }
  3017. else if (strieq(cmd,"translatetoxpath"))
  3018. {
  3019. CHECKPARAMS(1,2);
  3020. DfsXmlBranchKind branchType;
  3021. if (np>1)
  3022. {
  3023. const char *typeStr = params.item(2);
  3024. branchType = queryDfsXmlBranchType(typeStr);
  3025. }
  3026. else
  3027. branchType = DXB_File;
  3028. translateToXpath(params.item(1), branchType);
  3029. }
  3030. else
  3031. {
  3032. UERRLOG("Unknown command %s",cmd);
  3033. ret = 255;
  3034. }
  3035. }
  3036. catch (IException *e)
  3037. {
  3038. EXCLOG(e,"daliadmin");
  3039. e->Release();
  3040. ret = 255;
  3041. }
  3042. return ret;
  3043. }
  3044. else
  3045. {
  3046. try {
  3047. SocketEndpoint ep(daliserv.str(),DALI_SERVER_PORT);
  3048. SocketEndpointArray epa;
  3049. epa.append(ep);
  3050. Owned<IGroup> group = createIGroup(epa);
  3051. unsigned start = msTick();
  3052. initClientProcess(group, DCR_DaliAdmin);
  3053. daliconnectelapsed = msTick()-start;
  3054. }
  3055. catch (IException *e) {
  3056. EXCLOG(e,"daliadmin initClientProcess");
  3057. e->Release();
  3058. ret = 254;
  3059. }
  3060. if (!ret) {
  3061. try {
  3062. Owned<IUserDescriptor> userDesc;
  3063. if (props->getProp("user",tmps.clear())) {
  3064. userDesc.setown(createUserDescriptor());
  3065. StringBuffer ps;
  3066. props->getProp("password",ps);
  3067. userDesc->set(tmps.str(),ps.str());
  3068. queryDistributedFileDirectory().setDefaultUser(userDesc);
  3069. }
  3070. daliConnectTimeoutMs = 1000 * props->getPropInt("timeout", DEFAULT_DALICONNECT_TIMEOUT);
  3071. if (strieq(cmd,"export")) {
  3072. CHECKPARAMS(2,2);
  3073. _export_(params.item(1),params.item(2));
  3074. }
  3075. else if (strieq(cmd,"import")) {
  3076. CHECKPARAMS(2,2);
  3077. import(params.item(1),params.item(2),false);
  3078. }
  3079. else if (strieq(cmd,"importadd")) {
  3080. CHECKPARAMS(2,2);
  3081. import(params.item(1),params.item(2),true);
  3082. }
  3083. else if (strieq(cmd,"delete")) {
  3084. CHECKPARAMS(1,2);
  3085. bool backup = np<2 || !strieq("nobackup", params.item(2));
  3086. _delete_(params.item(1),backup);
  3087. }
  3088. else if (strieq(cmd,"set")) {
  3089. CHECKPARAMS(2,2);
  3090. set(params.item(1),params.item(2));
  3091. }
  3092. else if (strieq(cmd,"get")) {
  3093. CHECKPARAMS(1,1);
  3094. get(params.item(1));
  3095. }
  3096. else if (strieq(cmd,"bget")) {
  3097. CHECKPARAMS(2,2);
  3098. bget(params.item(1),params.item(2));
  3099. }
  3100. else if (strieq(cmd,"wget")) {
  3101. CHECKPARAMS(1,1);
  3102. wget(params.item(1));
  3103. }
  3104. else if (strieq(cmd,"xget")) {
  3105. CHECKPARAMS(1,1);
  3106. wget(params.item(1));
  3107. }
  3108. else if (strieq(cmd,"add")) {
  3109. CHECKPARAMS(1,2);
  3110. add(params.item(1), (np>1) ? params.item(2) : nullptr);
  3111. }
  3112. else if (strieq(cmd,"delv")) {
  3113. CHECKPARAMS(1,1);
  3114. delv(params.item(1));
  3115. }
  3116. else if (strieq(cmd,"count")) {
  3117. CHECKPARAMS(1,1);
  3118. count(params.item(1));
  3119. }
  3120. else if (strieq(cmd,"dfsfile")) {
  3121. CHECKPARAMS(1,1);
  3122. dfsfile(params.item(1),userDesc);
  3123. }
  3124. else if (strieq(cmd,"dfspart")) {
  3125. CHECKPARAMS(2,2);
  3126. dfspart(params.item(1),userDesc,atoi(params.item(2)));
  3127. }
  3128. else if (strieq(cmd,"setdfspartattr")) {
  3129. CHECKPARAMS(3,4);
  3130. setdfspartattr(params.item(1), atoi(params.item(2)), params.item(3), np>3 ? params.item(4) : nullptr, userDesc);
  3131. }
  3132. else if (strieq(cmd,"dfscheck")) {
  3133. CHECKPARAMS(0,0);
  3134. dfsCheck();
  3135. }
  3136. else if (strieq(cmd,"dfscsv")) {
  3137. CHECKPARAMS(1,1);
  3138. dfscsv(params.item(1),userDesc);
  3139. }
  3140. else if (strieq(cmd,"dfsgroup")) {
  3141. CHECKPARAMS(1,2);
  3142. dfsGroup(params.item(1),(np>1)?params.item(2):NULL);
  3143. }
  3144. else if (strieq(cmd,"clusternodes")) {
  3145. CHECKPARAMS(1,2);
  3146. ret = clusterGroup(params.item(1),(np>1)?params.item(2):NULL);
  3147. }
  3148. else if (strieq(cmd,"dfsls")) {
  3149. CHECKPARAMS(0,2);
  3150. dfsLs((np>0)?params.item(1):NULL,(np>1)?params.item(2):NULL);
  3151. }
  3152. else if (strieq(cmd,"dfsmap")) {
  3153. CHECKPARAMS(1,1);
  3154. dfsmap(params.item(1), userDesc);
  3155. }
  3156. else if (strieq(cmd,"dfsexist")) {
  3157. CHECKPARAMS(1,1);
  3158. ret = dfsexists(params.item(1),userDesc);
  3159. }
  3160. else if (strieq(cmd,"dfsparents")) {
  3161. CHECKPARAMS(1,1);
  3162. dfsparents(params.item(1),userDesc);
  3163. }
  3164. else if (strieq(cmd,"dfsunlink")) {
  3165. CHECKPARAMS(1,1);
  3166. dfsunlink(params.item(1),userDesc);
  3167. }
  3168. else if (strieq(cmd,"dfsverify")) {
  3169. CHECKPARAMS(1,1);
  3170. ret = dfsverify(params.item(1),NULL,userDesc);
  3171. }
  3172. else if (strieq(cmd,"setprotect")) {
  3173. CHECKPARAMS(2,2);
  3174. setprotect(params.item(1),params.item(2),userDesc);
  3175. }
  3176. else if (strieq(cmd,"unprotect")) {
  3177. CHECKPARAMS(2,2);
  3178. unprotect(params.item(1),params.item(2),userDesc);
  3179. }
  3180. else if (strieq(cmd,"listprotect")) {
  3181. CHECKPARAMS(0,2);
  3182. listprotect((np>1)?params.item(1):"*",(np>2)?params.item(2):"*");
  3183. }
  3184. else if (strieq(cmd,"checksuperfile")) {
  3185. CHECKPARAMS(1,1);
  3186. bool fix = props->getPropBool("fix");
  3187. checksuperfile(params.item(1),fix);
  3188. }
  3189. else if (strieq(cmd,"checksubfile")) {
  3190. CHECKPARAMS(1,1);
  3191. checksubfile(params.item(1));
  3192. }
  3193. else if (strieq(cmd,"listexpires")) {
  3194. CHECKPARAMS(0,1);
  3195. listexpires((np>1)?params.item(1):"*",userDesc);
  3196. }
  3197. else if (strieq(cmd,"listrelationships")) {
  3198. CHECKPARAMS(2,2);
  3199. listrelationships(params.item(1),params.item(2));
  3200. }
  3201. else if (strieq(cmd,"dfsperm")) {
  3202. if (!userDesc.get())
  3203. throw MakeStringException(-1,"dfsperm requires username to be set (user=)");
  3204. CHECKPARAMS(1,1);
  3205. ret = dfsperm(params.item(1),userDesc);
  3206. }
  3207. else if (strieq(cmd,"dfscompratio")) {
  3208. CHECKPARAMS(1,1);
  3209. dfscompratio(params.item(1),userDesc);
  3210. }
  3211. else if (strieq(cmd,"dfsscopes")) {
  3212. CHECKPARAMS(0,1);
  3213. dfsscopes((np>0)?params.item(1):"*",userDesc);
  3214. }
  3215. else if (strieq(cmd,"cleanscopes")) {
  3216. CHECKPARAMS(0,0);
  3217. cleanscopes(userDesc);
  3218. }
  3219. else if (strieq(cmd,"normalizefilenames")) {
  3220. CHECKPARAMS(0,1);
  3221. normalizeFileNames(userDesc, np>0 ? params.item(1) : nullptr);
  3222. }
  3223. else if (strieq(cmd,"listworkunits")) {
  3224. CHECKPARAMS(0,3);
  3225. listworkunits((np>0)?params.item(1):NULL,(np>1)?params.item(2):NULL,(np>2)?params.item(3):NULL);
  3226. }
  3227. else if (strieq(cmd,"listmatches")) {
  3228. CHECKPARAMS(0,3);
  3229. listmatches((np>0)?params.item(1):NULL,(np>1)?params.item(2):NULL,(np>2)?params.item(3):NULL);
  3230. }
  3231. else if (strieq(cmd,"workunittimings")) {
  3232. CHECKPARAMS(1,1);
  3233. workunittimings(params.item(1));
  3234. }
  3235. else if (strieq(cmd,"serverlist")) {
  3236. CHECKPARAMS(1,1);
  3237. serverlist(params.item(1));
  3238. }
  3239. else if (strieq(cmd,"clusterlist")) {
  3240. CHECKPARAMS(1,1);
  3241. clusterlist(params.item(1));
  3242. }
  3243. else if (strieq(cmd,"auditlog")) {
  3244. CHECKPARAMS(2,3);
  3245. auditlog(params.item(1),params.item(2),(np>2)?params.item(3):NULL);
  3246. }
  3247. else if (strieq(cmd,"coalesce")) {
  3248. CHECKPARAMS(0,0);
  3249. coalesce();
  3250. }
  3251. else if (strieq(cmd,"mpping")) {
  3252. CHECKPARAMS(1,1);
  3253. mpping(params.item(1));
  3254. }
  3255. else if (strieq(cmd,"daliping")) {
  3256. CHECKPARAMS(0,1);
  3257. daliping(daliserv.str(),daliconnectelapsed,(np>0)?atoi(params.item(1)):1);
  3258. }
  3259. else if (strieq(cmd,"getxref")) {
  3260. CHECKPARAMS(1,1);
  3261. getxref(params.item(1));
  3262. }
  3263. else if (strieq(cmd,"dalilocks")) {
  3264. CHECKPARAMS(0,2);
  3265. bool filesonly = false;
  3266. if (np&&(strieq(params.item(np),"files"))) {
  3267. filesonly = true;
  3268. np--;
  3269. }
  3270. dalilocks(np>0?params.item(1):NULL,filesonly);
  3271. }
  3272. else if (strieq(cmd,"unlock")) {
  3273. CHECKPARAMS(2,2);
  3274. const char *fileOrPath = params.item(2);
  3275. if (strieq("file", fileOrPath))
  3276. unlock(params.item(1), true);
  3277. else if (strieq("path", fileOrPath))
  3278. unlock(params.item(1), false);
  3279. else
  3280. throw MakeStringException(0, "unknown type [ %s ], must be 'file' or 'path'", fileOrPath);
  3281. }
  3282. else if (strieq(cmd,"validateStore")) {
  3283. CHECKPARAMS(0,2);
  3284. bool fix = props->getPropBool("fix");
  3285. bool verbose = props->getPropBool("verbose");
  3286. bool deleteFiles = props->getPropBool("deletefiles");
  3287. validateStore(fix, deleteFiles, verbose);
  3288. }
  3289. else if (strieq(cmd, "workunit")) {
  3290. CHECKPARAMS(1,2);
  3291. bool includeProgress=false;
  3292. if (np>1)
  3293. includeProgress = strToBool(params.item(2));
  3294. dumpWorkunit(params.item(1), includeProgress);
  3295. }
  3296. else if (strieq(cmd,"wuidCompress")) {
  3297. CHECKPARAMS(2,2);
  3298. wuidCompress(params.item(1), params.item(2), true);
  3299. }
  3300. else if (strieq(cmd,"wuidDecompress")) {
  3301. CHECKPARAMS(2,2);
  3302. wuidCompress(params.item(1), params.item(2), false);
  3303. }
  3304. else if (strieq(cmd,"dfsreplication")) {
  3305. CHECKPARAMS(3,4);
  3306. bool dryRun = np>3 && strieq("dryrun", params.item(4));
  3307. dfsreplication(params.item(1), params.item(2), atoi(params.item(3)), dryRun);
  3308. }
  3309. else if (strieq(cmd,"holdlock")) {
  3310. CHECKPARAMS(2,2);
  3311. holdlock(params.item(1), params.item(2), userDesc);
  3312. }
  3313. else if (strieq(cmd, "progress")) {
  3314. CHECKPARAMS(2,2);
  3315. dumpProgress(params.item(1), params.item(2));
  3316. }
  3317. else if (strieq(cmd, "migratefiles"))
  3318. {
  3319. CHECKPARAMS(2, 7);
  3320. const char *srcGroup = params.item(1);
  3321. const char *dstGroup = params.item(2);
  3322. const char *filemask = "*";
  3323. StringBuffer options;
  3324. if (params.isItem(3))
  3325. {
  3326. filemask = params.item(3);
  3327. unsigned arg=4;
  3328. StringArray optArray;
  3329. while (arg<params.ordinality())
  3330. optArray.append(params.item(arg++));
  3331. optArray.getString(options, ",");
  3332. }
  3333. migrateFiles(srcGroup, dstGroup, filemask, options);
  3334. }
  3335. else if (stricmp(cmd, "wuattr") == 0) {
  3336. CHECKPARAMS(1, 2);
  3337. if (params.ordinality() > 2)
  3338. dumpWorkunitAttr(params.item(1), params.item(2));
  3339. else
  3340. dumpWorkunitAttr(params.item(1), nullptr);
  3341. }
  3342. else
  3343. UERRLOG("Unknown command %s",cmd);
  3344. }
  3345. catch (IException *e)
  3346. {
  3347. EXCLOG(e,"daliadmin");
  3348. e->Release();
  3349. ret = 255;
  3350. }
  3351. closedownClientProcess();
  3352. }
  3353. }
  3354. }
  3355. setDaliServixSocketCaching(false);
  3356. setNodeCaching(false);
  3357. releaseAtoms();
  3358. fflush(stdout);
  3359. fflush(stderr);
  3360. return ret;
  3361. }