ctfile.cpp 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052
  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 <string.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #ifdef __linux__
  18. #include <alloca.h>
  19. #endif
  20. #include "jmisc.hpp"
  21. #include "hlzw.h"
  22. #include "ctfile.hpp"
  23. #include "jstats.h"
  24. inline void SwapBigEndian(KeyHdr &hdr)
  25. {
  26. _WINREV(hdr.phyrec);
  27. _WINREV(hdr.delstk);
  28. _WINREV(hdr.numrec);
  29. _WINREV(hdr.reshdr);
  30. _WINREV(hdr.lstmbr);
  31. _WINREV(hdr.sernum);
  32. _WINREV(hdr.nument);
  33. _WINREV(hdr.root);
  34. _WINREV(hdr.fileid);
  35. _WINREV(hdr.servid);
  36. _WINREV(hdr.verson);
  37. _WINREV(hdr.nodeSize);
  38. _WINREV(hdr.extsiz);
  39. _WINREV(hdr.flmode);
  40. _WINREV(hdr.maxkbl);
  41. _WINREV(hdr.maxkbn);
  42. // _WINREV(hdr.updflg);
  43. // _WINREV(hdr.autodup);
  44. // _WINREV(hdr.deltyp);
  45. // _WINREV(hdr.keypad);
  46. // _WINREV(hdr.flflvr);
  47. // _WINREV(hdr.flalgn);
  48. // _WINREV(hdr.flpntr);
  49. _WINREV(hdr.clstyp);
  50. _WINREV(hdr.length);
  51. _WINREV(hdr.nmem);
  52. _WINREV(hdr.kmem);
  53. _WINREV(hdr.lanchr);
  54. _WINREV(hdr.supid);
  55. _WINREV(hdr.hdrpos);
  56. _WINREV(hdr.sihdr);
  57. _WINREV(hdr.timeid);
  58. _WINREV(hdr.suptyp);
  59. _WINREV(hdr.maxmrk);
  60. _WINREV(hdr.namlen);
  61. _WINREV(hdr.xflmod);
  62. _WINREV(hdr.defrel);
  63. _WINREV(hdr.hghtrn);
  64. _WINREV(hdr.hdrseq);
  65. _WINREV(hdr.tstamp);
  66. _WINREV(hdr.rs3[0]);
  67. _WINREV(hdr.rs3[1]);
  68. _WINREV(hdr.rs3[2]);
  69. _WINREV(hdr.fposOffset);
  70. _WINREV(hdr.fileSize);
  71. _WINREV(hdr.nodeKeyLength);
  72. _WINREV(hdr.version);
  73. _WINREV(hdr.blobHead);
  74. _WINREV(hdr.metadataHead);
  75. }
  76. inline void SwapBigEndian(NodeHdr &hdr)
  77. {
  78. _WINREV(hdr.rightSib);
  79. _WINREV(hdr.leftSib);
  80. _WINREV(hdr.numKeys);
  81. _WINREV(hdr.keyBytes);
  82. _WINREV(hdr.crc32);
  83. // _WINREV(hdr.memNumber);
  84. // _WINREV(hdr.leafFlag);
  85. }
  86. extern bool isCompressedIndex(const char *filename)
  87. {
  88. OwnedIFile file = createIFile(filename);
  89. OwnedIFileIO io = file->open(IFOread);
  90. unsigned __int64 size = file->size();
  91. if (size)
  92. {
  93. KeyHdr hdr;
  94. if (io->read(0, sizeof(hdr), &hdr) == sizeof(hdr))
  95. {
  96. SwapBigEndian(hdr);
  97. if (size % hdr.nodeSize == 0 && hdr.phyrec == size-1 && hdr.root && hdr.root % hdr.nodeSize == 0 && hdr.ktype & (HTREE_COMPRESSED_KEY|HTREE_QUICK_COMPRESSED_KEY))
  98. {
  99. NodeHdr root;
  100. if (io->read(hdr.root, sizeof(root), &root) == sizeof(root))
  101. {
  102. SwapBigEndian(root);
  103. return root.leftSib==0 && root.rightSib==0;
  104. }
  105. }
  106. }
  107. }
  108. return false;
  109. }
  110. // CKeyHdr
  111. CKeyHdr::CKeyHdr()
  112. {
  113. memset(&hdr, 0, sizeof(hdr));
  114. }
  115. void CKeyHdr::load(KeyHdr &_hdr)
  116. {
  117. memcpy(&hdr, &_hdr, sizeof(hdr));
  118. SwapBigEndian(hdr);
  119. if (0xffff != hdr.version && KEYBUILD_VERSION < hdr.version)
  120. throw MakeKeyException(KeyExcpt_IncompatVersion, "This build is compatible with key versions <= %u. Key is version %u", KEYBUILD_VERSION, (unsigned) hdr.version);
  121. }
  122. void CKeyHdr::write(IWriteSeq *out, CRC32 *crc)
  123. {
  124. unsigned nodeSize = hdr.nodeSize;
  125. assertex(out->getRecordSize()==nodeSize);
  126. MemoryAttr ma;
  127. byte *buf = (byte *) ma.allocate(nodeSize);
  128. memcpy(buf, &hdr, sizeof(hdr));
  129. memset(buf+sizeof(hdr), 0xff, nodeSize-sizeof(hdr));
  130. SwapBigEndian(*(KeyHdr*) buf);
  131. out->put(buf);
  132. if (crc)
  133. crc->tally(nodeSize, buf);
  134. }
  135. void CKeyHdr::write(IFileIOStream *out, CRC32 *crc)
  136. {
  137. unsigned nodeSize = hdr.nodeSize;
  138. MemoryAttr ma;
  139. byte *buf = (byte *) ma.allocate(nodeSize);
  140. memcpy(buf, &hdr, sizeof(hdr));
  141. memset(buf+sizeof(hdr), 0xff, nodeSize-sizeof(hdr));
  142. SwapBigEndian(*(KeyHdr*) buf);
  143. out->write(nodeSize, buf);
  144. if (crc)
  145. crc->tally(nodeSize, buf);
  146. }
  147. unsigned int CKeyHdr::getMaxKeyLength()
  148. {
  149. return hdr.length;
  150. }
  151. bool CKeyHdr::isVariable()
  152. {
  153. return (hdr.ktype & HTREE_VARSIZE) == HTREE_VARSIZE;
  154. }
  155. //=========================================================================================================
  156. CNodeBase::CNodeBase()
  157. {
  158. keyHdr = NULL;
  159. fpos = 0;
  160. keyLen = 0;
  161. keyCompareLen = 0;
  162. isVariable = false;
  163. }
  164. void CNodeBase::load(CKeyHdr *_keyHdr, offset_t _fpos)
  165. {
  166. _keyHdr->Link();
  167. keyHdr = _keyHdr;
  168. keyLen = keyHdr->getMaxKeyLength();
  169. keyCompareLen = keyHdr->getNodeKeyLength();
  170. keyType = keyHdr->getKeyType();
  171. memset(&hdr, 0, sizeof(hdr));
  172. fpos = _fpos;
  173. isVariable = keyHdr->isVariable();
  174. }
  175. CNodeBase::~CNodeBase()
  176. {
  177. keyHdr->Release();
  178. }
  179. //=========================================================================================================
  180. CWriteNodeBase::CWriteNodeBase(offset_t _fpos, CKeyHdr *_keyHdr)
  181. {
  182. CNodeBase::load(_keyHdr, _fpos);
  183. unsigned nodeSize = keyHdr->getNodeSize();
  184. nodeBuf = (char *) malloc(nodeSize);
  185. memset(nodeBuf, 0, nodeSize);
  186. maxBytes = keyHdr->getMaxNodeBytes();
  187. keyPtr = nodeBuf + sizeof(hdr);
  188. }
  189. CWriteNodeBase::~CWriteNodeBase()
  190. {
  191. free(nodeBuf);
  192. }
  193. void CWriteNodeBase::writeHdr()
  194. {
  195. hdr.crc32 = crc32(nodeBuf+sizeof(hdr), hdr.keyBytes, 0);
  196. memcpy(nodeBuf, &hdr, sizeof(hdr));
  197. SwapBigEndian(*(NodeHdr *) nodeBuf);
  198. }
  199. void CWriteNodeBase::write(IFileIOStream *out, CRC32 *crc)
  200. {
  201. if (isLeaf() && (keyType & HTREE_COMPRESSED_KEY))
  202. lzwcomp.close();
  203. assertex(hdr.keyBytes<=maxBytes);
  204. writeHdr();
  205. assertex(fpos);
  206. out->seek(fpos, IFSbegin);
  207. out->write(keyHdr->getNodeSize(), nodeBuf);
  208. if (crc)
  209. crc->tally(keyHdr->getNodeSize(), nodeBuf);
  210. }
  211. //=========================================================================================================
  212. CWriteNode::CWriteNode(offset_t _fpos, CKeyHdr *_keyHdr, bool isLeaf) : CWriteNodeBase(_fpos, _keyHdr)
  213. {
  214. hdr.leafFlag = isLeaf ? 1 : 0;
  215. if (!isLeaf)
  216. {
  217. keyLen = keyHdr->getNodeKeyLength();
  218. }
  219. lastKeyValue = (char *) malloc(keyLen);
  220. lastSequence = 0;
  221. }
  222. CWriteNode::~CWriteNode()
  223. {
  224. free(lastKeyValue);
  225. }
  226. bool CWriteNode::add(offset_t pos, const void *indata, size32_t insize, unsigned __int64 sequence)
  227. {
  228. if (isLeaf() && !hdr.numKeys)
  229. {
  230. unsigned __int64 rsequence = sequence;
  231. _WINREV(rsequence);
  232. memcpy(keyPtr, &rsequence, sizeof(rsequence));
  233. keyPtr += sizeof(rsequence);
  234. hdr.keyBytes += sizeof(rsequence);
  235. }
  236. #if 0
  237. // This test is no longer valid if we don't treat all fields as keyed
  238. if (hdr.numKeys)
  239. {
  240. if (memcmp(indata, lastKeyValue, keyedSize) < 0)
  241. {
  242. // dump out the rows in question
  243. StringBuffer hex;
  244. unsigned i;
  245. for (i = 0; i < insize; i++)
  246. {
  247. hex.appendf("%02x ", ((unsigned char *) indata)[i]);
  248. }
  249. DBGLOG("this: %s", hex.str());
  250. hex.clear();
  251. for (i = 0; i < insize; i++)
  252. {
  253. hex.appendf("%02x ", ((unsigned char *) lastKeyValue)[i]);
  254. }
  255. DBGLOG("last: %s", hex.str());
  256. hex.clear();
  257. for (i = 0; i < insize; i++)
  258. {
  259. unsigned char c = ((unsigned char *) indata)[i];
  260. hex.appendf("%c", isprint(c) ? c : '.');
  261. }
  262. DBGLOG("this: %s", hex.str());
  263. hex.clear();
  264. for (i = 0; i < insize; i++)
  265. {
  266. unsigned char c = ((unsigned char *) lastKeyValue)[i];
  267. hex.appendf("%c", isprint(c) ? c : '.');
  268. }
  269. DBGLOG("last: %s", hex.str());
  270. throw MakeStringException(0, "Data written to key must be in sorted order");
  271. }
  272. }
  273. #endif
  274. if (isLeaf() && keyType & HTREE_COMPRESSED_KEY)
  275. {
  276. if (0 == hdr.numKeys)
  277. lzwcomp.open(keyPtr, maxBytes-hdr.keyBytes, isVariable, (keyType&HTREE_QUICK_COMPRESSED_KEY)==HTREE_QUICK_COMPRESSED_KEY);
  278. if (0xffff == hdr.numKeys || 0 == lzwcomp.writekey(pos, (const char *)indata, insize, sequence))
  279. {
  280. lzwcomp.close();
  281. return false;
  282. }
  283. hdr.keyBytes = lzwcomp.buflen() + sizeof(unsigned __int64); // rsequence added above
  284. }
  285. else
  286. {
  287. if (0xffff == hdr.numKeys)
  288. return false;
  289. bool lastnode = false;
  290. if (!indata)
  291. {
  292. lastnode = true;
  293. indata = alloca(insize);
  294. memset((void *) indata, 0xff, insize);
  295. }
  296. //assertex(insize==keyLen);
  297. const void *data;
  298. int size;
  299. if (keyType & COL_PREFIX)
  300. {
  301. char *result = (char *) alloca(insize+1); // Gets bigger if no leading common!
  302. size = compressValue((const char *) indata, insize, result);
  303. data = result;
  304. }
  305. else
  306. {
  307. size = insize;
  308. data = indata;
  309. }
  310. int bytes = sizeof(pos) + size;
  311. if (isVariable)
  312. bytes += sizeof(KEYRECSIZE_T);
  313. if (hdr.keyBytes + bytes >= maxBytes) // probably could be '>' (loses byte)
  314. return false;
  315. if (isVariable && isLeaf())
  316. {
  317. KEYRECSIZE_T _insize = insize;
  318. _WINREV(_insize);
  319. memcpy(keyPtr, &_insize, sizeof(_insize));
  320. keyPtr += sizeof(_insize);
  321. }
  322. _WINREV(pos);
  323. memcpy(keyPtr, &pos, sizeof(pos));
  324. keyPtr += sizeof(pos);
  325. memcpy(keyPtr, data, size);
  326. keyPtr += size;
  327. hdr.keyBytes += bytes;
  328. }
  329. if (insize>keyLen)
  330. throw MakeStringException(0, "key+payload (%u) exceeds max length (%u)", insize, keyLen);
  331. memcpy(lastKeyValue, indata, insize);
  332. lastSequence = sequence;
  333. hdr.numKeys++;
  334. return true;
  335. }
  336. size32_t CWriteNode::compressValue(const char *keyData, size32_t size, char *result)
  337. {
  338. unsigned int pack = 0;
  339. if (hdr.numKeys)
  340. {
  341. for (; pack<size && pack<255; pack++)
  342. {
  343. if (keyData[pack] != lastKeyValue[pack])
  344. break;
  345. }
  346. }
  347. result[0] = pack;
  348. memcpy(&result[1], keyData+pack, size-pack);
  349. return size-pack+1;
  350. }
  351. //=========================================================================================================
  352. CBlobWriteNode::CBlobWriteNode(offset_t _fpos, CKeyHdr *_keyHdr) : CWriteNodeBase(_fpos, _keyHdr)
  353. {
  354. hdr.leafFlag = 2;
  355. lzwcomp.openBlob(keyPtr, maxBytes);
  356. }
  357. CBlobWriteNode::~CBlobWriteNode()
  358. {
  359. }
  360. unsigned __int64 CBlobWriteNode::makeBlobId(offset_t nodepos, unsigned offset)
  361. {
  362. assertex(nodepos != 0);
  363. assertex((nodepos & I64C(0xffff000000000000)) == 0);
  364. assertex((offset & 0xf) == 0);
  365. return (((unsigned __int64) offset) << 44) | nodepos;
  366. }
  367. unsigned __int64 CBlobWriteNode::add(const char * &data, size32_t &size)
  368. {
  369. assertex(fpos);
  370. unsigned __int64 ret = makeBlobId(fpos, lzwcomp.getCurrentOffset());
  371. unsigned written = lzwcomp.writeBlob(data, size);
  372. if (written)
  373. {
  374. size -= written;
  375. data = (const char *) data + written;
  376. return ret;
  377. }
  378. else
  379. return 0;
  380. }
  381. //=========================================================================================================
  382. CMetadataWriteNode::CMetadataWriteNode(offset_t _fpos, CKeyHdr *_keyHdr) : CWriteNodeBase(_fpos, _keyHdr)
  383. {
  384. hdr.leafFlag = 3;
  385. }
  386. size32_t CMetadataWriteNode::set(const char * &data, size32_t &size)
  387. {
  388. assertex(fpos);
  389. unsigned short written = ((size > (maxBytes-sizeof(unsigned short))) ? (maxBytes-sizeof(unsigned short)) : size);
  390. _WINCPYREV2(keyPtr, &written);
  391. memcpy(keyPtr+sizeof(unsigned short), data, written);
  392. data += written;
  393. size -= written;
  394. return written;
  395. }
  396. //=========================================================================================================
  397. CNodeHeader::CNodeHeader()
  398. {
  399. }
  400. void CNodeHeader::load(NodeHdr &_hdr)
  401. {
  402. memcpy(&hdr, &_hdr, sizeof(hdr));
  403. SwapBigEndian(hdr);
  404. }
  405. //=========================================================================================================
  406. CJHTreeNode::CJHTreeNode()
  407. {
  408. keyBuf = NULL;
  409. keyRecLen = 0;
  410. firstSequence = 0;
  411. expandedSize = 0;
  412. }
  413. void CJHTreeNode::load(CKeyHdr *_keyHdr, const void *rawData, offset_t _fpos, bool needCopy)
  414. {
  415. CNodeBase::load(_keyHdr, _fpos);
  416. unpack(rawData, needCopy);
  417. }
  418. CJHTreeNode::~CJHTreeNode()
  419. {
  420. releaseMem(keyBuf, expandedSize);
  421. }
  422. void CJHTreeNode::releaseMem(void *togo, size32_t len)
  423. {
  424. free(togo);
  425. unsigned __int64 _totalAllocatedCurrent;
  426. unsigned _countAllocationsCurrent;
  427. {
  428. SpinBlock b(spin);
  429. totalAllocatedCurrent -= len;
  430. countAllocationsCurrent--;
  431. _totalAllocatedCurrent = totalAllocatedCurrent;
  432. _countAllocationsCurrent = countAllocationsCurrent;
  433. }
  434. if (traceJHtreeAllocations)
  435. DBGLOG("JHTREE memory usage: Released %d - %" I64F "d currently allocated in %d allocations", len, _totalAllocatedCurrent, _countAllocationsCurrent);
  436. }
  437. void *CJHTreeNode::allocMem(size32_t len)
  438. {
  439. char *ret = (char *) malloc(len);
  440. if (!ret)
  441. {
  442. Owned<IException> E = MakeStringException(MSGAUD_operator,0, "Out of memory in CJHTreeNode::allocMem, requesting %d bytes", len);
  443. EXCLOG(E);
  444. if (flushJHtreeCacheOnOOM)
  445. {
  446. clearKeyStoreCache(false);
  447. ret = (char *) malloc(len);
  448. }
  449. if (!ret)
  450. throw E.getClear();
  451. }
  452. unsigned __int64 _totalAllocatedCurrent;
  453. unsigned __int64 _totalAllocatedEver;
  454. unsigned _countAllocationsCurrent;
  455. unsigned _countAllocationsEver;
  456. {
  457. SpinBlock b(spin);
  458. totalAllocatedCurrent += len;
  459. totalAllocatedEver += len;
  460. countAllocationsCurrent ++;
  461. countAllocationsEver ++;
  462. _totalAllocatedCurrent = totalAllocatedCurrent;
  463. _totalAllocatedEver = totalAllocatedEver;
  464. _countAllocationsCurrent = countAllocationsCurrent;
  465. _countAllocationsEver = countAllocationsEver;
  466. }
  467. if (traceJHtreeAllocations)
  468. DBGLOG("JHTREE memory usage: Allocated %d - %" I64F "d currently allocated in %d allocations", len, _totalAllocatedCurrent, _countAllocationsCurrent);
  469. return ret;
  470. }
  471. unsigned __int64 CJHTreeNode::totalAllocatedCurrent;
  472. unsigned __int64 CJHTreeNode::totalAllocatedEver;
  473. unsigned CJHTreeNode::countAllocationsCurrent;
  474. unsigned CJHTreeNode::countAllocationsEver;
  475. SpinLock CJHTreeNode::spin; // MORE: Could replace with atomic operations, but since 4 of them it may be less efficient when uncontested
  476. char *CJHTreeNode::expandKeys(void *src,unsigned keylength,size32_t &retsize, bool rowcompression)
  477. {
  478. Owned<IExpander> exp = rowcompression?createRDiffExpander():createLZWExpander(true);
  479. int len=exp->init(src);
  480. if (len==0) {
  481. retsize = 0;
  482. return NULL;
  483. }
  484. char *outkeys=(char *) allocMem(len);
  485. exp->expand(outkeys);
  486. retsize = len;
  487. return outkeys;
  488. }
  489. IRandRowExpander *CJHTreeNode::expandQuickKeys(void *src, bool needCopy)
  490. {
  491. if (IRandRowExpander::isRand(src)) {
  492. // we are going to use node
  493. IRandRowExpander *rowexp=createRandRDiffExpander();
  494. rowexp->init(src, needCopy);
  495. return rowexp;
  496. }
  497. return NULL;
  498. }
  499. void CJHTreeNode::unpack(const void *node, bool needCopy)
  500. {
  501. memcpy(&hdr, node, sizeof(hdr));
  502. SwapBigEndian(hdr);
  503. __int64 maxsib = keyHdr->getHdrStruct()->phyrec;
  504. if (!hdr.isValid(keyHdr->getNodeSize()))
  505. {
  506. PROGLOG("hdr.leafFlag=%d",(int)hdr.leafFlag);
  507. PROGLOG("hdr.rightSib=%" I64F "d",hdr.rightSib);
  508. PROGLOG("hdr.leftSib=%" I64F "d",hdr.leftSib);
  509. PROGLOG("maxsib=%" I64F "d",maxsib);
  510. PROGLOG("nodeSize=%d", keyHdr->getNodeSize());
  511. PROGLOG("keyBytes=%d",(int)hdr.keyBytes);
  512. PrintStackReport();
  513. throw MakeStringException(0, "Htree: Corrupt key node detected");
  514. }
  515. if (!hdr.leafFlag)
  516. keyLen = keyHdr->getNodeKeyLength();
  517. keyRecLen = keyLen + sizeof(offset_t);
  518. char *keys = ((char *) node) + sizeof(hdr);
  519. if (hdr.crc32)
  520. {
  521. unsigned crc = crc32(keys, hdr.keyBytes, 0);
  522. if (hdr.crc32 != crc)
  523. throw MakeStringException(0, "CRC error on key node");
  524. }
  525. if (hdr.leafFlag==1)
  526. {
  527. firstSequence = *(unsigned __int64 *) keys;
  528. keys += sizeof(unsigned __int64);
  529. _WINREV(firstSequence);
  530. }
  531. if(isMetadata())
  532. {
  533. unsigned short len = *reinterpret_cast<unsigned short *>(keys);
  534. _WINREV(len);
  535. expandedSize = len;
  536. keyBuf = (char *) allocMem(len);
  537. memcpy(keyBuf, keys+sizeof(unsigned short), len);
  538. }
  539. else if (isLeaf() && (keyType & HTREE_COMPRESSED_KEY))
  540. {
  541. {
  542. MTIME_SECTION(queryActiveTimer(), "Compressed node expand");
  543. expandedSize = keyHdr->getNodeSize();
  544. bool quick = (keyType&HTREE_QUICK_COMPRESSED_KEY)==HTREE_QUICK_COMPRESSED_KEY;
  545. #ifndef _OLD_VERSION
  546. keyBuf = NULL;
  547. if (quick)
  548. rowexp.setown(expandQuickKeys(keys, needCopy));
  549. if (!quick||!rowexp.get())
  550. #endif
  551. {
  552. keyBuf = expandKeys(keys,keyLen,expandedSize,quick);
  553. }
  554. }
  555. assertex(keyBuf||rowexp.get());
  556. }
  557. else
  558. {
  559. int i;
  560. if (keyType & COL_PREFIX)
  561. {
  562. MTIME_SECTION(queryActiveTimer(), "COL_PREFIX expand");
  563. if (hdr.numKeys) {
  564. bool handleVariable = isVariable && isLeaf();
  565. KEYRECSIZE_T workRecLen;
  566. MemoryBuffer keyBufMb;
  567. const char *source = keys;
  568. char *target;
  569. // do first row
  570. if (handleVariable) {
  571. memcpy(&workRecLen, source, sizeof(workRecLen));
  572. _WINREV(workRecLen);
  573. size32_t tmpSz = sizeof(workRecLen) + sizeof(offset_t);
  574. target = (char *)keyBufMb.reserve(tmpSz+workRecLen);
  575. memcpy(target, source, tmpSz);
  576. source += tmpSz;
  577. target += tmpSz;
  578. }
  579. else {
  580. target = (char *)keyBufMb.reserveTruncate(hdr.numKeys * keyRecLen);
  581. workRecLen = keyRecLen - sizeof(offset_t);
  582. memcpy(target, source, sizeof(offset_t));
  583. source += sizeof(offset_t);
  584. target += sizeof(offset_t);
  585. }
  586. // this is where next row gets data from
  587. const char *prev, *next = NULL;
  588. unsigned prevOffset = 0;
  589. if (handleVariable)
  590. prevOffset = target-((char *)keyBufMb.bufferBase());
  591. else
  592. next = target;
  593. unsigned char pack1 = *source++;
  594. #ifdef _DEBUG
  595. assertex(0==pack1); // 1st time will be always be 0
  596. #endif
  597. KEYRECSIZE_T left = workRecLen;
  598. while (left--) {
  599. *target = *source;
  600. source++;
  601. target++;
  602. }
  603. // do subsequent rows
  604. for (i = 1; i < hdr.numKeys; i++) {
  605. if (handleVariable) {
  606. memcpy(&workRecLen, source, sizeof(workRecLen));
  607. _WINREV(workRecLen);
  608. target = (char *)keyBufMb.reserve(sizeof(workRecLen)+sizeof(offset_t)+workRecLen);
  609. size32_t tmpSz = sizeof(workRecLen)+sizeof(offset_t);
  610. memcpy(target, source, tmpSz);
  611. target += tmpSz;
  612. source += tmpSz;
  613. }
  614. else
  615. {
  616. memcpy(target, source, sizeof(offset_t));
  617. source += sizeof(offset_t);
  618. target += sizeof(offset_t);
  619. }
  620. pack1 = *source++;
  621. #ifdef _DEBUG
  622. assertex(pack1<=workRecLen);
  623. #endif
  624. if (handleVariable) {
  625. prev = ((char *)keyBufMb.bufferBase())+prevOffset;
  626. // for next
  627. prevOffset = target-((char *)keyBufMb.bufferBase());
  628. }
  629. else {
  630. prev = next;
  631. next = target;
  632. }
  633. left = workRecLen - pack1;
  634. while (pack1--) {
  635. *target = *prev;
  636. prev++;
  637. target++;
  638. }
  639. while (left--) {
  640. *target = *source;
  641. source++;
  642. target++;
  643. }
  644. }
  645. expandedSize = keyBufMb.length();
  646. keyBuf = (char *)keyBufMb.detach();
  647. assertex(keyBuf);
  648. }
  649. else {
  650. keyBuf = NULL;
  651. expandedSize = 0;
  652. }
  653. }
  654. else
  655. {
  656. MTIME_SECTION(queryActiveTimer(), "NO compression copy");
  657. expandedSize = hdr.keyBytes + sizeof( __int64 ); // MORE - why is the +sizeof() there?
  658. keyBuf = (char *) allocMem(expandedSize);
  659. memcpy(keyBuf, keys, hdr.keyBytes + sizeof( __int64 ));
  660. }
  661. }
  662. }
  663. offset_t CJHTreeNode::prevNodeFpos() const
  664. {
  665. offset_t ll;
  666. if (!isLeaf())
  667. ll = getFPosAt(0);
  668. else
  669. ll = hdr.leftSib;
  670. return ll;
  671. }
  672. offset_t CJHTreeNode::nextNodeFpos() const
  673. {
  674. offset_t ll;
  675. if (!isLeaf())
  676. ll = getFPosAt(hdr.numKeys - 1);
  677. else
  678. ll = hdr.rightSib;
  679. return ll;
  680. }
  681. void CJHTreeNode::dump()
  682. {
  683. for (unsigned int i=0; i<getNumKeys(); i++)
  684. {
  685. unsigned char *dst = (unsigned char *) alloca(keyLen+50);
  686. getValueAt(i,(char *) dst);
  687. offset_t pos = getFPosAt(i);
  688. StringBuffer nodeval;
  689. for (unsigned j = 0; j < keyLen; j++)
  690. nodeval.appendf("%02x", dst[j] & 0xff);
  691. DBGLOG("keyVal %d [%" I64F "d] = %s", i, pos, nodeval.str());
  692. }
  693. DBGLOG("==========");
  694. }
  695. int CJHTreeNode::compareValueAt(const char *src, unsigned int index) const
  696. {
  697. if (rowexp.get())
  698. return rowexp->cmpRow(src,index,sizeof(__int64),keyCompareLen);
  699. return memcmp(src, keyBuf + index*keyRecLen + sizeof(__int64), keyCompareLen);
  700. }
  701. bool CJHTreeNode::getValueAt(unsigned int index, char *dst) const
  702. {
  703. if (index >= hdr.numKeys) return false;
  704. if (dst)
  705. {
  706. if (rowexp.get()) {
  707. rowexp->expandRow(dst,index,sizeof(__int64),keyLen);
  708. }
  709. else {
  710. const char * p = keyBuf + index*keyRecLen + sizeof(__int64);
  711. memcpy(dst, p, keyLen);
  712. }
  713. }
  714. return true;
  715. }
  716. size32_t CJHTreeNode::getSizeAt(unsigned int index) const
  717. {
  718. return keyLen;
  719. }
  720. offset_t CJHTreeNode::getFPosAt(unsigned int index) const
  721. {
  722. if (index >= hdr.numKeys) return 0;
  723. offset_t pos;
  724. if (rowexp.get())
  725. rowexp->expandRow(&pos,index,0,sizeof(pos));
  726. else {
  727. const char * p = keyBuf + index*keyRecLen;
  728. memcpy( &pos, p, sizeof(__int64));
  729. }
  730. _WINREV(pos);
  731. return pos;
  732. }
  733. unsigned __int64 CJHTreeNode::getSequence(unsigned int index) const
  734. {
  735. if (index >= hdr.numKeys) return 0;
  736. return firstSequence + index;
  737. }
  738. bool CJHTreeNode::contains(const char *src) const
  739. { // returns true if node contains key
  740. if (compareValueAt(src, 0)<0)
  741. return false;
  742. if (compareValueAt(src, hdr.numKeys-1)>0)
  743. return false;
  744. return true;
  745. }
  746. extern jhtree_decl void validateKeyFile(const char *filename, offset_t nodePos)
  747. {
  748. OwnedIFile file = createIFile(filename);
  749. OwnedIFileIO io = file->open(IFOread);
  750. if (!io)
  751. throw MakeStringException(1, "Invalid key %s: cannot open file", filename);
  752. unsigned __int64 size = file->size();
  753. if (!size)
  754. throw MakeStringException(2, "Invalid key %s: zero size", filename);
  755. KeyHdr hdr;
  756. if (io->read(0, sizeof(hdr), &hdr) != sizeof(hdr))
  757. throw MakeStringException(4, "Invalid key %s: failed to read key header", filename);
  758. CKeyHdr keyHdr;
  759. keyHdr.load(hdr);
  760. _WINREV(hdr.phyrec);
  761. _WINREV(hdr.root);
  762. _WINREV(hdr.nodeSize);
  763. if (hdr.phyrec != size-1)
  764. throw MakeStringException(5, "Invalid key %s: phyrec was %" I64F "d, expected %" I64F "d", filename, hdr.phyrec, size-1);
  765. if (size % hdr.nodeSize)
  766. throw MakeStringException(3, "Invalid key %s: size %" I64F "d is not a multiple of key node size (%d)", filename, size, hdr.nodeSize);
  767. if (!hdr.root || hdr.root % hdr.nodeSize !=0)
  768. throw MakeStringException(6, "Invalid key %s: invalid root pointer %" I64F "x", filename, hdr.root);
  769. NodeHdr root;
  770. if (io->read(hdr.root, sizeof(root), &root) != sizeof(root))
  771. throw MakeStringException(7, "Invalid key %s: failed to read root node", filename);
  772. _WINREV(root.rightSib);
  773. _WINREV(root.leftSib);
  774. if (root.leftSib || root.rightSib)
  775. throw MakeStringException(8, "Invalid key %s: invalid root node sibling pointers 0x%" I64F "x, 0x%" I64F "x (expected 0,0)", filename, root.leftSib, root.rightSib);
  776. for (offset_t nodeOffset = (nodePos ? nodePos : hdr.nodeSize); nodeOffset < (nodePos ? nodePos+1 : size); nodeOffset += hdr.nodeSize)
  777. {
  778. MemoryAttr ma;
  779. char *buffer = (char *) ma.allocate(hdr.nodeSize);
  780. {
  781. MTIME_SECTION(queryActiveTimer(), "JHTREE read index node");
  782. io->read(nodeOffset, hdr.nodeSize, buffer);
  783. }
  784. CJHTreeNode theNode;
  785. {
  786. MTIME_SECTION(queryActiveTimer(), "JHTREE load index node");
  787. theNode.load(&keyHdr, buffer, nodeOffset, true);
  788. }
  789. NodeHdr *nodeHdr = (NodeHdr *) buffer;
  790. SwapBigEndian(*nodeHdr);
  791. if (!nodeHdr->isValid(hdr.nodeSize))
  792. throw MakeStringException(9, "Invalid key %s: invalid node header at position 0x%" I64F "x", filename, nodeOffset);
  793. if (nodeHdr->leftSib >= size || nodeHdr->rightSib >= size)
  794. throw MakeStringException(9, "Invalid key %s: out of range sibling pointers 0x%" I64F "x, 0x%" I64F "x at position 0x%" I64F "x", filename, nodeHdr->leftSib, nodeHdr->rightSib, nodeOffset);
  795. if (nodeHdr->crc32)
  796. {
  797. unsigned crc = crc32(buffer + sizeof(NodeHdr), nodeHdr->keyBytes, 0);
  798. if (crc != nodeHdr->crc32)
  799. throw MakeStringException(9, "Invalid key %s: crc mismatch at position 0x%" I64F "x", filename, nodeOffset);
  800. }
  801. else
  802. {
  803. // MORE - if we felt so inclined, we could decode the node and check records were in ascending order
  804. }
  805. }
  806. }
  807. //=========================================================================================================
  808. CJHVarTreeNode::CJHVarTreeNode()
  809. {
  810. recArray = NULL;
  811. }
  812. void CJHVarTreeNode::load(CKeyHdr *_keyHdr, const void *rawData, offset_t _fpos, bool needCopy)
  813. {
  814. CJHTreeNode::load(_keyHdr, rawData, _fpos, needCopy);
  815. unsigned n = getNumKeys();
  816. recArray = new const char * [n];
  817. const char *finger = keyBuf;
  818. for (unsigned int i=0; i<getNumKeys(); i++)
  819. {
  820. recArray[i] = finger + sizeof(KEYRECSIZE_T);
  821. KEYRECSIZE_T recsize = *(KEYRECSIZE_T *)finger;
  822. _WINREV(recsize);
  823. finger += recsize + sizeof(KEYRECSIZE_T) + sizeof(offset_t);
  824. }
  825. }
  826. CJHVarTreeNode::~CJHVarTreeNode()
  827. {
  828. delete [] recArray;
  829. }
  830. void CJHVarTreeNode::dump()
  831. {
  832. for (unsigned int i=0; i<getNumKeys(); i++)
  833. {
  834. const void * p = recArray[i];
  835. unsigned reclen = ((KEYRECSIZE_T *) p)[-1];
  836. _WINREV(reclen);
  837. unsigned char *dst = (unsigned char *) alloca(reclen);
  838. getValueAt(i,(char *) dst);
  839. offset_t pos = getFPosAt(i);
  840. StringBuffer nodeval;
  841. for (unsigned j = 0; j < reclen; j++)
  842. nodeval.appendf("%02x", dst[j] & 0xff);
  843. DBGLOG("keyVal %d [%" I64F "d] = %s", i, pos, nodeval.str());
  844. }
  845. DBGLOG("==========");
  846. }
  847. int CJHVarTreeNode::compareValueAt(const char *src, unsigned int index) const
  848. {
  849. return memcmp(src, recArray[index] + sizeof(offset_t), keyCompareLen);
  850. }
  851. bool CJHVarTreeNode::getValueAt(unsigned int num, char *dst) const
  852. {
  853. if (num >= hdr.numKeys) return false;
  854. if (NULL != dst)
  855. {
  856. const char * p = recArray[num];
  857. KEYRECSIZE_T reclen = ((KEYRECSIZE_T *) p)[-1];
  858. _WINREV(reclen);
  859. memcpy(dst, p + sizeof(offset_t), reclen);
  860. }
  861. return true;
  862. }
  863. size32_t CJHVarTreeNode::getSizeAt(unsigned int num) const
  864. {
  865. const char * p = recArray[num];
  866. KEYRECSIZE_T reclen = ((KEYRECSIZE_T *) p)[-1];
  867. _WINREV(reclen);
  868. return reclen;
  869. }
  870. offset_t CJHVarTreeNode::getFPosAt(unsigned int num) const
  871. {
  872. if (num >= hdr.numKeys) return 0;
  873. const char * p = recArray[num];
  874. offset_t pos;
  875. memcpy( &pos, p, sizeof(__int64) );
  876. _WINREV(pos);
  877. return pos;
  878. }
  879. //=========================================================================================================
  880. CJHTreeBlobNode::CJHTreeBlobNode()
  881. {
  882. }
  883. CJHTreeBlobNode::~CJHTreeBlobNode()
  884. {
  885. }
  886. size32_t CJHTreeBlobNode::getTotalBlobSize(unsigned offset)
  887. {
  888. assertex(offset < expandedSize);
  889. unsigned datalen;
  890. memcpy(&datalen, keyBuf+offset, sizeof(datalen));
  891. _WINREV(datalen);
  892. return datalen;
  893. }
  894. size32_t CJHTreeBlobNode::getBlobData(unsigned offset, void *dst)
  895. {
  896. unsigned sizeHere = getTotalBlobSize(offset);
  897. offset += sizeof(unsigned);
  898. if (sizeHere > expandedSize - offset)
  899. sizeHere = expandedSize - offset;
  900. memcpy(dst, keyBuf+offset, sizeHere);
  901. return sizeHere;
  902. }
  903. void CJHTreeMetadataNode::get(StringBuffer & out)
  904. {
  905. out.append(expandedSize, keyBuf);
  906. }
  907. class DECL_EXCEPTION CKeyException : implements IKeyException, public CInterface
  908. {
  909. int errCode;
  910. StringBuffer errMsg;
  911. public:
  912. IMPLEMENT_IINTERFACE;
  913. CKeyException(int _errCode, const char *_errMsg, va_list &args) __attribute__((format(printf,3,0))) : errCode(_errCode)
  914. {
  915. if (_errMsg)
  916. errMsg.valist_appendf(_errMsg, args);
  917. }
  918. StringBuffer &translateCode(StringBuffer &out) const
  919. {
  920. out.append("IKeyException: ");
  921. switch (errCode)
  922. {
  923. case KeyExcpt_IncompatVersion:
  924. return out.append("Incompatible key version.");
  925. default:
  926. return out.append("UNKNOWN ERROR");
  927. }
  928. }
  929. // IException
  930. int errorCode() const { return errCode; }
  931. StringBuffer &errorMessage(StringBuffer &out) const
  932. {
  933. return translateCode(out).append("\n").append(errMsg.str());
  934. }
  935. MessageAudience errorAudience() const { return MSGAUD_user; }
  936. };
  937. IKeyException *MakeKeyException(int code, const char *format, ...)
  938. {
  939. va_list args;
  940. va_start(args, format);
  941. IKeyException *e = new CKeyException(code, format, args);
  942. va_end(args);
  943. return e;
  944. }