]> granicus.if.org Git - postgresql/blob - src/backend/access/transam/varsup.c
Update copyrights that were missed.
[postgresql] / src / backend / access / transam / varsup.c
1 /*-------------------------------------------------------------------------
2  *
3  * varsup.c
4  *        postgres OID & XID variables support routines
5  *
6  * Copyright (c) 2000-2005, PostgreSQL Global Development Group
7  *
8  * IDENTIFICATION
9  *        $PostgreSQL: pgsql/src/backend/access/transam/varsup.c,v 1.60 2005/01/01 05:43:06 momjian Exp $
10  *
11  *-------------------------------------------------------------------------
12  */
13
14 #include "postgres.h"
15
16 #include "access/clog.h"
17 #include "access/subtrans.h"
18 #include "access/transam.h"
19 #include "storage/ipc.h"
20 #include "storage/proc.h"
21
22
23 /* Number of OIDs to prefetch (preallocate) per XLOG write */
24 #define VAR_OID_PREFETCH                8192
25
26 /* pointer to "variable cache" in shared memory (set up by shmem.c) */
27 VariableCache ShmemVariableCache = NULL;
28
29
30 /*
31  * Allocate the next XID for my new transaction.
32  */
33 TransactionId
34 GetNewTransactionId(bool isSubXact)
35 {
36         TransactionId xid;
37
38         /*
39          * During bootstrap initialization, we return the special bootstrap
40          * transaction id.
41          */
42         if (AMI_OVERRIDE)
43                 return BootstrapTransactionId;
44
45         LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
46
47         xid = ShmemVariableCache->nextXid;
48
49         /*
50          * If we are allocating the first XID of a new page of the commit log,
51          * zero out that commit-log page before returning. We must do this
52          * while holding XidGenLock, else another xact could acquire and
53          * commit a later XID before we zero the page.  Fortunately, a page of
54          * the commit log holds 32K or more transactions, so we don't have to
55          * do this very often.
56          *
57          * Extend pg_subtrans too.
58          */
59         ExtendCLOG(xid);
60         ExtendSUBTRANS(xid);
61
62         /*
63          * Now advance the nextXid counter.  This must not happen until after
64          * we have successfully completed ExtendCLOG() --- if that routine
65          * fails, we want the next incoming transaction to try it again.  We
66          * cannot assign more XIDs until there is CLOG space for them.
67          */
68         TransactionIdAdvance(ShmemVariableCache->nextXid);
69
70         /*
71          * We must store the new XID into the shared PGPROC array before
72          * releasing XidGenLock.  This ensures that when GetSnapshotData calls
73          * ReadNewTransactionId, all active XIDs before the returned value of
74          * nextXid are already present in PGPROC.  Else we have a race
75          * condition.
76          *
77          * XXX by storing xid into MyProc without acquiring SInvalLock, we are
78          * relying on fetch/store of an xid to be atomic, else other backends
79          * might see a partially-set xid here.  But holding both locks at once
80          * would be a nasty concurrency hit (and in fact could cause a
81          * deadlock against GetSnapshotData).  So for now, assume atomicity.
82          * Note that readers of PGPROC xid field should be careful to fetch
83          * the value only once, rather than assume they can read it multiple
84          * times and get the same answer each time.
85          *
86          * The same comments apply to the subxact xid count and overflow fields.
87          *
88          * A solution to the atomic-store problem would be to give each PGPROC
89          * its own spinlock used only for fetching/storing that PGPROC's xid
90          * and related fields.  (SInvalLock would then mean primarily that
91          * PGPROCs couldn't be added/removed while holding the lock.)
92          *
93          * If there's no room to fit a subtransaction XID into PGPROC, set the
94          * cache-overflowed flag instead.  This forces readers to look in
95          * pg_subtrans to map subtransaction XIDs up to top-level XIDs. There
96          * is a race-condition window, in that the new XID will not appear as
97          * running until its parent link has been placed into pg_subtrans.
98          * However, that will happen before anyone could possibly have a
99          * reason to inquire about the status of the XID, so it seems OK.
100          * (Snapshots taken during this window *will* include the parent XID,
101          * so they will deliver the correct answer later on when someone does
102          * have a reason to inquire.)
103          */
104         if (MyProc != NULL)
105         {
106                 if (!isSubXact)
107                         MyProc->xid = xid;
108                 else
109                 {
110                         if (MyProc->subxids.nxids < PGPROC_MAX_CACHED_SUBXIDS)
111                         {
112                                 MyProc->subxids.xids[MyProc->subxids.nxids] = xid;
113                                 MyProc->subxids.nxids++;
114                         }
115                         else
116                                 MyProc->subxids.overflowed = true;
117                 }
118         }
119
120         LWLockRelease(XidGenLock);
121
122         return xid;
123 }
124
125 /*
126  * Read nextXid but don't allocate it.
127  */
128 TransactionId
129 ReadNewTransactionId(void)
130 {
131         TransactionId xid;
132
133         LWLockAcquire(XidGenLock, LW_SHARED);
134         xid = ShmemVariableCache->nextXid;
135         LWLockRelease(XidGenLock);
136
137         return xid;
138 }
139
140 /* ----------------------------------------------------------------
141  *                                      object id generation support
142  * ----------------------------------------------------------------
143  */
144
145 static Oid      lastSeenOid = InvalidOid;
146
147 Oid
148 GetNewObjectId(void)
149 {
150         Oid                     result;
151
152         LWLockAcquire(OidGenLock, LW_EXCLUSIVE);
153
154         /*
155          * Check for wraparound of the OID counter.  We *must* not return 0
156          * (InvalidOid); and as long as we have to check that, it seems a good
157          * idea to skip over everything below BootstrapObjectIdData too. (This
158          * basically just reduces the odds of OID collision right after a wrap
159          * occurs.)  Note we are relying on unsigned comparison here.
160          */
161         if (ShmemVariableCache->nextOid < ((Oid) BootstrapObjectIdData))
162         {
163                 ShmemVariableCache->nextOid = BootstrapObjectIdData;
164                 ShmemVariableCache->oidCount = 0;
165         }
166
167         /* If we run out of logged for use oids then we must log more */
168         if (ShmemVariableCache->oidCount == 0)
169         {
170                 XLogPutNextOid(ShmemVariableCache->nextOid + VAR_OID_PREFETCH);
171                 ShmemVariableCache->oidCount = VAR_OID_PREFETCH;
172         }
173
174         result = ShmemVariableCache->nextOid;
175
176         (ShmemVariableCache->nextOid)++;
177         (ShmemVariableCache->oidCount)--;
178
179         LWLockRelease(OidGenLock);
180
181         lastSeenOid = result;
182
183         return result;
184 }
185
186 void
187 CheckMaxObjectId(Oid assigned_oid)
188 {
189         if (lastSeenOid != InvalidOid && assigned_oid < lastSeenOid)
190                 return;
191
192         LWLockAcquire(OidGenLock, LW_EXCLUSIVE);
193
194         if (assigned_oid < ShmemVariableCache->nextOid)
195         {
196                 lastSeenOid = ShmemVariableCache->nextOid - 1;
197                 LWLockRelease(OidGenLock);
198                 return;
199         }
200
201         /* If we are in the logged oid range, just bump nextOid up */
202         if (assigned_oid <= ShmemVariableCache->nextOid +
203                 ShmemVariableCache->oidCount - 1)
204         {
205                 ShmemVariableCache->oidCount -=
206                         assigned_oid - ShmemVariableCache->nextOid + 1;
207                 ShmemVariableCache->nextOid = assigned_oid + 1;
208                 LWLockRelease(OidGenLock);
209                 return;
210         }
211
212         /*
213          * We have exceeded the logged oid range. We should lock the database
214          * and kill all other backends but we are loading oid's that we can
215          * not guarantee are unique anyway, so we must rely on the user.
216          */
217
218         XLogPutNextOid(assigned_oid + VAR_OID_PREFETCH);
219         ShmemVariableCache->nextOid = assigned_oid + 1;
220         ShmemVariableCache->oidCount = VAR_OID_PREFETCH - 1;
221
222         LWLockRelease(OidGenLock);
223 }