1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-22 12:22:45 +03:00

Redefine backend ID to be an index into the proc array

Previously, backend ID was an index into the ProcState array, in the
shared cache invalidation manager (sinvaladt.c). The entry in the
ProcState array was reserved at backend startup by scanning the array
for a free entry, and that was also when the backend got its backend
ID. Things become slightly simpler if we redefine backend ID to be the
index into the PGPROC array, and directly use it also as an index to
the ProcState array. This uses a little more memory, as we reserve a
few extra slots in the ProcState array for aux processes that don't
need them, but the simplicity is worth it.

Aux processes now also have a backend ID. This simplifies the
reservation of BackendStatusArray and ProcSignal slots.

You can now convert a backend ID into an index into the PGPROC array
simply by subtracting 1. We still use 0-based "pgprocnos" in various
places, for indexes into the PGPROC array, but the only difference now
is that backend IDs start at 1 while pgprocnos start at 0. (The next
commmit will get rid of the term "backend ID" altogether and make
everything 0-based.)

There is still a 'backendId' field in PGPROC, now part of 'vxid' which
encapsulates the backend ID and local transaction ID together. It's
needed for prepared xacts. For regular backends, the backendId is
always equal to pgprocno + 1, but for prepared xact PGPROC entries,
it's the ID of the original backend that processed the transaction.

Reviewed-by: Andres Freund, Reid Thompson
Discussion: https://www.postgresql.org/message-id/8171f1aa-496f-46a6-afc3-c46fe7a9b407@iki.fi
This commit is contained in:
Heikki Linnakangas
2024-03-03 19:37:28 +02:00
parent 30b8d6e4ce
commit ab355e3a88
28 changed files with 282 additions and 322 deletions

View File

@@ -19,6 +19,7 @@
#include "port/atomics.h" /* for memory barriers */
#include "storage/ipc.h"
#include "storage/proc.h" /* for MyProc */
#include "storage/procarray.h"
#include "storage/sinvaladt.h"
#include "utils/ascii.h"
#include "utils/backend_status.h"
@@ -29,13 +30,12 @@
/* ----------
* Total number of backends including auxiliary
*
* We reserve a slot for each possible BackendId, plus one for each
* possible auxiliary process type. (This scheme assumes there is not
* more than one of any auxiliary process type at a time.) MaxBackends
* includes autovacuum workers and background workers as well.
* We reserve a slot for each possible PGPROC entry, including aux processes.
* (But not including PGPROC entries reserved for prepared xacts; they are not
* real processes.)
* ----------
*/
#define NumBackendStatSlots (MaxBackends + NUM_AUXPROCTYPES)
#define NumBackendStatSlots (MaxBackends + NUM_AUXILIARY_PROCS)
/* ----------
@@ -238,10 +238,9 @@ CreateSharedBackendStatus(void)
/*
* Initialize pgstats backend activity state, and set up our on-proc-exit
* hook. Called from InitPostgres and AuxiliaryProcessMain. For auxiliary
* process, MyBackendId is invalid. Otherwise, MyBackendId must be set, but we
* must not have started any transaction yet (since the exit hook must run
* after the last transaction exit).
* hook. Called from InitPostgres and AuxiliaryProcessMain. MyBackendId must
* be set, but we must not have started any transaction yet (since the exit
* hook must run after the last transaction exit).
*
* NOTE: MyDatabaseId isn't set yet; so the shutdown hook has to be careful.
*/
@@ -249,26 +248,9 @@ void
pgstat_beinit(void)
{
/* Initialize MyBEEntry */
if (MyBackendId != InvalidBackendId)
{
Assert(MyBackendId >= 1 && MyBackendId <= MaxBackends);
MyBEEntry = &BackendStatusArray[MyBackendId - 1];
}
else
{
/* Must be an auxiliary process */
Assert(MyAuxProcType != NotAnAuxProcess);
/*
* Assign the MyBEEntry for an auxiliary process. Since it doesn't
* have a BackendId, the slot is statically allocated based on the
* auxiliary process type (MyAuxProcType). Backends use slots indexed
* in the range from 0 to MaxBackends (exclusive), so we use
* MaxBackends + AuxProcType as the index of the slot for an auxiliary
* process.
*/
MyBEEntry = &BackendStatusArray[MaxBackends + MyAuxProcType];
}
Assert(MyBackendId != InvalidBackendId);
Assert(MyBackendId >= 1 && MyBackendId <= NumBackendStatSlots);
MyBEEntry = &BackendStatusArray[MyBackendId - 1];
/* Set up a process-exit hook to clean up */
on_shmem_exit(pgstat_beshutdown_hook, 0);
@@ -281,12 +263,12 @@ pgstat_beinit(void)
* Initialize this backend's entry in the PgBackendStatus array.
* Called from InitPostgres.
*
* Apart from auxiliary processes, MyBackendId, MyDatabaseId,
* session userid, and application_name must be set for a
* backend (hence, this cannot be combined with pgstat_beinit).
* Note also that we must be inside a transaction if this isn't an aux
* process, as we may need to do encoding conversion on some strings.
* ----------
* Apart from auxiliary processes, MyDatabaseId, session userid, and
* application_name must already be set (hence, this cannot be combined
* with pgstat_beinit). Note also that we must be inside a transaction
* if this isn't an aux process, as we may need to do encoding conversion
* on some strings.
*----------
*/
void
pgstat_bestart(void)

View File

@@ -353,7 +353,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
break;
}
values[10] = VXIDGetDatum(instance->backend, instance->lxid);
values[10] = VXIDGetDatum(instance->vxid.backendId, instance->vxid.localTransactionId);
if (instance->pid != 0)
values[11] = Int32GetDatum(instance->pid);
else

