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.43 2001/08/10 18:57:33 tgl Exp $
11 *-------------------------------------------------------------------------
16 #include "access/transam.h"
17 #include "access/xlog.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(TransactionId *xid)
39 * During bootstrap initialization, we return the special bootstrap
44 *xid = AmiTransactionId;
48 SpinAcquire(XidGenLockId);
50 *xid = ShmemVariableCache->nextXid;
52 (ShmemVariableCache->nextXid)++;
55 * Must set MyProc->xid before releasing XidGenLock. This ensures that
56 * when GetSnapshotData calls ReadNewTransactionId, all active XIDs
57 * before the returned value of nextXid are already present in the shared
58 * PROC array. Else we have a race condition.
60 * XXX by storing xid into MyProc without acquiring SInvalLock, we are
61 * relying on fetch/store of an xid to be atomic, else other backends
62 * might see a partially-set xid here. But holding both locks at once
63 * would be a nasty concurrency hit (and in fact could cause a deadlock
64 * against GetSnapshotData). So for now, assume atomicity. Note that
65 * readers of PROC xid field should be careful to fetch the value only
66 * once, rather than assume they can read it multiple times and get the
67 * same answer each time.
69 * A solution to the atomic-store problem would be to give each PROC
70 * its own spinlock used only for fetching/storing that PROC's xid.
71 * (SInvalLock would then mean primarily that PROCs couldn't be added/
72 * removed while holding the lock.)
74 if (MyProc != (PROC *) NULL)
77 SpinRelease(XidGenLockId);
81 * Read nextXid but don't allocate it.
84 ReadNewTransactionId(TransactionId *xid)
87 * During bootstrap initialization, we return the special bootstrap
92 *xid = AmiTransactionId;
96 SpinAcquire(XidGenLockId);
97 *xid = ShmemVariableCache->nextXid;
98 SpinRelease(XidGenLockId);
101 /* ----------------------------------------------------------------
102 * object id generation support
103 * ----------------------------------------------------------------
106 static Oid lastSeenOid = InvalidOid;
113 SpinAcquire(OidGenLockId);
116 * Check for wraparound of the OID counter. We *must* not return 0
117 * (InvalidOid); and as long as we have to check that, it seems a good
118 * idea to skip over everything below BootstrapObjectIdData too. (This
119 * basically just reduces the odds of OID collision right after a wrap
120 * occurs.) Note we are relying on unsigned comparison here.
122 if (ShmemVariableCache->nextOid < ((Oid) BootstrapObjectIdData))
124 ShmemVariableCache->nextOid = BootstrapObjectIdData;
125 ShmemVariableCache->oidCount = 0;
128 /* If we run out of logged for use oids then we must log more */
129 if (ShmemVariableCache->oidCount == 0)
131 XLogPutNextOid(ShmemVariableCache->nextOid + VAR_OID_PREFETCH);
132 ShmemVariableCache->oidCount = VAR_OID_PREFETCH;
135 result = ShmemVariableCache->nextOid;
137 (ShmemVariableCache->nextOid)++;
138 (ShmemVariableCache->oidCount)--;
140 SpinRelease(OidGenLockId);
142 lastSeenOid = result;
148 CheckMaxObjectId(Oid assigned_oid)
150 if (lastSeenOid != InvalidOid && assigned_oid < lastSeenOid)
153 SpinAcquire(OidGenLockId);
155 if (assigned_oid < ShmemVariableCache->nextOid)
157 lastSeenOid = ShmemVariableCache->nextOid - 1;
158 SpinRelease(OidGenLockId);
162 /* If we are in the logged oid range, just bump nextOid up */
163 if (assigned_oid <= ShmemVariableCache->nextOid +
164 ShmemVariableCache->oidCount - 1)
166 ShmemVariableCache->oidCount -=
167 assigned_oid - ShmemVariableCache->nextOid + 1;
168 ShmemVariableCache->nextOid = assigned_oid + 1;
169 SpinRelease(OidGenLockId);
174 * We have exceeded the logged oid range. We should lock the database
175 * and kill all other backends but we are loading oid's that we can
176 * not guarantee are unique anyway, so we must rely on the user.
179 XLogPutNextOid(assigned_oid + VAR_OID_PREFETCH);
180 ShmemVariableCache->nextOid = assigned_oid + 1;
181 ShmemVariableCache->oidCount = VAR_OID_PREFETCH - 1;
183 SpinRelease(OidGenLockId);