dumpkey.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  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 "jliball.hpp"
  14. #include "jhtree.hpp"
  15. #include "ctfile.hpp"
  16. #include "rtlrecord.hpp"
  17. #include "rtlformat.hpp"
  18. #include "eclhelper_dyn.hpp"
  19. void fatal(const char *format, ...) __attribute__((format(printf, 1, 2)));
  20. void fatal(const char *format, ...)
  21. {
  22. va_list args;
  23. va_start(args, format);
  24. vfprintf(stderr, format, args);
  25. va_end(args);
  26. fflush(stderr);
  27. releaseAtoms();
  28. ExitModuleObjects();
  29. _exit(2);
  30. }
  31. bool optHex = false;
  32. bool optRaw = false;
  33. bool optFullHeader = false;
  34. bool optHeader = false;
  35. StringArray files;
  36. void usage()
  37. {
  38. fprintf(stderr, "Usage: dumpkey [options] dataset [dataset...]\n"
  39. "Options:\n"
  40. " node=[n] - dump node n (0 = just header)\n"
  41. " fpos=[n] - dump node at offset fpos\n"
  42. " recs=[n] - output n rows\n"
  43. " fields=[fieldnames] - output specified fields only\n"
  44. " filter=[filter] - filter rows\n"
  45. " -H - hex display\n"
  46. " -R - raw output\n"
  47. " -fullheader - output full header info for each file\n"
  48. " -header - output minimal header info for each file\n"
  49. );
  50. fflush(stderr);
  51. releaseAtoms();
  52. ExitModuleObjects();
  53. _exit(2);
  54. }
  55. void doOption(const char *opt)
  56. {
  57. if (streq(opt, "-H"))
  58. optHex = true;
  59. else if (streq(opt, "-R"))
  60. optRaw = true;
  61. else if (streq(opt, "-header"))
  62. optHeader = true;
  63. else if (streq(opt, "-fullheader"))
  64. optFullHeader = true;
  65. else
  66. usage();
  67. }
  68. int main(int argc, const char **argv)
  69. {
  70. InitModuleObjects();
  71. #ifdef _WIN32
  72. _setmode( _fileno( stdout ), _O_BINARY );
  73. _setmode( _fileno( stdin ), _O_BINARY );
  74. #endif
  75. Owned<IProperties> globals = createProperties("dumpkey.ini", true);
  76. StringArray filters;
  77. for (int i = 1; i < argc; i++)
  78. {
  79. if (argv[i][0] == '-')
  80. doOption(argv[i]);
  81. else if (strncmp(argv[i], "filter=", 7)==0)
  82. filters.append(argv[i]+7);
  83. else if (strchr(argv[i], '='))
  84. globals->loadProp(argv[i]);
  85. else
  86. files.append(argv[i]);
  87. }
  88. try
  89. {
  90. StringBuffer logname("dumpkey.");
  91. logname.append(GetCachedHostName()).append(".");
  92. StringBuffer lf;
  93. openLogFile(lf, logname.append("log").str());
  94. }
  95. catch (IException *E)
  96. {
  97. // Silently ignore failure to open logfile.
  98. E->Release();
  99. }
  100. ForEachItemIn(idx, files)
  101. {
  102. try
  103. {
  104. Owned <IKeyIndex> index;
  105. const char * keyName = files.item(idx);
  106. index.setown(createKeyIndex(keyName, 0, false, false));
  107. size32_t key_size = index->keySize(); // NOTE - in variable size case, this is 32767
  108. unsigned nodeSize = index->getNodeSize();
  109. if (optFullHeader)
  110. {
  111. Owned<IFile> in = createIFile(keyName);
  112. Owned<IFileIO> io = in->open(IFOread);
  113. if (!io)
  114. throw MakeStringException(999, "Failed to open file %s", keyName);
  115. Owned<CKeyHdr> header = new CKeyHdr;
  116. MemoryAttr block(sizeof(KeyHdr));
  117. io->read(0, sizeof(KeyHdr), (void *)block.get());
  118. header->load(*(KeyHdr*)block.get());
  119. printf("Key '%s'\nkeySize=%d NumParts=%x, Top=%d\n", keyName, key_size, index->numParts(), index->isTopLevelKey());
  120. printf("File size = %" I64F "d, nodes = %" I64F "d\n", in->size(), in->size() / nodeSize - 1);
  121. printf("rootoffset=%" I64F "d[%" I64F "d]\n", header->getRootFPos(), header->getRootFPos()/nodeSize);
  122. Owned<IPropertyTree> metadata = index->getMetadata();
  123. if (metadata)
  124. {
  125. StringBuffer xml;
  126. toXML(metadata, xml);
  127. printf("MetaData:\n%s\n", xml.str());
  128. }
  129. }
  130. else if (optHeader)
  131. {
  132. if (idx)
  133. printf("\n");
  134. printf("%s:\n\n", keyName);
  135. }
  136. if (globals->hasProp("node"))
  137. {
  138. if (stricmp(globals->queryProp("node"), "all")==0)
  139. {
  140. }
  141. else
  142. {
  143. int node = globals->getPropInt("node");
  144. if (node != 0)
  145. index->dumpNode(stdout, node * nodeSize, globals->getPropInt("recs", 0), optRaw);
  146. }
  147. }
  148. else if (globals->hasProp("fpos"))
  149. {
  150. index->dumpNode(stdout, globals->getPropInt("fpos"), globals->getPropInt("recs", 0), optRaw);
  151. }
  152. else
  153. {
  154. Owned<IKeyManager> manager = createLocalKeyManager(index, key_size, NULL);
  155. Owned<IPropertyTree> metadata = index->getMetadata();
  156. Owned<IOutputMetaData> diskmeta;
  157. Owned<IOutputMetaData> translatedmeta;
  158. ArrayOf<const RtlFieldInfo *> deleteFields;
  159. ArrayOf<const RtlFieldInfo *> fields; // Note - the lifetime of the array needs to extend beyond the lifetime of outmeta. The fields themselves are shared with diskmeta, and do not need to be released.
  160. Owned<IOutputMetaData> outmeta;
  161. Owned<IHThorIndexReadArg> helper;
  162. Owned<IXmlWriterExt> writer;
  163. class MyIndexCallback : public CInterfaceOf<IThorIndexCallback>
  164. {
  165. public:
  166. MyIndexCallback(IKeyManager *_manager) : manager(_manager) {}
  167. virtual unsigned __int64 getFilePosition(const void * row)
  168. {
  169. return manager->queryFpos();
  170. }
  171. virtual byte * lookupBlob(unsigned __int64 id)
  172. {
  173. UNIMPLEMENTED;
  174. }
  175. Linked<IKeyManager> manager;
  176. } callback(manager);
  177. unsigned __int64 count = globals->getPropInt("recs", 1);
  178. const RtlRecordTypeInfo *outRecType = nullptr;
  179. if (metadata && metadata->hasProp("_rtlType"))
  180. {
  181. MemoryBuffer layoutBin;
  182. metadata->getPropBin("_rtlType", layoutBin);
  183. diskmeta.setown(createTypeInfoOutputMetaData(layoutBin, &callback));
  184. writer.setown(new SimpleOutputWriter);
  185. const RtlRecord &inrec = diskmeta->queryRecordAccessor(true);
  186. size32_t minRecSize = 0;
  187. if (globals->hasProp("fields"))
  188. {
  189. StringArray fieldNames;
  190. fieldNames.appendList(globals->queryProp("fields"), ",");
  191. ForEachItemIn(idx, fieldNames)
  192. {
  193. unsigned fieldNum = inrec.getFieldNum(fieldNames.item(idx));
  194. if (fieldNum == (unsigned) -1)
  195. throw MakeStringException(0, "Requested output field '%s' not found", fieldNames.item(idx));
  196. const RtlFieldInfo *field = inrec.queryOriginalField(fieldNum);
  197. if (field->type->getType() == type_filepos)
  198. {
  199. // We can't just use the original source field in this case (as output record does not have a special filepos)
  200. // So instead, create a field in the target with the original type.
  201. field = new RtlFieldStrInfo(field->name, field->xpath, field->type->queryChildType());
  202. deleteFields.append(field);
  203. }
  204. fields.append(field);
  205. minRecSize += field->type->getMinSize();
  206. }
  207. }
  208. else
  209. {
  210. // Copy all fields from the source record
  211. unsigned numFields = inrec.getNumFields();
  212. for (unsigned idx = 0; idx < numFields;idx++)
  213. {
  214. const RtlFieldInfo *field = inrec.queryOriginalField(idx);
  215. if (field->type->getType() == type_filepos)
  216. {
  217. // See above - filepos field in source needs special treatment
  218. field = new RtlFieldStrInfo(field->name, field->xpath, field->type->queryChildType());
  219. deleteFields.append(field);
  220. }
  221. fields.append(field);
  222. minRecSize += field->type->getMinSize();
  223. }
  224. outmeta.set(diskmeta);
  225. }
  226. fields.append(nullptr);
  227. outRecType = new RtlRecordTypeInfo(type_record, minRecSize, fields.getArray(0));
  228. outmeta.setown(new CDynamicOutputMetaData(*outRecType));
  229. helper.setown(createIndexReadArg(keyName, diskmeta.getLink(), outmeta.getLink(), count, 0, (uint64_t) -1));
  230. helper->setCallback(&callback);
  231. if (filters.ordinality())
  232. {
  233. IDynamicIndexReadArg *arg = QUERYINTERFACE(helper.get(), IDynamicIndexReadArg);
  234. assertex(arg);
  235. ForEachItemIn(idx, filters)
  236. {
  237. arg->addFilter(filters.item(idx));
  238. }
  239. }
  240. helper->createSegmentMonitors(manager);
  241. count = helper->getChooseNLimit(); // Just because this is testing out the createIndexReadArg functionality
  242. }
  243. manager->finishSegmentMonitors();
  244. manager->reset();
  245. while (manager->lookup(true) && count--)
  246. {
  247. offset_t pos;
  248. byte const * buffer = manager->queryKeyBuffer(pos);
  249. size32_t size = manager->queryRowSize();
  250. unsigned __int64 seq = manager->querySequence();
  251. if (optRaw)
  252. {
  253. fwrite(buffer, 1, size, stdout);
  254. }
  255. else if (optHex)
  256. {
  257. for (unsigned i = 0; i < size; i++)
  258. printf("%02x", ((unsigned char) buffer[i]) & 0xff);
  259. printf(" :%" I64F "u:%012" I64F "x\n", seq, pos);
  260. }
  261. else if (helper)
  262. {
  263. MemoryBuffer buf;
  264. MemoryBufferBuilder aBuilder(buf, 0);
  265. if (helper->transform(aBuilder, (const byte *) buffer))
  266. {
  267. outmeta->toXML((const byte *) buf.toByteArray(), *writer.get());
  268. printf("%s\n", writer->str());
  269. writer->clear();
  270. }
  271. else
  272. count++; // Don't count this row as it was postfiltered
  273. }
  274. else
  275. printf("%.*s :%" I64F "u:%012" I64F "x\n", size, buffer, seq, pos);
  276. }
  277. if (outRecType)
  278. outRecType->doDelete();
  279. ForEachItemIn(idx, deleteFields)
  280. {
  281. delete deleteFields.item(idx);
  282. }
  283. }
  284. }
  285. catch (IException *E)
  286. {
  287. StringBuffer msg;
  288. E->errorMessage(msg);
  289. printf("%s\n", msg.str());
  290. E->Release();
  291. }
  292. }
  293. releaseAtoms();
  294. ExitModuleObjects();
  295. return 0;
  296. }