mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Invent qsort_interruptible().
Justin Pryzby reported that some scenarios could cause gathering of extended statistics to spend many seconds in an un-cancelable qsort() operation. To fix, invent qsort_interruptible(), which is just like qsort_arg() except that it will also do CHECK_FOR_INTERRUPTS every so often. This bloats the backend by a couple of kB, which seems like a good investment. (We considered just enabling CHECK_FOR_INTERRUPTS in the existing qsort and qsort_arg functions, but there are some callers for which that'd demonstrably be unsafe. Opt-in seems like a better way.) For now, just apply qsort_interruptible() in statistics collection. There's probably more places where it could be useful, but we can always change other call sites as we find problems. Back-patch to v14. Before that we didn't have extended stats on expressions, so that the problem was less severe. Also, this patch depends on the sort_template infrastructure introduced in v14. Tom Lane and Justin Pryzby Discussion: https://postgr.es/m/20220509000108.GQ28830@telsasoft.com
This commit is contained in:
		@@ -100,7 +100,7 @@ static VacAttrStats *examine_attribute(Relation onerel, int attnum,
 | 
			
		||||
static int	acquire_sample_rows(Relation onerel, int elevel,
 | 
			
		||||
								HeapTuple *rows, int targrows,
 | 
			
		||||
								double *totalrows, double *totaldeadrows);
 | 
			
		||||
static int	compare_rows(const void *a, const void *b);
 | 
			
		||||
static int	compare_rows(const void *a, const void *b, void *arg);
 | 
			
		||||
static int	acquire_inherited_sample_rows(Relation onerel, int elevel,
 | 
			
		||||
										  HeapTuple *rows, int targrows,
 | 
			
		||||
										  double *totalrows, double *totaldeadrows);
 | 
			
		||||
@@ -1306,7 +1306,8 @@ acquire_sample_rows(Relation onerel, int elevel,
 | 
			
		||||
	 * tuples are already sorted.
 | 
			
		||||
	 */
 | 
			
		||||
	if (numrows == targrows)
 | 
			
		||||
		qsort((void *) rows, numrows, sizeof(HeapTuple), compare_rows);
 | 
			
		||||
		qsort_interruptible((void *) rows, numrows, sizeof(HeapTuple),
 | 
			
		||||
							compare_rows, NULL);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Estimate total numbers of live and dead rows in relation, extrapolating
 | 
			
		||||
@@ -1342,10 +1343,10 @@ acquire_sample_rows(Relation onerel, int elevel,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * qsort comparator for sorting rows[] array
 | 
			
		||||
 * Comparator for sorting rows[] array
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
compare_rows(const void *a, const void *b)
 | 
			
		||||
compare_rows(const void *a, const void *b, void *arg)
 | 
			
		||||
{
 | 
			
		||||
	HeapTuple	ha = *(const HeapTuple *) a;
 | 
			
		||||
	HeapTuple	hb = *(const HeapTuple *) b;
 | 
			
		||||
@@ -1836,7 +1837,7 @@ static void compute_scalar_stats(VacAttrStatsP stats,
 | 
			
		||||
								 int samplerows,
 | 
			
		||||
								 double totalrows);
 | 
			
		||||
static int	compare_scalars(const void *a, const void *b, void *arg);
 | 
			
		||||
static int	compare_mcvs(const void *a, const void *b);
 | 
			
		||||
static int	compare_mcvs(const void *a, const void *b, void *arg);
 | 
			
		||||
static int	analyze_mcv_list(int *mcv_counts,
 | 
			
		||||
							 int num_mcv,
 | 
			
		||||
							 double stadistinct,
 | 
			
		||||
@@ -2473,8 +2474,8 @@ compute_scalar_stats(VacAttrStatsP stats,
 | 
			
		||||
		/* Sort the collected values */
 | 
			
		||||
		cxt.ssup = &ssup;
 | 
			
		||||
		cxt.tupnoLink = tupnoLink;
 | 
			
		||||
		qsort_arg((void *) values, values_cnt, sizeof(ScalarItem),
 | 
			
		||||
				  compare_scalars, (void *) &cxt);
 | 
			
		||||
		qsort_interruptible((void *) values, values_cnt, sizeof(ScalarItem),
 | 
			
		||||
							compare_scalars, (void *) &cxt);
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Now scan the values in order, find the most common ones, and also
 | 
			
		||||
@@ -2718,8 +2719,8 @@ compute_scalar_stats(VacAttrStatsP stats,
 | 
			
		||||
						deltafrac;
 | 
			
		||||
 | 
			
		||||
			/* Sort the MCV items into position order to speed next loop */
 | 
			
		||||
			qsort((void *) track, num_mcv,
 | 
			
		||||
				  sizeof(ScalarMCVItem), compare_mcvs);
 | 
			
		||||
			qsort_interruptible((void *) track, num_mcv, sizeof(ScalarMCVItem),
 | 
			
		||||
								compare_mcvs, NULL);
 | 
			
		||||
 | 
			
		||||
			/*
 | 
			
		||||
			 * Collapse out the MCV items from the values[] array.
 | 
			
		||||
@@ -2882,7 +2883,7 @@ compute_scalar_stats(VacAttrStatsP stats,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * qsort_arg comparator for sorting ScalarItems
 | 
			
		||||
 * Comparator for sorting ScalarItems
 | 
			
		||||
 *
 | 
			
		||||
 * Aside from sorting the items, we update the tupnoLink[] array
 | 
			
		||||
 * whenever two ScalarItems are found to contain equal datums.  The array
 | 
			
		||||
@@ -2919,10 +2920,10 @@ compare_scalars(const void *a, const void *b, void *arg)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * qsort comparator for sorting ScalarMCVItems by position
 | 
			
		||||
 * Comparator for sorting ScalarMCVItems by position
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
compare_mcvs(const void *a, const void *b)
 | 
			
		||||
compare_mcvs(const void *a, const void *b, void *arg)
 | 
			
		||||
{
 | 
			
		||||
	int			da = ((const ScalarMCVItem *) a)->first;
 | 
			
		||||
	int			db = ((const ScalarMCVItem *) b)->first;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user