Further twiddling of nodeHash.c hashtable sizing calculation.

On reflection, the submitted patch didn't really work to prevent the
request size from exceeding MaxAllocSize, because of the fact that we'd
happily round nbuckets up to the next power of 2 after we'd limited it to
max_pointers.  The simplest way to enforce the limit correctly is to
round max_pointers down to a power of 2 when it isn't one already.

(Note that the constraint to INT_MAX / 2, if it were doing anything useful
at all, is properly applied after that.)
This commit is contained in:
Tom Lane 2015-10-04 15:55:07 -04:00
parent a31e64d065
commit f2fc98fb8e

View File

@ -415,6 +415,7 @@ ExecChooseHashTableSize(double ntuples, int tupwidth, bool useskew,
long hash_table_bytes; long hash_table_bytes;
long skew_table_bytes; long skew_table_bytes;
long max_pointers; long max_pointers;
long mppow2;
int nbatch = 1; int nbatch = 1;
int nbuckets; int nbuckets;
double dbuckets; double dbuckets;
@ -485,14 +486,20 @@ ExecChooseHashTableSize(double ntuples, int tupwidth, bool useskew,
*/ */
max_pointers = (work_mem * 1024L) / sizeof(HashJoinTuple); max_pointers = (work_mem * 1024L) / sizeof(HashJoinTuple);
max_pointers = Min(max_pointers, MaxAllocSize / sizeof(HashJoinTuple)); max_pointers = Min(max_pointers, MaxAllocSize / sizeof(HashJoinTuple));
/* also ensure we avoid integer overflow in nbatch and nbuckets */ /* If max_pointers isn't a power of 2, must round it down to one */
mppow2 = 1L << my_log2(max_pointers);
if (max_pointers != mppow2)
max_pointers = mppow2 / 2;
/* Also ensure we avoid integer overflow in nbatch and nbuckets */
/* (this step is redundant given the current value of MaxAllocSize) */ /* (this step is redundant given the current value of MaxAllocSize) */
max_pointers = Min(max_pointers, INT_MAX / 2); max_pointers = Min(max_pointers, INT_MAX / 2);
dbuckets = ceil(ntuples / NTUP_PER_BUCKET); dbuckets = ceil(ntuples / NTUP_PER_BUCKET);
dbuckets = Min(dbuckets, max_pointers); dbuckets = Min(dbuckets, max_pointers);
nbuckets = (int) dbuckets;
/* don't let nbuckets be really small, though ... */ /* don't let nbuckets be really small, though ... */
nbuckets = Max((int) dbuckets, 1024); nbuckets = Max(nbuckets, 1024);
/* ... and force it to be a power of 2. */ /* ... and force it to be a power of 2. */
nbuckets = 1 << my_log2(nbuckets); nbuckets = 1 << my_log2(nbuckets);