diff options
author | Alvaro Herrera <alvherre@alvh.no-ip.org> | 2020-08-12 15:33:36 -0400 |
---|---|---|
committer | Alvaro Herrera <alvherre@alvh.no-ip.org> | 2020-08-12 15:33:36 -0400 |
commit | 1f42d35a1d6144a23602b2c0bc7f97f3046cf890 (patch) | |
tree | 58fc88aa21fc52a479867904e1e1c9657f7cd169 /src | |
parent | 3546cf8a7a9dc57e6aa98f5fc1ac5476ad6b99ff (diff) | |
download | postgresql-1f42d35a1d6144a23602b2c0bc7f97f3046cf890.tar.gz postgresql-1f42d35a1d6144a23602b2c0bc7f97f3046cf890.zip |
BRIN: Handle concurrent desummarization properly
If a page range is desummarized at just the right time concurrently with
an index walk, BRIN would raise an error indicating index corruption.
This is scary and unhelpful; silently returning that the page range is
not summarized is sufficient reaction.
This bug was introduced by commit 975ad4e602ff as additional protection
against a bug whose actual fix was elsewhere. Backpatch equally.
Reported-By: Anastasia Lubennikova <a.lubennikova@postgrespro.ru>
Diagnosed-By: Alexander Lakhin <exclusion@gmail.com>
Discussion: https://postgr.es/m/2588667e-d07d-7e10-74e2-7e1e46194491@postgrespro.ru
Backpatch: 9.5 - master
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/access/brin/brin_revmap.c | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/src/backend/access/brin/brin_revmap.c b/src/backend/access/brin/brin_revmap.c index e8b8308f82e..35746714a7c 100644 --- a/src/backend/access/brin/brin_revmap.c +++ b/src/backend/access/brin/brin_revmap.c @@ -282,10 +282,17 @@ brinGetTupleForHeapBlock(BrinRevmap *revmap, BlockNumber heapBlk, /* If we land on a revmap page, start over */ if (BRIN_IS_REGULAR_PAGE(page)) { + /* + * If the offset number is greater than what's in the page, it's + * possible that the range was desummarized concurrently. Just + * return NULL to handle that case. + */ if (*off > PageGetMaxOffsetNumber(page)) - ereport(ERROR, - (errcode(ERRCODE_INDEX_CORRUPTED), - errmsg_internal("corrupted BRIN index: inconsistent range map"))); + { + LockBuffer(*buf, BUFFER_LOCK_UNLOCK); + return NULL; + } + lp = PageGetItemId(page, *off); if (ItemIdIsUsed(lp)) { |