Example #1
0
/*
 *	_hash_pgaddtup() -- add a tuple to a particular page in the index.
 *
 * This routine adds the tuple to the page as requested; it does not write out
 * the page.  It is an error to call pgaddtup() without pin and write lock on
 * the target buffer.
 *
 * Returns the offset number at which the tuple was inserted.  This function
 * is responsible for preserving the condition that tuples in a hash index
 * page are sorted by hashkey value.
 */
OffsetNumber
_hash_pgaddtup(Relation rel, Buffer buf, Size itemsize, IndexTuple itup)
{
	OffsetNumber itup_off;
	Page		page;
	uint32		hashkey;

	_hash_checkpage(rel, buf, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
	page = BufferGetPage(buf);

	/* Find where to insert the tuple (preserving page's hashkey ordering) */
	hashkey = _hash_get_indextuple_hashkey(itup);
	itup_off = _hash_binsearch(page, hashkey);

	if (PageAddItem(page, (Item) itup, itemsize, itup_off, false, false)
		== InvalidOffsetNumber)
		elog(ERROR, "failed to add index item to \"%s\"",
			 RelationGetRelationName(rel));

	return itup_off;
}
Example #2
0
/*
 *	_hash_step() -- step to the next valid item in a scan in the bucket.
 *
 *		If no valid record exists in the requested direction, return
 *		false.	Else, return true and set the hashso_curpos for the
 *		scan to the right thing.
 *
 *		'bufP' points to the current buffer, which is pinned and read-locked.
 *		On success exit, we have pin and read-lock on whichever page
 *		contains the right item; on failure, we have released all buffers.
 */
bool
_hash_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
{
	Relation	rel = scan->indexRelation;
	HashScanOpaque so = (HashScanOpaque) scan->opaque;
	ItemPointer current;
	Buffer		buf;
	Page		page;
	HashPageOpaque opaque;
	OffsetNumber maxoff;
	OffsetNumber offnum;
	BlockNumber blkno;
	IndexTuple	itup;

	current = &(so->hashso_curpos);

	buf = *bufP;
	_hash_checkpage(rel, buf, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
	page = BufferGetPage(buf);
	opaque = (HashPageOpaque) PageGetSpecialPointer(page);

	/*
	 * If _hash_step is called from _hash_first, current will not be valid, so
	 * we can't dereference it.  However, in that case, we presumably want to
	 * start at the beginning/end of the page...
	 */
	maxoff = PageGetMaxOffsetNumber(page);
	if (ItemPointerIsValid(current))
		offnum = ItemPointerGetOffsetNumber(current);
	else
		offnum = InvalidOffsetNumber;

	/*
	 * 'offnum' now points to the last tuple we examined (if any).
	 *
	 * continue to step through tuples until: 1) we get to the end of the
	 * bucket chain or 2) we find a valid tuple.
	 */
	do
	{
		switch (dir)
		{
			case ForwardScanDirection:
				if (offnum != InvalidOffsetNumber)
					offnum = OffsetNumberNext(offnum);	/* move forward */
				else
				{
					/* new page, locate starting position by binary search */
					offnum = _hash_binsearch(page, so->hashso_sk_hash);
				}

				for (;;)
				{
					/*
					 * check if we're still in the range of items with the
					 * target hash key
					 */
					if (offnum <= maxoff)
					{
						Assert(offnum >= FirstOffsetNumber);
						itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
						if (so->hashso_sk_hash == _hash_get_indextuple_hashkey(itup))
							break;		/* yes, so exit for-loop */
					}

					/*
					 * ran off the end of this page, try the next
					 */
					_hash_readnext(rel, &buf, &page, &opaque);
					if (BufferIsValid(buf))
					{
						maxoff = PageGetMaxOffsetNumber(page);
						offnum = _hash_binsearch(page, so->hashso_sk_hash);
					}
					else
					{
						/* end of bucket */
						itup = NULL;
						break;	/* exit for-loop */
					}
				}
				break;

			case BackwardScanDirection:
				if (offnum != InvalidOffsetNumber)
					offnum = OffsetNumberPrev(offnum);	/* move back */
				else
				{
					/* new page, locate starting position by binary search */
					offnum = _hash_binsearch_last(page, so->hashso_sk_hash);
				}

				for (;;)
				{
					/*
					 * check if we're still in the range of items with the
					 * target hash key
					 */
					if (offnum >= FirstOffsetNumber)
					{
						Assert(offnum <= maxoff);
						itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
						if (so->hashso_sk_hash == _hash_get_indextuple_hashkey(itup))
							break;		/* yes, so exit for-loop */
					}

					/*
					 * ran off the end of this page, try the next
					 */
					_hash_readprev(rel, &buf, &page, &opaque);
					if (BufferIsValid(buf))
					{
						maxoff = PageGetMaxOffsetNumber(page);
						offnum = _hash_binsearch_last(page, so->hashso_sk_hash);
					}
					else
					{
						/* end of bucket */
						itup = NULL;
						break;	/* exit for-loop */
					}
				}
				break;

			default:
				/* NoMovementScanDirection */
				/* this should not be reached */
				itup = NULL;
				break;
		}

		if (itup == NULL)
		{
			/* we ran off the end of the bucket without finding a match */
			*bufP = so->hashso_curbuf = InvalidBuffer;
			ItemPointerSetInvalid(current);
			return false;
		}

		/* check the tuple quals, loop around if not met */
	} while (!_hash_checkqual(scan, itup));

	/* if we made it to here, we've found a valid tuple */
	blkno = BufferGetBlockNumber(buf);
	*bufP = so->hashso_curbuf = buf;
	ItemPointerSet(current, blkno, offnum);
	return true;
}
Example #3
0
/*
 *	_hash_step() -- step to the next valid item in a scan in the bucket.
 *
 *		If no valid record exists in the requested direction, return
 *		false.	Else, return true and set the hashso_curpos for the
 *		scan to the right thing.
 *
 *		'bufP' points to the current buffer, which is pinned and read-locked.
 *		On success exit, we have pin and read-lock on whichever page
 *		contains the right item; on failure, we have released all buffers.
 */
bool
_hash_step(struct index_scan* scan, buf_id_t* bufP, enum scandir dir)
{
	struct relation *rel = scan->indexRelation;
	struct hash_scan_opaque_data *so = (struct hash_scan_opaque_data *)scan->opaque;
	struct item_ptr *current;
	buf_id_t buf;
	page_p page;
	struct hash_page *opaque;
	item_id_t maxoff;
	item_id_t offnum;
	block_t blkno;
	struct index_tuple *itup;

	current = &(so->hashso_curpos);

	buf = *bufP;
	_hash_checkpage(rel, buf, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
	page = BUF_PAGE(buf);
	opaque = (struct hash_page *)PAGE_SPECIAL_PTR(page);

	/*
	 * If _hash_step is called from _hash_first, current will not be valid, so
	 * we can't dereference it.  However, in that case, we presumably want to
	 * start at the beginning/end of the page...
	 */
	maxoff = PAGE_MAX_ITEM_ID(page);
	if (ITEM_PTR_VALID(current))
		offnum = ITEM_PTR_OFFSET(current);
	else
		offnum = INVALID_ITEM_ID;

	/*
	 * 'offnum' now points to the last tuple we examined (if any).
	 *
	 * continue to step through tuples until: 1) we get to the end of the
	 * bucket chain or 2) we find a valid tuple.
	 */
	do {
		switch (dir) {
		case FORWARD_SCANDIR:
			if (offnum != INVALID_ITEM_ID) {
				offnum = ITEM_ID_NEXT(offnum);	/* move forward */
			} else {
				/* new page, locate starting position by binary search */
				offnum = _hash_binsearch(page, so->hashso_sk_hash);
			}

			for (;;) {
				/*
				 * check if we're still in the range of items with the
				 * target hash key
				 */
				if (offnum <= maxoff) {
					ASSERT(offnum >= FIRST_ITEM_ID);
					itup = (struct index_tuple*) PAGE_GET_ITEM(
						page,
						PAGE_ITEM_ID(page, offnum));
					if (so->hashso_sk_hash == 
						_hash_get_indextuple_hashkey(itup))
						break;	/* yes, so exit for-loop */
				}

				/*
				 * ran off the end of this page, try the next
				 */
				_hash_readnext(rel, &buf, &page, &opaque);
				if (BUF_VALID(buf)) {
					maxoff = PAGE_MAX_ITEM_ID(page);
					offnum = _hash_binsearch(page, so->hashso_sk_hash);
				} else {
					/* end of bucket */
					itup = NULL;
					break;	/* exit for-loop */
				}
			}
			break;

		case BACKWARD_SCANDIR:
			if (offnum != INVALID_ITEM_ID)
				offnum = ITEM_ID_PREV(offnum);	/* move back */
			else {
				/* new page, locate starting position by binary search */
				offnum = _hash_binsearch_last(page, so->hashso_sk_hash);
			}

			for (;;) {
				/*
				 * check if we're still in the range of items with the
				 * target hash key
				 */
				if (offnum >= FIRST_ITEM_ID) {
					ASSERT(offnum <= maxoff);
					itup = (struct index_tuple*) PAGE_GET_ITEM(
						page,
						PAGE_ITEM_ID(page, offnum));
					if (so->hashso_sk_hash ==
						_hash_get_indextuple_hashkey(itup))
						break;	/* yes, so exit for-loop */
				}

				/*
				 * ran off the end of this page, try the next
				 */
				_hash_readprev(rel, &buf, &page, &opaque);
				if (BUF_VALID(buf)) {
					maxoff = PAGE_MAX_ITEM_ID(page);
					offnum = _hash_binsearch_last(page, so->hashso_sk_hash);
				} else {
					/* end of bucket */
					itup = NULL;
					break;	/* exit for-loop */
				}
			}
			break;

		default:
			/* NO_MOVEMENT_SCANDIR */
			/* this should not be reached */
			itup = NULL;
			break;
		}

		if (itup == NULL) {
			/* we ran off the end of the bucket without finding a match */
			*bufP = so->hashso_curbuf = INVALID_BUF;
			ITEM_PTR_SET_INVALID(current);
			return false;
		}

		/* check the tuple quals, loop around if not met */
	} while (!_hash_checkqual(scan, itup));

	/* if we made it to here, we've found a valid tuple */
	blkno = buf_block_nr(buf);
	*bufP = so->hashso_curbuf = buf;
	ITEM_PTR_SET(current, blkno, offnum);
	return true;
}