void
table_block_parallelscan_startblock_init(Relation rel,
										 ParallelBlockTableScanWork workspace,
										 ParallelBlockTableScanDesc pbscan)
{
    BlockNumber sync_startpage = InvalidBlockNumber;
	
	/* Reset the state we use for controlling allocation size. */
	memset(workspace, 0, sizeof(*workspace));

	StaticAssertStmt(MaxBlockNumber <= 0xFFFFFFFE,
					 "pg_nextpower2_32 may be too small for non-standard BlockNumber width");

	workspace->phsw_chunk_size = pg_nextpower2_32(Max(pbscan->phs_nblocks /
												  PARALLEL_SEQSCAN_NCHUNKS, 1));

	/* Ensure we don't go over the maximum size with larger rels */
	workspace->phsw_chunk_size = Min(workspace->phsw_chunk_size,
									 PARALLEL_SEQSCAN_MAX_CHUNK_SIZE);

    /* Grab the spinlock. */
    SpinLockAcquire(&pbscan->phs_mutex);

retry:
	/*
	 * If the scan's startblock has not yet been initialized, we must do so
	 * now.  If this is not a synchronized scan, we just start at block 0, but
	 * if it is a synchronized scan, we must get the starting position from
	 * the synchronized scan machinery.  We can't hold the spinlock while
	 * doing that, though, so release the spinlock, get the information we
	 * need, and retry.  If nobody else has initialized the scan in the
	 * meantime, we'll fill in the value we fetched on the second time
	 * through.
	 */
	if (pbscan->phs_startblock == InvalidBlockNumber)
	{
		if (!pbscan->base.phs_syncscan)
			pbscan->phs_startblock = 0;
		else if (sync_startpage != InvalidBlockNumber)
			pbscan->phs_startblock = sync_startpage;
		else
		{
			sync_startpage = ss_get_location(rel, pbscan->phs_nblocks);
			goto retry;
		}
	}
    SpinLockRelease(&pbscan->phs_mutex);
}
