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.47 2001/10/25 05:49:22 momjian Exp $
11 *-------------------------------------------------------------------------
16 #include "access/clog.h"
17 #include "access/transam.h"
18 #include "storage/ipc.h"
19 #include "storage/proc.h"
22 /* Number of OIDs to prefetch (preallocate) per XLOG write */
23 #define VAR_OID_PREFETCH 8192
25 /* pointer to "variable cache" in shared memory (set up by shmem.c) */
26 VariableCache ShmemVariableCache = NULL;
30 * Allocate the next XID for my new transaction.
33 GetNewTransactionId(void)
38 * During bootstrap initialization, we return the special bootstrap
42 return BootstrapTransactionId;
44 LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
46 xid = ShmemVariableCache->nextXid;
48 TransactionIdAdvance(ShmemVariableCache->nextXid);
51 * If we have just allocated the first XID of a new page of the commit
52 * log, zero out that commit-log page before returning. We must do
53 * this while holding XidGenLock, else another xact could acquire and
54 * commit a later XID before we zero the page. Fortunately, a page of
55 * the commit log holds 32K or more transactions, so we don't have to
61 * Must set MyProc->xid before releasing XidGenLock. This ensures
62 * that when GetSnapshotData calls ReadNewTransactionId, all active
63 * XIDs before the returned value of nextXid are already present in
64 * the shared PROC array. Else we have a race condition.
66 * XXX by storing xid into MyProc without acquiring SInvalLock, we are
67 * relying on fetch/store of an xid to be atomic, else other backends
68 * might see a partially-set xid here. But holding both locks at once
69 * would be a nasty concurrency hit (and in fact could cause a
70 * deadlock against GetSnapshotData). So for now, assume atomicity.
71 * Note that readers of PROC xid field should be careful to fetch the
72 * value only once, rather than assume they can read it multiple times
73 * and get the same answer each time.
75 * A solution to the atomic-store problem would be to give each PROC its
76 * own spinlock used only for fetching/storing that PROC's xid.
77 * (SInvalLock would then mean primarily that PROCs couldn't be added/
78 * removed while holding the lock.)
80 if (MyProc != (PROC *) NULL)
83 LWLockRelease(XidGenLock);
89 * Read nextXid but don't allocate it.
92 ReadNewTransactionId(void)
97 * During bootstrap initialization, we return the special bootstrap
101 return BootstrapTransactionId;
103 LWLockAcquire(XidGenLock, LW_SHARED);
104 xid = ShmemVariableCache->nextXid;
105 LWLockRelease(XidGenLock);
110 /* ----------------------------------------------------------------
111 * object id generation support
112 * ----------------------------------------------------------------
115 static Oid lastSeenOid = InvalidOid;
122 LWLockAcquire(OidGenLock, LW_EXCLUSIVE);
125 * Check for wraparound of the OID counter. We *must* not return 0
126 * (InvalidOid); and as long as we have to check that, it seems a good
127 * idea to skip over everything below BootstrapObjectIdData too.
128 * (This basically just reduces the odds of OID collision right after
129 * a wrap occurs.) Note we are relying on unsigned comparison here.
131 if (ShmemVariableCache->nextOid < ((Oid) BootstrapObjectIdData))
133 ShmemVariableCache->nextOid = BootstrapObjectIdData;
134 ShmemVariableCache->oidCount = 0;
137 /* If we run out of logged for use oids then we must log more */
138 if (ShmemVariableCache->oidCount == 0)
140 XLogPutNextOid(ShmemVariableCache->nextOid + VAR_OID_PREFETCH);
141 ShmemVariableCache->oidCount = VAR_OID_PREFETCH;
144 result = ShmemVariableCache->nextOid;
146 (ShmemVariableCache->nextOid)++;
147 (ShmemVariableCache->oidCount)--;
149 LWLockRelease(OidGenLock);
151 lastSeenOid = result;
157 CheckMaxObjectId(Oid assigned_oid)
159 if (lastSeenOid != InvalidOid && assigned_oid < lastSeenOid)
162 LWLockAcquire(OidGenLock, LW_EXCLUSIVE);
164 if (assigned_oid < ShmemVariableCache->nextOid)
166 lastSeenOid = ShmemVariableCache->nextOid - 1;
167 LWLockRelease(OidGenLock);
171 /* If we are in the logged oid range, just bump nextOid up */
172 if (assigned_oid <= ShmemVariableCache->nextOid +
173 ShmemVariableCache->oidCount - 1)
175 ShmemVariableCache->oidCount -=
176 assigned_oid - ShmemVariableCache->nextOid + 1;
177 ShmemVariableCache->nextOid = assigned_oid + 1;
178 LWLockRelease(OidGenLock);
183 * We have exceeded the logged oid range. We should lock the database
184 * and kill all other backends but we are loading oid's that we can
185 * not guarantee are unique anyway, so we must rely on the user.
188 XLogPutNextOid(assigned_oid + VAR_OID_PREFETCH);
189 ShmemVariableCache->nextOid = assigned_oid + 1;
190 ShmemVariableCache->oidCount = VAR_OID_PREFETCH - 1;
192 LWLockRelease(OidGenLock);