Commit 4bc6fb57 authored by Heikki Linnakangas's avatar Heikki Linnakangas

Fix integer overflow bug in GiST buffering build calculations.

The result of (maintenance_work_mem * 1024) / BLCKSZ doesn't fit in a signed
32-bit integer, if maintenance_work_mem >= 2GB. Use double instead. And
while we're at it, write the calculations in an easier to understand form,
with the intermediary steps written out and commented.
parent 2755abf3
...@@ -323,8 +323,8 @@ gistInitBuffering(GISTBuildState *buildstate) ...@@ -323,8 +323,8 @@ gistInitBuffering(GISTBuildState *buildstate)
* calculating levelStep is very close to Arge et al's formula. For a * calculating levelStep is very close to Arge et al's formula. For a
* large B, our formula gives a value that is 2x higher. * large B, our formula gives a value that is 2x higher.
* *
* The average size of a subtree of depth n can be calculated as a * The average size (in pages) of a subtree of depth n can be calculated
* geometric series: * as a geometric series:
* *
* B^0 + B^1 + B^2 + ... + B^n = (1 - B^(n + 1)) / (1 - B) * B^0 + B^1 + B^2 + ... + B^n = (1 - B^(n + 1)) / (1 - B)
* *
...@@ -353,14 +353,28 @@ gistInitBuffering(GISTBuildState *buildstate) ...@@ -353,14 +353,28 @@ gistInitBuffering(GISTBuildState *buildstate)
* the hash table. * the hash table.
*/ */
levelStep = 1; levelStep = 1;
while ( for (;;)
{
double subtreesize;
double maxlowestlevelpages;
/* size of an average subtree at this levelStep (in pages). */
subtreesize =
(1 - pow(avgIndexTuplesPerPage, (double) (levelStep + 1))) /
(1 - avgIndexTuplesPerPage);
/* max number of pages at the lowest level of a subtree */
maxlowestlevelpages = pow(maxIndexTuplesPerPage, (double) levelStep);
/* subtree must fit in cache (with safety factor of 4) */ /* subtree must fit in cache (with safety factor of 4) */
(1 - pow(avgIndexTuplesPerPage, (double) (levelStep + 1))) / (1 - avgIndexTuplesPerPage) < effective_cache_size / 4 if (subtreesize > effective_cache_size / 4)
&& break;
/* each node in the lowest level of a subtree has one page in memory */ /* each node in the lowest level of a subtree has one page in memory */
(pow(maxIndexTuplesPerPage, (double) levelStep) < (maintenance_work_mem * 1024) / BLCKSZ) if (maxlowestlevelpages > ((double) maintenance_work_mem * 1024) / BLCKSZ)
) break;
{
/* Good, we can handle this levelStep. See if we can go one higher. */
levelStep++; levelStep++;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment