| 52 | } |
| 53 | |
| 54 | void BaseAggregateSharedState::HashTableQueue::appendTuple(std::span<uint8_t> tuple) { |
| 55 | while (true) { |
| 56 | auto* block = headBlock.load(); |
| 57 | DASSERT(tuple.size() == block->table.getTableSchema()->getNumBytesPerTuple()); |
| 58 | auto posToWrite = block->numTuplesReserved++; |
| 59 | if (posToWrite < numTuplesPerBlock) { |
| 60 | memcpy(block->table.getTuple(posToWrite), tuple.data(), tuple.size()); |
| 61 | block->numTuplesWritten++; |
| 62 | return; |
| 63 | } else { |
| 64 | // No more space in the block, allocate and replace it |
| 65 | auto* newBlock = new TupleBlock(block->table.getMemoryManager(), |
| 66 | block->table.getTableSchema()->copy()); |
| 67 | if (headBlock.compare_exchange_strong(block, newBlock)) { |
| 68 | // TODO(bmwinger): if the queuedTuples has at least a certain size (benchmark to see |
| 69 | // if there's a benefit to waiting for multiple blocks) then cycle through the queue |
| 70 | // and flush any blocks which have been fully written |
| 71 | queuedTuples.push(block); |
| 72 | } else { |
| 73 | // If the block was replaced by another thread, discard the block we created and try |
| 74 | // again with the block allocated by the other thread |
| 75 | delete newBlock; |
| 76 | } |
| 77 | } |
| 78 | } |
| 79 | } |
| 80 | |
| 81 | void BaseAggregateSharedState::HashTableQueue::mergeInto(AggregateHashTable& hashTable) { |
| 82 | TupleBlock* partitionToMerge = nullptr; |
no test coverage detected