src/backend/access/hash/hashpage.c
uint32
_hash_metapinit(Relation rel, double num_tuples, ForkNumber forkNum)
{
	HashMetaPage metap;
	HashPageOpaque pageopaque;
	Buffer		metabuf;
	Buffer		buf;
	Page		pg;
	int32		data_width;
	int32		item_width;
	int32		ffactor;
	double		dnumbuckets;
	uint32		num_buckets;
	uint32		log2_num_buckets;
	uint32		i;

	/* safety check */
	if (RelationGetNumberOfBlocksInFork(rel, forkNum) != 0)
		elog(ERROR, "cannot initialize non-empty hash index \"%s\"",
			 RelationGetRelationName(rel));

	/*
	 * Determine the target fill factor (in tuples per bucket) for this index.
	 * The idea is to make the fill factor correspond to pages about as full
	 * as the user-settable fillfactor parameter says.  We can compute it
	 * exactly since the index datatype (i.e. uint32 hash key) is fixed-width.
	 */
	data_width = sizeof(uint32);
	item_width = MAXALIGN(sizeof(IndexTupleData)) + MAXALIGN(data_width) +
		sizeof(ItemIdData);		/* include the line pointer */
	ffactor = RelationGetTargetPageUsage(rel, HASH_DEFAULT_FILLFACTOR) / item_width;
	/* keep to a sane range */
	if (ffactor < 10)
		ffactor = 10;

	/*
	 * Choose the number of initial bucket pages to match the fill factor
	 * given the estimated number of tuples.  We round up the result to the
	 * next power of 2, however, and always force at least 2 bucket pages. The
	 * upper limit is determined by considerations explained in
	 * _hash_expandtable().
	 */
	dnumbuckets = num_tuples / ffactor;
	if (dnumbuckets <= 2.0)
		num_buckets = 2;
	else if (dnumbuckets >= (double) 0x40000000)
		num_buckets = 0x40000000;
	else
		num_buckets = ((uint32) 1) << _hash_log2((uint32) dnumbuckets);

	log2_num_buckets = _hash_log2(num_buckets);
	Assert(num_buckets == (((uint32) 1) << log2_num_buckets));
	Assert(log2_num_buckets < HASH_MAX_SPLITPOINTS);

	/*
	 * We initialize the metapage, the first N bucket pages, and the first
	 * bitmap page in sequence, using _hash_getnewbuf to cause smgrextend()
	 * calls to occur.  This ensures that the smgr level has the right idea of
	 * the physical index length.
	 */
	metabuf = _hash_getnewbuf(rel, HASH_METAPAGE, forkNum);
	pg = BufferGetPage(metabuf);

	pageopaque = (HashPageOpaque) PageGetSpecialPointer(pg);
	pageopaque->hasho_prevblkno = InvalidBlockNumber;
	pageopaque->hasho_nextblkno = InvalidBlockNumber;
	pageopaque->hasho_bucket = -1;
	pageopaque->hasho_flag = LH_META_PAGE;
	pageopaque->hasho_page_id = HASHO_PAGE_ID;

	metap = HashPageGetMeta(pg);

	metap->hashm_magic = HASH_MAGIC;
	metap->hashm_version = HASH_VERSION;
	metap->hashm_ntuples = 0;
	metap->hashm_nmaps = 0;
	metap->hashm_ffactor = ffactor;
	metap->hashm_bsize = HashGetMaxBitmapSize(pg);
	/* find largest bitmap array size that will fit in page size */
	for (i = _hash_log2(metap->hashm_bsize); i > 0; --i)
	{
		if ((1 << i) <= metap->hashm_bsize)
			break;
	}
	Assert(i > 0);
	metap->hashm_bmsize = 1 << i;
	metap->hashm_bmshift = i + BYTE_TO_BIT;
	Assert((1 << BMPG_SHIFT(metap)) == (BMPG_MASK(metap) + 1));

	/*
	 * Label the index with its primary hash support function's OID.  This is
	 * pretty useless for normal operation (in fact, hashm_procid is not used
	 * anywhere), but it might be handy for forensic purposes so we keep it.
	 */
	metap->hashm_procid = index_getprocid(rel, 1, HASHPROC);

	/*
	 * We initialize the index with N buckets, 0 .. N-1, occupying physical
	 * blocks 1 to N.  The first freespace bitmap page is in block N+1. Since
	 * N is a power of 2, we can set the masks this way:
	 */
	metap->hashm_maxbucket = metap->hashm_lowmask = num_buckets - 1;
	metap->hashm_highmask = (num_buckets << 1) - 1;

	MemSet(metap->hashm_spares, 0, sizeof(metap->hashm_spares));
	MemSet(metap->hashm_mapp, 0, sizeof(metap->hashm_mapp));

	/* Set up mapping for one spare page after the initial splitpoints */
	metap->hashm_spares[log2_num_buckets] = 1;
	metap->hashm_ovflpoint = log2_num_buckets;
	metap->hashm_firstfree = 0;

	/*
	 * Release buffer lock on the metapage while we initialize buckets.
	 * Otherwise, we'll be in interrupt holdoff and the CHECK_FOR_INTERRUPTS
	 * won't accomplish anything.  It's a bad idea to hold buffer locks for
	 * long intervals in any case, since that can block the bgwriter.
	 */
	MarkBufferDirty(metabuf);
	LockBuffer(metabuf, BUFFER_LOCK_UNLOCK);

	/*
	 * Initialize the first N buckets
	 */
	for (i = 0; i < num_buckets; i++)
	{
		/* Allow interrupts, in case N is huge */
		CHECK_FOR_INTERRUPTS();

		buf = _hash_getnewbuf(rel, BUCKET_TO_BLKNO(metap, i), forkNum);
		pg = BufferGetPage(buf);
		pageopaque = (HashPageOpaque) PageGetSpecialPointer(pg);
		pageopaque->hasho_prevblkno = InvalidBlockNumber;
		pageopaque->hasho_nextblkno = InvalidBlockNumber;
		pageopaque->hasho_bucket = i;
		pageopaque->hasho_flag = LH_BUCKET_PAGE;
		pageopaque->hasho_page_id = HASHO_PAGE_ID;
		MarkBufferDirty(buf);
		_hash_relbuf(rel, buf);
	}

	/* Now reacquire buffer lock on metapage */
	LockBuffer(metabuf, BUFFER_LOCK_EXCLUSIVE);

	/*
	 * Initialize first bitmap page
	 */
	_hash_initbitmap(rel, metap, num_buckets + 1, forkNum);

	/* all done */
	MarkBufferDirty(metabuf);
	_hash_relbuf(rel, metabuf);

	return num_buckets;
}
/*
 *	_hash_metapinit() -- Initialize the metadata page of a hash index,
 *				the initial buckets, and the initial bitmap page.
 *
 * The initial number of buckets is dependent on num_tuples, an estimate
 * of the number of tuples to be loaded into the index initially.  The
 * chosen number of buckets is returned.
 *
 * We are fairly cavalier about locking here, since we know that no one else
 * could be accessing this index.  In particular the rule about not holding
 * multiple buffer locks is ignored.
 */
