| 332 | } |
| 333 | |
| 334 | void copyVectorsToTable( |
| 335 | const std::vector<RowVectorPtr>& batches, |
| 336 | int32_t tableOffset, |
| 337 | BaseHashTable* table) { |
| 338 | const int32_t batchSize = batches[0]->size(); |
| 339 | raw_vector<uint64_t> dummy(batchSize); |
| 340 | int32_t batchOffset = 0; |
| 341 | rowOfKey_.resize(tableOffset + batchSize * batches.size()); |
| 342 | auto rowContainer = table->rows(); |
| 343 | auto& hashers = table->hashers(); |
| 344 | auto numKeys = hashers.size(); |
| 345 | // We init a DecodedVector for each member of the RowVectors in 'batches'. |
| 346 | std::vector<std::vector<DecodedVector>> decoded; |
| 347 | SelectivityVector rows(batchSize); |
| 348 | SelectivityVector insertedRows(batchSize); |
| 349 | for (auto& batch : batches) { |
| 350 | // If we are only inserting a fraction of the rows, we set insertedRows to |
| 351 | // that fraction so that the VectorHashers only see keys that will |
| 352 | // actually be inserted. |
| 353 | if (insertPct_ < 100) { |
| 354 | bits::copyBits( |
| 355 | isInTable_.data(), |
| 356 | tableOffset + batchOffset, |
| 357 | insertedRows.asMutableRange().bits(), |
| 358 | 0, |
| 359 | batchSize); |
| 360 | insertedRows.updateBounds(); |
| 361 | } |
| 362 | decoded.emplace_back(batch->childrenSize()); |
| 363 | BOLT_CHECK_EQ(batch->size(), batchSize); |
| 364 | auto& decoders = decoded.back(); |
| 365 | for (auto i = 0; i < batch->childrenSize(); ++i) { |
| 366 | decoders[i].decode(*batch->childAt(i), rows); |
| 367 | if (i < numKeys) { |
| 368 | auto hasher = table->hashers()[i].get(); |
| 369 | hasher->decode(*batch->childAt(i), insertedRows); |
| 370 | if (table->hashMode() != BaseHashTable::HashMode::kHash && |
| 371 | hasher->mayUseValueIds()) { |
| 372 | hasher->computeValueIds(insertedRows, dummy); |
| 373 | } |
| 374 | } |
| 375 | } |
| 376 | batchOffset += batchSize; |
| 377 | } |
| 378 | |
| 379 | const auto size = batchSize * batches.size(); |
| 380 | const auto powerOfTwo = bits::nextPowerOfTwo(size); |
| 381 | const int32_t mask = powerOfTwo - 1; |
| 382 | int32_t position = 0; |
| 383 | int32_t delta = 1; |
| 384 | const auto nextOffset = rowContainer->nextOffset(); |
| 385 | |
| 386 | // We insert values in a geometric skip order. 1, 2, 4, 7, |
| 387 | // 11,... where the skip increments by one. We wrap around at the |
| 388 | // power of two boundary. This sequence hits every place in the |
| 389 | // power of two range once. Like this, when we probe the data for |
| 390 | // consecutive keys the hits will have no cache locality. |
| 391 | for (auto count = 0; count < powerOfTwo; ++count) { |
nothing calls this directly
no test coverage detected