diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c index e2ed80a5de..a90ab3614c 100644 --- a/src/backend/catalog/catalog.c +++ b/src/backend/catalog/catalog.c @@ -47,6 +47,13 @@ #include "utils/snapmgr.h" #include "utils/syscache.h" +/* + * Parameters to determine when to emit a warning in + * GetNewOidWithIndex() + */ +#define GETNEWOID_WARN_THRESHOLD 1000000 +#define GETNEWOID_WARN_MAX_INTERVAL 100000000 + /* * IsSystemRelation * True iff the relation is either a system catalog or a toast table. @@ -318,6 +325,8 @@ GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn) SysScanDesc scan; ScanKeyData key; bool collides; + uint64 retries = 0; + uint64 retries_before_warn = GETNEWOID_WARN_THRESHOLD; /* Only system relations are supported */ Assert(IsSystemRelation(relation)); @@ -353,8 +362,48 @@ GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn) collides = HeapTupleIsValid(systable_getnext(scan)); systable_endscan(scan); + + /* + * Warn users that we iterate more than GETNEWOID_WARN_THRESHOLD but + * have not yet found OID unused in the relation. Then repeat warning + * with exponentially increasing intervals until we iterate more than + * GETNEWOID_WARN_MAX_INTERVAL. Finally repeat warning every + * GETNEWOID_WARN_MAX_INTERVAL unless an unused OID is found. This + * logic is necessary not to fill up the server log with the similar + * messages. + */ + if (retries >= retries_before_warn) + { + ereport(WARNING, + (errmsg("still finding an unused OID within relation \"%s\"", + RelationGetRelationName(relation)), + errdetail("OID candidates were checked \"%llu\" times, but no unused OID is yet found.", + (unsigned long long) retries))); + + /* + * Double the number of retries to do before warning next until it + * reaches GETNEWOID_WARN_MAX_INTERVAL. + */ + if (retries_before_warn * 2 <= GETNEWOID_WARN_MAX_INTERVAL) + retries_before_warn *= 2; + else + retries_before_warn += GETNEWOID_WARN_MAX_INTERVAL; + } + + retries++; } while (collides); + /* + * If at least one warning is emitted, also warn the completion of OID + * assignment. + */ + if (retries > GETNEWOID_WARN_THRESHOLD) + { + ereport(WARNING, + (errmsg("new OID has been assigned in relation \"%s\" after \"%llu\" retries", + RelationGetRelationName(relation), (unsigned long long) retries))); + } + return newOid; }