1 /*-------------------------------------------------------------------------
4 * postgres OID & XID variables support routines
6 * Copyright (c) 2000, PostgreSQL Global Development Group
9 * $Header: /cvsroot/pgsql/src/backend/access/transam/varsup.c,v 1.45 2001/08/25 18:52:41 tgl Exp $
11 *-------------------------------------------------------------------------
16 #include "access/clog.h"
17 #include "access/transam.h"
18 #include "storage/proc.h"
21 /* Number of OIDs to prefetch (preallocate) per XLOG write */
22 #define VAR_OID_PREFETCH 8192
24 /* Spinlocks for serializing generation of XIDs and OIDs, respectively */
25 SPINLOCK XidGenLockId;
26 SPINLOCK OidGenLockId;
28 /* pointer to "variable cache" in shared memory (set up by shmem.c) */
29 VariableCache ShmemVariableCache = NULL;
33 * Allocate the next XID for my new transaction.
36 GetNewTransactionId(void)
41 * During bootstrap initialization, we return the special bootstrap
45 return BootstrapTransactionId;
47 SpinAcquire(XidGenLockId);
49 xid = ShmemVariableCache->nextXid;
51 TransactionIdAdvance(ShmemVariableCache->nextXid);
54 * If we have just allocated the first XID of a new page of the
55 * commit log, zero out that commit-log page before returning.
56 * We must do this while holding XidGenLock, else another xact could
57 * acquire and commit a later XID before we zero the page. Fortunately,
58 * a page of the commit log holds 32K or more transactions, so we don't
59 * have to do this very often.
64 * Must set MyProc->xid before releasing XidGenLock. This ensures that
65 * when GetSnapshotData calls ReadNewTransactionId, all active XIDs
66 * before the returned value of nextXid are already present in the shared
67 * PROC array. Else we have a race condition.
69 * XXX by storing xid into MyProc without acquiring SInvalLock, we are
70 * relying on fetch/store of an xid to be atomic, else other backends
71 * might see a partially-set xid here. But holding both locks at once
72 * would be a nasty concurrency hit (and in fact could cause a deadlock
73 * against GetSnapshotData). So for now, assume atomicity. Note that
74 * readers of PROC xid field should be careful to fetch the value only
75 * once, rather than assume they can read it multiple times and get the
76 * same answer each time.
78 * A solution to the atomic-store problem would be to give each PROC
79 * its own spinlock used only for fetching/storing that PROC's xid.
80 * (SInvalLock would then mean primarily that PROCs couldn't be added/
81 * removed while holding the lock.)
83 if (MyProc != (PROC *) NULL)
86 SpinRelease(XidGenLockId);
92 * Read nextXid but don't allocate it.
95 ReadNewTransactionId(void)
100 * During bootstrap initialization, we return the special bootstrap
104 return BootstrapTransactionId;
106 SpinAcquire(XidGenLockId);
107 xid = ShmemVariableCache->nextXid;
108 SpinRelease(XidGenLockId);
113 /* ----------------------------------------------------------------
114 * object id generation support
115 * ----------------------------------------------------------------
118 static Oid lastSeenOid = InvalidOid;
125 SpinAcquire(OidGenLockId);
128 * Check for wraparound of the OID counter. We *must* not return 0
129 * (InvalidOid); and as long as we have to check that, it seems a good
130 * idea to skip over everything below BootstrapObjectIdData too. (This
131 * basically just reduces the odds of OID collision right after a wrap
132 * occurs.) Note we are relying on unsigned comparison here.
134 if (ShmemVariableCache->nextOid < ((Oid) BootstrapObjectIdData))
136 ShmemVariableCache->nextOid = BootstrapObjectIdData;
137 ShmemVariableCache->oidCount = 0;
140 /* If we run out of logged for use oids then we must log more */
141 if (ShmemVariableCache->oidCount == 0)
143 XLogPutNextOid(ShmemVariableCache->nextOid + VAR_OID_PREFETCH);
144 ShmemVariableCache->oidCount = VAR_OID_PREFETCH;
147 result = ShmemVariableCache->nextOid;
149 (ShmemVariableCache->nextOid)++;
150 (ShmemVariableCache->oidCount)--;
152 SpinRelease(OidGenLockId);
154 lastSeenOid = result;
160 CheckMaxObjectId(Oid assigned_oid)
162 if (lastSeenOid != InvalidOid && assigned_oid < lastSeenOid)
165 SpinAcquire(OidGenLockId);
167 if (assigned_oid < ShmemVariableCache->nextOid)
169 lastSeenOid = ShmemVariableCache->nextOid - 1;
170 SpinRelease(OidGenLockId);
174 /* If we are in the logged oid range, just bump nextOid up */
175 if (assigned_oid <= ShmemVariableCache->nextOid +
176 ShmemVariableCache->oidCount - 1)
178 ShmemVariableCache->oidCount -=
179 assigned_oid - ShmemVariableCache->nextOid + 1;
180 ShmemVariableCache->nextOid = assigned_oid + 1;
181 SpinRelease(OidGenLockId);
186 * We have exceeded the logged oid range. We should lock the database
187 * and kill all other backends but we are loading oid's that we can
188 * not guarantee are unique anyway, so we must rely on the user.
191 XLogPutNextOid(assigned_oid + VAR_OID_PREFETCH);
192 ShmemVariableCache->nextOid = assigned_oid + 1;
193 ShmemVariableCache->oidCount = VAR_OID_PREFETCH - 1;
195 SpinRelease(OidGenLockId);