mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-31 00:03:57 -04:00 
			
		
		
		
	Clean up manipulations of hash indexes' hasho_flag field.
Standardize on testing a hash index page's type by doing (opaque->hasho_flag & LH_PAGE_TYPE) == LH_xxx_PAGE Various places were taking shortcuts like opaque->hasho_flag & LH_BUCKET_PAGE which while not actually wrong, is still bad practice because it encourages use of opaque->hasho_flag & LH_UNUSED_PAGE which *is* wrong (LH_UNUSED_PAGE == 0, so the above is constant false). hash_xlog.c's hash_mask() contained such an incorrect test. This also ensures that we mask out the additional flag bits that hasho_flag has accreted since 9.6. pgstattuple's pgstat_hash_page(), for one, was failing to do that and was thus actively broken. Also fix assorted comments that hadn't been updated to reflect the extended usage of hasho_flag, and fix some macros that were testing just "(hasho_flag & bit)" to use the less dangerous, project-approved form "((hasho_flag & bit) != 0)". Coverity found the bug in hash_mask(); I noted the one in pgstat_hash_page() through code reading.
This commit is contained in:
		
							parent
							
								
									1dffabed49
								
							
						
					
					
						commit
						2040bb4a0b
					
				| @ -184,7 +184,8 @@ hash_page_type(PG_FUNCTION_ARGS) | ||||
| 	bytea	   *raw_page = PG_GETARG_BYTEA_P(0); | ||||
| 	Page		page; | ||||
| 	HashPageOpaque opaque; | ||||
| 	char	   *type; | ||||
| 	int			pagetype; | ||||
| 	const char *type; | ||||
| 
 | ||||