- Initialize the metadata page of a hash index,
the initial buckets, and the initial bitmap page.

The initial number of buckets is dependent on num_tuples, an estimate
of the number of tuples to be loaded into the index initially.  The
chosen number of buckets is returned.

We are fairly cavalier about locking here, since we know that no one else
could be accessing this index.  In particular the rule about not holding
multiple buffer locks is ignored.
- Initialize the metadata page of a hash index the initial buckets and the initial bitmap page . The initial number of buckets is dependent on num_tuples an estimate of the number of tuples to be loaded into the index initially . The chosen number of buckets is returned . We are fairly cavalier about locking here since we know that no one else could be accessing this index . In particular the rule about not holding multiple buffer locks is ignored .
uint32
_hash_metapinit(Relation rel, double num_tuples, ForkNumber forkNum)
{
	HashMetaPage metap;
	HashPageOpaque pageopaque;
	Buffer		metabuf;
	Buffer		buf;
	Page		pg;
	int32		data_width;
	int32		item_width;
	int32		ffactor;
	double		dnumbuckets;
	uint32		num_buckets;
	uint32		log2_num_buckets;
	uint32		i;
	if (RelationGetNumberOfBlocksInFork(rel, forkNum) != 0)
		elog(ERROR, "cannot initialize non-empty hash index \"%s\"",
			 RelationGetRelationName(rel));
	data_width = sizeof(uint32);
	item_width = MAXALIGN(sizeof(IndexTupleData)) + MAXALIGN(data_width) +
		sizeof(ItemIdData);		
	ffactor = RelationGetTargetPageUsage(rel, HASH_DEFAULT_FILLFACTOR) / item_width;
	if (ffactor < 10)
		ffactor = 10;
	dnumbuckets = num_tuples / ffactor;
	if (dnumbuckets <= 2.0)
		num_buckets = 2;
	else if (dnumbuckets >= (double) 0x40000000)
		num_buckets = 0x40000000;
	else
		num_buckets = ((uint32) 1) << _hash_log2((uint32) dnumbuckets);
	log2_num_buckets = _hash_log2(num_buckets);
	Assert(num_buckets == (((uint32) 1) << log2_num_buckets));
	Assert(log2_num_buckets < HASH_MAX_SPLITPOINTS);
	metabuf = _hash_getnewbuf(rel, HASH_METAPAGE, forkNum);
	pg = BufferGetPage(metabuf);
	pageopaque = (HashPageOpaque) PageGetSpecialPointer(pg);
	pageopaque->hasho_prevblkno = InvalidBlockNumber;
	pageopaque->hasho_nextblkno = InvalidBlockNumber;
	pageopaque->hasho_bucket = -1;
	pageopaque->hasho_flag = LH_META_PAGE;
	pageopaque->hasho_page_id = HASHO_PAGE_ID;
	metap = HashPageGetMeta(pg);
	metap->hashm_magic = HASH_MAGIC;
	metap->hashm_version = HASH_VERSION;
	metap->hashm_ntuples = 0;
	metap->hashm_nmaps = 0;
	metap->hashm_ffactor = ffactor;
	metap->hashm_bsize = HashGetMaxBitmapSize(pg);
	for (i = _hash_log2(metap->hashm_bsize); i > 0; --i)
	{
		if ((1 << i) <= metap->hashm_bsize)
			break;
	}
	Assert(i > 0);
	metap->hashm_bmsize = 1 << i;
	metap->hashm_bmshift = i + BYTE_TO_BIT;
	Assert((1 << BMPG_SHIFT(metap)) == (BMPG_MASK(metap) + 1));
	metap->hashm_procid = index_getprocid(rel, 1, HASHPROC);
	metap->hashm_maxbucket = metap->hashm_lowmask = num_buckets - 1;
	metap->hashm_highmask = (num_buckets << 1) - 1;
	MemSet(metap->hashm_spares, 0, sizeof(metap->hashm_spares));
	MemSet(metap->hashm_mapp, 0, sizeof(metap->hashm_mapp));
	metap->hashm_spares[log2_num_buckets] = 1;
	metap->hashm_ovflpoint = log2_num_buckets;
	metap->hashm_firstfree = 0;
	MarkBufferDirty(metabuf);
	LockBuffer(metabuf, BUFFER_LOCK_UNLOCK);
	for (i = 0; i < num_buckets; i++)
	{
		CHECK_FOR_INTERRUPTS();
		buf = _hash_getnewbuf(rel, BUCKET_TO_BLKNO(metap, i), forkNum);
		pg = BufferGetPage(buf);
		pageopaque = (HashPageOpaque) PageGetSpecialPointer(pg);
		pageopaque->hasho_prevblkno = InvalidBlockNumber;
		pageopaque->hasho_nextblkno = InvalidBlockNumber;
		pageopaque->hasho_bucket = i;
		pageopaque->hasho_flag = LH_BUCKET_PAGE;
		pageopaque->hasho_page_id = HASHO_PAGE_ID;
		MarkBufferDirty(buf);
		_hash_relbuf(rel, buf);
	}
	LockBuffer(metabuf, BUFFER_LOCK_EXCLUSIVE);
	_hash_initbitmap(rel, metap, num_buckets + 1, forkNum);
	MarkBufferDirty(metabuf);
	_hash_relbuf(rel, metabuf);
	return num_buckets;
}
uint32 _hash_metapinit ( Relation rel , double num_tuples , ForkNumber forkNum ) { HashMetaPage metap ; HashPageOpaque pageopaque ; Buffer metabuf ; Buffer buf ; Page pg ; int32 data_width ; int32 item_width ; int32 ffactor ; double dnumbuckets ; uint32 num_buckets ; uint32 log2_num_buckets ; uint32 i ; if ( RelationGetNumberOfBlocksInFork ( rel , forkNum ) != 0 ) elog ( ERROR , " \" \" " , RelationGetRelationName ( rel ) ) ; data_width = sizeof ( uint32 ) ; item_width = MAXALIGN ( sizeof ( IndexTupleData ) ) + MAXALIGN ( data_width ) + sizeof ( ItemIdData ) ; ffactor = RelationGetTargetPageUsage ( rel , HASH_DEFAULT_FILLFACTOR ) / item_width ; if ( ffactor < 10 ) ffactor = 10 ; dnumbuckets = num_tuples / ffactor ; if ( dnumbuckets <= 2.0 ) num_buckets = 2 ; else if ( dnumbuckets >= ( double ) 0x40000000 ) num_buckets = 0x40000000 ; else num_buckets = ( ( uint32 ) 1 ) << _hash_log2 ( ( uint32 ) dnumbuckets ) ; log2_num_buckets = _hash_log2 ( num_buckets ) ; Assert ( num_buckets == ( ( ( uint32 ) 1 ) << log2_num_buckets ) ) ; Assert ( log2_num_buckets < HASH_MAX_SPLITPOINTS ) ; metabuf = _hash_getnewbuf ( rel , HASH_METAPAGE , forkNum ) ; pg = BufferGetPage ( metabuf ) ; pageopaque = ( HashPageOpaque ) PageGetSpecialPointer ( pg ) ; pageopaque -> hasho_prevblkno = InvalidBlockNumber ; pageopaque -> hasho_nextblkno = InvalidBlockNumber ; pageopaque -> hasho_bucket = -1 ; pageopaque -> hasho_flag = LH_META_PAGE ; pageopaque -> hasho_page_id = HASHO_PAGE_ID ; metap = HashPageGetMeta ( pg ) ; metap -> hashm_magic = HASH_MAGIC ; metap -> hashm_version = HASH_VERSION ; metap -> hashm_ntuples = 0 ; metap -> hashm_nmaps = 0 ; metap -> hashm_ffactor = ffactor ; metap -> hashm_bsize = HashGetMaxBitmapSize ( pg ) ; for ( i = _hash_log2 ( metap -> hashm_bsize ) ; i > 0 ; -- i ) { if ( ( 1 << i ) <= metap -> hashm_bsize ) break ; } Assert ( i > 0 ) ; metap -> hashm_bmsize = 1 << i ; metap -> hashm_bmshift = i + BYTE_TO_BIT ; Assert ( ( 1 << BMPG_SHIFT ( metap ) ) == ( BMPG_MASK ( metap ) + 1 ) ) ; metap -> hashm_procid = index_getprocid ( rel , 1 , HASHPROC ) ; metap -> hashm_maxbucket = metap -> hashm_lowmask = num_buckets - 1 ; metap -> hashm_highmask = ( num_buckets << 1 ) - 1 ; MemSet ( metap -> hashm_spares , 0 , sizeof ( metap -> hashm_spares ) ) ; MemSet ( metap -> hashm_mapp , 0 , sizeof ( metap -> hashm_mapp ) ) ; metap -> hashm_spares [ log2_num_buckets ] = 1 ; metap -> hashm_ovflpoint = log2_num_buckets ; metap -> hashm_firstfree = 0 ; MarkBufferDirty ( metabuf ) ; LockBuffer ( metabuf , BUFFER_LOCK_UNLOCK ) ; for ( i = 0 ; i < num_buckets ; i ++ ) { CHECK_FOR_INTERRUPTS ( ) ; buf = _hash_getnewbuf ( rel , BUCKET_TO_BLKNO ( metap , i ) , forkNum ) ; pg = BufferGetPage ( buf ) ; pageopaque = ( HashPageOpaque ) PageGetSpecialPointer ( pg ) ; pageopaque -> hasho_prevblkno = InvalidBlockNumber ; pageopaque -> hasho_nextblkno = InvalidBlockNumber ; pageopaque -> hasho_bucket = i ; pageopaque -> hasho_flag = LH_BUCKET_PAGE ; pageopaque -> hasho_page_id = HASHO_PAGE_ID ; MarkBufferDirty ( buf ) ; _hash_relbuf ( rel , buf ) ; } LockBuffer ( metabuf , BUFFER_LOCK_EXCLUSIVE ) ; _hash_initbitmap ( rel , metap , num_buckets + 1 , forkNum ) ; MarkBufferDirty ( metabuf ) ; _hash_relbuf ( rel , metabuf ) ; return num_buckets ; }
_hash_metapinit() -- Initialize the metadata page of a hash index,
                              the initial buckets, and the initial bitmap page.
