From 006cf4fee64f9292bdeb9cf1f002850c8398dfcf Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Thu, 14 Aug 2025 12:15:15 +0900 Subject: [PATCH v10 10/14] 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 6fa91bfcdc03..3e9fd29f0425 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 */ /* @@ -355,6 +355,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 0591a885dd1b..443d7c99fb62 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -255,7 +255,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 7503db1af51c..ca0ca206b554 100644 --- a/src/include/catalog/pg_control.h +++ b/src/include/catalog/pg_control.h @@ -43,7 +43,7 @@ typedef struct CheckPoint int wal_level; /* current wal_level */ bool logicalDecodingEnabled; /* current logical decoding status */ 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 ff078f22264d..77a51ae24f35 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; logical decoding %s; xid %u:%u; oid %u; multi %u; offset %" PRIu64 "; " + "tli %u; prev tli %u; fpw %s; wal_level %s; logical decoding %s; xid %u:%u; oid " OID8_FORMAT "; multi %u; offset %" PRIu64 "; " "oldest xid %u in DB %u; oldest multi %u in DB %u; " "oldest/newest commit timestamp xid: %u/%u; " "oldest running xid %u; %s", @@ -92,10 +92,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 3e95d4cfd164..0dab8f3369e7 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 81dc86847c01..a104024f7984 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -8153,10 +8153,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); /* @@ -8379,7 +8379,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 @@ -8388,7 +8388,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 0b5f871abe74..edbee448db04 100644 --- a/src/backend/access/transam/xlogrecovery.c +++ b/src/backend/access/transam/xlogrecovery.c @@ -892,7 +892,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 a4060309ae0e..bfb89536280f 100644 --- a/src/bin/pg_controldata/pg_controldata.c +++ b/src/bin/pg_controldata/pg_controldata.c @@ -267,7 +267,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 b2c4b9db395a..1959bf419419 100644 --- a/src/bin/pg_resetwal/pg_resetwal.c +++ b/src/bin/pg_resetwal/pg_resetwal.c @@ -82,7 +82,7 @@ static TransactionId oldest_commit_ts_xid_val; static TransactionId newest_commit_ts_xid_val; static bool next_oid_given = false; -static Oid next_oid_val; +static Oid8 next_oid_val; static bool mxids_given = false; static MultiXactId next_mxid_val; @@ -253,7 +253,7 @@ main(int argc, char *argv[]) case 'o': errno = 0; - next_oid_val = strtouint32_strict(optarg, &endptr, 0); + next_oid_val = strtou64(optarg, &endptr, 0); if (endptr == optarg || *endptr != '\0' || errno != 0) { pg_log_error("invalid argument for option %s", "-o"); @@ -771,7 +771,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); @@ -857,7 +857,7 @@ PrintNewControlValues(void) if (next_oid_given) { - printf(_("NextOID: %u\n"), + printf(_("NextOID: " OID8_FORMAT "\n"), ControlFile.checkPointCopy.nextOid); } @@ -1227,7 +1227,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 41f2b1d480c5..83483d883bd1 100644 --- a/doc/src/sgml/ref/pg_resetwal.sgml +++ b/doc/src/sgml/ref/pg_resetwal.sgml @@ -282,11 +282,11 @@ PostgreSQL documentation - - + + - Manually set the next OID. + Manually set the next OID (8 bytes). -- 2.51.0