rtlrecord.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2016 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 <math.h>
  15. #include <stdio.h>
  16. #include "jmisc.hpp"
  17. #include "jlib.hpp"
  18. #include "eclhelper.hpp"
  19. #include "eclrtl_imp.hpp"
  20. #include "rtlds_imp.hpp"
  21. #include "rtlrecord.hpp"
  22. #include "rtldynfield.hpp"
  23. /*
  24. * Potential different implementations (for all fixed size has no penalty):
  25. *
  26. * a. when row changes, update offsets of all offset fields
  27. * + access is simple, single array lookup
  28. * - lots more fields are updated even if the fields aren't used.
  29. *
  30. * b. when a row changes update the next offset for all variable size fields.
  31. * + minimal updates
  32. * - offset access is more complex
  33. *
  34. * c. when row changes clear cache, and calculate on demand.
  35. * + trivial update on row change
  36. * + no cost of fields not accessed
  37. * + may be required to implement ifblocks - since fields in the test expression must be evaluated before all the
  38. * offsets are known. Depends on the implementation of ifblocks!
  39. * - accessing an offset will involve a loop and be more expensive
  40. *
  41. * Handling complications:
  42. * a. Nested rows
  43. * A dilemma. Should they be expanded?
  44. * + If they are expanded then it makes it much simpler to use externally.
  45. * - The nested fields have compound names storing and matching them is a complication.
  46. * - The code generator doesn't expand.
  47. * + It is easier to calculate offsets since all fields are supported by the same class.
  48. * + Sizes for unexpanded rows would need their own size caching classes. That is more complex!
  49. * + The meta information currently processes child information.
  50. *
  51. * Not expanding is complicated if you also try and only calculate the offsets of fields in nested records once - since you end
  52. * up needing to call back and forth between instances and the static information.
  53. * However, if nested records are processed by using size(), and selections from them are processed by instantiating
  54. * an instance of the nested row it is all much simpler. The cost is potentially re-evaluating sizes of nested fields. Potentially
  55. * inefficient if most are fixed size, but some are variable.
  56. *
  57. * b. bitfields
  58. * the last bitfield in a bitfield container has the size of the container, the others have 0 size.
  59. *
  60. * c. ifblocks
  61. * A field in an ifblock can be viewed as a variable size field - size is either 0 or normal size
  62. * depending on the condition in question. We add a flag and a pointer to the ifblock info into
  63. * each contained field. Only properly supported in expanded mode.
  64. * Might be cleanest to have a different derived implementation which was used if the record
  65. * contained ifblocks, though this would mean we would need to make some functions virtual or else move
  66. * the responsibility for knowing about ifblocks out to all customers?
  67. * Added calls to check ifblocks before size()/getValue() etc. will require an extra row parameter
  68. * to every RtlTypeInfo::getX() function? Not if it is required that the offsets have been set first.
  69. * Evaluating the test expression without compiling will require expression interpreting.
  70. *
  71. * d. alien datatypes
  72. * As long as the rtlField class implements the functions then it shouldn't cause any problems. Evaluating at
  73. * from a record at runtime without compiling will be tricky - requires an interpreter.
  74. *
  75. * Other
  76. * Add a minSize to each field (unless already stored in the record information)
  77. *
  78. * Expression interpreting:
  79. * Replace the no_select with a CHqlBoundExpr(no_select, fieldid).
  80. * Evaluate (ctx [ logical->RtlFieldOffsetCalculator mapping ]).
  81. * Even better if mapped direct to something that represents the base cursor so no need to search ctx.
  82. * For nested selects the code would need to be consistent.
  83. */
  84. static unsigned countFields(const RtlFieldInfo * const * fields, bool & containsNested, unsigned &numIfBlocks)
  85. {
  86. unsigned cnt = 0;
  87. for (;*fields;fields++)
  88. {
  89. const RtlTypeInfo * type = (*fields)->type;
  90. if (type->getType() == type_record || type->getType()==type_ifblock)
  91. {
  92. containsNested = true;
  93. if (type->getType()==type_ifblock)
  94. numIfBlocks++;
  95. const RtlFieldInfo * const * nested = type->queryFields();
  96. if (nested)
  97. cnt += countFields(nested, containsNested, numIfBlocks);
  98. }
  99. else
  100. cnt++;
  101. }
  102. return cnt;
  103. }
  104. class IfBlockInfo
  105. {
  106. public:
  107. IfBlockInfo(const RtlFieldInfo &_field, const IfBlockInfo *_parent, unsigned _idx)
  108. : field(_field), parent(_parent), idx(_idx)
  109. {}
  110. bool excluded(const byte *row, byte *conditions) const
  111. {
  112. if (conditions[idx]==2)
  113. {
  114. if (parent && parent->excluded(row, conditions))
  115. conditions[idx] = 0;
  116. else
  117. {
  118. const RtlIfBlockTypeInfo *cond = static_cast<const RtlIfBlockTypeInfo *>(field.type);
  119. conditions[idx] = cond->getCondition(row) ? 1 : 0;
  120. }
  121. }
  122. return conditions[idx]==0;
  123. }
  124. private:
  125. const RtlFieldInfo &field;
  126. const IfBlockInfo *parent = nullptr; // for nested ifblocks
  127. unsigned idx;
  128. };
  129. class RtlCondFieldStrInfo : public RtlFieldStrInfo
  130. {
  131. public:
  132. RtlCondFieldStrInfo(const RtlFieldInfo &from, const IfBlockInfo &_ifblock)
  133. : RtlFieldStrInfo(from.name, from.xpath, from.type, from.flags | (RFTMinifblock|RFTMdynamic), (const char *) from.initializer),
  134. origField(from),ifblock(_ifblock)
  135. {
  136. }
  137. public:
  138. const RtlFieldInfo &origField;
  139. const IfBlockInfo &ifblock;
  140. };
  141. static unsigned expandNestedRows(unsigned idx, const char *prefix, const RtlFieldInfo * const * fields, const RtlFieldInfo * * target, const char * *names, const IfBlockInfo *inIfBlock, ConstPointerArrayOf<IfBlockInfo> &ifblocks)
  142. {
  143. for (;*fields;fields++)
  144. {
  145. const RtlFieldInfo * cur = *fields;
  146. const RtlTypeInfo * type = cur->type;
  147. bool isIfBlock = type->getType()==type_ifblock;
  148. if (isIfBlock || type->getType() == type_record)
  149. {
  150. const IfBlockInfo *nestIfBlock = inIfBlock;
  151. if (isIfBlock)
  152. {
  153. nestIfBlock = new IfBlockInfo(*cur, inIfBlock, ifblocks.ordinality());
  154. ifblocks.append(nestIfBlock);
  155. }
  156. const RtlFieldInfo * const * nested = type->queryFields();
  157. if (nested)
  158. {
  159. StringBuffer newPrefix(prefix);
  160. if (cur->name && *cur->name)
  161. newPrefix.append(cur->name).append('.');
  162. idx = expandNestedRows(idx, newPrefix.str(), nested, target, names, nestIfBlock, ifblocks);
  163. }
  164. }
  165. else
  166. {
  167. if (prefix)
  168. {
  169. StringBuffer name(prefix);
  170. name.append(cur->name);
  171. names[idx] = name.detach();
  172. }
  173. else
  174. names[idx] = nullptr;
  175. if (inIfBlock && !(cur->flags & RFTMinifblock))
  176. target[idx++] = new RtlCondFieldStrInfo(*cur, *inIfBlock);
  177. else
  178. {
  179. dbgassertex((cur->flags & RFTMdynamic) == 0);
  180. target[idx++] = cur;
  181. }
  182. }
  183. }
  184. return idx;
  185. }
  186. class FieldNameToFieldNumMap
  187. {
  188. public:
  189. FieldNameToFieldNumMap(const RtlRecord &record)
  190. {
  191. unsigned numFields = record.getNumFields();
  192. for (unsigned idx = 0; idx < numFields;idx++)
  193. map.setValue(record.queryName(idx), idx);
  194. }
  195. unsigned lookup(const char *name) const
  196. {
  197. unsigned *result = map.getValue(name);
  198. if (result)
  199. return *result;
  200. else
  201. return (unsigned) -1;
  202. }
  203. MapConstStringTo<unsigned> map; // Note - does not copy strings - they should all have sufficient lifetime
  204. };
  205. RtlRecord::RtlRecord(const RtlRecordTypeInfo & record, bool expandFields)
  206. : RtlRecord(record.fields, expandFields) // delegated constructor
  207. {
  208. }
  209. RtlRecord::RtlRecord(const RtlFieldInfo * const *_fields, bool expandFields) : fields(_fields), originalFields(_fields), names(nullptr), nameMap(nullptr)
  210. {
  211. numVarFields = 0;
  212. numTables = 0;
  213. numIfBlocks = 0;
  214. ifblocks = nullptr;
  215. //Optionally expand out nested rows.
  216. if (expandFields)
  217. {
  218. bool containsNested = false;
  219. numFields = countFields(fields, containsNested, numIfBlocks);
  220. if (containsNested)
  221. {
  222. ConstPointerArrayOf<IfBlockInfo> _ifblocks;
  223. const RtlFieldInfo * * allocated = new const RtlFieldInfo * [numFields+1];
  224. names = new const char *[numFields];
  225. fields = allocated;
  226. unsigned idx = expandNestedRows(0, nullptr, originalFields, allocated, names, nullptr, _ifblocks);
  227. ifblocks = _ifblocks.detach();
  228. assertex(idx == numFields);
  229. allocated[idx] = nullptr;
  230. }
  231. }
  232. else
  233. {
  234. numFields = countFields(fields);
  235. }
  236. for (unsigned i=0; i < numFields; i++)
  237. {
  238. const RtlTypeInfo *curType = queryType(i);
  239. if (!curType->isFixedSize() || (fields[i]->flags & RFTMinifblock))
  240. numVarFields++;
  241. if (curType->getType()==type_table || curType->getType()==type_record)
  242. numTables++;
  243. }
  244. fixedOffsets = new size_t[numFields + 1];
  245. whichVariableOffset = new unsigned[numFields + 1];
  246. variableFieldIds = new unsigned[numVarFields];
  247. if (numTables)
  248. {
  249. nestedTables = new const RtlRecord *[numTables];
  250. tableIds = new unsigned[numTables];
  251. }
  252. else
  253. {
  254. nestedTables = nullptr;
  255. tableIds = nullptr;
  256. }
  257. unsigned curVariable = 0;
  258. unsigned curTable = 0;
  259. size_t fixedOffset = 0;
  260. for (unsigned i=0;; i++)
  261. {
  262. whichVariableOffset[i] = curVariable;
  263. fixedOffsets[i] = fixedOffset;
  264. if (i == numFields)
  265. break;
  266. const RtlTypeInfo * curType = queryType(i);
  267. if (curType->isFixedSize() && !(fields[i]->flags & RFTMinifblock))
  268. {
  269. size_t thisSize = curType->size(nullptr, nullptr);
  270. fixedOffset += thisSize;
  271. }
  272. else
  273. {
  274. variableFieldIds[curVariable] = i;
  275. curVariable++;
  276. fixedOffset = 0;
  277. }
  278. switch (curType->getType())
  279. {
  280. case type_table:
  281. tableIds[curTable] = i;
  282. nestedTables[curTable++] = new RtlRecord(curType->queryChildType()->queryFields(), expandFields);
  283. break;
  284. case type_record:
  285. tableIds[curTable] = i;
  286. nestedTables[curTable++] = new RtlRecord(curType->queryFields(), expandFields);
  287. break;
  288. }
  289. }
  290. }
  291. RtlRecord::~RtlRecord()
  292. {
  293. if (names)
  294. {
  295. for (unsigned i = 0; i < numFields; i++)
  296. {
  297. free((char *) names[i]);
  298. }
  299. delete [] names;
  300. }
  301. if (fields != originalFields)
  302. {
  303. for (const RtlFieldInfo * const * finger = fields; *finger; finger++)
  304. {
  305. const RtlFieldInfo *thisField = *finger;
  306. if (thisField->flags & RFTMdynamic)
  307. delete thisField;
  308. }
  309. delete [] fields;
  310. }
  311. if (ifblocks)
  312. {
  313. for (unsigned i = 0; i < numIfBlocks; i++)
  314. {
  315. delete(ifblocks[i]);
  316. }
  317. delete [] ifblocks;
  318. }
  319. delete [] fixedOffsets;
  320. delete [] whichVariableOffset;
  321. delete [] variableFieldIds;
  322. delete [] tableIds;
  323. if (nestedTables)
  324. {
  325. for (unsigned i = 0; i < numTables; i++)
  326. delete nestedTables[i];
  327. delete [] nestedTables;
  328. }
  329. delete nameMap;
  330. }
  331. unsigned RtlRecord::getNumKeyedFields() const
  332. {
  333. unsigned ret = 0;
  334. for (const RtlFieldInfo * const * finger = originalFields; *finger; finger++)
  335. {
  336. if ((*finger)->flags & RFTMispayloadfield)
  337. break;
  338. ret++;
  339. }
  340. return ret;
  341. }
  342. void RtlRecord::calcRowOffsets(size_t * variableOffsets, const void * _row, unsigned numFieldsUsed) const
  343. {
  344. const byte * row = static_cast<const byte *>(_row);
  345. unsigned maxVarField = (numFieldsUsed>=numFields) ? numVarFields : whichVariableOffset[numFieldsUsed];
  346. if (numIfBlocks)
  347. {
  348. byte *conditions = (byte *) alloca(numIfBlocks * sizeof(byte));
  349. memset(conditions, 2, numIfBlocks); // Meaning condition not yet calculated
  350. for (unsigned i = 0; i < maxVarField; i++)
  351. {
  352. unsigned fieldIndex = variableFieldIds[i];
  353. const RtlFieldInfo *field = fields[fieldIndex];
  354. size_t offset = getOffset(variableOffsets, fieldIndex);
  355. if (field->flags & RFTMinifblock)
  356. {
  357. const RtlCondFieldStrInfo *condfield = static_cast<const RtlCondFieldStrInfo *>(field);
  358. if (condfield->ifblock.excluded(row, conditions))
  359. {
  360. variableOffsets[i+1] = offset; // (meaning size ends up as zero);
  361. continue;
  362. }
  363. }
  364. size_t fieldSize = queryType(fieldIndex)->size(row + offset, row);
  365. variableOffsets[i+1] = offset+fieldSize;
  366. }
  367. }
  368. else
  369. {
  370. size32_t varoffset = 0;
  371. for (unsigned i = 0; i < maxVarField; i++)
  372. {
  373. unsigned fieldIndex = variableFieldIds[i];
  374. size32_t offset = fixedOffsets[fieldIndex] + varoffset;
  375. size32_t fieldSize = queryType(fieldIndex)->size(row + offset, row);
  376. varoffset = offset+fieldSize;
  377. variableOffsets[i+1] = varoffset;
  378. }
  379. }
  380. #ifdef _DEBUG
  381. for (unsigned i = maxVarField; i < numVarFields; i++)
  382. {
  383. variableOffsets[i+1] = 0x7fffffff;
  384. }
  385. #endif
  386. }
  387. size32_t RtlRecord::getMinRecordSize() const
  388. {
  389. if (numVarFields == 0)
  390. return fixedOffsets[numFields];
  391. size32_t minSize = 0;
  392. for (unsigned i=0; i < numFields; i++)
  393. {
  394. const RtlFieldInfo *field = fields[i];
  395. if (!(field->flags & RFTMinifblock))
  396. minSize += queryType(i)->getMinSize();
  397. }
  398. return minSize;
  399. }
  400. size32_t RtlRecord::deserialize(ARowBuilder & rowBuilder, IRowDeserializerSource & in) const
  401. {
  402. size32_t offset = 0;
  403. byte *conditionValues = (byte *) alloca(numIfBlocks);
  404. memset(conditionValues, 2, numIfBlocks);
  405. for (unsigned i = 0; i < numVarFields; i++)
  406. {
  407. unsigned fieldIndex = variableFieldIds[i];
  408. const RtlFieldInfo *field = fields[fieldIndex];
  409. size32_t fixedSize = fixedOffsets[fieldIndex];
  410. byte * self = rowBuilder.ensureCapacity(offset + fixedSize, ""); // Why not field->name?
  411. in.read(fixedSize, self + offset);
  412. if (field->omitable() && static_cast<const RtlCondFieldStrInfo *>(field)->ifblock.excluded(self, conditionValues))
  413. continue;
  414. offset = queryType(fieldIndex)->deserialize(rowBuilder, in, offset);
  415. }
  416. size32_t lastFixedSize = fixedOffsets[numFields];
  417. byte * self = rowBuilder.ensureCapacity(offset + lastFixedSize, "");
  418. in.read(lastFixedSize, self + offset);
  419. return offset + lastFixedSize;
  420. }
  421. void RtlRecord::readAhead(IRowDeserializerSource & in) const
  422. {
  423. // Note - this should not and can not be used when ifblocks present - canprefetch flag should take care of that.
  424. dbgassertex(numIfBlocks==0);
  425. for (unsigned i=0; i < numVarFields; i++)
  426. {
  427. unsigned fieldIndex = variableFieldIds[i];
  428. in.skip(fixedOffsets[fieldIndex]);
  429. queryType(fieldIndex)->readAhead(in);
  430. }
  431. in.skip(fixedOffsets[numFields]);
  432. }
  433. static const FieldNameToFieldNumMap *setupNameMap(const RtlRecord &record, std::atomic<const FieldNameToFieldNumMap *> &aNameMap)
  434. {
  435. const FieldNameToFieldNumMap *lnameMap = new FieldNameToFieldNumMap(record);
  436. const FieldNameToFieldNumMap *expected = nullptr;
  437. if (aNameMap.compare_exchange_strong(expected, lnameMap))
  438. return lnameMap;
  439. else
  440. {
  441. // Other thread already set it while we were creating
  442. delete lnameMap;
  443. return expected; // has been updated to the value set by other thread
  444. }
  445. }
  446. unsigned RtlRecord::getFieldNum(const char *fieldName) const
  447. {
  448. // NOTE: the nameMap field cannot be declared as atomic, since the class definition is included in generated
  449. // code which is not (yet) compiled using C++11. If that changes then the reinterpret_cast can be removed.
  450. std::atomic<const FieldNameToFieldNumMap *> &aNameMap = reinterpret_cast<std::atomic<const FieldNameToFieldNumMap *> &>(nameMap);
  451. const FieldNameToFieldNumMap *useMap = aNameMap.load(std::memory_order_relaxed);
  452. if (!useMap)
  453. useMap = setupNameMap(*this, aNameMap);
  454. return useMap->lookup(fieldName);
  455. }
  456. const char *RtlRecord::queryName(unsigned field) const
  457. {
  458. if (names && names[field])
  459. return names[field];
  460. return fields[field]->name;
  461. }
  462. const RtlRecord *RtlRecord::queryNested(unsigned fieldId) const
  463. {
  464. // Map goes in wrong direction (for size reasons). We could replace with a hashtable or binsearch but
  465. // should not be enough nested tables for it to be worth it;
  466. for (unsigned i = 0; i < numTables; i++)
  467. if (tableIds[i]==fieldId)
  468. return nestedTables[i];
  469. return nullptr;
  470. }
  471. const RtlFieldInfo *RtlRecord::queryOriginalField(unsigned idx) const
  472. {
  473. const RtlFieldInfo *field = queryField(idx);
  474. if (field->flags & RFTMdynamic)
  475. return &static_cast<const RtlCondFieldStrInfo *>(field)->origField;
  476. else
  477. return field;
  478. }
  479. bool RtlRecord::excluded(const RtlFieldInfo *field, const byte *row, byte *conditionValues)
  480. {
  481. return (field->omitable() && static_cast<const RtlCondFieldStrInfo *>(field)->ifblock.excluded(row, conditionValues));
  482. }
  483. size_t RtlRecord::getFixedOffset(unsigned field) const
  484. {
  485. assert(whichVariableOffset[field]==0);
  486. return fixedOffsets[field];
  487. }
  488. size32_t RtlRecord::getRecordSize(const void *_row) const
  489. {
  490. size32_t size = getFixedSize();
  491. if (!size)
  492. {
  493. const byte * row = static_cast<const byte *>(_row);
  494. size32_t varoffset = 0;
  495. for (unsigned i = 0; i < numVarFields; i++)
  496. {
  497. unsigned fieldIndex = variableFieldIds[i];
  498. size32_t offset = fixedOffsets[fieldIndex] + varoffset;
  499. size32_t fieldSize = queryType(fieldIndex)->size(row + offset, row);
  500. varoffset = offset + fieldSize;
  501. }
  502. size = fixedOffsets[numFields] + varoffset;
  503. }
  504. return size;
  505. }
  506. //---------------------------------------------------------------------------------------------------------------------
  507. RtlRow::RtlRow(const RtlRecord & _info, const void * optRow, unsigned numOffsets, size_t * _variableOffsets) : info(_info), variableOffsets(_variableOffsets)
  508. {
  509. assertex(numOffsets == info.getNumVarFields()+1);
  510. //variableOffset[0] is used for all fixed offset fields to avoid any special casing.
  511. variableOffsets[0] = 0;
  512. setRow(optRow);
  513. }
  514. __int64 RtlRow::getInt(unsigned field) const
  515. {
  516. const byte * self = reinterpret_cast<const byte *>(row);
  517. const RtlFieldInfo *fieldInfo = info.queryField(field);
  518. const RtlTypeInfo * type = fieldInfo->type;
  519. if (!fieldInfo->omitable() || getSize(field))
  520. return type->getInt(self + getOffset(field));
  521. else if (fieldInfo->initializer)
  522. return type->getInt(fieldInfo->initializer);
  523. else
  524. return 0;
  525. }
  526. double RtlRow::getReal(unsigned field) const
  527. {
  528. const byte * self = reinterpret_cast<const byte *>(row);
  529. const RtlFieldInfo *fieldInfo = info.queryField(field);
  530. const RtlTypeInfo * type = fieldInfo->type;
  531. if (!fieldInfo->omitable() || getSize(field))
  532. return type->getReal(self + getOffset(field));
  533. else if (fieldInfo->initializer)
  534. return type->getReal(fieldInfo->initializer);
  535. else
  536. return 0;
  537. }
  538. void RtlRow::getString(size32_t & resultLen, char * & result, unsigned field) const
  539. {
  540. const byte * self = reinterpret_cast<const byte *>(row);
  541. const RtlFieldInfo *fieldInfo = info.queryField(field);
  542. const RtlTypeInfo * type = fieldInfo->type;
  543. if (!fieldInfo->omitable() || getSize(field))
  544. type->getString(resultLen, result, self + getOffset(field));
  545. else if (fieldInfo->initializer)
  546. type->getString(resultLen, result, fieldInfo->initializer);
  547. else
  548. {
  549. resultLen = 0;
  550. result = nullptr;
  551. }
  552. }
  553. void RtlRow::getUtf8(size32_t & resultLen, char * & result, unsigned field) const
  554. {
  555. const byte * self = reinterpret_cast<const byte *>(row);
  556. const RtlFieldInfo *fieldInfo = info.queryField(field);
  557. const RtlTypeInfo * type = fieldInfo->type;
  558. if (!fieldInfo->omitable() || getSize(field))
  559. type->getUtf8(resultLen, result, self + getOffset(field));
  560. else if (fieldInfo->initializer)
  561. type->getUtf8(resultLen, result, fieldInfo->initializer);
  562. else
  563. {
  564. resultLen = 0;
  565. result = nullptr;
  566. }
  567. }
  568. void RtlRow::setRow(const void * _row)
  569. {
  570. row = (const byte *)_row;
  571. if (_row)
  572. info.calcRowOffsets(variableOffsets, _row);
  573. }
  574. void RtlRow::setRow(const void * _row, unsigned _numFields)
  575. {
  576. row = (const byte *)_row;
  577. if (_row)
  578. info.calcRowOffsets(variableOffsets, _row, _numFields);
  579. }
  580. RtlDynRow::RtlDynRow(const RtlRecord & _info, const void * optRow) : RtlRow(_info, optRow, _info.getNumVarFields()+1, new size_t[_info.getNumVarFields()+1])
  581. {
  582. }
  583. RtlDynRow::~RtlDynRow()
  584. {
  585. delete [] variableOffsets;
  586. }
  587. //---------------------------------------------------------------------------------------------------------------------
  588. class CDefaultDeserializer : public CInterfaceOf<IOutputRowDeserializer>
  589. {
  590. public:
  591. CDefaultDeserializer(const RtlRecord & _record) : record(_record) {}
  592. virtual size32_t deserialize(ARowBuilder & rowBuilder, IRowDeserializerSource & in)
  593. {
  594. return record.deserialize(rowBuilder, in);
  595. }
  596. private:
  597. const RtlRecord & record;
  598. };
  599. class CDefaultPrefetcher : public CInterfaceOf<ISourceRowPrefetcher>
  600. {
  601. public:
  602. CDefaultPrefetcher(const RtlRecord & _record) : record(_record) {}
  603. virtual void readAhead(IRowDeserializerSource & in)
  604. {
  605. record.readAhead(in);
  606. }
  607. private:
  608. const RtlRecord & record;
  609. };
  610. //-----------------
  611. static const RtlRecord *setupRecordAccessor(const COutputMetaData &meta, bool expand, std::atomic<const RtlRecord *> &aRecordAccessor)
  612. {
  613. const RtlRecord *lRecordAccessor = new RtlRecord(meta.queryTypeInfo()->queryFields(), expand);
  614. const RtlRecord *expected = nullptr;
  615. if (aRecordAccessor.compare_exchange_strong(expected, lRecordAccessor))
  616. return lRecordAccessor;
  617. else
  618. {
  619. // Other thread already set it while we were creating
  620. delete lRecordAccessor;
  621. return expected; // has been updated to the value set by other thread
  622. }
  623. }
  624. COutputMetaData::COutputMetaData()
  625. {
  626. recordAccessor[0] = recordAccessor[1] = NULL;
  627. }
  628. COutputMetaData::~COutputMetaData()
  629. {
  630. delete recordAccessor[0]; delete recordAccessor[1];
  631. }
  632. const RtlRecord &COutputMetaData::queryRecordAccessor(bool expand) const
  633. {
  634. // NOTE: the recordAccessor field cannot be declared as atomic, since the class definition is included in generated
  635. // code which does not include <atomic>. If that changes then the reinterpret_cast can be removed.
  636. std::atomic<const RtlRecord *> &aRecordAccessor = reinterpret_cast<std::atomic<const RtlRecord *> &>(recordAccessor[expand]);
  637. const RtlRecord *useAccessor = aRecordAccessor.load(std::memory_order_relaxed);
  638. if (!useAccessor)
  639. useAccessor = setupRecordAccessor(*this, expand, aRecordAccessor);
  640. return *useAccessor;
  641. }
  642. size32_t COutputMetaData::getRecordSize(const void * data)
  643. {
  644. return queryRecordAccessor(true).getRecordSize(data);
  645. }
  646. class CVariableOutputRowSerializer : public COutputRowSerializer
  647. {
  648. public:
  649. inline CVariableOutputRowSerializer(unsigned _activityId, IOutputMetaData * _meta) : COutputRowSerializer(_activityId) { meta = _meta; }
  650. virtual void serialize(IRowSerializerTarget & out, const byte * self)
  651. {
  652. unsigned size = meta->getRecordSize(self);
  653. out.put(size, self);
  654. }
  655. protected:
  656. IOutputMetaData * meta;
  657. };
  658. class ECLRTL_API CSimpleSourceRowPrefetcher : public ISourceRowPrefetcher, public RtlCInterface
  659. {
  660. public:
  661. CSimpleSourceRowPrefetcher(IOutputMetaData & _meta, ICodeContext * _ctx, unsigned _activityId)
  662. {
  663. deserializer.setown(_meta.querySerializedDiskMeta()->createDiskDeserializer(_ctx, _activityId));
  664. rowAllocator.setown(_ctx->getRowAllocator(&_meta, _activityId));
  665. }
  666. RTLIMPLEMENT_IINTERFACE
  667. virtual void readAhead(IRowDeserializerSource & in)
  668. {
  669. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  670. size32_t len = deserializer->deserialize(rowBuilder, in);
  671. rtlReleaseRow(rowBuilder.finalizeRowClear(len));
  672. }
  673. protected:
  674. Owned<IOutputRowDeserializer> deserializer;
  675. Owned<IEngineRowAllocator> rowAllocator;
  676. };
  677. //---------------------------------------------------------------------------
  678. IOutputRowSerializer * COutputMetaData::createDiskSerializer(ICodeContext * ctx, unsigned activityId)
  679. {
  680. return new CVariableOutputRowSerializer(activityId, this);
  681. }
  682. ISourceRowPrefetcher * COutputMetaData::createDiskPrefetcher(ICodeContext * ctx, unsigned activityId)
  683. {
  684. ISourceRowPrefetcher * fetcher = defaultCreateDiskPrefetcher(ctx, activityId);
  685. if (fetcher)
  686. return fetcher;
  687. if (queryTypeInfo()->canPrefetch())
  688. return new CDefaultPrefetcher(queryRecordAccessor(true));
  689. return new CSimpleSourceRowPrefetcher(*this, ctx, activityId);
  690. }
  691. IOutputRowDeserializer *COutputMetaData::createDiskDeserializer(ICodeContext * ctx, unsigned activityId)
  692. {
  693. return new CDefaultDeserializer(queryRecordAccessor(true));
  694. }
  695. ISourceRowPrefetcher *COutputMetaData::defaultCreateDiskPrefetcher(ICodeContext * ctx, unsigned activityId)
  696. {
  697. if (getMetaFlags() & MDFneedserializedisk)
  698. return querySerializedDiskMeta()->createDiskPrefetcher(ctx, activityId);
  699. CSourceRowPrefetcher * fetcher = doCreateDiskPrefetcher(activityId);
  700. if (fetcher)
  701. {
  702. fetcher->onCreate(ctx);
  703. return fetcher;
  704. }
  705. return NULL;
  706. }
  707. IOutputRowSerializer *CFixedOutputMetaData::createDiskSerializer(ICodeContext * ctx, unsigned activityId)
  708. {
  709. return new CFixedOutputRowSerializer(activityId, fixedSize);
  710. }
  711. IOutputRowDeserializer *CFixedOutputMetaData::createDiskDeserializer(ICodeContext * ctx, unsigned activityId)
  712. {
  713. return new CFixedOutputRowDeserializer(activityId, fixedSize);
  714. }
  715. ISourceRowPrefetcher *CFixedOutputMetaData::createDiskPrefetcher(ICodeContext * ctx, unsigned activityId)
  716. {
  717. ISourceRowPrefetcher * fetcher = defaultCreateDiskPrefetcher(ctx, activityId);
  718. if (fetcher)
  719. return fetcher;
  720. return new CFixedSourceRowPrefetcher(activityId, fixedSize);
  721. }
  722. IOutputRowSerializer * CActionOutputMetaData::createDiskSerializer(ICodeContext * ctx, unsigned activityId)
  723. {
  724. return new CFixedOutputRowSerializer(activityId, 0);
  725. }
  726. IOutputRowDeserializer * CActionOutputMetaData::createDiskDeserializer(ICodeContext * ctx, unsigned activityId)
  727. {
  728. return new CFixedOutputRowDeserializer(activityId, 0);
  729. }
  730. ISourceRowPrefetcher * CActionOutputMetaData::createDiskPrefetcher(ICodeContext * ctx, unsigned activityId)
  731. {
  732. return new CFixedSourceRowPrefetcher(activityId, 0);
  733. }