daliadmin.cpp 130 KB

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