Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite64cdab

Browse files
committed
Invent qsort_interruptible().
Justin Pryzby reported that some scenarios could cause gatheringof extended statistics to spend many seconds in an un-cancelableqsort() operation. To fix, invent qsort_interruptible(), which isjust like qsort_arg() except that it will also do CHECK_FOR_INTERRUPTSevery so often. This bloats the backend by a couple of kB, whichseems like a good investment. (We considered just enablingCHECK_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 canalways change other call sites as we find problems.Back-patch to v14. Before that we didn't have extended stats onexpressions, so that the problem was less severe. Also, this patchdepends on the sort_template infrastructure introduced in v14.Tom Lane and Justin PryzbyDiscussion:https://postgr.es/m/20220509000108.GQ28830@telsasoft.com
1 parent9200723 commite64cdab

File tree

10 files changed

+80
-55
lines changed

10 files changed

+80
-55
lines changed

‎src/backend/commands/analyze.c

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ static VacAttrStats *examine_attribute(Relation onerel, int attnum,
100100
staticintacquire_sample_rows(Relationonerel,intelevel,
101101
HeapTuple*rows,inttargrows,
102102
double*totalrows,double*totaldeadrows);
103-
staticintcompare_rows(constvoid*a,constvoid*b);
103+
staticintcompare_rows(constvoid*a,constvoid*b,void*arg);
104104
staticintacquire_inherited_sample_rows(Relationonerel,intelevel,
105105
HeapTuple*rows,inttargrows,
106106
double*totalrows,double*totaldeadrows);
@@ -1306,7 +1306,8 @@ acquire_sample_rows(Relation onerel, int elevel,
13061306
* tuples are already sorted.
13071307
*/
13081308
if (numrows==targrows)
1309-
qsort((void*)rows,numrows,sizeof(HeapTuple),compare_rows);
1309+
qsort_interruptible((void*)rows,numrows,sizeof(HeapTuple),
1310+
compare_rows,NULL);
13101311

13111312
/*
13121313
* Estimate total numbers of live and dead rows in relation, extrapolating
@@ -1342,10 +1343,10 @@ acquire_sample_rows(Relation onerel, int elevel,
13421343
}
13431344

13441345
/*
1345-
*qsort comparator for sorting rows[] array
1346+
*Comparator for sorting rows[] array
13461347
*/
13471348
staticint
1348-
compare_rows(constvoid*a,constvoid*b)
1349+
compare_rows(constvoid*a,constvoid*b,void*arg)
13491350
{
13501351
HeapTupleha=*(constHeapTuple*)a;
13511352
HeapTuplehb=*(constHeapTuple*)b;
@@ -1836,7 +1837,7 @@ static void compute_scalar_stats(VacAttrStatsP stats,
18361837
intsamplerows,
18371838
doubletotalrows);
18381839
staticintcompare_scalars(constvoid*a,constvoid*b,void*arg);
1839-
staticintcompare_mcvs(constvoid*a,constvoid*b);
1840+
staticintcompare_mcvs(constvoid*a,constvoid*b,void*arg);
18401841
staticintanalyze_mcv_list(int*mcv_counts,
18411842
intnum_mcv,
18421843
doublestadistinct,
@@ -2473,8 +2474,8 @@ compute_scalar_stats(VacAttrStatsP stats,
24732474
/* Sort the collected values */
24742475
cxt.ssup=&ssup;
24752476
cxt.tupnoLink=tupnoLink;
2476-
qsort_arg((void*)values,values_cnt,sizeof(ScalarItem),
2477-
compare_scalars, (void*)&cxt);
2477+
qsort_interruptible((void*)values,values_cnt,sizeof(ScalarItem),
2478+
compare_scalars, (void*)&cxt);
24782479

24792480
/*
24802481
* Now scan the values in order, find the most common ones, and also
@@ -2718,8 +2719,8 @@ compute_scalar_stats(VacAttrStatsP stats,
27182719
deltafrac;
27192720

27202721
/* Sort the MCV items into position order to speed next loop */
2721-
qsort((void*)track,num_mcv,
2722-
sizeof(ScalarMCVItem),compare_mcvs);
2722+
qsort_interruptible((void*)track,num_mcv,sizeof(ScalarMCVItem),
2723+
compare_mcvs,NULL);
27232724

27242725
/*
27252726
* Collapse out the MCV items from the values[] array.
@@ -2882,7 +2883,7 @@ compute_scalar_stats(VacAttrStatsP stats,
28822883
}
28832884

28842885
/*
2885-
*qsort_arg comparator for sorting ScalarItems
2886+
*Comparator for sorting ScalarItems
28862887
*
28872888
* Aside from sorting the items, we update the tupnoLink[] array
28882889
* 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)
29192920
}
29202921

29212922
/*
2922-
*qsort comparator for sorting ScalarMCVItems by position
2923+
*Comparator for sorting ScalarMCVItems by position
29232924
*/
29242925
staticint
2925-
compare_mcvs(constvoid*a,constvoid*b)
2926+
compare_mcvs(constvoid*a,constvoid*b,void*arg)
29262927
{
29272928
intda= ((constScalarMCVItem*)a)->first;
29282929
intdb= ((constScalarMCVItem*)b)->first;

‎src/backend/statistics/extended_stats.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,8 +1129,8 @@ build_sorted_items(StatsBuildData *data, int *nitems,
11291129
}
11301130

11311131
/* do the sort, using the multi-sort */
1132-
qsort_arg((void*)items,nrows,sizeof(SortItem),
1133-
multi_sort_compare,mss);
1132+
qsort_interruptible((void*)items,nrows,sizeof(SortItem),
1133+
multi_sort_compare,mss);
11341134

11351135
returnitems;
11361136
}

‎src/backend/statistics/mcv.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ count_distinct_groups(int numrows, SortItem *items, MultiSortSupport mss)
404404
*order.
405405
*/
406406
staticint
407-
compare_sort_item_count(constvoid*a,constvoid*b)
407+
compare_sort_item_count(constvoid*a,constvoid*b,void*arg)
408408
{
409409
SortItem*ia= (SortItem*)a;
410410
SortItem*ib= (SortItem*)b;
@@ -457,8 +457,8 @@ build_distinct_groups(int numrows, SortItem *items, MultiSortSupport mss,
457457
Assert(j+1==ngroups);
458458

459459
/* Sort the distinct groups by frequency (in descending order). */
460-
pg_qsort((void*)groups,ngroups,sizeof(SortItem),
461-
compare_sort_item_count);
460+
qsort_interruptible((void*)groups,ngroups,sizeof(SortItem),
461+
compare_sort_item_count,NULL);
462462

463463
*ndistinct=ngroups;
464464
returngroups;
@@ -528,8 +528,8 @@ build_column_frequencies(SortItem *groups, int ngroups,
528528
}
529529

530530
/* sort the values, deduplicate */
531-
qsort_arg((void*)result[dim],ngroups,sizeof(SortItem),
532-
sort_item_compare,ssup);
531+
qsort_interruptible((void*)result[dim],ngroups,sizeof(SortItem),
532+
sort_item_compare,ssup);
533533

534534
/*
535535
* Identify distinct values, compute frequency (there might be
@@ -696,8 +696,8 @@ statext_mcv_serialize(MCVList *mcvlist, VacAttrStats **stats)
696696

697697
PrepareSortSupportFromOrderingOp(typentry->lt_opr,&ssup[dim]);
698698

699-
qsort_arg(values[dim],counts[dim],sizeof(Datum),
700-
compare_scalars_simple,&ssup[dim]);
699+
qsort_interruptible(values[dim],counts[dim],sizeof(Datum),
700+
compare_scalars_simple,&ssup[dim]);
701701

702702
/*
703703
* Walk through the array and eliminate duplicate values, but keep the

‎src/backend/statistics/mvdistinct.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -489,8 +489,8 @@ ndistinct_for_combination(double totalrows, StatsBuildData *data,
489489
}
490490

491491
/* We can sort the array now ... */
492-
qsort_arg((void*)items,numrows,sizeof(SortItem),
493-
multi_sort_compare,mss);
492+
qsort_interruptible((void*)items,numrows,sizeof(SortItem),
493+
multi_sort_compare,mss);
494494

495495
/* ... and count the number of distinct combinations */
496496

‎src/backend/tsearch/ts_typanalyze.c

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,10 @@ static void prune_lexemes_hashtable(HTAB *lexemes_tab, int b_current);
4444
staticuint32lexeme_hash(constvoid*key,Sizekeysize);
4545
staticintlexeme_match(constvoid*key1,constvoid*key2,Sizekeysize);
4646
staticintlexeme_compare(constvoid*key1,constvoid*key2);
47-
staticinttrackitem_compare_frequencies_desc(constvoid*e1,constvoid*e2);
48-
staticinttrackitem_compare_lexemes(constvoid*e1,constvoid*e2);
47+
staticinttrackitem_compare_frequencies_desc(constvoid*e1,constvoid*e2,
48+
void*arg);
49+
staticinttrackitem_compare_lexemes(constvoid*e1,constvoid*e2,
50+
void*arg);
4951

5052

5153
/*
@@ -347,8 +349,8 @@ compute_tsvector_stats(VacAttrStats *stats,
347349
*/
348350
if (num_mcelem<track_len)
349351
{
350-
qsort(sort_table,track_len,sizeof(TrackItem*),
351-
trackitem_compare_frequencies_desc);
352+
qsort_interruptible(sort_table,track_len,sizeof(TrackItem*),
353+
trackitem_compare_frequencies_desc,NULL);
352354
/* reset minfreq to the smallest frequency we're keeping */
353355
minfreq=sort_table[num_mcelem-1]->frequency;
354356
}
@@ -376,8 +378,8 @@ compute_tsvector_stats(VacAttrStats *stats,
376378
* presorted we can employ binary search for that. See
377379
* ts_selfuncs.c for a real usage scenario.
378380
*/
379-
qsort(sort_table,num_mcelem,sizeof(TrackItem*),
380-
trackitem_compare_lexemes);
381+
qsort_interruptible(sort_table,num_mcelem,sizeof(TrackItem*),
382+
trackitem_compare_lexemes,NULL);
381383

382384
/* Must copy the target values into anl_context */
383385
old_context=MemoryContextSwitchTo(stats->anl_context);
@@ -510,10 +512,10 @@ lexeme_compare(const void *key1, const void *key2)
510512
}
511513

512514
/*
513-
*qsort() comparator for sorting TrackItems on frequencies (descending sort)
515+
*Comparator for sorting TrackItems on frequencies (descending sort)
514516
*/
515517
staticint
516-
trackitem_compare_frequencies_desc(constvoid*e1,constvoid*e2)
518+
trackitem_compare_frequencies_desc(constvoid*e1,constvoid*e2,void*arg)
517519
{
518520
constTrackItem*const*t1= (constTrackItem*const*)e1;
519521
constTrackItem*const*t2= (constTrackItem*const*)e2;
@@ -522,10 +524,10 @@ trackitem_compare_frequencies_desc(const void *e1, const void *e2)
522524
}
523525

524526
/*
525-
*qsort() comparator for sorting TrackItems on lexemes
527+
*Comparator for sorting TrackItems on lexemes
526528
*/
527529
staticint
528-
trackitem_compare_lexemes(constvoid*e1,constvoid*e2)
530+
trackitem_compare_lexemes(constvoid*e1,constvoid*e2,void*arg)
529531
{
530532
constTrackItem*const*t1= (constTrackItem*const*)e1;
531533
constTrackItem*const*t2= (constTrackItem*const*)e2;

‎src/backend/utils/adt/array_typanalyze.c

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,9 @@ static void prune_element_hashtable(HTAB *elements_tab, int b_current);
8686
staticuint32element_hash(constvoid*key,Sizekeysize);
8787
staticintelement_match(constvoid*key1,constvoid*key2,Sizekeysize);
8888
staticintelement_compare(constvoid*key1,constvoid*key2);
89-
staticinttrackitem_compare_frequencies_desc(constvoid*e1,constvoid*e2);
90-
staticinttrackitem_compare_element(constvoid*e1,constvoid*e2);
91-
staticintcountitem_compare_count(constvoid*e1,constvoid*e2);
89+
staticinttrackitem_compare_frequencies_desc(constvoid*e1,constvoid*e2,void*arg);
90+
staticinttrackitem_compare_element(constvoid*e1,constvoid*e2,void*arg);
91+
staticintcountitem_compare_count(constvoid*e1,constvoid*e2,void*arg);
9292

9393

9494
/*
@@ -502,8 +502,8 @@ compute_array_stats(VacAttrStats *stats, AnalyzeAttrFetchFunc fetchfunc,
502502
*/
503503
if (num_mcelem<track_len)
504504
{
505-
qsort(sort_table,track_len,sizeof(TrackItem*),
506-
trackitem_compare_frequencies_desc);
505+
qsort_interruptible(sort_table,track_len,sizeof(TrackItem*),
506+
trackitem_compare_frequencies_desc,NULL);
507507
/* reset minfreq to the smallest frequency we're keeping */
508508
minfreq=sort_table[num_mcelem-1]->frequency;
509509
}
@@ -522,8 +522,8 @@ compute_array_stats(VacAttrStats *stats, AnalyzeAttrFetchFunc fetchfunc,
522522
* the element type's default comparison function. This permits
523523
* fast binary searches in selectivity estimation functions.
524524
*/
525-
qsort(sort_table,num_mcelem,sizeof(TrackItem*),
526-
trackitem_compare_element);
525+
qsort_interruptible(sort_table,num_mcelem,sizeof(TrackItem*),
526+
trackitem_compare_element,NULL);
527527

528528
/* Must copy the target values into anl_context */
529529
old_context=MemoryContextSwitchTo(stats->anl_context);
@@ -599,8 +599,9 @@ compute_array_stats(VacAttrStats *stats, AnalyzeAttrFetchFunc fetchfunc,
599599
{
600600
sorted_count_items[j++]=count_item;
601601
}
602-
qsort(sorted_count_items,count_items_count,
603-
sizeof(DECountItem*),countitem_compare_count);
602+
qsort_interruptible(sorted_count_items,count_items_count,
603+
sizeof(DECountItem*),
604+
countitem_compare_count,NULL);
604605

605606
/*
606607
* Prepare to fill stanumbers with the histogram, followed by the
@@ -751,10 +752,10 @@ element_compare(const void *key1, const void *key2)
751752
}
752753

753754
/*
754-
*qsort() comparator for sorting TrackItems by frequencies (descending sort)
755+
*Comparator for sorting TrackItems by frequencies (descending sort)
755756
*/
756757
staticint
757-
trackitem_compare_frequencies_desc(constvoid*e1,constvoid*e2)
758+
trackitem_compare_frequencies_desc(constvoid*e1,constvoid*e2,void*arg)
758759
{
759760
constTrackItem*const*t1= (constTrackItem*const*)e1;
760761
constTrackItem*const*t2= (constTrackItem*const*)e2;
@@ -763,10 +764,10 @@ trackitem_compare_frequencies_desc(const void *e1, const void *e2)
763764
}
764765

765766
/*
766-
*qsort() comparator for sorting TrackItems by element values
767+
*Comparator for sorting TrackItems by element values
767768
*/
768769
staticint
769-
trackitem_compare_element(constvoid*e1,constvoid*e2)
770+
trackitem_compare_element(constvoid*e1,constvoid*e2,void*arg)
770771
{
771772
constTrackItem*const*t1= (constTrackItem*const*)e1;
772773
constTrackItem*const*t2= (constTrackItem*const*)e2;
@@ -775,10 +776,10 @@ trackitem_compare_element(const void *e1, const void *e2)
775776
}
776777

777778
/*
778-
*qsort() comparator for sorting DECountItems by count
779+
*Comparator for sorting DECountItems by count
779780
*/
780781
staticint
781-
countitem_compare_count(constvoid*e1,constvoid*e2)
782+
countitem_compare_count(constvoid*e1,constvoid*e2,void*arg)
782783
{
783784
constDECountItem*const*t1= (constDECountItem*const*)e1;
784785
constDECountItem*const*t2= (constDECountItem*const*)e2;

‎src/backend/utils/adt/rangetypes_typanalyze.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
#include"utils/rangetypes.h"
3333
#include"utils/multirangetypes.h"
3434

35-
staticintfloat8_qsort_cmp(constvoid*a1,constvoid*a2);
35+
staticintfloat8_qsort_cmp(constvoid*a1,constvoid*a2,void*arg);
3636
staticintrange_bound_qsort_cmp(constvoid*a1,constvoid*a2,void*arg);
3737
staticvoidcompute_range_stats(VacAttrStats*stats,
3838
AnalyzeAttrFetchFuncfetchfunc,intsamplerows,
@@ -93,7 +93,7 @@ multirange_typanalyze(PG_FUNCTION_ARGS)
9393
* Comparison function for sorting float8s, used for range lengths.
9494
*/
9595
staticint
96-
float8_qsort_cmp(constvoid*a1,constvoid*a2)
96+
float8_qsort_cmp(constvoid*a1,constvoid*a2,void*arg)
9797
{
9898
constfloat8*f1= (constfloat8*)a1;
9999
constfloat8*f2= (constfloat8*)a2;
@@ -280,10 +280,10 @@ compute_range_stats(VacAttrStats *stats, AnalyzeAttrFetchFunc fetchfunc,
280280
if (non_empty_cnt >=2)
281281
{
282282
/* Sort bound values */
283-
qsort_arg(lowers,non_empty_cnt,sizeof(RangeBound),
284-
range_bound_qsort_cmp,typcache);
285-
qsort_arg(uppers,non_empty_cnt,sizeof(RangeBound),
286-
range_bound_qsort_cmp,typcache);
283+
qsort_interruptible(lowers,non_empty_cnt,sizeof(RangeBound),
284+
range_bound_qsort_cmp,typcache);
285+
qsort_interruptible(uppers,non_empty_cnt,sizeof(RangeBound),
286+
range_bound_qsort_cmp,typcache);
287287

288288
num_hist=non_empty_cnt;
289289
if (num_hist>num_bins)
@@ -345,7 +345,8 @@ compute_range_stats(VacAttrStats *stats, AnalyzeAttrFetchFunc fetchfunc,
345345
* Ascending sort of range lengths for further filling of
346346
* histogram
347347
*/
348-
qsort(lengths,non_empty_cnt,sizeof(float8),float8_qsort_cmp);
348+
qsort_interruptible(lengths,non_empty_cnt,sizeof(float8),
349+
float8_qsort_cmp,NULL);
349350

350351
num_hist=non_empty_cnt;
351352
if (num_hist>num_bins)

‎src/backend/utils/sort/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS)
1616

1717
OBJS =\
1818
logtape.o\
19+
qsort_interruptible.o\
1920
sharedtuplestore.o\
2021
sortsupport.o\
2122
tuplesort.o\
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/*
2+
*qsort_interruptible.c: qsort_arg that includes CHECK_FOR_INTERRUPTS
3+
*/
4+
5+
#include"postgres.h"
6+
#include"miscadmin.h"
7+
8+
#defineST_SORT qsort_interruptible
9+
#defineST_ELEMENT_TYPE_VOID
10+
#defineST_COMPARATOR_TYPE_NAME qsort_arg_comparator
11+
#defineST_COMPARE_RUNTIME_POINTER
12+
#defineST_COMPARE_ARG_TYPE void
13+
#defineST_SCOPE
14+
#defineST_DEFINE
15+
#defineST_CHECK_FOR_INTERRUPTS
16+
#include"lib/sort_template.h"

‎src/include/port.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,9 @@ typedef int (*qsort_arg_comparator) (const void *a, const void *b, void *arg);
499499
externvoidqsort_arg(void*base,size_tnel,size_telsize,
500500
qsort_arg_comparatorcmp,void*arg);
501501

502+
externvoidqsort_interruptible(void*base,size_tnel,size_telsize,
503+
qsort_arg_comparatorcmp,void*arg);
504+
502505
externvoid*bsearch_arg(constvoid*key,constvoid*base,
503506
size_tnmemb,size_tsize,
504507
int (*compar) (constvoid*,constvoid*,void*),

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp