@@ -36,6 +36,7 @@ typedef struct
3636{
3737HSpool * spool ;/* NULL if not using spooling */
3838double indtuples ;/* # tuples accepted into index */
39+ Relation heapRel ;/* heap relation descriptor */
3940}HashBuildState ;
4041
4142static void hashbuildCallback (Relation index ,
@@ -154,6 +155,7 @@ hashbuild(Relation heap, Relation index, IndexInfo *indexInfo)
154155
155156/* prepare to build the index */
156157buildstate .indtuples = 0 ;
158+ buildstate .heapRel = heap ;
157159
158160/* do the heap scan */
159161reltuples = IndexBuildHeapScan (heap ,index ,indexInfo , true,
@@ -162,7 +164,7 @@ hashbuild(Relation heap, Relation index, IndexInfo *indexInfo)
162164if (buildstate .spool )
163165{
164166/* sort the tuples and insert them into the index */
165- _h_indexbuild (buildstate .spool );
167+ _h_indexbuild (buildstate .spool , buildstate . heapRel );
166168_h_spooldestroy (buildstate .spool );
167169}
168170
@@ -218,7 +220,7 @@ hashbuildCallback(Relation index,
218220itup = index_form_tuple (RelationGetDescr (index ),
219221index_values ,index_isnull );
220222itup -> t_tid = htup -> t_self ;
221- _hash_doinsert (index ,itup );
223+ _hash_doinsert (index ,itup , buildstate -> heapRel );
222224pfree (itup );
223225}
224226
@@ -251,7 +253,7 @@ hashinsert(Relation rel, Datum *values, bool *isnull,
251253itup = index_form_tuple (RelationGetDescr (rel ),index_values ,index_isnull );
252254itup -> t_tid = * ht_ctid ;
253255
254- _hash_doinsert (rel ,itup );
256+ _hash_doinsert (rel ,itup , heapRel );
255257
256258pfree (itup );
257259
@@ -331,14 +333,24 @@ hashgettuple(IndexScanDesc scan, ScanDirection dir)
331333if (scan -> kill_prior_tuple )
332334{
333335/*
334- * Yes, so mark it by setting the LP_DEAD state in the item flags.
336+ * Yes, so remember it for later. (We'll deal with all such
337+ * tuples at once right after leaving the index page or at
338+ * end of scan.) In case if caller reverses the indexscan
339+ * direction it is quite possible that the same item might
340+ * get entered multiple times. But, we don't detect that;
341+ * instead, we just forget any excess entries.
335342 */
336- ItemIdMarkDead (PageGetItemId (page ,offnum ));
343+ if (so -> killedItems == NULL )
344+ so -> killedItems = palloc (MaxIndexTuplesPerPage *
345+ sizeof (HashScanPosItem ));
337346
338- /*
339- * Since this can be redone later if needed, mark as a hint.
340- */
341- MarkBufferDirtyHint (buf , true);
347+ if (so -> numKilled < MaxIndexTuplesPerPage )
348+ {
349+ so -> killedItems [so -> numKilled ].heapTid = so -> hashso_heappos ;
350+ so -> killedItems [so -> numKilled ].indexOffset =
351+ ItemPointerGetOffsetNumber (& (so -> hashso_curpos ));
352+ so -> numKilled ++ ;
353+ }
342354}
343355
344356/*
@@ -446,6 +458,9 @@ hashbeginscan(Relation rel, int nkeys, int norderbys)
446458so -> hashso_buc_populated = false;
447459so -> hashso_buc_split = false;
448460
461+ so -> killedItems = NULL ;
462+ so -> numKilled = 0 ;
463+
449464scan -> opaque = so ;
450465
451466return scan ;
@@ -461,6 +476,10 @@ hashrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
461476HashScanOpaque so = (HashScanOpaque )scan -> opaque ;
462477Relation rel = scan -> indexRelation ;
463478
479+ /* Before leaving current page, deal with any killed items */
480+ if (so -> numKilled > 0 )
481+ _hash_kill_items (scan );
482+
464483_hash_dropscanbuf (rel ,so );
465484
466485/* set position invalid (this will cause _hash_first call) */
@@ -488,8 +507,14 @@ hashendscan(IndexScanDesc scan)
488507HashScanOpaque so = (HashScanOpaque )scan -> opaque ;
489508Relation rel = scan -> indexRelation ;
490509
510+ /* Before leaving current page, deal with any killed items */
511+ if (so -> numKilled > 0 )
512+ _hash_kill_items (scan );
513+
491514_hash_dropscanbuf (rel ,so );
492515
516+ if (so -> killedItems != NULL )
517+ pfree (so -> killedItems );
493518pfree (so );
494519scan -> opaque = NULL ;
495520}
@@ -848,6 +873,16 @@ hashbucketcleanup(Relation rel, Bucket cur_bucket, Buffer bucket_buf,
848873
849874PageIndexMultiDelete (page ,deletable ,ndeletable );
850875bucket_dirty = true;
876+
877+ /*
878+ * Let us mark the page as clean if vacuum removes the DEAD tuples
879+ * from an index page. We do this by clearing LH_PAGE_HAS_DEAD_TUPLES
880+ * flag. Clearing this flag is just a hint; replay won't redo this.
881+ */
882+ if (tuples_removed && * tuples_removed > 0 &&
883+ opaque -> hasho_flag & LH_PAGE_HAS_DEAD_TUPLES )
884+ opaque -> hasho_flag &= ~LH_PAGE_HAS_DEAD_TUPLES ;
885+
851886MarkBufferDirty (buf );
852887
853888/* XLOG stuff */