Skip to content

Commit 742cd87

Browse files
committed
Ensure that if the OID counter wraps around, we will not generate 0,
nor any OID in the reserved range (1-16383).
1 parent 667d5ed commit 742cd87

File tree

1 file changed

+83
-91
lines changed

1 file changed

+83
-91
lines changed

src/backend/access/transam/varsup.c

Lines changed: 83 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/access/transam/varsup.c,v 1.28 2000/04/12 17:14:53 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/access/transam/varsup.c,v 1.29 2000/07/25 20:18:19 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -22,16 +22,21 @@
2222
static void GetNewObjectIdBlock(Oid *oid_return, int oid_block_size);
2323
static void VariableRelationGetNextOid(Oid *oid_return);
2424
static void VariableRelationGetNextXid(TransactionId *xidP);
25-
static void VariableRelationPutNextOid(Oid *oidP);
25+
static void VariableRelationPutNextOid(Oid oid);
2626

2727
/* ---------------------
2828
* spin lock for oid generation
2929
* ---------------------
3030
*/
3131
int OidGenLockId;
3232

33+
/* ---------------------
34+
* pointer to "variable cache" in shared memory (set up by shmem.c)
35+
* ---------------------
36+
*/
3337
VariableCache ShmemVariableCache = NULL;
3438

39+
3540
/* ----------------------------------------------------------------
3641
* variable relation query/update routines
3742
* ----------------------------------------------------------------
@@ -48,7 +53,7 @@ VariableRelationGetNextXid(TransactionId *xidP)
4853
VariableRelationContents var;
4954

5055
/* ----------------
51-
* We assume that a spinlock has been acquire to guarantee
56+
* We assume that a spinlock has been acquired to guarantee
5257
* exclusive access to the variable relation.
5358
* ----------------
5459
*/
@@ -76,6 +81,7 @@ VariableRelationGetNextXid(TransactionId *xidP)
7681
var = (VariableRelationContents) BufferGetBlock(buf);
7782

7883
TransactionIdStore(var->nextXidData, xidP);
84+
7985
ReleaseBuffer(buf);
8086
}
8187

@@ -90,7 +96,7 @@ VariableRelationPutNextXid(TransactionId xid)
9096
VariableRelationContents var;
9197

9298
/* ----------------
93-
* We assume that a spinlock has been acquire to guarantee
99+
* We assume that a spinlock has been acquired to guarantee
94100
* exclusive access to the variable relation.
95101
* ----------------
96102
*/
@@ -133,22 +139,20 @@ VariableRelationGetNextOid(Oid *oid_return)
133139
VariableRelationContents var;
134140

135141
/* ----------------
136-
* We assume that a spinlock has been acquire to guarantee
142+
* We assume that a spinlock has been acquired to guarantee
137143
* exclusive access to the variable relation.
138144
* ----------------
139145
*/
140146

141147
/* ----------------
142148
* if the variable relation is not initialized, then we
143149
* assume we are running at bootstrap time and so we return
144-
* an invalid object id -- during this time GetNextBootstrapObjectId
145-
* should be called instead..
150+
* an invalid object id (this path should never be taken, probably).
146151
* ----------------
147152
*/
148153
if (!RelationIsValid(VariableRelation))
149154
{
150-
if (PointerIsValid(oid_return))
151-
(*oid_return) = InvalidOid;
155+
(*oid_return) = InvalidOid;
152156
return;
153157
}
154158

@@ -162,32 +166,12 @@ VariableRelationGetNextOid(Oid *oid_return)
162166
if (!BufferIsValid(buf))
163167
{
164168
SpinRelease(OidGenLockId);
165-
elog(ERROR, "VariableRelationGetNextXid: ReadBuffer failed");
169+
elog(ERROR, "VariableRelationGetNextOid: ReadBuffer failed");
166170
}
167171

168172
var = (VariableRelationContents) BufferGetBlock(buf);
169173

170-
if (PointerIsValid(oid_return))
171-
{
172-
173-
/* ----------------
174-
* nothing up my sleeve... what's going on here is that this code
175-
* is guaranteed never to be called until all files in data/base/
176-
* are created, and the template database exists. at that point,
177-
* we want to append a pg_database tuple. the first time we do
178-
* this, the oid stored in pg_variable will be bogus, so we use
179-
* a bootstrap value defined at the top of this file.
180-
*
181-
* this comment no longer holds true. This code is called before
182-
* all of the files in data/base are created and you can't rely
183-
* on system oid's to be less than BootstrapObjectIdData. mer 9/18/91
184-
* ----------------
185-
*/
186-
if (OidIsValid(var->nextOid))
187-
(*oid_return) = var->nextOid;
188-
else
189-
(*oid_return) = BootstrapObjectIdData;
190-
}
174+
(*oid_return) = var->nextOid;
191175

