From 73bbacd36de89a7d79b87270ddd89bf74fe2e1aa Mon Sep 17 00:00:00 2001 From: Nikita Malakhov Date: Mon, 28 Nov 2022 18:05:53 +0300 Subject: [PATCH] Infinite loop while acquiring new TOAST value Oid When TOASTed value is inserted it acquires new Oid which is stored in the TOAST Pointer. Acquired Oid is checked if it already exists in TOAST table the value is inserted into. If such value already exists Oid acquiring is repeated, and when all values for the type of value id - uint32 - are used - the cycle is repeated infinitely. This results in DB stalling and SQL queries freezing. The problem is actual for production databases with large amounts of data. Fix proposes limiting repeatable calls of GetNewOidWithIndex function that acquires new Oid to the value defined by GETNEWOID_MAX_THRESHOLD macro (3 in this patch) and return error if acquired Oid still . Author: Nikita Malakhov --- src/backend/access/common/toast_internals.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c index 576e585a89..e32796c75f 100644 --- a/src/backend/access/common/toast_internals.c +++ b/src/backend/access/common/toast_internals.c @@ -27,6 +27,8 @@ #include "utils/rel.h" #include "utils/snapmgr.h" +#define GETNEWOID_MAX_THRESHOLD 3 + static bool toastrel_valueid_exists(Relation toastrel, Oid valueid); static bool toastid_valueid_exists(Oid toastrelid, Oid valueid); @@ -144,6 +146,7 @@ toast_save_datum(Relation rel, Datum value, Pointer dval = DatumGetPointer(value); int num_indexes; int validIndex; + uint32 getnewoid_counter = 0; Assert(!VARATT_IS_EXTERNAL(value)); @@ -281,10 +284,20 @@ toast_save_datum(Relation rel, Datum value, */ do { + if(getnewoid_counter > GETNEWOID_MAX_THRESHOLD) + { + toast_close_indexes(toastidxs, num_indexes, NoLock); + table_close(toastrel, NoLock); + + elog(ERROR, "Cannot get new TOAST value Oid for toast relation with Oid %u", + RelationGetRelid(toastrel)); + } + toast_pointer.va_valueid = GetNewOidWithIndex(toastrel, RelationGetRelid(toastidxs[validIndex]), (AttrNumber) 1); + getnewoid_counter++; } while (toastid_valueid_exists(rel->rd_toastoid, toast_pointer.va_valueid)); } -- 2.25.1