| 	if (!superuser()) | ||||
| 		ereport(ERROR, | ||||
| @ -200,13 +201,14 @@ hash_page_type(PG_FUNCTION_ARGS) | ||||
| 		opaque = (HashPageOpaque) PageGetSpecialPointer(page); | ||||
| 
 | ||||
| 		/* page type (flags) */ | ||||
| 		if (opaque->hasho_flag & LH_META_PAGE) | ||||
| 		pagetype = opaque->hasho_flag & LH_PAGE_TYPE; | ||||
| 		if (pagetype == LH_META_PAGE) | ||||
| 			type = "metapage"; | ||||
| 		else if (opaque->hasho_flag & LH_OVERFLOW_PAGE) | ||||
| 		else if (pagetype == LH_OVERFLOW_PAGE) | ||||
| 			type = "overflow"; | ||||
| 		else if (opaque->hasho_flag & LH_BUCKET_PAGE) | ||||
| 		else if (pagetype == LH_BUCKET_PAGE) | ||||
| 			type = "bucket"; | ||||
| 		else if (opaque->hasho_flag & LH_BITMAP_PAGE) | ||||
| 		else if (pagetype == LH_BITMAP_PAGE) | ||||
| 			type = "bitmap"; | ||||
| 		else | ||||
| 			type = "unused"; | ||||
|  | ||||
| @ -453,7 +453,7 @@ pgstat_hash_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno, | ||||
| 		HashPageOpaque opaque; | ||||
| 
 | ||||
| 		opaque = (HashPageOpaque) PageGetSpecialPointer(page); | ||||
| 		switch (opaque->hasho_flag) | ||||
| 		switch (opaque->hasho_flag & LH_PAGE_TYPE) | ||||
| 		{ | ||||
| 			case LH_UNUSED_PAGE: | ||||
| 				stat->free_space += BLCKSZ; | ||||
|  | ||||
| @ -1234,6 +1234,7 @@ hash_mask(char *pagedata, BlockNumber blkno) | ||||
| { | ||||
| 	Page		page = (Page) pagedata; | ||||
| 	HashPageOpaque opaque; | ||||
| 	int			pagetype; | ||||
| 
 | ||||
| 	mask_page_lsn(page); | ||||
| 
 | ||||
| @ -1242,15 +1243,16 @@ hash_mask(char *pagedata, BlockNumber blkno) | ||||
| 
 | ||||
| 	opaque = (HashPageOpaque) PageGetSpecialPointer(page); | ||||
| 
 | ||||
| 	if (opaque->hasho_flag & LH_UNUSED_PAGE) | ||||
| 	pagetype = opaque->hasho_flag & LH_PAGE_TYPE; | ||||
| 	if (pagetype == LH_UNUSED_PAGE) | ||||
| 	{ | ||||
| 		/*
 | ||||
| 		 * Mask everything on a UNUSED page. | ||||
| 		 */ | ||||
| 		mask_page_content(page); | ||||
| 	} | ||||
| 	else if ((opaque->hasho_flag & LH_BUCKET_PAGE) || | ||||
| 			 (opaque->hasho_flag & LH_OVERFLOW_PAGE)) | ||||
| 	else if (pagetype == LH_BUCKET_PAGE || | ||||
| 			 pagetype == LH_OVERFLOW_PAGE) | ||||
| 	{ | ||||
| 		/*
 | ||||
| 		 * In hash bucket and overflow pages, it is possible to modify the | ||||
|  | ||||
| @ -168,7 +168,7 @@ _hash_addovflpage(Relation rel, Buffer metabuf, Buffer buf, bool retain_pin) | ||||
| 		if (retain_pin) | ||||
| 		{ | ||||
| 			/* pin will be retained only for the primary bucket page */ | ||||
| 			Assert(pageopaque->hasho_flag & LH_BUCKET_PAGE); | ||||
| 			Assert((pageopaque->hasho_flag & LH_PAGE_TYPE) == LH_BUCKET_PAGE); | ||||
| 			LockBuffer(buf, BUFFER_LOCK_UNLOCK); | ||||
| 		} | ||||
| 		else | ||||
|  | ||||
| @ -218,8 +218,8 @@ _hash_get_totalbuckets(uint32 splitpoint_phase) | ||||
| /*
 | ||||
|  * _hash_checkpage -- sanity checks on the format of all hash pages | ||||
|  * | ||||
|  * If flags is not zero, it is a bitwise OR of the acceptable values of | ||||
|  * hasho_flag. | ||||
|  * If flags is not zero, it is a bitwise OR of the acceptable page types | ||||
|  * (values of hasho_flag & LH_PAGE_TYPE). | ||||
|  */ | ||||
| void | ||||
| _hash_checkpage(Relation rel, Buffer buf, int flags) | ||||
|  | ||||
| @ -41,13 +41,13 @@ typedef uint32 Bucket; | ||||
| /*
 | ||||
|  * Special space for hash index pages. | ||||
|  * | ||||
|  * hasho_flag tells us which type of page we're looking at.  For | ||||
|  * example, knowing overflow pages from bucket pages is necessary | ||||
|  * information when you're deleting tuples from a page. If all the | ||||
|  * tuples are deleted from an overflow page, the overflow is made | ||||
|  * available to other buckets by calling _hash_freeovflpage(). If all | ||||
|  * the tuples are deleted from a bucket page, no additional action is | ||||
|  * necessary. | ||||
|  * hasho_flag's LH_PAGE_TYPE bits tell us which type of page we're looking at. | ||||
|  * Additional bits in the flag word are used for more transient purposes. | ||||
|  * | ||||
|  * To test a page's type, do (hasho_flag & LH_PAGE_TYPE) == LH_xxx_PAGE. | ||||
|  * However, we ensure that each used page type has a distinct bit so that | ||||
|  * we can OR together page types for uses such as the allowable-page-types | ||||
|  * argument of _hash_checkpage(). | ||||
|  */ | ||||
| #define LH_UNUSED_PAGE			(0) | ||||
| #define LH_OVERFLOW_PAGE		(1 << 0) | ||||
| @ -60,7 +60,7 @@ typedef uint32 Bucket; | ||||
| #define LH_PAGE_HAS_DEAD_TUPLES	(1 << 7) | ||||
| 
 | ||||
| #define LH_PAGE_TYPE \ | ||||
| 	(LH_OVERFLOW_PAGE|LH_BUCKET_PAGE|LH_BITMAP_PAGE|LH_META_PAGE) | ||||
| 	(LH_OVERFLOW_PAGE | LH_BUCKET_PAGE | LH_BITMAP_PAGE | LH_META_PAGE) | ||||
| 
 | ||||
| /*
 | ||||
|  * In an overflow page, hasho_prevblkno stores the block number of the previous | ||||
| @ -78,16 +78,16 @@ typedef struct HashPageOpaqueData | ||||
| 	BlockNumber hasho_prevblkno;	/* see above */ | ||||
| 	BlockNumber hasho_nextblkno;	/* see above */ | ||||
| 	Bucket		hasho_bucket;	/* bucket number this pg belongs to */ | ||||
| 	uint16		hasho_flag;		/* page type code, see above */ | ||||
| 	uint16		hasho_flag;		/* page type code + flag bits, see above */ | ||||
| 	uint16		hasho_page_id;	/* for identification of hash indexes */ | ||||
| } HashPageOpaqueData; | ||||
| 
 | ||||
| typedef HashPageOpaqueData *HashPageOpaque; | ||||
| 
 | ||||
| #define H_NEEDS_SPLIT_CLEANUP(opaque)	((opaque)->hasho_flag & LH_BUCKET_NEEDS_SPLIT_CLEANUP) | ||||
| #define H_BUCKET_BEING_SPLIT(opaque)	((opaque)->hasho_flag & LH_BUCKET_BEING_SPLIT) | ||||
| #define H_BUCKET_BEING_POPULATED(opaque)	((opaque)->hasho_flag & LH_BUCKET_BEING_POPULATED) | ||||
| #define H_HAS_DEAD_TUPLES(opaque)		((opaque)->hasho_flag & LH_PAGE_HAS_DEAD_TUPLES) | ||||
| #define H_NEEDS_SPLIT_CLEANUP(opaque)	(((opaque)->hasho_flag & LH_BUCKET_NEEDS_SPLIT_CLEANUP) != 0) | ||||
| #define H_BUCKET_BEING_SPLIT(opaque)	(((opaque)->hasho_flag & LH_BUCKET_BEING_SPLIT) != 0) | ||||
| #define H_BUCKET_BEING_POPULATED(opaque)	(((opaque)->hasho_flag & LH_BUCKET_BEING_POPULATED) != 0) | ||||
| #define H_HAS_DEAD_TUPLES(opaque)		(((opaque)->hasho_flag & LH_PAGE_HAS_DEAD_TUPLES) != 0) | ||||
| 
 | ||||
| /*
 | ||||
|  * The page ID is for the convenience of pg_filedump and similar utilities, | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user