@@ -109,6 +109,8 @@ static void index_update_stats(Relation rel,
109
109
static void IndexCheckExclusion (Relation heapRelation ,
110
110
Relation indexRelation ,
111
111
IndexInfo * indexInfo );
112
+ static inline int64 itemptr_encode (ItemPointer itemptr );
113
+ static inline void itemptr_decode (ItemPointer itemptr , int64 encoded );
112
114
static bool validate_index_callback (ItemPointer itemptr , void * opaque );
113
115
static void validate_index_heapscan (Relation heapRelation ,
114
116
Relation indexRelation ,
@@ -2832,7 +2834,13 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
2832
2834
ivinfo .num_heap_tuples = heapRelation -> rd_rel -> reltuples ;
2833
2835
ivinfo .strategy = NULL ;
2834
2836
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 ,
2836
2844
InvalidOid , false,
2837
2845
maintenance_work_mem ,
2838
2846
false);
@@ -2871,15 +2879,56 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
2871
2879
heap_close (heapRelation , NoLock );
2872
2880
}
2873
2881
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
+
2874
2922
/*
2875
2923
* validate_index_callback - bulkdelete callback to collect the index TIDs
2876
2924
*/
2877
2925
static bool
2878
2926
validate_index_callback (ItemPointer itemptr , void * opaque )
2879
2927
{
2880
2928
v_i_state * state = (v_i_state * ) opaque ;
2929
+ int64 encoded = itemptr_encode (itemptr );
2881
2930
2882
- tuplesort_putdatum (state -> tuplesort , PointerGetDatum ( itemptr ), false);
2931
+ tuplesort_putdatum (state -> tuplesort , Int64GetDatum ( encoded ), false);
2883
2932
state -> itups += 1 ;
2884
2933
return false; /* never actually delete anything */
2885
2934
}
@@ -2911,6 +2960,7 @@ validate_index_heapscan(Relation heapRelation,
2911
2960
2912
2961
/* state variables for the merge */
2913
2962
ItemPointer indexcursor = NULL ;
2963
+ ItemPointerData decoded ;
2914
2964
bool tuplesort_empty = false;
2915
2965
2916
2966
/*
@@ -3020,13 +3070,26 @@ validate_index_heapscan(Relation heapRelation,
3020
3070
*/
3021
3071
if (ItemPointerGetBlockNumber (indexcursor ) == root_blkno )
3022
3072
in_index [ItemPointerGetOffsetNumber (indexcursor ) - 1 ] = true;
3023
- pfree (indexcursor );
3024
3073
}
3025
3074
3026
3075
tuplesort_empty = !tuplesort_getdatum (state -> tuplesort , true,
3027
3076
& ts_val , & ts_isnull );
3028
3077
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
+ }
3030
3093
}
3031
3094
3032
3095
/*
0 commit comments