* Allocate space for a tuple in shared dense storage. This is equivalent to * dense_alloc but for Parallel Hash using shared memory. * * While loading a tuple into shared memory, we might run out of memory and * decide to repartition, or determine that the load factor is too high and * decide to expand the bucket array, or discover that another participant has * commanded us to help do that
| 3502 | * possibility that the tuple no longer belongs in the same batch). |
| 3503 | */ |
| 3504 | static HashJoinTuple |
| 3505 | ExecParallelHashTupleAlloc(HashJoinTable hashtable, size_t size, |
| 3506 | dsa_pointer *shared) |
| 3507 | { |
| 3508 | ParallelHashJoinState *pstate = hashtable->parallel_state; |
| 3509 | dsa_pointer chunk_shared; |
| 3510 | HashMemoryChunk chunk; |
| 3511 | Size chunk_size; |
| 3512 | HashJoinTuple result; |
| 3513 | int curbatch = hashtable->curbatch; |
| 3514 | |
| 3515 | size = MAXALIGN(size); |
| 3516 | |
| 3517 | /* |
| 3518 | * Fast path: if there is enough space in this backend's current chunk, |
| 3519 | * then we can allocate without any locking. |
| 3520 | */ |
| 3521 | chunk = hashtable->current_chunk; |
| 3522 | if (chunk != NULL && |
| 3523 | size <= HASH_CHUNK_THRESHOLD && |
| 3524 | chunk->maxlen - chunk->used >= size) |
| 3525 | { |
| 3526 | |
| 3527 | chunk_shared = hashtable->current_chunk_shared; |
| 3528 | Assert(chunk == dsa_get_address(hashtable->area, chunk_shared)); |
| 3529 | *shared = chunk_shared + HASH_CHUNK_HEADER_SIZE + chunk->used; |
| 3530 | result = (HashJoinTuple) (HASH_CHUNK_DATA(chunk) + chunk->used); |
| 3531 | chunk->used += size; |
| 3532 | |
| 3533 | Assert(chunk->used <= chunk->maxlen); |
| 3534 | Assert(result == dsa_get_address(hashtable->area, *shared)); |
| 3535 | |
| 3536 | return result; |
| 3537 | } |
| 3538 | |
| 3539 | /* Slow path: try to allocate a new chunk. */ |
| 3540 | LWLockAcquire(&pstate->lock, LW_EXCLUSIVE); |
| 3541 | |
| 3542 | /* |
| 3543 | * Check if we need to help increase the number of buckets or batches. |
| 3544 | */ |
| 3545 | if (pstate->growth == PHJ_GROWTH_NEED_MORE_BATCHES || |
| 3546 | pstate->growth == PHJ_GROWTH_NEED_MORE_BUCKETS) |
| 3547 | { |
| 3548 | ParallelHashGrowth growth = pstate->growth; |
| 3549 | |
| 3550 | hashtable->current_chunk = NULL; |
| 3551 | LWLockRelease(&pstate->lock); |
| 3552 | |
| 3553 | /* Another participant has commanded us to help grow. */ |
| 3554 | if (growth == PHJ_GROWTH_NEED_MORE_BATCHES) |
| 3555 | ExecParallelHashIncreaseNumBatches(hashtable); |
| 3556 | else if (growth == PHJ_GROWTH_NEED_MORE_BUCKETS) |
| 3557 | ExecParallelHashIncreaseNumBuckets(hashtable); |
| 3558 | |
| 3559 | /* The caller must retry. */ |
| 3560 | return NULL; |
| 3561 | } |
no test coverage detected