@@ -523,7 +523,8 @@ hashbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
523523 orig_maxbucket = metap -> hashm_maxbucket ;
524524 orig_ntuples = metap -> hashm_ntuples ;
525525 memcpy (& local_metapage , metap , sizeof (local_metapage ));
526- _hash_relbuf (rel , metabuf );
526+ /* release the lock, but keep pin */
527+ _hash_chgbufaccess (rel , metabuf , HASH_READ , HASH_NOLOCK );
527528
528529 /* Scan the buckets that we know exist */
529530 cur_bucket = 0 ;
@@ -563,8 +564,23 @@ hashbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
563564 */
564565 if (!H_BUCKET_BEING_SPLIT (bucket_opaque ) &&
565566 H_NEEDS_SPLIT_CLEANUP (bucket_opaque ))
567+ {
566568 split_cleanup = true;
567569
570+ /*
571+ * This bucket might have been split since we last held a lock on
572+ * the metapage. If so, hashm_maxbucket, hashm_highmask and
573+ * hashm_lowmask might be old enough to cause us to fail to remove
574+ * tuples left behind by the most recent split. To prevent that,
575+ * now that the primary page of the target bucket has been locked
576+ * (and thus can't be further split), update our cached metapage
577+ * data.
578+ */
579+ _hash_chgbufaccess (rel , metabuf , HASH_NOLOCK , HASH_READ );
580+ memcpy (& local_metapage , metap , sizeof (local_metapage ));
581+ _hash_chgbufaccess (rel , metabuf , HASH_READ , HASH_NOLOCK );
582+ }
583+
568584 bucket_buf = buf ;
569585
570586 hashbucketcleanup (rel , cur_bucket , bucket_buf , blkno , info -> strategy ,
@@ -581,15 +597,15 @@ hashbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
581597 }
582598
583599 /* Write-lock metapage and check for split since we started */
584- metabuf = _hash_getbuf (rel , HASH_METAPAGE , HASH_WRITE , LH_META_PAGE );
600+ _hash_chgbufaccess (rel , metabuf , HASH_NOLOCK , HASH_WRITE );
585601 metap = HashPageGetMeta (BufferGetPage (metabuf ));
586602
587603 if (cur_maxbucket != metap -> hashm_maxbucket )
588604 {
589605 /* There's been a split, so process the additional bucket(s) */
590606 cur_maxbucket = metap -> hashm_maxbucket ;
591607 memcpy (& local_metapage , metap , sizeof (local_metapage ));
592- _hash_relbuf (rel , metabuf );
608+ _hash_chgbufaccess (rel , metabuf , HASH_READ , HASH_NOLOCK );
593609 goto loop_top ;
594610 }
595611
0 commit comments