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 */
2222static void GetNewObjectIdBlock (Oid * oid_return ,int oid_block_size );
2323static void VariableRelationGetNextOid (Oid * oid_return );
2424static 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 */
3131int OidGenLockId ;
3232
33+ /* ---------------------
34+ *pointer to "variable cache" in shared memory (set up by shmem.c)
35+ * ---------------------
36+ */
3337VariableCache ShmemVariableCache = NULL ;
3438
39+
3540/* ----------------------------------------------------------------
3641 * variable relation query/update routines
3742 * ----------------------------------------------------------------
@@ -48,7 +53,7 @@ VariableRelationGetNextXid(TransactionId *xidP)
4853VariableRelationContents var ;
4954
5055/* ----------------
51- * We assume that a spinlock has beenacquire to guarantee
56+ * We assume that a spinlock has beenacquired to guarantee
5257 * exclusive access to the variable relation.
5358 * ----------------
5459 */
@@ -76,6 +81,7 @@ VariableRelationGetNextXid(TransactionId *xidP)
7681var = (VariableRelationContents )BufferGetBlock (buf );
7782
7883TransactionIdStore (var -> nextXidData ,xidP );
84+
7985ReleaseBuffer (buf );
8086}
8187
@@ -90,7 +96,7 @@ VariableRelationPutNextXid(TransactionId xid)
9096VariableRelationContents var ;
9197
9298/* ----------------
93- * We assume that a spinlock has beenacquire to guarantee
99+ * We assume that a spinlock has beenacquired to guarantee
94100 * exclusive access to the variable relation.
95101 * ----------------
96102 */
@@ -133,22 +139,20 @@ VariableRelationGetNextOid(Oid *oid_return)
133139VariableRelationContents var ;
134140
135141/* ----------------
136- * We assume that a spinlock has beenacquire to guarantee
142+ * We assume that a spinlock has beenacquired 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 */
148153if (!RelationIsValid (VariableRelation ))
149154{
150- if (PointerIsValid (oid_return ))
151- (* oid_return )= InvalidOid ;
155+ (* oid_return )= InvalidOid ;
152156return ;
153157}
154158
@@ -162,32 +166,12 @@ VariableRelationGetNextOid(Oid *oid_return)
162166if (!BufferIsValid (buf ))
163167{
164168SpinRelease (OidGenLockId );
165- elog (ERROR ,"VariableRelationGetNextXid : ReadBuffer failed" );
169+ elog (ERROR ,"VariableRelationGetNextOid : ReadBuffer failed" );
166170}
167171
168172var = (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
192176ReleaseBuffer (buf );
193177}
@@ -197,13 +181,13 @@ VariableRelationGetNextOid(Oid *oid_return)
197181 * --------------------------------
198182 */
199183static void
200- VariableRelationPutNextOid (Oid * oidP )
184+ VariableRelationPutNextOid (Oid oid )
201185{
202186Buffer buf ;
203187VariableRelationContents var ;
204188
205189/* ----------------
206- * We assume that a spinlock has beenacquire to guarantee
190+ * We assume that a spinlock has beenacquired to guarantee
207191 * exclusive access to the variable relation.
208192 * ----------------
209193 */
@@ -215,16 +199,6 @@ VariableRelationPutNextOid(Oid *oidP)
215199if (!RelationIsValid (VariableRelation ))
216200return ;
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
241215var = (VariableRelationContents )BufferGetBlock (buf );
242216
243- var -> nextOid = ( * oidP ) ;
217+ var -> nextOid = oid ;
244218
245219WriteBuffer (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 */
359332static void
360- GetNewObjectIdBlock (Oid * oid_return ,/* place to return thenew object
361- * id */
333+ GetNewObjectIdBlock (Oid * oid_return ,/* place to return thefirst new
334+ *object id */
362335int oid_block_size )/* number of oids desired */
363336{
337+ Oid firstfreeoid ;
364338Oid 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 */
371344SpinAcquire (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 */
395390SpinRelease (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 becauseif 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 */
431431int 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 */
441437if (!RelationIsValid (VariableRelation ))
@@ -469,12 +465,11 @@ GetNewObjectId(Oid *oid_return) /* place to return the new object id */
469465void
470466CheckMaxObjectId (Oid assigned_oid )
471467{
472- Oid pass_oid ;
473-
468+ Oid temp_oid ;
474469
475470if (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}