Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Postgres/src/test/modules/xid_wraparound/   (Postgres Database Version 18.4©)  Datei vom 11.4.2026 mit Größe 5 kB image not shown  

Quelle  xid_wraparound.c

  Sprache: C
 

/*--------------------------------------------------------------------------
 *
 * xid_wraparound.c
 *  Utilities for testing XID wraparound
 *
 *
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *  src/test/modules/xid_wraparound/xid_wraparound.c
 *
 * -------------------------------------------------------------------------
 */

#include "postgres.h"

#include "access/xact.h"
#include "miscadmin.h"
#include "storage/proc.h"
#include "utils/xid8.h"

PG_MODULE_MAGIC;

static int64 consume_xids_shortcut(void);
static FullTransactionId consume_xids_common(FullTransactionId untilxid, uint64 nxids);

/*
 * Consume the specified number of XIDs.
 */

PG_FUNCTION_INFO_V1(consume_xids);
Datum
consume_xids(PG_FUNCTION_ARGS)
{
 int64  nxids = PG_GETARG_INT64(0);
 FullTransactionId lastxid;

 if (nxids < 0)
  elog(ERROR, "invalid nxids argument: %" PRId64, nxids);

 if (nxids == 0)
  lastxid = ReadNextFullTransactionId();
 else
  lastxid = consume_xids_common(InvalidFullTransactionId, (uint64) nxids);

 PG_RETURN_FULLTRANSACTIONID(lastxid);
}

/*
 * Consume XIDs, up to the given XID.
 */

PG_FUNCTION_INFO_V1(consume_xids_until);
Datum
consume_xids_until(PG_FUNCTION_ARGS)
{
 FullTransactionId targetxid = PG_GETARG_FULLTRANSACTIONID(0);
 FullTransactionId lastxid;

 if (!FullTransactionIdIsNormal(targetxid))
  elog(ERROR, "targetxid %" PRIu64 " is not normal",
    U64FromFullTransactionId(targetxid));

 lastxid = consume_xids_common(targetxid, 0);

 PG_RETURN_FULLTRANSACTIONID(lastxid);
}

/*
 * Common functionality between the two public functions.
 */

static FullTransactionId
consume_xids_common(FullTransactionId untilxid, uint64 nxids)
{
 FullTransactionId lastxid;
 uint64  last_reported_at = 0;
 uint64  consumed = 0;

 /* Print a NOTICE every REPORT_INTERVAL xids */
#define REPORT_INTERVAL (10 * 1000000)

 /* initialize 'lastxid' with the system's current next XID */
 lastxid = ReadNextFullTransactionId();

 /*
  * We consume XIDs by calling GetNewTransactionId(true), which marks the
  * consumed XIDs as subtransactions of the current top-level transaction.
  * For that to work, this transaction must have a top-level XID.
  *
  * GetNewTransactionId registers them in the subxid cache in PGPROC, until
  * the cache overflows, but beyond that, we don't keep track of the
  * consumed XIDs.
 */

 (void) GetTopTransactionId();

 for (;;)
 {
  uint64  xids_left;

  CHECK_FOR_INTERRUPTS();

  /* How many XIDs do we have left to consume? */
  if (nxids > 0)
  {
   if (consumed >= nxids)
    break;
   xids_left = nxids - consumed;
  }
  else
  {
   if (FullTransactionIdFollowsOrEquals(lastxid, untilxid))
    break;
   xids_left = U64FromFullTransactionId(untilxid) - U64FromFullTransactionId(lastxid);
  }

  /*
   * If we still have plenty of XIDs to consume, try to take a shortcut
   * and bump up the nextXid counter directly.
 */

  if (xids_left > 2000 &&
   consumed - last_reported_at < REPORT_INTERVAL &&
   MyProc->subxidStatus.overflowed)
  {
   int64  consumed_by_shortcut = consume_xids_shortcut();

   if (consumed_by_shortcut > 0)
   {
    consumed += consumed_by_shortcut;
    continue;
   }
  }

  /* Slow path: Call GetNewTransactionId to allocate a new XID. */
  lastxid = GetNewTransactionId(true);
  consumed++;

  /* Report progress */
  if (consumed - last_reported_at >= REPORT_INTERVAL)
  {
   if (nxids > 0)
    elog(NOTICE, "consumed %" PRIu64 " / %" PRIu64 " XIDs, latest %u:%u",
      consumed, nxids,
      EpochFromFullTransactionId(lastxid),
      XidFromFullTransactionId(lastxid));
   else
    elog(NOTICE, "consumed up to %u:%u / %u:%u",
      EpochFromFullTransactionId(lastxid),
      XidFromFullTransactionId(lastxid),
      EpochFromFullTransactionId(untilxid),
      XidFromFullTransactionId(untilxid));
   last_reported_at = consumed;
  }
 }

 return lastxid;
}

/*
 * These constants copied from .c files, because they're private.
 */

#define COMMIT_TS_XACTS_PER_PAGE (BLCKSZ / 10)
#define SUBTRANS_XACTS_PER_PAGE (BLCKSZ / sizeof(TransactionId))
#define CLOG_XACTS_PER_BYTE 4
#define CLOG_XACTS_PER_PAGE (BLCKSZ * CLOG_XACTS_PER_BYTE)

/*
 * All the interesting action in GetNewTransactionId happens when we extend
 * the SLRUs, or at the uint32 wraparound. If the nextXid counter is not close
 * to any of those interesting values, take a shortcut and bump nextXID
 * directly, close to the next "interesting" value.
 */

static inline uint32
XidSkip(FullTransactionId fullxid)
{
 uint32  low = XidFromFullTransactionId(fullxid);
 uint32  rem;
 uint32  distance;

 if (low < 5 || low >= UINT32_MAX - 5)
  return 0;
 distance = UINT32_MAX - 5 - low;

 rem = low % COMMIT_TS_XACTS_PER_PAGE;
 if (rem == 0)
  return 0;
 distance = Min(distance, COMMIT_TS_XACTS_PER_PAGE - rem);

 rem = low % SUBTRANS_XACTS_PER_PAGE;
 if (rem == 0)
  return 0;
 distance = Min(distance, SUBTRANS_XACTS_PER_PAGE - rem);

 rem = low % CLOG_XACTS_PER_PAGE;
 if (rem == 0)
  return 0;
 distance = Min(distance, CLOG_XACTS_PER_PAGE - rem);

 return distance;
}

static int64
consume_xids_shortcut(void)
{
 FullTransactionId nextXid;
 uint32  consumed;

 LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
 nextXid = TransamVariables->nextXid;

 /*
  * Go slow near the "interesting values". The interesting zones include 5
  * transactions before and after SLRU page switches.
 */

 consumed = XidSkip(nextXid);
 if (consumed > 0)
  TransamVariables->nextXid.value += (uint64) consumed;

 LWLockRelease(XidGenLock);

 return consumed;
}

Messung V0.5 in Prozent
C=94 H=94 G=93

¤ Dauer der Verarbeitung: 0.20 Sekunden  (vorverarbeitet am  2026-08-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.