]> granicus.if.org Git - postgresql/blob - src/backend/access/transam/varsup.c
Replace implementation of pg_log as a relation accessed through the
[postgresql] / src / backend / access / transam / varsup.c
1 /*-------------------------------------------------------------------------
2  *
3  * varsup.c
4  *        postgres OID & XID variables support routines
5  *
6  * Copyright (c) 2000, PostgreSQL Global Development Group
7  *
8  * IDENTIFICATION
9  *        $Header: /cvsroot/pgsql/src/backend/access/transam/varsup.c,v 1.45 2001/08/25 18:52:41 tgl Exp $
10  *
11  *-------------------------------------------------------------------------
12  */
13
14 #include "postgres.h"
15
16 #include "access/clog.h"
17 #include "access/transam.h"
18 #include "storage/proc.h"
19
20
21 /* Number of OIDs to prefetch (preallocate) per XLOG write */
22 #define VAR_OID_PREFETCH                8192
23
24 /* Spinlocks for serializing generation of XIDs and OIDs, respectively */
25 SPINLOCK        XidGenLockId;
26 SPINLOCK        OidGenLockId;
27
28 /* pointer to "variable cache" in shared memory (set up by shmem.c) */
29 VariableCache ShmemVariableCache = NULL;
30
31
32 /*
33  * Allocate the next XID for my new transaction.
34  */
35 TransactionId
36 GetNewTransactionId(void)
37 {
38         TransactionId   xid;
39
40         /*
41          * During bootstrap initialization, we return the special bootstrap
42          * transaction id.
43          */
44         if (AMI_OVERRIDE)
45                 return BootstrapTransactionId;
46
47         SpinAcquire(XidGenLockId);
48
49         xid = ShmemVariableCache->nextXid;
50
51         TransactionIdAdvance(ShmemVariableCache->nextXid);
52
53         /*
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.
60          */
61         ExtendCLOG(xid);
62
63         /*
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.
68          *
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.
77          *
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.)
82          */
83         if (MyProc != (PROC *) NULL)
84                 MyProc->xid = xid;
85
86         SpinRelease(XidGenLockId);
87
88         return xid;
89 }
90
91 /*
92  * Read nextXid but don't allocate it.
93  */
94 TransactionId
95 ReadNewTransactionId(void)
96 {
97         TransactionId   xid;
98
99         /*
100          * During bootstrap initialization, we return the special bootstrap
101          * transaction id.
102          */
103         if (AMI_OVERRIDE)
104                 return BootstrapTransactionId;
105
106         SpinAcquire(XidGenLockId);
107         xid = ShmemVariableCache->nextXid;
108         SpinRelease(XidGenLockId);
109
110         return xid;
111 }
112
113 /* ----------------------------------------------------------------
114  *                                      object id generation support
115  * ----------------------------------------------------------------
116  */
117
118 static Oid      lastSeenOid = InvalidOid;
119
120 Oid
121 GetNewObjectId(void)
122 {
123         Oid             result;
124
125         SpinAcquire(OidGenLockId);
126
127         /*
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.
133          */
134         if (ShmemVariableCache->nextOid < ((Oid) BootstrapObjectIdData))
135         {
136                 ShmemVariableCache->nextOid = BootstrapObjectIdData;
137                 ShmemVariableCache->oidCount = 0;
138         }
139
140         /* If we run out of logged for use oids then we must log more */
141         if (ShmemVariableCache->oidCount == 0)
142         {
143                 XLogPutNextOid(ShmemVariableCache->nextOid + VAR_OID_PREFETCH);
144                 ShmemVariableCache->oidCount = VAR_OID_PREFETCH;
145         }
146
147         result = ShmemVariableCache->nextOid;
148
149         (ShmemVariableCache->nextOid)++;
150         (ShmemVariableCache->oidCount)--;
151
152         SpinRelease(OidGenLockId);
153
154         lastSeenOid = result;
155
156         return result;
157 }
158
159 void
160 CheckMaxObjectId(Oid assigned_oid)
161 {
162         if (lastSeenOid != InvalidOid && assigned_oid < lastSeenOid)
163                 return;
164
165         SpinAcquire(OidGenLockId);
166
167         if (assigned_oid < ShmemVariableCache->nextOid)
168         {
169                 lastSeenOid = ShmemVariableCache->nextOid - 1;
170                 SpinRelease(OidGenLockId);
171                 return;
172         }
173
174         /* If we are in the logged oid range, just bump nextOid up */
175         if (assigned_oid <= ShmemVariableCache->nextOid +
176                 ShmemVariableCache->oidCount - 1)
177         {
178                 ShmemVariableCache->oidCount -=
179                         assigned_oid - ShmemVariableCache->nextOid + 1;
180                 ShmemVariableCache->nextOid = assigned_oid + 1;
181                 SpinRelease(OidGenLockId);
182                 return;
183         }
184
185         /*
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.
189          */
190
191         XLogPutNextOid(assigned_oid + VAR_OID_PREFETCH);
192         ShmemVariableCache->nextOid = assigned_oid + 1;
193         ShmemVariableCache->oidCount = VAR_OID_PREFETCH - 1;
194
195         SpinRelease(OidGenLockId);
196 }