Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 9563d5b

Browse files
committed
Add regression test case exercising the sorting path for hash index build.
We've broken this code path at least twice in the past, so it's prudent to have a test case that covers it. To allow exercising the code path without creating a very large (and slow to run) test case, redefine the sort threshold to be bounded by maintenance_work_mem as well as the number of available buffers. While at it, fix an ancient oversight that when building a temp index, the number of available buffers is not NBuffers but NLocBuffer. Also, if assertions are enabled, apply a direct test that the sort actually does return the tuples in the expected order. Peter Geoghegan Patch: <CAM3SWZTBAo4hjbBd780+MrOKiKp_TMo1N3A0Rw9_im8gbD7fQA@mail.gmail.com>
1 parent 2781489 commit 9563d5b

File tree

4 files changed

+51
-6
lines changed

4 files changed

+51
-6
lines changed

src/backend/access/hash/hash.c

+17-3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "access/relscan.h"
2323
#include "catalog/index.h"
2424
#include "commands/vacuum.h"
25+
#include "miscadmin.h"
2526
#include "optimizer/plancat.h"
2627
#include "utils/index_selfuncs.h"
2728
#include "utils/rel.h"
@@ -97,6 +98,7 @@ hashbuild(Relation heap, Relation index, IndexInfo *indexInfo)
9798
double reltuples;
9899
double allvisfrac;
99100
uint32 num_buckets;
101+
long sort_threshold;
100102
HashBuildState buildstate;
101103

102104
/*
@@ -120,12 +122,24 @@ hashbuild(Relation heap, Relation index, IndexInfo *indexInfo)
120122
* then we'll thrash horribly. To prevent that scenario, we can sort the
121123
* tuples by (expected) bucket number. However, such a sort is useless
122124
* overhead when the index does fit in RAM. We choose to sort if the
123-
* initial index size exceeds NBuffers.
125+
* initial index size exceeds maintenance_work_mem, or the number of
126+
* buffers usable for the index, whichever is less. (Limiting by the
127+
* number of buffers should reduce thrashing between PG buffers and kernel
128+
* buffers, which seems useful even if no physical I/O results. Limiting
129+
* by maintenance_work_mem is useful to allow easy testing of the sort
130+
* code path, and may be useful to DBAs as an additional control knob.)
124131
*
125132
* NOTE: this test will need adjustment if a bucket is ever different from
126-
* one page.
133+
* one page. Also, "initial index size" accounting does not include the
134+
* metapage, nor the first bitmap page.
127135
*/
128-
if (num_buckets >= (uint32) NBuffers)
136+
sort_threshold = (maintenance_work_mem * 1024L) / BLCKSZ;
137+
if (index->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
138+
sort_threshold = Min(sort_threshold, NBuffers);
139+
else
140+
sort_threshold = Min(sort_threshold, NLocBuffer);
141+
142+
if (num_buckets >= (uint32) sort_threshold)
129143
buildstate.spool = _h_spoolinit(heap, index, num_buckets);
130144
else
131145
buildstate.spool = NULL;

src/backend/access/hash/hashsort.c

+20-3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ struct HSpool
3737
{
3838
Tuplesortstate *sortstate; /* state data for tuplesort.c */
3939
Relation index;
40+
uint32 hash_mask; /* bitmask for hash codes */
4041
};
4142

4243

@@ -47,7 +48,6 @@ HSpool *
4748
_h_spoolinit(Relation heap, Relation index, uint32 num_buckets)
4849
{
4950
HSpool *hspool = (HSpool *) palloc0(sizeof(HSpool));
50-
uint32 hash_mask;
5151

5252
hspool->index = index;
5353

@@ -60,7 +60,7 @@ _h_spoolinit(Relation heap, Relation index, uint32 num_buckets)
6060
* we could just compute num_buckets - 1. We prefer not to assume that
6161
* here, though.
6262
*/
63-
hash_mask = (((uint32) 1) << _hash_log2(num_buckets)) - 1;
63+
hspool->hash_mask = (((uint32) 1) << _hash_log2(num_buckets)) - 1;
6464

6565
/*
6666
* We size the sort area as maintenance_work_mem rather than work_mem to
@@ -69,7 +69,7 @@ _h_spoolinit(Relation heap, Relation index, uint32 num_buckets)
6969
*/
7070
hspool->sortstate = tuplesort_begin_index_hash(heap,
7171
index,
72-
hash_mask,
72+
hspool->hash_mask,
7373
maintenance_work_mem,
7474
false);
7575

@@ -105,12 +105,29 @@ _h_indexbuild(HSpool *hspool)
105105
{
106106
IndexTuple itup;
107107
bool should_free;
108+
#ifdef USE_ASSERT_CHECKING
109+
uint32 hashkey = 0;
110+
#endif
108111

109112
tuplesort_performsort(hspool->sortstate);
110113

111114
while ((itup = tuplesort_getindextuple(hspool->sortstate,
112115
true, &should_free)) != NULL)
113116
{
117+
/*
118+
* Technically, it isn't critical that hash keys be found in sorted
119+
* order, since this sorting is only used to increase locality of
120+
* access as a performance optimization. It still seems like a good
121+
* idea to test tuplesort.c's handling of hash index tuple sorts
122+
* through an assertion, though.
123+
*/
124+
#ifdef USE_ASSERT_CHECKING
125+
uint32 lasthashkey = hashkey;
126+
127+
hashkey = _hash_get_indextuple_hashkey(itup) & hspool->hash_mask;
128+
Assert(hashkey >= lasthashkey);
129+
#endif
130+
114131
_hash_doinsert(hspool->index, itup);
115132
if (should_free)
116133
pfree(itup);

src/test/regress/expected/create_index.out

+7
Original file line numberDiff line numberDiff line change
@@ -2346,6 +2346,13 @@ CREATE UNLOGGED TABLE unlogged_hash_table (id int4);
23462346
CREATE INDEX unlogged_hash_index ON unlogged_hash_table USING hash (id int4_ops);
23472347
DROP TABLE unlogged_hash_table;
23482348
-- CREATE INDEX hash_ovfl_index ON hash_ovfl_heap USING hash (x int4_ops);
2349+
-- Test hash index build tuplesorting. Force hash tuplesort using low
2350+
-- maintenance_work_mem setting and fillfactor:
2351+
SET maintenance_work_mem = '1MB';
2352+
CREATE INDEX hash_tuplesort_idx ON tenk1 USING hash (stringu1 name_ops) WITH (fillfactor = 10);
2353+
WARNING: hash indexes are not WAL-logged and their use is discouraged
2354+
DROP INDEX hash_tuplesort_idx;
2355+
RESET maintenance_work_mem;
23492356
--
23502357
-- Test functional index
23512358
--

src/test/regress/sql/create_index.sql

+7
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,13 @@ DROP TABLE unlogged_hash_table;
690690

691691
-- CREATE INDEX hash_ovfl_index ON hash_ovfl_heap USING hash (x int4_ops);
692692

693+
-- Test hash index build tuplesorting. Force hash tuplesort using low
694+
-- maintenance_work_mem setting and fillfactor:
695+
SET maintenance_work_mem = '1MB';
696+
CREATE INDEX hash_tuplesort_idx ON tenk1 USING hash (stringu1 name_ops) WITH (fillfactor = 10);
697+
DROP INDEX hash_tuplesort_idx;
698+
RESET maintenance_work_mem;
699+
693700

694701
--
695702
-- Test functional index

0 commit comments

Comments
 (0)