From 1cbccca63cdb1dd7a9e31be70f570f71940e01e9 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Thu, 14 Aug 2025 12:15:15 +0900 Subject: [PATCH v5 11/15] Enlarge OID generation to 8 bytes This adds a new routine called GetNewObjectId8() in varsup.c, which is able to retrieve a 64b OID. GetNewObjectId() is kept compatible with its origin, where we still check that the lower 32 bits of the counter do not wraparound, handling the FirstNormalObjectId case. pg_resetwal -o/--next-oid is updated to be able to handle 8-byte OIDs. --- src/include/access/transam.h | 3 +- src/include/access/xlog.h | 2 +- src/include/catalog/pg_control.h | 2 +- src/backend/access/rmgrdesc/xlogdesc.c | 8 +-- src/backend/access/transam/varsup.c | 62 ++++++++++++++++------- src/backend/access/transam/xlog.c | 8 +-- src/backend/access/transam/xlogrecovery.c | 2 +- src/bin/pg_controldata/pg_controldata.c | 2 +- src/bin/pg_resetwal/pg_resetwal.c | 10 ++-- doc/src/sgml/ref/pg_resetwal.sgml | 6 +-- 10 files changed, 66 insertions(+), 39 deletions(-) diff --git a/src/include/access/transam.h b/src/include/access/transam.h index 7d82cd2eb562..2ef3000bdb1f 100644 --- a/src/include/access/transam.h +++ b/src/include/access/transam.h @@ -211,7 +211,7 @@ typedef struct TransamVariablesData /* * These fields are protected by OidGenLock. */ - Oid nextOid; /* next OID to assign */ + Oid8 nextOid; /* next OID (8 bytes) to assign */ uint32 oidCount; /* OIDs available before must do XLOG work */ /* @@ -293,6 +293,7 @@ extern void SetTransactionIdLimit(TransactionId oldest_datfrozenxid, extern void AdvanceOldestClogXid(TransactionId oldest_datfrozenxid); extern bool ForceTransactionIdLimitUpdate(void); extern Oid GetNewObjectId(void); +extern Oid8 GetNewObjectId8(void); extern void StopGeneratingPinnedObjectIds(void); #ifdef USE_ASSERT_CHECKING diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index d12798be3d80..21d915ae5802 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -243,7 +243,7 @@ extern void ShutdownXLOG(int code, Datum arg); extern bool CreateCheckPoint(int flags); extern bool CreateRestartPoint(int flags); extern WALAvailability GetWALAvailability(XLogRecPtr targetLSN); -extern void XLogPutNextOid(Oid nextOid); +extern void XLogPutNextOid(Oid8 nextOid); extern XLogRecPtr XLogRestorePoint(const char *rpName); extern void UpdateFullPageWrites(void); extern void GetFullPageWriteInfo(XLogRecPtr *RedoRecPtr_p, bool *doPageWrites_p); diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h index 63e834a6ce47..c85c84bbfdbb 100644 --- a/src/include/catalog/pg_control.h +++ b/src/include/catalog/pg_control.h @@ -42,7 +42,7 @@ typedef struct CheckPoint bool fullPageWrites; /* current full_page_writes */ int wal_level; /* current wal_level */ FullTransactionId nextXid; /* next free transaction ID */ - Oid nextOid; /* next free OID */ + Oid8 nextOid; /* next free OID */ MultiXactId nextMulti; /* next free MultiXactId */ MultiXactOffset nextMultiOffset; /* next free MultiXact offset */ TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */ diff --git a/src/backend/access/rmgrdesc/xlogdesc.c b/src/backend/access/rmgrdesc/xlogdesc.c index cd6c2a2f650a..23920d32092a 100644 --- a/src/backend/access/rmgrdesc/xlogdesc.c +++ b/src/backend/access/rmgrdesc/xlogdesc.c @@ -66,7 +66,7 @@ xlog_desc(StringInfo buf, XLogReaderState *record) CheckPoint *checkpoint = (CheckPoint *) rec; appendStringInfo(buf, "redo %X/%08X; " - "tli %u; prev tli %u; fpw %s; wal_level %s; xid %u:%u; oid %u; multi %u; offset %u; " + "tli %u; prev tli %u; fpw %s; wal_level %s; xid %u:%u; oid " OID8_FORMAT "; multi %u; offset %u; " "oldest xid %u in DB %u; oldest multi %u in DB %u; " "oldest/newest commit timestamp xid: %u/%u; " "oldest running xid %u; %s", @@ -91,10 +91,10 @@ xlog_desc(StringInfo buf, XLogReaderState *record) } else if (info == XLOG_NEXTOID) { - Oid nextOid; + Oid8 nextOid; - memcpy(&nextOid, rec, sizeof(Oid)); - appendStringInfo(buf, "%u", nextOid); + memcpy(&nextOid, rec, sizeof(Oid8)); + appendStringInfo(buf, OID8_FORMAT, nextOid); } else if (info == XLOG_RESTORE_POINT) { diff --git a/src/backend/access/transam/varsup.c b/src/backend/access/transam/varsup.c index fe895787cb72..7dcac9e210e4 100644 --- a/src/backend/access/transam/varsup.c +++ b/src/backend/access/transam/varsup.c @@ -542,31 +542,51 @@ ForceTransactionIdLimitUpdate(void) /* - * GetNewObjectId -- allocate a new OID + * GetNewObjectId -- allocate a new OID (4 bytes) * - * OIDs are generated by a cluster-wide counter. Since they are only 32 bits - * wide, counter wraparound will occur eventually, and therefore it is unwise - * to assume they are unique unless precautions are taken to make them so. - * Hence, this routine should generally not be used directly. The only direct - * callers should be GetNewOidWithIndex() and GetNewRelFileNumber() in - * catalog/catalog.c. + * OIDs are generated by a cluster-wide counter. The callers of this routine + * expect a 32 bit-wide counter, and counter wraparound will occur eventually, + * and therefore it is unwise to assume they are unique unless precautions are + * taken to make them so. This routine should generally not be used directly. + * The only direct callers should be GetNewOidWithIndex() and + * GetNewRelFileNumber() in catalog/catalog.c. */ Oid GetNewObjectId(void) { - Oid result; + return (Oid) GetNewObjectId8(); +} + +/* + * GetNewObjectId8 -- allocate a new OID (8 bytes) + * + * This routine can be called directly if the consumer of the OID allocated + * stores the counter in an 8-byte space, where wraparound does not matter. + * We still need to care about the wraparound case in the low 32 bits of the + * space allocated, GetNewObjectId() expecting OIDs to never be allocated + * up to FirstNormalObjectId. + */ +Oid8 +GetNewObjectId8(void) +{ + Oid8 result; + Oid nextoid_lo; + uint32 nextoid_hi; /* safety check, we should never get this far in a HS standby */ if (RecoveryInProgress()) elog(ERROR, "cannot assign OIDs during recovery"); LWLockAcquire(OidGenLock, LW_EXCLUSIVE); + nextoid_lo = (Oid) TransamVariables->nextOid; + nextoid_hi = (uint32) (TransamVariables->nextOid >> 32); /* - * Check for wraparound of the OID counter. We *must* not return 0 - * (InvalidOid), and in normal operation we mustn't return anything below - * FirstNormalObjectId since that range is reserved for initdb (see - * IsCatalogRelationOid()). Note we are relying on unsigned comparison. + * Check for wraparound of the OID counter in its lower 4 bytes. We + * *must* not return 0 (InvalidOid), and in normal operation we + * mustn't return anything below FirstNormalObjectId since that range + * is reserved for initdb (see IsCatalogRelationOid()). Note we are + * relying on unsigned comparison. * * During initdb, we start the OID generator at FirstGenbkiObjectId, so we * only wrap if before that point when in bootstrap or standalone mode. @@ -576,26 +596,32 @@ GetNewObjectId(void) * available for automatic assignment during initdb, while ensuring they * will never conflict with user-assigned OIDs. */ - if (TransamVariables->nextOid < ((Oid) FirstNormalObjectId)) + if (nextoid_lo < ((Oid) FirstNormalObjectId)) { if (IsPostmasterEnvironment) { /* wraparound, or first post-initdb assignment, in normal mode */ - TransamVariables->nextOid = FirstNormalObjectId; + nextoid_lo = FirstNormalObjectId; TransamVariables->oidCount = 0; } else { /* we may be bootstrapping, so don't enforce the full range */ - if (TransamVariables->nextOid < ((Oid) FirstGenbkiObjectId)) + if (nextoid_lo < ((Oid) FirstGenbkiObjectId)) { /* wraparound in standalone mode (unlikely but possible) */ - TransamVariables->nextOid = FirstNormalObjectId; + nextoid_lo = FirstNormalObjectId; TransamVariables->oidCount = 0; } } } + /* + * Set next OID in its 8-byte space, skipping the first post-init + * assignment. + */ + TransamVariables->nextOid = ((Oid8) nextoid_hi) << 32 | nextoid_lo; + /* If we run out of logged for use oids then we must log more */ if (TransamVariables->oidCount == 0) { @@ -620,7 +646,7 @@ GetNewObjectId(void) * to the specified value. */ static void -SetNextObjectId(Oid nextOid) +SetNextObjectId(Oid8 nextOid) { /* Safety check, this is only allowable during initdb */ if (IsPostmasterEnvironment) @@ -630,7 +656,7 @@ SetNextObjectId(Oid nextOid) LWLockAcquire(OidGenLock, LW_EXCLUSIVE); if (TransamVariables->nextOid > nextOid) - elog(ERROR, "too late to advance OID counter to %u, it is now %u", + elog(ERROR, "too late to advance OID counter to " OID8_FORMAT ", it is now " OID8_FORMAT, nextOid, TransamVariables->nextOid); TransamVariables->nextOid = nextOid; diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index e8909406686d..6194bf5ef5aa 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -8192,10 +8192,10 @@ KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo) * Write a NEXTOID log record */ void -XLogPutNextOid(Oid nextOid) +XLogPutNextOid(Oid8 nextOid) { XLogBeginInsert(); - XLogRegisterData(&nextOid, sizeof(Oid)); + XLogRegisterData(&nextOid, sizeof(Oid8)); (void) XLogInsert(RM_XLOG_ID, XLOG_NEXTOID); /* @@ -8418,7 +8418,7 @@ xlog_redo(XLogReaderState *record) if (info == XLOG_NEXTOID) { - Oid nextOid; + Oid8 nextOid; /* * We used to try to take the maximum of TransamVariables->nextOid and @@ -8427,7 +8427,7 @@ xlog_redo(XLogReaderState *record) * anyway, better to just believe the record exactly. We still take * OidGenLock while setting the variable, just in case. */ - memcpy(&nextOid, XLogRecGetData(record), sizeof(Oid)); + memcpy(&nextOid, XLogRecGetData(record), sizeof(Oid8)); LWLockAcquire(OidGenLock, LW_EXCLUSIVE); TransamVariables->nextOid = nextOid; TransamVariables->oidCount = 0; diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c index f23ec8969c27..00807eb66874 100644 --- a/src/backend/access/transam/xlogrecovery.c +++ b/src/backend/access/transam/xlogrecovery.c @@ -880,7 +880,7 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr, LSN_FORMAT_ARGS(checkPoint.redo), wasShutdown ? "true" : "false")); ereport(DEBUG1, - (errmsg_internal("next transaction ID: " UINT64_FORMAT "; next OID: %u", + (errmsg_internal("next transaction ID: " UINT64_FORMAT "; next OID: " OID8_FORMAT, U64FromFullTransactionId(checkPoint.nextXid), checkPoint.nextOid))); ereport(DEBUG1, diff --git a/src/bin/pg_controldata/pg_controldata.c b/src/bin/pg_controldata/pg_controldata.c index 10de058ce91f..992111d3a1d2 100644 --- a/src/bin/pg_controldata/pg_controldata.c +++ b/src/bin/pg_controldata/pg_controldata.c @@ -260,7 +260,7 @@ main(int argc, char *argv[]) printf(_("Latest checkpoint's NextXID: %u:%u\n"), EpochFromFullTransactionId(ControlFile->checkPointCopy.nextXid), XidFromFullTransactionId(ControlFile->checkPointCopy.nextXid)); - printf(_("Latest checkpoint's NextOID: %u\n"), + printf(_("Latest checkpoint's NextOID: " OID8_FORMAT "\n"), ControlFile->checkPointCopy.nextOid); printf(_("Latest checkpoint's NextMultiXactId: %u\n"), ControlFile->checkPointCopy.nextMulti); diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c index 7a4e4eb95706..c1039a8a4d16 100644 --- a/src/bin/pg_resetwal/pg_resetwal.c +++ b/src/bin/pg_resetwal/pg_resetwal.c @@ -68,7 +68,7 @@ static TransactionId set_oldest_xid = 0; static TransactionId set_xid = 0; static TransactionId set_oldest_commit_ts_xid = 0; static TransactionId set_newest_commit_ts_xid = 0; -static Oid set_oid = 0; +static Oid8 set_oid = 0; static MultiXactId set_mxid = 0; static MultiXactOffset set_mxoff = (MultiXactOffset) -1; static TimeLineID minXlogTli = 0; @@ -225,7 +225,7 @@ main(int argc, char *argv[]) case 'o': errno = 0; - set_oid = strtoul(optarg, &endptr, 0); + set_oid = strtou64(optarg, &endptr, 0); if (endptr == optarg || *endptr != '\0' || errno != 0) { pg_log_error("invalid argument for option %s", "-o"); @@ -755,7 +755,7 @@ PrintControlValues(bool guessed) printf(_("Latest checkpoint's NextXID: %u:%u\n"), EpochFromFullTransactionId(ControlFile.checkPointCopy.nextXid), XidFromFullTransactionId(ControlFile.checkPointCopy.nextXid)); - printf(_("Latest checkpoint's NextOID: %u\n"), + printf(_("Latest checkpoint's NextOID: " OID8_FORMAT "\n"), ControlFile.checkPointCopy.nextOid); printf(_("Latest checkpoint's NextMultiXactId: %u\n"), ControlFile.checkPointCopy.nextMulti); @@ -839,7 +839,7 @@ PrintNewControlValues(void) if (set_oid != 0) { - printf(_("NextOID: %u\n"), + printf(_("NextOID: " OID8_FORMAT "\n"), ControlFile.checkPointCopy.nextOid); } @@ -1208,7 +1208,7 @@ usage(void) printf(_(" -e, --epoch=XIDEPOCH set next transaction ID epoch\n")); printf(_(" -l, --next-wal-file=WALFILE set minimum starting location for new WAL\n")); printf(_(" -m, --multixact-ids=MXID,MXID set next and oldest multitransaction ID\n")); - printf(_(" -o, --next-oid=OID set next OID\n")); + printf(_(" -o, --next-oid=OID8 set next OID (8 bytes)\n")); printf(_(" -O, --multixact-offset=OFFSET set next multitransaction offset\n")); printf(_(" -u, --oldest-transaction-id=XID set oldest transaction ID\n")); printf(_(" -x, --next-transaction-id=XID set next transaction ID\n")); diff --git a/doc/src/sgml/ref/pg_resetwal.sgml b/doc/src/sgml/ref/pg_resetwal.sgml index 2c019c2aac6e..b03251cedbbe 100644 --- a/doc/src/sgml/ref/pg_resetwal.sgml +++ b/doc/src/sgml/ref/pg_resetwal.sgml @@ -279,11 +279,11 @@ PostgreSQL documentation - - + + - Manually set the next OID. + Manually set the next OID (8 bytes). -- 2.50.0