v2-0007-Introduce-global-64-bit-TOAST-ID-counter-in-contr.patch
text/x-diff
Filename: v2-0007-Introduce-global-64-bit-TOAST-ID-counter-in-contr.patch
Type: text/x-diff
Part: 6
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v2-0007
Subject: Introduce global 64-bit TOAST ID counter in control file
| File | + | − |
|---|---|---|
| doc/src/sgml/func.sgml | 5 | 0 |
| src/backend/access/common/Makefile | 1 | 0 |
| src/backend/access/common/meson.build | 1 | 0 |
| src/backend/access/common/toast_counter.c | 98 | 0 |
| src/backend/access/rmgrdesc/xlogdesc.c | 10 | 0 |
| src/backend/access/transam/xlog.c | 44 | 0 |
| src/backend/replication/logical/decode.c | 1 | 0 |
| src/backend/storage/ipc/ipci.c | 4 | 1 |
| src/backend/utils/activity/wait_event_names.txt | 1 | 0 |
| src/backend/utils/misc/pg_controldata.c | 13 | 10 |
| src/bin/pg_controldata/pg_controldata.c | 2 | 0 |
| src/bin/pg_resetwal/pg_resetwal.c | 2 | 0 |
| src/include/access/toast_counter.h | 35 | 0 |
| src/include/access/xlog.h | 1 | 0 |
| src/include/catalog/pg_control.h | 3 | 1 |
| src/include/catalog/pg_proc.dat | 3 | 3 |
| src/include/storage/lwlocklist.h | 1 | 0 |
| src/tools/pgindent/typedefs.list | 1 | 0 |
From ca099d7bc6b4598592048c3370b82b09d317d98b Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Wed, 18 Jun 2025 16:23:16 +0900
Subject: [PATCH v2 07/13] Introduce global 64-bit TOAST ID counter in control
file
An 8 byte counter is added to the control file, providing a unique
64-bit-wide source for toast value IDs, with the same guarantees as OIDs
in terms of durability. SQL functions and tools looking at the control
file are updated. A WAL record is generated every 8k values generated,
that can be adjusted if required.
Requires a bump of WAL format.
Requires a bump of control file version.
Requires a catalog version bump.
---
src/include/access/toast_counter.h | 35 +++++++
src/include/access/xlog.h | 1 +
src/include/catalog/pg_control.h | 4 +-
src/include/catalog/pg_proc.dat | 6 +-
src/include/storage/lwlocklist.h | 1 +
src/backend/access/common/Makefile | 1 +
src/backend/access/common/meson.build | 1 +
src/backend/access/common/toast_counter.c | 98 +++++++++++++++++++
src/backend/access/rmgrdesc/xlogdesc.c | 10 ++
src/backend/access/transam/xlog.c | 44 +++++++++
src/backend/replication/logical/decode.c | 1 +
src/backend/storage/ipc/ipci.c | 5 +-
.../utils/activity/wait_event_names.txt | 1 +
src/backend/utils/misc/pg_controldata.c | 23 +++--
src/bin/pg_controldata/pg_controldata.c | 2 +
src/bin/pg_resetwal/pg_resetwal.c | 2 +
doc/src/sgml/func.sgml | 5 +
src/tools/pgindent/typedefs.list | 1 +
18 files changed, 226 insertions(+), 15 deletions(-)
create mode 100644 src/include/access/toast_counter.h
create mode 100644 src/backend/access/common/toast_counter.c
diff --git a/src/include/access/toast_counter.h b/src/include/access/toast_counter.h
new file mode 100644
index 000000000000..80749cba0f87
--- /dev/null
+++ b/src/include/access/toast_counter.h
@@ -0,0 +1,35 @@
+/*-------------------------------------------------------------------------
+ *
+ * toast_counter.h
+ * Machinery for TOAST value counter.
+ *
+ * Copyright (c) 2000-2025, PostgreSQL Global Development Group
+ *
+ * src/include/access/toast_counter.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef TOAST_COUNTER_H
+#define TOAST_COUNTER_H
+
+#define InvalidToastId 0 /* Invalid TOAST value ID */
+#define FirstToastId 1 /* First TOAST value ID assigned */
+
+/*
+ * Structure in shared memory to track TOAST value counter activity.
+ * These are protected by ToastIdGenLock.
+ */
+typedef struct ToastCounterData
+{
+ uint64 nextId; /* next TOAST value ID to assign */
+ uint32 idCount; /* IDs available before WAL work */
+} ToastCounterData;
+
+extern PGDLLIMPORT ToastCounterData *ToastCounter;
+
+/* external declarations */
+extern Size ToastCounterShmemSize(void);
+extern void ToastCounterShmemInit(void);
+extern uint64 GetNewToastId(void);
+
+#endif /* TOAST_TYPE_H */
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index d313099c027f..a50296736242 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -245,6 +245,7 @@ extern bool CreateCheckPoint(int flags);
extern bool CreateRestartPoint(int flags);
extern WALAvailability GetWALAvailability(XLogRecPtr targetLSN);
extern void XLogPutNextOid(Oid nextOid);
+extern void XLogPutNextToastId(uint64 nextId);
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..1194b4928155 100644
--- a/src/include/catalog/pg_control.h
+++ b/src/include/catalog/pg_control.h
@@ -22,7 +22,7 @@
/* Version identifier for this pg_control format */
-#define PG_CONTROL_VERSION 1800
+#define PG_CONTROL_VERSION 1900
/* Nonce key length, see below */
#define MOCK_AUTH_NONCE_LEN 32
@@ -45,6 +45,7 @@ typedef struct CheckPoint
Oid nextOid; /* next free OID */
MultiXactId nextMulti; /* next free MultiXactId */
MultiXactOffset nextMultiOffset; /* next free MultiXact offset */
+ uint64 nextToastId; /* next free TOAST ID */
TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */
Oid oldestXidDB; /* database with minimum datfrozenxid */
MultiXactId oldestMulti; /* cluster-wide minimum datminmxid */
@@ -80,6 +81,7 @@ typedef struct CheckPoint
/* 0xC0 is used in Postgres 9.5-11 */
#define XLOG_OVERWRITE_CONTRECORD 0xD0
#define XLOG_CHECKPOINT_REDO 0xE0
+#define XLOG_NEXT_TOAST_ID 0xF0
/*
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index d4650947c63a..ff0871037c53 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -12306,9 +12306,9 @@
descr => 'pg_controldata checkpoint state information as a function',
proname => 'pg_control_checkpoint', provolatile => 'v',
prorettype => 'record', proargtypes => '',
- proallargtypes => '{pg_lsn,pg_lsn,text,int4,int4,bool,text,oid,xid,xid,xid,oid,xid,xid,oid,xid,xid,timestamptz}',
- proargmodes => '{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}',
- proargnames => '{checkpoint_lsn,redo_lsn,redo_wal_file,timeline_id,prev_timeline_id,full_page_writes,next_xid,next_oid,next_multixact_id,next_multi_offset,oldest_xid,oldest_xid_dbid,oldest_active_xid,oldest_multi_xid,oldest_multi_dbid,oldest_commit_ts_xid,newest_commit_ts_xid,checkpoint_time}',
+ proallargtypes => '{pg_lsn,pg_lsn,text,int4,int4,bool,text,oid,xid,xid,int8,xid,oid,xid,xid,oid,xid,xid,timestamptz}',
+ proargmodes => '{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}',
+ proargnames => '{checkpoint_lsn,redo_lsn,redo_wal_file,timeline_id,prev_timeline_id,full_page_writes,next_xid,next_oid,next_multixact_id,next_multi_offset,next_toast_id,oldest_xid,oldest_xid_dbid,oldest_active_xid,oldest_multi_xid,oldest_multi_dbid,oldest_commit_ts_xid,newest_commit_ts_xid,checkpoint_time}',
prosrc => 'pg_control_checkpoint' },
{ oid => '3443',
diff --git a/src/include/storage/lwlocklist.h b/src/include/storage/lwlocklist.h
index a9681738146e..7f7ca92382b5 100644
--- a/src/include/storage/lwlocklist.h
+++ b/src/include/storage/lwlocklist.h
@@ -84,3 +84,4 @@ PG_LWLOCK(50, DSMRegistry)
PG_LWLOCK(51, InjectionPoint)
PG_LWLOCK(52, SerialControl)
PG_LWLOCK(53, AioWorkerSubmissionQueue)
+PG_LWLOCK(54, ToastIdGen)
diff --git a/src/backend/access/common/Makefile b/src/backend/access/common/Makefile
index 1ef86a245886..6e9a3a430c19 100644
--- a/src/backend/access/common/Makefile
+++ b/src/backend/access/common/Makefile
@@ -27,6 +27,7 @@ OBJS = \
syncscan.o \
tidstore.o \
toast_compression.o \
+ toast_counter.o \
toast_external.o \
toast_internals.o \
tupconvert.o \
diff --git a/src/backend/access/common/meson.build b/src/backend/access/common/meson.build
index c20f2e88921e..4254132c8dfd 100644
--- a/src/backend/access/common/meson.build
+++ b/src/backend/access/common/meson.build
@@ -15,6 +15,7 @@ backend_sources += files(
'syncscan.c',
'tidstore.c',
'toast_compression.c',
+ 'toast_counter.c',
'toast_external.c',
'toast_internals.c',
'tupconvert.c',
diff --git a/src/backend/access/common/toast_counter.c b/src/backend/access/common/toast_counter.c
new file mode 100644
index 000000000000..94d361d0d5c4
--- /dev/null
+++ b/src/backend/access/common/toast_counter.c
@@ -0,0 +1,98 @@
+/*-------------------------------------------------------------------------
+ *
+ * toast_counter.c
+ * Functions for TOAST value counter.
+ *
+ * Copyright (c) 2025, PostgreSQL Global Development Group
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/access/common/toast_counter.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/toast_counter.h"
+#include "access/xlog.h"
+#include "miscadmin.h"
+#include "storage/lwlock.h"
+#include "storage/shmem.h"
+
+/* Number of TOAST values to preallocate before WAL work */
+#define TOAST_ID_PREFETCH 8192
+
+/* pointer to variables struct in shared memory */
+ToastCounterData *ToastCounter = NULL;
+
+/*
+ * Initialization of shared memory for ToastCounter.
+ */
+Size
+ToastCounterShmemSize(void)
+{
+ return sizeof(ToastCounterData);
+}
+
+void
+ToastCounterShmemInit(void)
+{
+ bool found;
+
+ /* Initialize shared state struct */
+ ToastCounter = ShmemInitStruct("ToastCounter",
+ sizeof(ToastCounterData),
+ &found);
+ if (!IsUnderPostmaster)
+ {
+ Assert(!found);
+ memset(ToastCounter, 0, sizeof(ToastCounterData));
+ }
+ else
+ Assert(found);
+}
+
+/*
+ * GetNewToastId
+ *
+ * Toast IDs are generated as a cluster-wide counter. They are 64 bits
+ * wide, hence wraparound will unlikely happen.
+ */
+uint64
+GetNewToastId(void)
+{
+ uint64 result;
+
+ if (RecoveryInProgress())
+ elog(ERROR, "cannot assign TOAST IDs during recovery");
+
+ LWLockAcquire(ToastIdGenLock, LW_EXCLUSIVE);
+
+ /*
+ * Check for initialization or wraparound of the toast counter ID.
+ * InvalidToastId (0) should never be returned. We are 64 bit-wide, hence
+ * wraparound is unlikely going to happen, but this check is cheap so
+ * let's play it safe.
+ */
+ if (ToastCounter->nextId < ((uint64) FirstToastId))
+ {
+ /* Most-likely first bootstrap or initdb assignment */
+ ToastCounter->nextId = FirstToastId;
+ ToastCounter->idCount = 0;
+ }
+
+ /* If running out of logged for TOAST IDs, log more */
+ if (ToastCounter->idCount == 0)
+ {
+ XLogPutNextToastId(ToastCounter->nextId + TOAST_ID_PREFETCH);
+ ToastCounter->idCount = TOAST_ID_PREFETCH;
+ }
+
+ result = ToastCounter->nextId;
+ (ToastCounter->nextId)++;
+ (ToastCounter->idCount)--;
+
+ LWLockRelease(ToastIdGenLock);
+
+ return result;
+}
diff --git a/src/backend/access/rmgrdesc/xlogdesc.c b/src/backend/access/rmgrdesc/xlogdesc.c
index 58040f28656f..0940040b33ab 100644
--- a/src/backend/access/rmgrdesc/xlogdesc.c
+++ b/src/backend/access/rmgrdesc/xlogdesc.c
@@ -96,6 +96,13 @@ xlog_desc(StringInfo buf, XLogReaderState *record)
memcpy(&nextOid, rec, sizeof(Oid));
appendStringInfo(buf, "%u", nextOid);
}
+ else if (info == XLOG_NEXT_TOAST_ID)
+ {
+ uint64 nextId;
+
+ memcpy(&nextId, rec, sizeof(uint64));
+ appendStringInfo(buf, "%" PRIu64, nextId);
+ }
else if (info == XLOG_RESTORE_POINT)
{
xl_restore_point *xlrec = (xl_restore_point *) rec;
@@ -218,6 +225,9 @@ xlog_identify(uint8 info)
case XLOG_CHECKPOINT_REDO:
id = "CHECKPOINT_REDO";
break;
+ case XLOG_NEXT_TOAST_ID:
+ id = "NEXT_TOAST_ID";
+ break;
}
return id;
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 47ffc0a23077..4ae1ef8bb2c2 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -53,6 +53,7 @@
#include "access/rewriteheap.h"
#include "access/subtrans.h"
#include "access/timeline.h"
+#include "access/toast_counter.h"
#include "access/transam.h"
#include "access/twophase.h"
#include "access/xact.h"
@@ -5269,6 +5270,7 @@ BootStrapXLOG(uint32 data_checksum_version)
checkPoint.nextOid = FirstGenbkiObjectId;
checkPoint.nextMulti = FirstMultiXactId;
checkPoint.nextMultiOffset = 0;
+ checkPoint.nextToastId = FirstToastId;
checkPoint.oldestXid = FirstNormalTransactionId;
checkPoint.oldestXidDB = Template1DbOid;
checkPoint.oldestMulti = FirstMultiXactId;
@@ -5281,6 +5283,10 @@ BootStrapXLOG(uint32 data_checksum_version)
TransamVariables->nextXid = checkPoint.nextXid;
TransamVariables->nextOid = checkPoint.nextOid;
TransamVariables->oidCount = 0;
+
+ ToastCounter->nextId = checkPoint.nextToastId;
+ ToastCounter->idCount = 0;
+
MultiXactSetNextMXact(checkPoint.nextMulti, checkPoint.nextMultiOffset);
AdvanceOldestClogXid(checkPoint.oldestXid);
SetTransactionIdLimit(checkPoint.oldestXid, checkPoint.oldestXidDB);
@@ -5757,6 +5763,8 @@ StartupXLOG(void)
TransamVariables->nextXid = checkPoint.nextXid;
TransamVariables->nextOid = checkPoint.nextOid;
TransamVariables->oidCount = 0;
+ ToastCounter->nextId = checkPoint.nextToastId;
+ ToastCounter->idCount = 0;
MultiXactSetNextMXact(checkPoint.nextMulti, checkPoint.nextMultiOffset);
AdvanceOldestClogXid(checkPoint.oldestXid);
SetTransactionIdLimit(checkPoint.oldestXid, checkPoint.oldestXidDB);
@@ -7299,6 +7307,12 @@ CreateCheckPoint(int flags)
checkPoint.nextOid += TransamVariables->oidCount;
LWLockRelease(OidGenLock);
+ LWLockAcquire(ToastIdGenLock, LW_SHARED);
+ checkPoint.nextToastId = ToastCounter->nextId;
+ if (!shutdown)
+ checkPoint.nextToastId += ToastCounter->idCount;
+ LWLockRelease(ToastIdGenLock);
+
MultiXactGetCheckptMulti(shutdown,
&checkPoint.nextMulti,
&checkPoint.nextMultiOffset,
@@ -8238,6 +8252,22 @@ XLogPutNextOid(Oid nextOid)
*/
}
+/*
+ * Write a NEXT_TOAST_ID log record.
+ */
+void
+XLogPutNextToastId(uint64 nextId)
+{
+ XLogBeginInsert();
+ XLogRegisterData(&nextId, sizeof(uint64));
+ (void) XLogInsert(RM_XLOG_ID, XLOG_NEXT_TOAST_ID);
+
+ /*
+ * The next TOAST value ID is not flushed immediately, for the same reason
+ * as above for the OIDs in XLogPutNextOid().
+ */
+}
+
/*
* Write an XLOG SWITCH record.
*
@@ -8453,6 +8483,16 @@ xlog_redo(XLogReaderState *record)
TransamVariables->oidCount = 0;
LWLockRelease(OidGenLock);
}
+ else if (info == XLOG_NEXT_TOAST_ID)
+ {
+ uint64 nextToastId;
+
+ memcpy(&nextToastId, XLogRecGetData(record), sizeof(uint64));
+ LWLockAcquire(ToastIdGenLock, LW_EXCLUSIVE);
+ ToastCounter->nextId = nextToastId;
+ ToastCounter->idCount = 0;
+ LWLockRelease(ToastIdGenLock);
+ }
else if (info == XLOG_CHECKPOINT_SHUTDOWN)
{
CheckPoint checkPoint;
@@ -8467,6 +8507,10 @@ xlog_redo(XLogReaderState *record)
TransamVariables->nextOid = checkPoint.nextOid;
TransamVariables->oidCount = 0;
LWLockRelease(OidGenLock);
+ LWLockAcquire(ToastIdGenLock, LW_EXCLUSIVE);
+ ToastCounter->nextId = checkPoint.nextToastId;
+ ToastCounter->idCount = 0;
+ LWLockRelease(ToastIdGenLock);
MultiXactSetNextMXact(checkPoint.nextMulti,
checkPoint.nextMultiOffset);
diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c
index cc03f0706e9c..bb0337d37201 100644
--- a/src/backend/replication/logical/decode.c
+++ b/src/backend/replication/logical/decode.c
@@ -188,6 +188,7 @@ xlog_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
case XLOG_FPI:
case XLOG_OVERWRITE_CONTRECORD:
case XLOG_CHECKPOINT_REDO:
+ case XLOG_NEXT_TOAST_ID:
break;
default:
elog(ERROR, "unexpected RM_XLOG_ID record type: %u", info);
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index 2fa045e6b0f6..9102c267d7b0 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -20,6 +20,7 @@
#include "access/nbtree.h"
#include "access/subtrans.h"
#include "access/syncscan.h"
+#include "access/toast_counter.h"
#include "access/transam.h"
#include "access/twophase.h"
#include "access/xlogprefetcher.h"
@@ -119,6 +120,7 @@ CalculateShmemSize(int *num_semaphores)
size = add_size(size, ProcGlobalShmemSize());
size = add_size(size, XLogPrefetchShmemSize());
size = add_size(size, VarsupShmemSize());
+ size = add_size(size, ToastCounterShmemSize());
size = add_size(size, XLOGShmemSize());
size = add_size(size, XLogRecoveryShmemSize());
size = add_size(size, CLOGShmemSize());
@@ -280,8 +282,9 @@ CreateOrAttachShmemStructs(void)
DSMRegistryShmemInit();
/*
- * Set up xlog, clog, and buffers
+ * Set up TOAST counter, xlog, clog, and buffers
*/
+ ToastCounterShmemInit();
VarsupShmemInit();
XLOGShmemInit();
XLogPrefetchShmemInit();
diff --git a/src/backend/utils/activity/wait_event_names.txt b/src/backend/utils/activity/wait_event_names.txt
index 4da68312b5f9..9aa44de58770 100644
--- a/src/backend/utils/activity/wait_event_names.txt
+++ b/src/backend/utils/activity/wait_event_names.txt
@@ -352,6 +352,7 @@ DSMRegistry "Waiting to read or update the dynamic shared memory registry."
InjectionPoint "Waiting to read or update information related to injection points."
SerialControl "Waiting to read or update shared <filename>pg_serial</filename> state."
AioWorkerSubmissionQueue "Waiting to access AIO worker submission queue."
+ToastIdGen "Waiting to allocate a new TOAST value ID."
#
# END OF PREDEFINED LWLOCKS (DO NOT CHANGE THIS LINE)
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 6d036e3bf328..e4abf8593b8d 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -69,8 +69,8 @@ pg_control_system(PG_FUNCTION_ARGS)
Datum
pg_control_checkpoint(PG_FUNCTION_ARGS)
{
- Datum values[18];
- bool nulls[18];
+ Datum values[19];
+ bool nulls[19];
TupleDesc tupdesc;
HeapTuple htup;
ControlFileData *ControlFile;
@@ -130,30 +130,33 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
values[9] = TransactionIdGetDatum(ControlFile->checkPointCopy.nextMultiOffset);
nulls[9] = false;
- values[10] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestXid);
+ values[10] = UInt64GetDatum(ControlFile->checkPointCopy.nextToastId);
nulls[10] = false;
- values[11] = ObjectIdGetDatum(ControlFile->checkPointCopy.oldestXidDB);
+ values[11] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestXid);
nulls[11] = false;
- values[12] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestActiveXid);
+ values[12] = ObjectIdGetDatum(ControlFile->checkPointCopy.oldestXidDB);
nulls[12] = false;
- values[13] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestMulti);
+ values[13] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestActiveXid);
nulls[13] = false;
- values[14] = ObjectIdGetDatum(ControlFile->checkPointCopy.oldestMultiDB);
+ values[14] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestMulti);
nulls[14] = false;
- values[15] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestCommitTsXid);
+ values[15] = ObjectIdGetDatum(ControlFile->checkPointCopy.oldestMultiDB);
nulls[15] = false;
- values[16] = TransactionIdGetDatum(ControlFile->checkPointCopy.newestCommitTsXid);
+ values[16] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestCommitTsXid);
nulls[16] = false;
- values[17] = TimestampTzGetDatum(time_t_to_timestamptz(ControlFile->checkPointCopy.time));
+ values[17] = TransactionIdGetDatum(ControlFile->checkPointCopy.newestCommitTsXid);
nulls[17] = false;
+ values[18] = TimestampTzGetDatum(time_t_to_timestamptz(ControlFile->checkPointCopy.time));
+ nulls[18] = false;
+
htup = heap_form_tuple(tupdesc, values, nulls);
PG_RETURN_DATUM(HeapTupleGetDatum(htup));
diff --git a/src/bin/pg_controldata/pg_controldata.c b/src/bin/pg_controldata/pg_controldata.c
index 7bb801bb8861..d83368ba4910 100644
--- a/src/bin/pg_controldata/pg_controldata.c
+++ b/src/bin/pg_controldata/pg_controldata.c
@@ -266,6 +266,8 @@ main(int argc, char *argv[])
ControlFile->checkPointCopy.nextMulti);
printf(_("Latest checkpoint's NextMultiOffset: %u\n"),
ControlFile->checkPointCopy.nextMultiOffset);
+ printf(_("Latest checkpoint's NextToastID: %" PRIu64 "\n"),
+ ControlFile->checkPointCopy.nextToastId);
printf(_("Latest checkpoint's oldestXID: %u\n"),
ControlFile->checkPointCopy.oldestXid);
printf(_("Latest checkpoint's oldestXID's DB: %u\n"),
diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c
index e876f35f38ed..bb324c710911 100644
--- a/src/bin/pg_resetwal/pg_resetwal.c
+++ b/src/bin/pg_resetwal/pg_resetwal.c
@@ -45,6 +45,7 @@
#include "access/heaptoast.h"
#include "access/multixact.h"
+#include "access/toast_counter.h"
#include "access/transam.h"
#include "access/xlog.h"
#include "access/xlog_internal.h"
@@ -686,6 +687,7 @@ GuessControlValues(void)
ControlFile.checkPointCopy.nextOid = FirstGenbkiObjectId;
ControlFile.checkPointCopy.nextMulti = FirstMultiXactId;
ControlFile.checkPointCopy.nextMultiOffset = 0;
+ ControlFile.checkPointCopy.nextToastId = FirstToastId;
ControlFile.checkPointCopy.oldestXid = FirstNormalTransactionId;
ControlFile.checkPointCopy.oldestXidDB = InvalidOid;
ControlFile.checkPointCopy.oldestMulti = FirstMultiXactId;
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 810b2b50f0da..74bd691b0a8f 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -28157,6 +28157,11 @@ acl | {postgres=arwdDxtm/postgres,foo=r/postgres}
<entry><type>xid</type></entry>
</row>
+ <row>
+ <entry><structfield>next_toast_id</structfield></entry>
+ <entry><type>bigint</type></entry>
+ </row>
+
<row>
<entry><structfield>oldest_xid</structfield></entry>
<entry><type>xid</type></entry>
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 3b98606a1701..25ab35ea350f 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -3050,6 +3050,7 @@ TmFromChar
TmToChar
ToastAttrInfo
ToastCompressionId
+ToastCounterData
ToastTupleContext
ToastedAttribute
TocEntry
--
2.50.0