192176
ReleaseBuffer(buf);
193177
}
@@ -197,13 +181,13 @@ VariableRelationGetNextOid(Oid *oid_return)
197181
* --------------------------------
198182
*/
199183
static void
200-
VariableRelationPutNextOid(Oid *oidP)
184+
VariableRelationPutNextOid(Oid oid)
201185
{
202186
Buffer buf;
203187
VariableRelationContents var;
204188

205189
/* ----------------
206-
* We assume that a spinlock has been acquire to guarantee
190+
* We assume that a spinlock has been acquired to guarantee
207191
* exclusive access to the variable relation.
208192
* ----------------
209193
*/
@@ -215,16 +199,6 @@ VariableRelationPutNextOid(Oid *oidP)
215199
if (!RelationIsValid(VariableRelation))
216200
return;
217201

218-
/* ----------------
219-
* sanity check
220-
* ----------------
221-
*/
222-
if (!PointerIsValid(oidP))
223-
{
224-
SpinRelease(OidGenLockId);
225-
elog(ERROR, "VariableRelationPutNextOid: invalid oid pointer");
226-
}
227-
228202
/* ----------------
229203
* read the variable page, update the nextXid field and
230204
* write the page back out to disk.
@@ -240,7 +214,7 @@ VariableRelationPutNextOid(Oid *oidP)
240214

241215
var = (VariableRelationContents) BufferGetBlock(buf);
242216

243-
var->nextOid = (*oidP);
217+
var->nextOid = oid;
244218

245219
WriteBuffer(buf);
246220
}
@@ -253,20 +227,20 @@ VariableRelationPutNextOid(Oid *oidP)
253227
/* ----------------
254228
* GetNewTransactionId
255229
*
256-
* In the version 2 transaction system, transaction id's are
257-
* restricted in several ways.
258-
*
259-
* -- Old comments removed
230+
* Transaction IDs are allocated via a cache in shared memory.
231+
* Each time we need more IDs, we advance the "next XID" value
232+
* in pg_variable by VAR_XID_PREFETCH and set the cache to
233+
* show that many XIDs as available. Then, allocating those XIDs
234+
* requires just a spinlock and not a buffer read/write cycle.
260235
*
261-
* Second, since we may someday preform compression of the data
262-
* in the log and time relations, we cause the numbering of the
263-
* transaction ids to begin at 512. This means that some space
264-
* on the page of the log and time relations corresponding to
265-
* transaction id's 0 - 510 will never be used. This space is
266-
* in fact used to store the version number of the postgres
267-
* transaction log and will someday store compression information
268-
* about the log. -- this is also old comments...
236+
* Since the cache is shared across all backends, cached but unused
237+
* XIDs are not lost when a backend exits, only when the postmaster
238+
* quits or forces shared memory reinit. So we can afford to have
239+
* a pretty big value of VAR_XID_PREFETCH.
269240
*
241+
* This code does not worry about initializing the transaction counter
242+
* (see transam.c's InitializeTransactionLog() for that). We also
243+
* ignore the possibility that the counter could someday wrap around.
270244
* ----------------
271245
*/
272246

@@ -352,44 +326,65 @@ ReadNewTransactionId(TransactionId *xid)
352326
* GetNewObjectIdBlock
353327
*
354328
* This support function is used to allocate a block of object ids
355-
* of the given size. applications wishing to do their own object
356-
* id assignments should use this
329+
* of the given size.
357330
* ----------------
358331
*/
359332
static void
360-
GetNewObjectIdBlock(Oid *oid_return, /* place to return the new object
361-
* id */
333+
GetNewObjectIdBlock(Oid *oid_return, /* place to return the first new
334+
* object id */
362335
int oid_block_size) /* number of oids desired */
363336
{
337+
Oid firstfreeoid;
364338
Oid nextoid;
365339

366340
/* ----------------
367-
* SOMEDAY obtain exclusive access to the variable relation page
368-
* That someday is today -mer 6 Aug 1992
341+
* Obtain exclusive access to the variable relation page
369342
* ----------------
370343
*/
371344
SpinAcquire(OidGenLockId);
372345

373346
/* ----------------
374347
* get the "next" oid from the variable relation
375-
* and give it to the caller.
376348
* ----------------
377349
*/
378-
VariableRelationGetNextOid(&nextoid);
379-
if (PointerIsValid(oid_return))
380-
(*oid_return) = nextoid;
350+
VariableRelationGetNextOid(&firstfreeoid);
351+
352+
/* ----------------
353+
* Allocate the range of OIDs to be returned to the caller.
354+
*
355+
* There are two things going on here.
356+
*
357+
* One: in a virgin database pg_variable will initially contain zeroes,
358+
* so we will read out firstfreeoid = InvalidOid. We want to start
359+
* allocating OIDs at BootstrapObjectIdData instead (OIDs below that
360+
* are reserved for static assignment in the initial catalog data).
361+
*
362+
* Two: if a database is run long enough, the OID counter will wrap
363+
* around. We must not generate an invalid OID when that happens,
364+
* and it seems wise not to generate anything in the reserved range.
365+
* Therefore we advance to BootstrapObjectIdData in this case too.
366+
*
367+
* The comparison here assumes that Oid is an unsigned type.
368+
*/
369+
nextoid = firstfreeoid + oid_block_size;
370+
371+
if (! OidIsValid(firstfreeoid) || nextoid < firstfreeoid)
372+
{
373+
/* Initialization or wraparound time, force it up to safe range */
374+
firstfreeoid = BootstrapObjectIdData;
375+
nextoid = firstfreeoid + oid_block_size;
376+
}
377+
378+
(*oid_return) = firstfreeoid;
381379

382380
/* ----------------
383-
* now increment the variable relation's next oid
384-
* field by the size of the oid block requested.
381+
* Update the variable relation to show the block range as used.
385382
* ----------------
386383
*/
387-
nextoid += oid_block_size;
388-
VariableRelationPutNextOid(&nextoid);
384+
VariableRelationPutNextOid(nextoid);
389385

390386
/* ----------------
391-
* SOMEDAY relinquish our lock on the variable relation page
392-
* That someday is today -mer 6 Apr 1992
387+
* Relinquish our lock on the variable relation page
393388
* ----------------
394389
*/
395390
SpinRelease(OidGenLockId);
@@ -406,9 +401,14 @@ GetNewObjectIdBlock(Oid *oid_return, /* place to return the new object
406401
* relation by 32 for each backend.
407402
*
408403
* Note: 32 has no special significance. We don't want the
409-
* number to be too large because if when the backend
404+
* number to be too large because when the backend
410405
* terminates, we lose the oids we cached.
411406
*
407+
* Question: couldn't we use a shared-memory cache just like XIDs?
408+
* That would allow a larger interval between pg_variable updates
409+
* without cache losses. Note, however, that we can assign an OID
410+
* without even a spinlock from the backend-local OID cache.
411+
* Maybe two levels of caching would be good.
412412
* ----------------
413413
*/
414414

@@ -431,11 +431,7 @@ GetNewObjectId(Oid *oid_return) /* place to return the new object id */
431431
int oid_block_size = VAR_OID_PREFETCH;
432432

433433
/* ----------------
434-
* during bootstrap time, we want to allocate oids
435-
* one at a time. Otherwise there might be some
436-
* bootstrap oid's left in the block we prefetch which
437-
* would be passed out after the variable relation was
438-
* initialized. This would be bad.
434+
* Make sure pg_variable is open.
439435
* ----------------
440436
*/
441437
if (!RelationIsValid(VariableRelation))
@@ -469,12 +465,11 @@ GetNewObjectId(Oid *oid_return) /* place to return the new object id */
469465
void
470466
CheckMaxObjectId(Oid assigned_oid)
471467
{
472-
Oid pass_oid;
473-
468+
Oid temp_oid;
474469

475470
if (prefetched_oid_count == 0) /* make sure next/max is set, or
476471
* reload */
477-
GetNewObjectId(&pass_oid);
472+
GetNewObjectId(&temp_oid);
478473

479474
/* ----------------
480475
* If we are below prefetched limits, do nothing
@@ -488,7 +483,6 @@ CheckMaxObjectId(Oid assigned_oid)
488483
* If we are here, we are coming from a 'copy from' with oid's
489484
*
490485
* If we are in the prefetched oid range, just bump it up
491-
*
492486
* ----------------
493487
*/
494488

@@ -506,21 +500,19 @@ CheckMaxObjectId(Oid assigned_oid)
506500
* but we are loading oid's that we can not guarantee are unique
507501
* anyway, so we must rely on the user
508502
*
509-
*
510503
* We now:
511504
* set the variable relation with the new max oid
512505
* force the backend to reload its oid cache
513506
*
514-
* We use the oid cache so we don't have to update the variable
515-
* relation every time
516-
*
507+
* By reloading the oid cache, we don't have to update the variable
508+
* relation every time when sequential OIDs are being loaded by COPY.
517509
* ----------------
518510
*/
519511

520-
pass_oid = assigned_oid;
521-
VariableRelationPutNextOid(&pass_oid); /* not modified */
522-
prefetched_oid_count = 0; /* force reload */
523-
pass_oid = assigned_oid;
524-
GetNewObjectId(&pass_oid); /* throw away returned oid */
512+
SpinAcquire(OidGenLockId);
513+
VariableRelationPutNextOid(assigned_oid);
514+
SpinRelease(OidGenLockId);
525515

516+
prefetched_oid_count = 0; /* force reload */
517+
GetNewObjectId(&temp_oid); /* cause target OID to be allocated */
526518
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy