Skip to content

Commit

Permalink
Moved new OID generation functions into extension hooks
Browse files Browse the repository at this point in the history
Signed-off-by: Tim Chang <[email protected]>
  • Loading branch information
timchang514 committed Jan 8, 2024
1 parent 79916be commit 7bc64f9
Show file tree
Hide file tree
Showing 8 changed files with 24 additions and 243 deletions.
71 changes: 0 additions & 71 deletions src/backend/access/transam/varsup.c
Original file line number Diff line number Diff line change
Expand Up @@ -520,77 +520,6 @@ ForceTransactionIdLimitUpdate(void)
return false;
}

Oid
GetNewTempObjectId(void)
{
Oid result;
Oid tempOidStart;
static Oid nextTempOid = InvalidOid;

/* safety check, we should never get this far in a HS standby */
if (RecoveryInProgress())
elog(ERROR, "cannot assign OIDs during recovery");

if (!OidIsValid((Oid) temp_oid_buffer_start)) /* InvalidOid means it needs assigning */
{
/* First check to see if another connection has already picked a start, then update. */
LWLockAcquire(OidGenLock, LW_EXCLUSIVE);
if (OidIsValid(ShmemVariableCache->tempOidStart))
{
temp_oid_buffer_start = OID_TO_BUFFER_START(ShmemVariableCache->tempOidStart);
nextTempOid = ShmemVariableCache->tempOidStart;
}
else
{
/* We need to pick a new start for the buffer range. */
tempOidStart = ShmemVariableCache->nextOid;

/*
* Decrement ShmemVariableCache->oidCount to take into account the new buffer we're allocating
*/
if (ShmemVariableCache->oidCount < temp_oid_buffer_size)
ShmemVariableCache->oidCount = 0;
else
ShmemVariableCache->oidCount -= temp_oid_buffer_size;

/*
* If ShmemVariableCache->nextOid is below FirstNormalObjectId then we can start at FirstNormalObjectId here and
* GetNewObjectId will return the right value on the next call.
*/
if (tempOidStart < FirstNormalObjectId)
tempOidStart = FirstNormalObjectId;

/* If the OID range would wraparound, start from beginning instead. */
if (tempOidStart + temp_oid_buffer_size < tempOidStart)
tempOidStart = FirstNormalObjectId;

temp_oid_buffer_start = OID_TO_BUFFER_START(tempOidStart);
ShmemVariableCache->tempOidStart = tempOidStart;
ShmemVariableCache->tempOidBufferSize = temp_oid_buffer_size;

nextTempOid = (Oid) tempOidStart;

/* Skip nextOid ahead to end of range here as well. */
ShmemVariableCache->nextOid = (Oid) (tempOidStart + temp_oid_buffer_size);
}
LWLockRelease(OidGenLock);
}

/*
* Check for wraparound of the temp OID buffer.
*/
if (nextTempOid >= (Oid) (BUFFER_START_TO_OID + temp_oid_buffer_size)
|| nextTempOid < BUFFER_START_TO_OID)
{
nextTempOid = BUFFER_START_TO_OID;
}

result = nextTempOid;
nextTempOid++;

return result;
}

/*
* GetNewObjectId -- allocate a new OID
*
Expand Down
170 changes: 10 additions & 160 deletions src/backend/catalog/catalog.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ IsExtendedCatalogHookType IsExtendedCatalogHook;
IsToastRelationHookType IsToastRelationHook;
IsToastClassHookType IsToastClassHook;

GetNewTempObjectId_hook_type GetNewTempObjectId_hook;
GetNewTempOidWithIndex_hook_type GetNewTempOidWithIndex_hook;
GetNewPermanentRelFileNode_hook_type GetNewPermanentRelFileNode_hook;

/*
* Parameters to determine when to emit a log message in
* GetNewOidWithIndex()
Expand Down Expand Up @@ -497,76 +501,6 @@ GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
return newOid;
}

Oid
GetNewTempOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
{
Oid newOid;
SysScanDesc scan;
ScanKeyData key;
bool collides;
uint64 retries = 0;

/* Only system relations are supported */
Assert(IsSystemRelation(relation));

/* In bootstrap mode, we don't have any indexes to use. No temp objects in bootstrap mode. */
if (IsBootstrapProcessingMode())
return GetNewObjectId();

/*
* We should never be asked to generate a new pg_type OID during
* pg_upgrade; doing so would risk collisions with the OIDs it wants to
* assign. Hitting this assert means there's some path where we failed to
* ensure that a type OID is determined by commands in the dump script.
*/
Assert(!IsBinaryUpgrade || RelationGetRelid(relation) != TypeRelationId);

/* Generate new OIDs until we find one not in the table */
do
{
CHECK_FOR_INTERRUPTS();

newOid = GetNewTempObjectId();

ScanKeyInit(&key,
oidcolumn,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(newOid));

/* see notes above about using SnapshotAny */
scan = systable_beginscan(relation, indexId, true,
SnapshotAny, 1, &key);

collides = HeapTupleIsValid(systable_getnext(scan));

systable_endscan(scan);

/*
* Log that we iterate more than GETNEWOID_LOG_THRESHOLD but have not
* yet found OID unused in the relation. Then repeat logging with
* exponentially increasing intervals until we iterate more than
* GETNEWOID_LOG_MAX_INTERVAL. Finally repeat logging every
* GETNEWOID_LOG_MAX_INTERVAL unless an unused OID is found. This
* logic is necessary not to fill up the server log with the similar
* messages.
*/
if (OidIsValid((Oid) temp_oid_buffer_start) && retries >= temp_oid_buffer_size)
{
ereport(ERROR,
(errmsg("Unable to allocate oid for temp table. Drop some temporary tables or start a new session.")));
}
else if (OidIsValid((Oid) temp_oid_buffer_start) && retries >= (0.8 * temp_oid_buffer_size))
{
ereport(WARNING,
(errmsg("Temp object OID usage is over 80%%. Consider dropping some temp tables or starting a new session.")));
}

retries++;
} while (collides);

return newOid;
}

/*
* GetNewRelFileNode
* Generate a new relfilenode number that is unique within the
Expand Down Expand Up @@ -631,10 +565,10 @@ GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence)
/* Generate the OID */
if (pg_class)
{
if (relpersistence == RELPERSISTENCE_TEMP && sql_dialect == SQL_DIALECT_TSQL)
if (relpersistence == RELPERSISTENCE_TEMP && sql_dialect == SQL_DIALECT_TSQL && GetNewTempOidWithIndex_hook && temp_oid_buffer_size > 0)
{
/* Temp tables use temp OID logic */
rnode.node.relNode = GetNewTempOidWithIndex(pg_class, ClassOidIndexId,
rnode.node.relNode = GetNewTempOidWithIndex_hook(pg_class, ClassOidIndexId,
Anum_pg_class_oid);
}
else
Expand All @@ -645,10 +579,10 @@ GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence)
}
else
{
if (relpersistence == RELPERSISTENCE_TEMP && sql_dialect == SQL_DIALECT_TSQL)
if (relpersistence == RELPERSISTENCE_TEMP && sql_dialect == SQL_DIALECT_TSQL && GetNewTempObjectId_hook && temp_oid_buffer_size > 0)
{
/* Temp tables use temp OID logic */
rnode.node.relNode = GetNewTempObjectId();
rnode.node.relNode = GetNewTempObjectId_hook();
}
else
{
Expand Down Expand Up @@ -676,12 +610,12 @@ GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence)
collides = false;
}

if (OidIsValid((Oid) temp_oid_buffer_start) && tries > temp_oid_buffer_size)
if (relpersistence == RELPERSISTENCE_TEMP && sql_dialect == SQL_DIALECT_TSQL && tries > temp_oid_buffer_size)
{
ereport(ERROR,
(errmsg("Unable to allocate oid for temp table. Drop some temporary tables or start a new session.")));
}
else if (OidIsValid((Oid) temp_oid_buffer_start) && tries >= (0.8 * temp_oid_buffer_size))
else if (relpersistence == RELPERSISTENCE_TEMP && sql_dialect == SQL_DIALECT_TSQL && tries >= (0.8 * temp_oid_buffer_size))
{
ereport(WARNING,
(errmsg("Temp object OID usage is over 80%%. Consider dropping some temp tables or starting a new session.")));
Expand All @@ -694,90 +628,6 @@ GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence)
return rnode.node.relNode;
}

/*
* Until index_create properly uses the temp OID buffer, we need a workaround to provide
* the expected BackendId while not using the temp OID buffer. */
Oid
GetNewPermanentRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence)
{
RelFileNodeBackend rnode;
char *rpath;
bool collides;
BackendId backend;

/*
* If we ever get here during pg_upgrade, there's something wrong; all
* relfilenode assignments during a binary-upgrade run should be
* determined by commands in the dump script.
*/
Assert(!IsBinaryUpgrade);

switch (relpersistence)
{
case RELPERSISTENCE_TEMP:
backend = BackendIdForTempRelations();
break;
case RELPERSISTENCE_UNLOGGED:
case RELPERSISTENCE_PERMANENT:
backend = InvalidBackendId;
break;
default:
elog(ERROR, "invalid relpersistence: %c", relpersistence);
return InvalidOid; /* placate compiler */
}

/* This logic should match RelationInitPhysicalAddr */
rnode.node.spcNode = reltablespace ? reltablespace : MyDatabaseTableSpace;
rnode.node.dbNode = (rnode.node.spcNode == GLOBALTABLESPACE_OID) ? InvalidOid : MyDatabaseId;

/*
* The relpath will vary based on the backend ID, so we must initialize
* that properly here to make sure that any collisions based on filename
* are properly detected.
*/
rnode.backend = backend;

do
{
CHECK_FOR_INTERRUPTS();

/* Generate the OID */
if (pg_class)
{
rnode.node.relNode = GetNewOidWithIndex(pg_class, ClassOidIndexId,
Anum_pg_class_oid);
}
else
{
rnode.node.relNode = GetNewObjectId();
}

/* Check for existing file of same name */
rpath = relpath(rnode, MAIN_FORKNUM);

if (access(rpath, F_OK) == 0)
{
/* definite collision */
collides = true;
}
else
{
/*
* Here we have a little bit of a dilemma: if errno is something
* other than ENOENT, should we declare a collision and loop? In
* practice it seems best to go ahead regardless of the errno. If
* there is a colliding file we will get an smgr failure when we
* attempt to create the new relation file.
*/
collides = false;
}

pfree(rpath);
} while (collides);

return rnode.node.relNode;
}

