@@ -109,6 +109,8 @@ static void index_update_stats(Relation rel,
109109static void IndexCheckExclusion (Relation heapRelation ,
110110 Relation indexRelation ,
111111 IndexInfo * indexInfo );
112+ static inline int64 itemptr_encode (ItemPointer itemptr );
113+ static inline void itemptr_decode (ItemPointer itemptr , int64 encoded );
112114static bool validate_index_callback (ItemPointer itemptr , void * opaque );
113115static void validate_index_heapscan (Relation heapRelation ,
114116 Relation indexRelation ,
@@ -2832,7 +2834,13 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
28322834 ivinfo .num_heap_tuples = heapRelation -> rd_rel -> reltuples ;
28332835 ivinfo .strategy = NULL ;
28342836
2835- state .tuplesort = tuplesort_begin_datum (TIDOID , TIDLessOperator ,
2837+ /*
2838+ * Encode TIDs as int8 values for the sort, rather than directly sorting
2839+ * item pointers. This can be significantly faster, primarily because TID
2840+ * is a pass-by-reference type on all platforms, whereas int8 is
2841+ * pass-by-value on most platforms.
2842+ */
2843+ state .tuplesort = tuplesort_begin_datum (INT8OID , Int8LessOperator ,
28362844 InvalidOid , false,
28372845 maintenance_work_mem ,
28382846 false);
@@ -2871,15 +2879,56 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
28712879 heap_close (heapRelation , NoLock );
28722880}
28732881
2882+ /*
2883+ * itemptr_encode - Encode ItemPointer as int64/int8
2884+ *
2885+ * This representation must produce values encoded as int64 that sort in the
2886+ * same order as their corresponding original TID values would (using the
2887+ * default int8 opclass to produce a result equivalent to the default TID
2888+ * opclass).
2889+ *
2890+ * As noted in validate_index(), this can be significantly faster.
2891+ */
2892+ static inline int64
2893+ itemptr_encode (ItemPointer itemptr )
2894+ {
2895+ BlockNumber block = ItemPointerGetBlockNumber (itemptr );
2896+ OffsetNumber offset = ItemPointerGetOffsetNumber (itemptr );
2897+ int64 encoded ;
2898+
2899+ /*
2900+ * Use the 16 least significant bits for the offset. 32 adjacent bits are
2901+ * used for the block number. Since remaining bits are unused, there
2902+ * cannot be negative encoded values (We assume a two's complement
2903+ * representation).
2904+ */
2905+ encoded = ((uint64 ) block << 16 ) | (uint16 ) offset ;
2906+
2907+ return encoded ;
2908+ }
2909+
2910+ /*
2911+ * itemptr_decode - Decode int64/int8 representation back to ItemPointer
2912+ */
2913+ static inline void
2914+ itemptr_decode (ItemPointer itemptr , int64 encoded )
2915+ {
2916+ BlockNumber block = (BlockNumber ) (encoded >> 16 );
2917+ OffsetNumber offset = (OffsetNumber ) (encoded & 0xFFFF );
2918+
2919+ ItemPointerSet (itemptr , block , offset );
2920+ }
2921+
28742922/*
28752923 * validate_index_callback - bulkdelete callback to collect the index TIDs
28762924 */
28772925static bool
28782926validate_index_callback (ItemPointer itemptr , void * opaque )
28792927{
28802928 v_i_state * state = (v_i_state * ) opaque ;
2929+ int64 encoded = itemptr_encode (itemptr );
28812930
2882- tuplesort_putdatum (state -> tuplesort , PointerGetDatum ( itemptr ), false);
2931+ tuplesort_putdatum (state -> tuplesort , Int64GetDatum ( encoded ), false);
28832932 state -> itups += 1 ;
28842933 return false; /* never actually delete anything */
28852934}
@@ -2911,6 +2960,7 @@ validate_index_heapscan(Relation heapRelation,
29112960
29122961 /* state variables for the merge */
29132962 ItemPointer indexcursor = NULL ;
2963+ ItemPointerData decoded ;
29142964 bool tuplesort_empty = false;
29152965
29162966 /*
@@ -3020,13 +3070,26 @@ validate_index_heapscan(Relation heapRelation,
30203070 */
30213071 if (ItemPointerGetBlockNumber (indexcursor ) == root_blkno )
30223072 in_index [ItemPointerGetOffsetNumber (indexcursor ) - 1 ] = true;
3023- pfree (indexcursor );
30243073 }
30253074
30263075 tuplesort_empty = !tuplesort_getdatum (state -> tuplesort , true,
30273076 & ts_val , & ts_isnull );
30283077 Assert (tuplesort_empty || !ts_isnull );
3029- indexcursor = (ItemPointer ) DatumGetPointer (ts_val );
3078+ if (!tuplesort_empty )
3079+ {
3080+ itemptr_decode (& decoded , DatumGetInt64 (ts_val ));
3081+ indexcursor = & decoded ;
3082+
3083+ /* If int8 is pass-by-ref, free (encoded) TID Datum memory */
3084+ #ifndef USE_FLOAT8_BYVAL
3085+ pfree (DatumGetPointer (ts_val ));
3086+ #endif
3087+ }
3088+ else
3089+ {
3090+ /* Be tidy */
3091+ indexcursor = NULL ;
3092+ }
30303093 }
30313094
30323095 /*
0 commit comments