commit 0aa39891b73aa13cfa8499758984263bd75ecc84 Author: mithun Date: Fri Jul 22 11:35:37 2016 +0530 Commit cache metapage. diff --git a/src/backend/access/hash/hashpage.c b/src/backend/access/hash/hashpage.c index 6dfd411..4491602 100644 --- a/src/backend/access/hash/hashpage.c +++ b/src/backend/access/hash/hashpage.c @@ -447,7 +447,7 @@ _hash_metapinit(Relation rel, double num_tuples, ForkNumber forkNum) buf = _hash_getnewbuf(rel, BUCKET_TO_BLKNO(metap, i), forkNum); pg = BufferGetPage(buf); pageopaque = (HashPageOpaque) PageGetSpecialPointer(pg); - pageopaque->hasho_prevblkno = InvalidBlockNumber; + pageopaque->hasho_prevblkno = metap->hashm_maxbucket;; pageopaque->hasho_nextblkno = InvalidBlockNumber; pageopaque->hasho_bucket = i; pageopaque->hasho_flag = LH_BUCKET_PAGE; @@ -865,7 +865,7 @@ _hash_splitbucket(Relation rel, * vacuum will clear page_has_garbage flag after deleting such tuples. */ oopaque->hasho_flag |= LH_BUCKET_PAGE_HAS_GARBAGE | LH_BUCKET_OLD_PAGE_SPLIT; - + oopaque->hasho_prevblkno = maxbucket; npage = BufferGetPage(nbuf); /* @@ -873,7 +873,7 @@ _hash_splitbucket(Relation rel, * split is in progress. */ nopaque = (HashPageOpaque) PageGetSpecialPointer(npage); - nopaque->hasho_prevblkno = InvalidBlockNumber; + nopaque->hasho_prevblkno = maxbucket; nopaque->hasho_nextblkno = InvalidBlockNumber; nopaque->hasho_bucket = nbucket; nopaque->hasho_flag = LH_BUCKET_PAGE | LH_BUCKET_NEW_PAGE_SPLIT; diff --git a/src/backend/access/hash/hashsearch.c b/src/backend/access/hash/hashsearch.c index b0cb638..2fbdd5a 100644 --- a/src/backend/access/hash/hashsearch.c +++ b/src/backend/access/hash/hashsearch.c @@ -146,10 +146,8 @@ _hash_first(IndexScanDesc scan, ScanDirection dir) uint32 hashkey; Bucket bucket; BlockNumber blkno; - BlockNumber oldblkno = InvalidBuffer; - bool retry = false; Buffer buf; - Buffer metabuf; + Buffer metabuf = InvalidBuffer; Page page; HashPageOpaque opaque; HashMetaPage metap; @@ -207,101 +205,74 @@ _hash_first(IndexScanDesc scan, ScanDirection dir) so->hashso_sk_hash = hashkey; - /* Read the metapage */ - metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ, LH_META_PAGE); - page = BufferGetPage(metabuf); - metap = HashPageGetMeta(page); - - /* - * Conditionally get the lock on primary bucket page for search while - * holding lock on meta page. If we have to wait, then release the meta - * page lock and retry it in a hard way. - */ - bucket = _hash_hashkey2bucket(hashkey, - metap->hashm_maxbucket, - metap->hashm_highmask, - metap->hashm_lowmask); - - blkno = BUCKET_TO_BLKNO(metap, bucket); - - /* Fetch the primary bucket page for the bucket */ - buf = ReadBuffer(rel, blkno); - if (!ConditionalLockBufferShared(buf)) + if (rel->rd_amcache != NULL) { - _hash_chgbufaccess(rel, metabuf, HASH_READ, HASH_NOLOCK); - LockBuffer(buf, HASH_READ); - _hash_checkpage(rel, buf, LH_BUCKET_PAGE); - _hash_chgbufaccess(rel, metabuf, HASH_NOLOCK, HASH_READ); - oldblkno = blkno; - retry = true; + metap = (HashMetaPage)rel->rd_amcache; } else { - _hash_checkpage(rel, buf, LH_BUCKET_PAGE); + /* Read the metapage */ + metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ, LH_META_PAGE); + page = BufferGetPage(metabuf); + metap = HashPageGetMeta(page); + + /* Cache the metapage data for next time*/ + rel->rd_amcache = MemoryContextAlloc(rel->rd_indexcxt, + sizeof(HashMetaPageData)); + memcpy(rel->rd_amcache, metap, sizeof(HashMetaPageData)); + metap = (HashMetaPage)rel->rd_amcache; + + /* Release metapage lock, but keep pin. */ _hash_chgbufaccess(rel, metabuf, HASH_READ, HASH_NOLOCK); } - if (retry) + /* + * Loop until we get a lock on the correct target bucket. + */ + for (;;) { /* - * Loop until we get a lock on the correct target bucket. We get the - * lock on primary bucket page and retain the pin on it during read - * operation to prevent the concurrent splits. Retaining pin on a - * primary bucket page ensures that split can't happen as it needs to - * acquire the cleanup lock on primary bucket page. Acquiring lock on - * primary bucket and rechecking if it is a target bucket is mandatory - * as otherwise a concurrent split followed by vacuum could remove - * tuples from the selected bucket which otherwise would have been - * visible. + * Compute the target bucket number, and convert to block number. */ - for (;;) - { - /* - * Compute the target bucket number, and convert to block number. - */ - bucket = _hash_hashkey2bucket(hashkey, - metap->hashm_maxbucket, - metap->hashm_highmask, - metap->hashm_lowmask); - - blkno = BUCKET_TO_BLKNO(metap, bucket); - - /* Release metapage lock, but keep pin. */ - _hash_chgbufaccess(rel, metabuf, HASH_READ, HASH_NOLOCK); - - /* - * If the previous iteration of this loop locked what is still the - * correct target bucket, we are done. Otherwise, drop any old - * lock and lock what now appears to be the correct bucket. - */ - if (oldblkno == blkno) - break; - _hash_relbuf(rel, buf); + bucket = _hash_hashkey2bucket(hashkey, + metap->hashm_maxbucket, + metap->hashm_highmask, + metap->hashm_lowmask); + + blkno = BUCKET_TO_BLKNO(metap, bucket); - /* Fetch the primary bucket page for the bucket */ - buf = _hash_getbuf(rel, blkno, HASH_READ, LH_BUCKET_PAGE); + /* Fetch the primary bucket page for the bucket */ + buf = _hash_getbuf(rel, blkno, HASH_READ, LH_BUCKET_PAGE); + page = BufferGetPage(buf); + opaque = (HashPageOpaque) PageGetSpecialPointer(page); + Assert(opaque->hasho_bucket == bucket); - /* - * Reacquire metapage lock and check that no bucket split has - * taken place while we were awaiting the bucket lock. - */ - _hash_chgbufaccess(rel, metabuf, HASH_NOLOCK, HASH_READ); - oldblkno = blkno; + if (opaque->hasho_prevblkno <= metap->hashm_maxbucket) + { + /* Ok now we have the right bucket proceed to search in it. */ + break; } + + _hash_relbuf(rel, buf); + + /* Meta page cache is old try again updating it. */ + metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ, LH_META_PAGE); + page = BufferGetPage(metabuf); + metap = HashPageGetMeta(page); + memcpy(rel->rd_amcache, metap, sizeof(HashMetaPageData)); + metap = (HashMetaPage)rel->rd_amcache; + + /* Release Meta page buffer lock, but keep pin. */ + _hash_chgbufaccess(rel, metabuf, HASH_READ, HASH_NOLOCK); } - /* done with the metapage */ - _hash_dropbuf(rel, metabuf); + /* Done with the metapage */ + if (!BufferIsInvalid(metabuf)) + _hash_dropbuf(rel, metabuf); /* Update scan opaque state to show we have lock on the bucket */ so->hashso_bucket = bucket; so->hashso_bucket_valid = true; - - - page = BufferGetPage(buf); - opaque = (HashPageOpaque) PageGetSpecialPointer(page); - Assert(opaque->hasho_bucket == bucket); - so->hashso_bucket_buf = buf; /*