View File

@@ -148,19 +148,11 @@ pg_log_backend_memory_contexts(PG_FUNCTION_ARGS)
PGPROC *proc;
BackendId backendId = InvalidBackendId;
proc = BackendPidGetProc(pid);
/*
* See if the process with given pid is a backend or an auxiliary process.
*
* If the given process is a backend, use its backend id in
* SendProcSignal() later to speed up the operation. Otherwise, don't do
* that because auxiliary processes (except the startup process) don't
* have a valid backend id.
*/
if (proc != NULL)
backendId = proc->backendId;
else
proc = BackendPidGetProc(pid);
if (proc == NULL)
proc = AuxiliaryPidGetProc(pid);
/*
@@ -183,6 +175,8 @@ pg_log_backend_memory_contexts(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(false);
}
if (proc != NULL)
backendId = GetBackendIdFromPGProc(proc);
if (SendProcSignal(pid, PROCSIG_LOG_MEMORY_CONTEXT, backendId) < 0)
{
/* Again, just a warning to allow loops */

View File

@@ -152,8 +152,8 @@ write_csvlog(ErrorData *edata)
/* Virtual transaction id */
/* keep VXID format in sync with lockfuncs.c */
if (MyProc != NULL && MyProc->backendId != InvalidBackendId)
appendStringInfo(&buf, "%d/%u", MyProc->backendId, MyProc->lxid);
if (MyProc != NULL && MyProc->vxid.backendId != InvalidBackendId)
appendStringInfo(&buf, "%d/%u", MyProc->vxid.backendId, MyProc->vxid.lxid);
appendStringInfoChar(&buf, ',');
/* Transaction id */

View File

@@ -3076,18 +3076,18 @@ log_status_format(StringInfo buf, const char *format, ErrorData *edata)
break;
case 'v':
/* keep VXID format in sync with lockfuncs.c */
if (MyProc != NULL && MyProc->backendId != InvalidBackendId)
if (MyProc != NULL && MyProc->vxid.backendId != InvalidBackendId)
{
if (padding != 0)
{
char strfbuf[128];
snprintf(strfbuf, sizeof(strfbuf) - 1, "%d/%u",
MyProc->backendId, MyProc->lxid);
MyProc->vxid.backendId, MyProc->vxid.lxid);
appendStringInfo(buf, "%*s", padding, strfbuf);
}
else
appendStringInfo(buf, "%d/%u", MyProc->backendId, MyProc->lxid);
appendStringInfo(buf, "%d/%u", MyProc->vxid.backendId, MyProc->vxid.lxid);
}
else if (padding != 0)
appendStringInfoSpaces(buf,

View File

@@ -197,9 +197,9 @@ write_jsonlog(ErrorData *edata)
/* Virtual transaction id */
/* keep VXID format in sync with lockfuncs.c */
if (MyProc != NULL && MyProc->backendId != InvalidBackendId)
appendJSONKeyValueFmt(&buf, "vxid", true, "%d/%u", MyProc->backendId,
MyProc->lxid);
if (MyProc != NULL && MyProc->vxid.backendId != InvalidBackendId)
appendJSONKeyValueFmt(&buf, "vxid", true, "%d/%u",
MyProc->vxid.backendId, MyProc->vxid.lxid);
/* Transaction id */
appendJSONKeyValueFmt(&buf, "txid", false, "%u",

View File

@@ -742,18 +742,10 @@ InitPostgres(const char *in_dbname, Oid dboid,
/*
* Initialize my entry in the shared-invalidation manager's array of
* per-backend data.
*
* Sets up MyBackendId, a unique backend identifier.
*/
MyBackendId = InvalidBackendId;
SharedInvalBackendInit(false);
if (MyBackendId > MaxBackends || MyBackendId <= 0)
elog(FATAL, "bad backend ID: %d", MyBackendId);
/* Now that we have a BackendId, we can participate in ProcSignal */
ProcSignalInit(MyBackendId);
ProcSignalInit();
/*
* Also set up timeout handlers needed for backend operation. We need

View File

@@ -1154,7 +1154,8 @@ ExportSnapshot(Snapshot snapshot)
* inside the transaction from 1.
*/
snprintf(path, sizeof(path), SNAPSHOT_EXPORT_DIR "/%08X-%08X-%d",
MyProc->backendId, MyProc->lxid, list_length(exportedSnapshots) + 1);
MyProc->vxid.backendId, MyProc->vxid.lxid,
list_length(exportedSnapshots) + 1);
/*
* Copy the snapshot into TopTransactionContext, add it to the
@@ -1181,7 +1182,7 @@ ExportSnapshot(Snapshot snapshot)
*/
initStringInfo(&buf);
appendStringInfo(&buf, "vxid:%d/%u\n", MyProc->backendId, MyProc->lxid);
appendStringInfo(&buf, "vxid:%d/%u\n", MyProc->vxid.backendId, MyProc->vxid.lxid);
appendStringInfo(&buf, "pid:%d\n", MyProcPid);
appendStringInfo(&buf, "dbid:%u\n", MyDatabaseId);
appendStringInfo(&buf, "iso:%d\n", XactIsoLevel);