_hash_metapinit () -- Initialize the metadata page of a hash index the initial buckets and the initial bitmap page .
/* safety check */ /*
	 * Determine the target fill factor (in tuples per bucket) for this index.
	 * The idea is to make the fill factor correspond to pages about as full
	 * as the user-settable fillfactor parameter says.  We can compute it
	 * exactly since the index datatype (i.e. uint32 hash key) is fixed-width.
	 */ /* include the line pointer */ /* keep to a sane range */ /*
	 * Choose the number of initial bucket pages to match the fill factor
	 * given the estimated number of tuples.  We round up the result to the
	 * next power of 2, however, and always force at least 2 bucket pages. The
	 * upper limit is determined by considerations explained in
	 * _hash_expandtable().
	 */ /*
	 * We initialize the metapage, the first N bucket pages, and the first
	 * bitmap page in sequence, using _hash_getnewbuf to cause smgrextend()
	 * calls to occur.  This ensures that the smgr level has the right idea of
	 * the physical index length.
	 */ /* find largest bitmap array size that will fit in page size */ /*
	 * Label the index with its primary hash support function's OID.  This is
	 * pretty useless for normal operation (in fact, hashm_procid is not used
	 * anywhere), but it might be handy for forensic purposes so we keep it.
	 */ /*
	 * We initialize the index with N buckets, 0 .. N-1, occupying physical
	 * blocks 1 to N.  The first freespace bitmap page is in block N+1. Since
	 * N is a power of 2, we can set the masks this way:
	 */ /* Set up mapping for one spare page after the initial splitpoints */ /*
	 * Release buffer lock on the metapage while we initialize buckets.
	 * Otherwise, we'll be in interrupt holdoff and the CHECK_FOR_INTERRUPTS
	 * won't accomplish anything.  It's a bad idea to hold buffer locks for
	 * long intervals in any case, since that can block the bgwriter.
	 */ /*
	 * Initialize the first N buckets
	 */ /* Allow interrupts, in case N is huge */ /* Now reacquire buffer lock on metapage */ /*
	 * Initialize first bitmap page
	 */ /* all done */