/*
* SQL callable interface for GetNewOidWithIndex(). Outside of initdb's
* direct insertions into catalog tables, and recovering from corruption, this
Expand Down
4 changes: 2 additions & 2 deletions src/backend/catalog/index.c
Original file line number Diff line number Diff line change
Expand Up @@ -950,10 +950,10 @@ index_create(Relation heapRelation,
}
else
{
if (is_enr)
if (is_enr && GetNewPermanentRelFileNode_hook)
{
/* Index OIDs must be kept in normal OID range. */
indexRelationId = GetNewPermanentRelFileNode(tableSpaceId, pg_class, relpersistence);
indexRelationId = GetNewPermanentRelFileNode_hook(tableSpaceId, pg_class, relpersistence);
}
else
{
Expand Down
2 changes: 1 addition & 1 deletion src/backend/catalog/toasting.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
{
pg_toast_prefix = "@pg_toast";
}
else if (sql_dialect == SQL_DIALECT_TSQL && RelationIsBBFTempTable(rel) && get_ENR_withoid(currentQueryEnv, rel->rd_id, ENR_TSQL_TEMP))
else if (sql_dialect == SQL_DIALECT_TSQL && rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP && get_ENR_withoid(currentQueryEnv, rel->rd_id, ENR_TSQL_TEMP))
{
pg_toast_prefix = "#pg_toast";
}
Expand Down
2 changes: 1 addition & 1 deletion src/backend/commands/cluster.c
Original file line number Diff line number Diff line change
Expand Up @@ -1613,7 +1613,7 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
/* rename the toast table ... */
if (sql_dialect == SQL_DIALECT_TSQL && RelationIsBBFTableVariable(newrel))
pg_toast_prefix = "@pg_toast";
else if (sql_dialect == SQL_DIALECT_TSQL && RelationIsBBFTempTable(newrel) && get_ENR_withoid(currentQueryEnv, newrel->rd_id, ENR_TSQL_TEMP))
else if (sql_dialect == SQL_DIALECT_TSQL && newrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP && get_ENR_withoid(currentQueryEnv, newrel->rd_id, ENR_TSQL_TEMP))
pg_toast_prefix = "#pg_toast";

snprintf(NewToastName, NAMEDATALEN, "%s_%u",
Expand Down
2 changes: 1 addition & 1 deletion src/include/access/transam.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ typedef struct VariableCacheData
/*
* These fields are also protected by OidGenLock. For tempOidStart, Shmem will
* be the source of truth, as another process may have gotten there first and
* updated the start. For tempOidBufferSize, the GUC will be the source of truth.
* updated the start.
*/
Oid tempOidStart;
uint32 tempOidBufferSize;
Expand Down
9 changes: 9 additions & 0 deletions src/include/catalog/catalog.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ extern Oid GetNewRelFileNode(Oid reltablespace, Relation pg_class,
extern Oid GetNewPermanentRelFileNode(Oid reltablespace, Relation pg_class,
char relpersistence);

typedef Oid (*GetNewTempObjectId_hook_type) (void);
extern GetNewTempObjectId_hook_type GetNewTempObjectId_hook;

typedef Oid (*GetNewTempOidWithIndex_hook_type) (Relation relation, Oid indexId, AttrNumber oidcolumn);
extern GetNewTempOidWithIndex_hook_type GetNewTempOidWithIndex_hook;

typedef Oid (*GetNewPermanentRelFileNode_hook_type) (Oid reltablespace, Relation pg_class, char relpersistence);
extern GetNewPermanentRelFileNode_hook_type GetNewPermanentRelFileNode_hook;

typedef bool (*IsExtendedCatalogHookType) (Oid relationId);
extern IsExtendedCatalogHookType IsExtendedCatalogHook;

Expand Down
7 changes: 0 additions & 7 deletions src/include/utils/rel.h
Original file line number Diff line number Diff line change
Expand Up @@ -700,12 +700,5 @@ extern void RelationDecrementReferenceCount(Relation rel);
strlen((relation)->rd_rel->relname.data) >= 1 && \
(relation)->rd_rel->relname.data[0] == '@')

/* PG Tables can begin with '#' as well, so check sql_dialect additionally */
#define RelationIsBBFTempTable(relation) \
((relation)->rd_rel->relpersistence == RELPERSISTENCE_TEMP && \
(relation)->rd_rel->relname.data && \
strlen((relation)->rd_rel->relname.data) >= 1 && \
(relation)->rd_rel->relname.data[0] == '#')

#endif /* REL_H */

0 comments on commit 7bc64f9

Please sign in to comment.