mirror of
https://github.com/postgres/postgres.git
synced 2025-11-10 17:42:29 +03:00
pgindent run. Make it all clean.
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.41 2001/01/24 19:43:05 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.42 2001/03/22 03:59:44 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -63,8 +63,8 @@ long *PrivateRefCount; /* also used in freelist.c */
|
||||
bits8 *BufferLocks; /* flag bits showing locks I have set */
|
||||
BufferTag *BufferTagLastDirtied; /* tag buffer had when last
|
||||
* dirtied by me */
|
||||
BufferBlindId *BufferBlindLastDirtied;
|
||||
bool *BufferDirtiedByMe; /* T if buf has been dirtied in cur xact */
|
||||
BufferBlindId *BufferBlindLastDirtied;
|
||||
bool *BufferDirtiedByMe; /* T if buf has been dirtied in cur xact */
|
||||
|
||||
|
||||
/*
|
||||
@@ -149,7 +149,8 @@ InitBufferPool(void)
|
||||
|
||||
/*
|
||||
* It's probably not really necessary to grab the lock --- if there's
|
||||
* anyone else attached to the shmem at this point, we've got problems.
|
||||
* anyone else attached to the shmem at this point, we've got
|
||||
* problems.
|
||||
*/
|
||||
SpinAcquire(BufMgrLock);
|
||||
|
||||
@@ -240,13 +241,11 @@ InitBufferPoolAccess(void)
|
||||
BufferDirtiedByMe = (bool *) calloc(NBuffers, sizeof(bool));
|
||||
|
||||
/*
|
||||
* Convert shmem offsets into addresses as seen by this process.
|
||||
* This is just to speed up the BufferGetBlock() macro.
|
||||
* Convert shmem offsets into addresses as seen by this process. This
|
||||
* is just to speed up the BufferGetBlock() macro.
|
||||
*/
|
||||
for (i = 0; i < NBuffers; i++)
|
||||
{
|
||||
BufferBlockPointers[i] = (Block) MAKE_PTR(BufferDescriptors[i].data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now that buffer access is initialized, set up a callback to shut it
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_table.c,v 1.20 2001/01/24 19:43:05 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_table.c,v 1.21 2001/03/22 03:59:44 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -123,8 +123,8 @@ BufTableDelete(BufferDesc *buf)
|
||||
/*
|
||||
* Clear the buffer's tag. This doesn't matter for the hash table,
|
||||
* since the buffer is already removed from it, but it ensures that
|
||||
* sequential searches through the buffer table won't think the
|
||||
* buffer is still valid for its old page.
|
||||
* sequential searches through the buffer table won't think the buffer
|
||||
* is still valid for its old page.
|
||||
*/
|
||||
buf->tag.rnode.relNode = InvalidOid;
|
||||
buf->tag.rnode.tblNode = InvalidOid;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.108 2001/03/21 10:13:29 vadim Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.109 2001/03/22 03:59:44 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -401,7 +401,7 @@ BufferAlloc(Relation reln,
|
||||
bool smok;
|
||||
|
||||
/*
|
||||
* skip write error buffers
|
||||
* skip write error buffers
|
||||
*/
|
||||
if ((buf->flags & BM_IO_ERROR) != 0)
|
||||
{
|
||||
@@ -409,6 +409,7 @@ BufferAlloc(Relation reln,
|
||||
buf = (BufferDesc *) NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set BM_IO_IN_PROGRESS to keep anyone from doing anything
|
||||
* with the contents of the buffer while we write it out. We
|
||||
@@ -453,6 +454,7 @@ BufferAlloc(Relation reln,
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* BM_JUST_DIRTIED cleared by BufferReplace and shouldn't
|
||||
* be setted by anyone. - vadim 01/17/97
|
||||
@@ -689,9 +691,7 @@ ReleaseAndReadBuffer(Buffer buffer,
|
||||
bufHdr = &BufferDescriptors[buffer - 1];
|
||||
Assert(PrivateRefCount[buffer - 1] > 0);
|
||||
if (PrivateRefCount[buffer - 1] > 1)
|
||||
{
|
||||
PrivateRefCount[buffer - 1]--;
|
||||
}
|
||||
else
|
||||
{
|
||||
SpinAcquire(BufMgrLock);
|
||||
@@ -724,7 +724,7 @@ BufferSync()
|
||||
BufferDesc *bufHdr;
|
||||
Buffer buffer;
|
||||
int status;
|
||||
RelFileNode rnode;
|
||||
RelFileNode rnode;
|
||||
XLogRecPtr recptr;
|
||||
Relation reln = NULL;
|
||||
|
||||
@@ -754,8 +754,8 @@ BufferSync()
|
||||
}
|
||||
|
||||
/*
|
||||
* IO synchronization. Note that we do it with unpinned buffer
|
||||
* to avoid conflicts with FlushRelationBuffers.
|
||||
* IO synchronization. Note that we do it with unpinned buffer to
|
||||
* avoid conflicts with FlushRelationBuffers.
|
||||
*/
|
||||
if (bufHdr->flags & BM_IO_IN_PROGRESS)
|
||||
{
|
||||
@@ -769,12 +769,12 @@ BufferSync()
|
||||
}
|
||||
|
||||
/*
|
||||
* Here: no one doing IO for this buffer and it's dirty.
|
||||
* Pin buffer now and set IO state for it *before* acquiring
|
||||
* shlock to avoid conflicts with FlushRelationBuffers.
|
||||
* Here: no one doing IO for this buffer and it's dirty. Pin
|
||||
* buffer now and set IO state for it *before* acquiring shlock to
|
||||
* avoid conflicts with FlushRelationBuffers.
|
||||
*/
|
||||
PinBuffer(bufHdr);
|
||||
StartBufferIO(bufHdr, false); /* output IO start */
|
||||
StartBufferIO(bufHdr, false); /* output IO start */
|
||||
|
||||
buffer = BufferDescriptorGetBuffer(bufHdr);
|
||||
rnode = bufHdr->tag.rnode;
|
||||
@@ -810,16 +810,16 @@ BufferSync()
|
||||
if (reln == (Relation) NULL)
|
||||
{
|
||||
status = smgrblindwrt(DEFAULT_SMGR,
|
||||
bufHdr->tag.rnode,
|
||||
bufHdr->tag.blockNum,
|
||||
(char *) MAKE_PTR(bufHdr->data),
|
||||
true); /* must fsync */
|
||||
bufHdr->tag.rnode,
|
||||
bufHdr->tag.blockNum,
|
||||
(char *) MAKE_PTR(bufHdr->data),
|
||||
true); /* must fsync */
|
||||
}
|
||||
else
|
||||
{
|
||||
status = smgrwrite(DEFAULT_SMGR, reln,
|
||||
bufHdr->tag.blockNum,
|
||||
(char *) MAKE_PTR(bufHdr->data));
|
||||
bufHdr->tag.blockNum,
|
||||
(char *) MAKE_PTR(bufHdr->data));
|
||||
}
|
||||
|
||||
if (status == SM_FAIL) /* disk failure ?! */
|
||||
@@ -827,9 +827,9 @@ BufferSync()
|
||||
bufHdr->tag.blockNum, bufHdr->blind.relname);
|
||||
|
||||
/*
|
||||
* Note that it's safe to change cntxDirty here because of
|
||||
* we protect it from upper writers by share lock and from
|
||||
* other bufmgr routines by BM_IO_IN_PROGRESS
|
||||
* Note that it's safe to change cntxDirty here because of we
|
||||
* protect it from upper writers by share lock and from other
|
||||
* bufmgr routines by BM_IO_IN_PROGRESS
|
||||
*/
|
||||
bufHdr->cntxDirty = false;
|
||||
|
||||
@@ -842,12 +842,11 @@ BufferSync()
|
||||
SpinAcquire(BufMgrLock);
|
||||
|
||||
bufHdr->flags &= ~BM_IO_IN_PROGRESS; /* mark IO finished */
|
||||
TerminateBufferIO(bufHdr); /* Sync IO finished */
|
||||
TerminateBufferIO(bufHdr); /* Sync IO finished */
|
||||
|
||||
/*
|
||||
* If this buffer was marked by someone as DIRTY while
|
||||
* we were flushing it out we must not clear DIRTY
|
||||
* flag - vadim 01/17/97
|
||||
* If this buffer was marked by someone as DIRTY while we were
|
||||
* flushing it out we must not clear DIRTY flag - vadim 01/17/97
|
||||
*/
|
||||
if (!(bufHdr->flags & BM_JUST_DIRTIED))
|
||||
bufHdr->flags &= ~BM_DIRTY;
|
||||
@@ -1020,6 +1019,7 @@ void
|
||||
BufmgrCommit(void)
|
||||
{
|
||||
LocalBufferSync();
|
||||
|
||||
/*
|
||||
* All files created in current transaction will be fsync-ed
|
||||
*/
|
||||
@@ -1065,8 +1065,8 @@ BufferReplace(BufferDesc *bufHdr)
|
||||
SpinRelease(BufMgrLock);
|
||||
|
||||
/*
|
||||
* No need to lock buffer context - no one should be able to
|
||||
* end ReadBuffer
|
||||
* No need to lock buffer context - no one should be able to end
|
||||
* ReadBuffer
|
||||
*/
|
||||
recptr = BufferGetLSN(bufHdr);
|
||||
XLogFlush(recptr);
|
||||
@@ -1113,8 +1113,8 @@ BlockNumber
|
||||
RelationGetNumberOfBlocks(Relation relation)
|
||||
{
|
||||
return ((relation->rd_myxactonly) ? relation->rd_nblocks :
|
||||
((relation->rd_rel->relkind == RELKIND_VIEW) ? 0 :
|
||||
smgrnblocks(DEFAULT_SMGR, relation)));
|
||||
((relation->rd_rel->relkind == RELKIND_VIEW) ? 0 :
|
||||
smgrnblocks(DEFAULT_SMGR, relation)));
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
@@ -1122,7 +1122,7 @@ RelationGetNumberOfBlocks(Relation relation)
|
||||
*
|
||||
* This function removes all the buffered pages for a relation
|
||||
* from the buffer pool. Dirty pages are simply dropped, without
|
||||
* bothering to write them out first. This is NOT rollback-able,
|
||||
* bothering to write them out first. This is NOT rollback-able,
|
||||
* and so should be used only with extreme caution!
|
||||
*
|
||||
* We assume that the caller holds an exclusive lock on the relation,
|
||||
@@ -1196,6 +1196,7 @@ recheck:
|
||||
bufHdr->refcount == 1);
|
||||
ReleaseBufferWithBufferLock(i);
|
||||
}
|
||||
|
||||
/*
|
||||
* And mark the buffer as no longer occupied by this rel.
|
||||
*/
|
||||
@@ -1212,7 +1213,7 @@ recheck:
|
||||
* This is the same as DropRelationBuffers, except that the target
|
||||
* relation is specified by RelFileNode.
|
||||
*
|
||||
* This is NOT rollback-able. One legitimate use is to clear the
|
||||
* This is NOT rollback-able. One legitimate use is to clear the
|
||||
* buffer cache of buffers for a relation that is being deleted
|
||||
* during transaction abort.
|
||||
* --------------------------------------------------------------------
|
||||
@@ -1278,6 +1279,7 @@ recheck:
|
||||
bufHdr->refcount == 1);
|
||||
ReleaseBufferWithBufferLock(i);
|
||||
}
|
||||
|
||||
/*
|
||||
* And mark the buffer as no longer occupied by this rel.
|
||||
*/
|
||||
@@ -1293,7 +1295,7 @@ recheck:
|
||||
*
|
||||
* This function removes all the buffers in the buffer cache for a
|
||||
* particular database. Dirty pages are simply dropped, without
|
||||
* bothering to write them out first. This is used when we destroy a
|
||||
* bothering to write them out first. This is used when we destroy a
|
||||
* database, to avoid trying to flush data to disk when the directory
|
||||
* tree no longer exists. Implementation is pretty similar to
|
||||
* DropRelationBuffers() which is for destroying just one relation.
|
||||
@@ -1310,10 +1312,11 @@ DropBuffers(Oid dbid)
|
||||
{
|
||||
bufHdr = &BufferDescriptors[i - 1];
|
||||
recheck:
|
||||
|
||||
/*
|
||||
* We know that currently database OID is tblNode but
|
||||
* this probably will be changed in future and this
|
||||
* func will be used to drop tablespace buffers.
|
||||
* We know that currently database OID is tblNode but this
|
||||
* probably will be changed in future and this func will be used
|
||||
* to drop tablespace buffers.
|
||||
*/
|
||||
if (bufHdr->tag.rnode.tblNode == dbid)
|
||||
{
|
||||
@@ -1342,6 +1345,7 @@ recheck:
|
||||
* backends are running in that database.
|
||||
*/
|
||||
Assert(bufHdr->flags & BM_FREE);
|
||||
|
||||
/*
|
||||
* And mark the buffer as no longer occupied by this page.
|
||||
*/
|
||||
@@ -1383,8 +1387,8 @@ blockNum=%d, flags=0x%x, refcount=%d %ld)",
|
||||
for (i = 0; i < NBuffers; ++i, ++buf)
|
||||
{
|
||||
printf("[%-2d] (%s, %d) flags=0x%x, refcnt=%d %ld)\n",
|
||||
i, buf->blind.relname, buf->tag.blockNum,
|
||||
buf->flags, buf->refcount, PrivateRefCount[i]);
|
||||
i, buf->blind.relname, buf->tag.blockNum,
|
||||
buf->flags, buf->refcount, PrivateRefCount[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1441,7 +1445,7 @@ BufferPoolBlowaway()
|
||||
*
|
||||
* This function writes all dirty pages of a relation out to disk.
|
||||
* Furthermore, pages that have blocknumber >= firstDelBlock are
|
||||
* actually removed from the buffer pool. An error code is returned
|
||||
* actually removed from the buffer pool. An error code is returned
|
||||
* if we fail to dump a dirty buffer or if we find one of
|
||||
* the target pages is pinned into the cache.
|
||||
*
|
||||
@@ -1495,15 +1499,15 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock)
|
||||
{
|
||||
if (bufHdr->flags & BM_DIRTY || bufHdr->cntxDirty)
|
||||
{
|
||||
status = smgrwrite(DEFAULT_SMGR, rel,
|
||||
bufHdr->tag.blockNum,
|
||||
(char *) MAKE_PTR(bufHdr->data));
|
||||
status = smgrwrite(DEFAULT_SMGR, rel,
|
||||
bufHdr->tag.blockNum,
|
||||
(char *) MAKE_PTR(bufHdr->data));
|
||||
if (status == SM_FAIL)
|
||||
{
|
||||
elog(NOTICE, "FlushRelationBuffers(%s (local), %u): block %u is dirty, could not flush it",
|
||||
RelationGetRelationName(rel), firstDelBlock,
|
||||
bufHdr->tag.blockNum);
|
||||
return(-1);
|
||||
return (-1);
|
||||
}
|
||||
bufHdr->flags &= ~(BM_DIRTY | BM_JUST_DIRTIED);
|
||||
bufHdr->cntxDirty = false;
|
||||
@@ -1513,12 +1517,10 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock)
|
||||
elog(NOTICE, "FlushRelationBuffers(%s (local), %u): block %u is referenced (%ld)",
|
||||
RelationGetRelationName(rel), firstDelBlock,
|
||||
bufHdr->tag.blockNum, LocalRefCount[i]);
|
||||
return(-2);
|
||||
return (-2);
|
||||
}
|
||||
if (bufHdr->tag.blockNum >= firstDelBlock)
|
||||
{
|
||||
bufHdr->tag.rnode.relNode = InvalidOid;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -1559,10 +1561,10 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock)
|
||||
SpinRelease(BufMgrLock);
|
||||
|
||||
status = smgrwrite(DEFAULT_SMGR, rel,
|
||||
bufHdr->tag.blockNum,
|
||||
(char *) MAKE_PTR(bufHdr->data));
|
||||
bufHdr->tag.blockNum,
|
||||
(char *) MAKE_PTR(bufHdr->data));
|
||||
|
||||
if (status == SM_FAIL) /* disk failure ?! */
|
||||
if (status == SM_FAIL) /* disk failure ?! */
|
||||
elog(STOP, "FlushRelationBuffers: cannot write %u for %s",
|
||||
bufHdr->tag.blockNum, bufHdr->blind.relname);
|
||||
|
||||
@@ -1573,9 +1575,10 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock)
|
||||
TerminateBufferIO(bufHdr);
|
||||
Assert(!(bufHdr->flags & BM_JUST_DIRTIED));
|
||||
bufHdr->flags &= ~BM_DIRTY;
|
||||
|
||||
/*
|
||||
* Note that it's safe to change cntxDirty here because
|
||||
* of we protect it from upper writers by
|
||||
* Note that it's safe to change cntxDirty here
|
||||
* because of we protect it from upper writers by
|
||||
* AccessExclusiveLock and from other bufmgr routines
|
||||
* by BM_IO_IN_PROGRESS
|
||||
*/
|
||||
@@ -1593,9 +1596,7 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock)
|
||||
return -2;
|
||||
}
|
||||
if (bufHdr->tag.blockNum >= firstDelBlock)
|
||||
{
|
||||
BufTableDelete(bufHdr);
|
||||
}
|
||||
}
|
||||
}
|
||||
SpinRelease(BufMgrLock);
|
||||
@@ -1628,9 +1629,7 @@ ReleaseBuffer(Buffer buffer)
|
||||
|
||||
Assert(PrivateRefCount[buffer - 1] > 0);
|
||||
if (PrivateRefCount[buffer - 1] > 1)
|
||||
{
|
||||
PrivateRefCount[buffer - 1]--;
|
||||
}
|
||||
else
|
||||
{
|
||||
SpinAcquire(BufMgrLock);
|
||||
@@ -1671,9 +1670,7 @@ ReleaseBufferWithBufferLock(Buffer buffer)
|
||||
|
||||
Assert(PrivateRefCount[buffer - 1] > 0);
|
||||
if (PrivateRefCount[buffer - 1] > 1)
|
||||
{
|
||||
PrivateRefCount[buffer - 1]--;
|
||||
}
|
||||
else
|
||||
{
|
||||
PrivateRefCount[buffer - 1] = 0;
|
||||
@@ -2084,8 +2081,8 @@ LockBuffer(Buffer buffer, int mode)
|
||||
*buflock |= BL_W_LOCK;
|
||||
|
||||
/*
|
||||
* This is not the best place to set cntxDirty flag (eg indices
|
||||
* do not always change buffer they lock in excl mode). But please
|
||||
* This is not the best place to set cntxDirty flag (eg indices do
|
||||
* not always change buffer they lock in excl mode). But please
|
||||
* remember that it's critical to set cntxDirty *before* logging
|
||||
* changes with XLogInsert() - see comments in BufferSync().
|
||||
*/
|
||||
@@ -2200,6 +2197,7 @@ InitBufferIO(void)
|
||||
{
|
||||
InProgressBuf = (BufferDesc *) 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -2245,7 +2243,7 @@ AbortBufferIO(void)
|
||||
* NOTE: buffer must be excl locked.
|
||||
*/
|
||||
void
|
||||
MarkBufferForCleanup(Buffer buffer, void (*CleanupFunc)(Buffer))
|
||||
MarkBufferForCleanup(Buffer buffer, void (*CleanupFunc) (Buffer))
|
||||
{
|
||||
BufferDesc *bufHdr = &BufferDescriptors[buffer - 1];
|
||||
|
||||
@@ -2301,5 +2299,5 @@ BufferGetFileNode(Buffer buffer)
|
||||
else
|
||||
bufHdr = &BufferDescriptors[buffer - 1];
|
||||
|
||||
return(bufHdr->tag.rnode);
|
||||
return (bufHdr->tag.rnode);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/localbuf.c,v 1.39 2001/01/24 19:43:06 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/localbuf.c,v 1.40 2001/03/22 03:59:44 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -63,7 +63,7 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
|
||||
/* a low tech search for now -- not optimized for scans */
|
||||
for (i = 0; i < NLocBuffer; i++)
|
||||
{
|
||||
if (LocalBufferDescriptors[i].tag.rnode.relNode ==
|
||||
if (LocalBufferDescriptors[i].tag.rnode.relNode ==
|
||||
reln->rd_node.relNode &&
|
||||
LocalBufferDescriptors[i].tag.blockNum == blockNum)
|
||||
{
|
||||
@@ -125,8 +125,8 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
|
||||
/*
|
||||
* it's all ours now.
|
||||
*
|
||||
* We need not in tblNode currently but will in future I think,
|
||||
* when we'll give up rel->rd_fd to fmgr cache.
|
||||
* We need not in tblNode currently but will in future I think, when
|
||||
* we'll give up rel->rd_fd to fmgr cache.
|
||||
*/
|
||||
bufHdr->tag.rnode = reln->rd_node;
|
||||
bufHdr->tag.blockNum = blockNum;
|
||||
@@ -142,12 +142,14 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
|
||||
|
||||
if (data == NULL)
|
||||
elog(FATAL, "Out of memory in LocalBufferAlloc");
|
||||
|
||||
/*
|
||||
* This is a bit of a hack: bufHdr->data needs to be a shmem offset
|
||||
* for consistency with the shared-buffer case, so make it one
|
||||
* even though it's not really a valid shmem offset.
|
||||
* This is a bit of a hack: bufHdr->data needs to be a shmem
|
||||
* offset for consistency with the shared-buffer case, so make it
|
||||
* one even though it's not really a valid shmem offset.
|
||||
*/
|
||||
bufHdr->data = MAKE_OFFSET(data);
|
||||
|
||||
/*
|
||||
* Set pointer for use by BufferGetBlock() macro.
|
||||
*/
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/Attic/s_lock.c,v 1.34 2001/02/24 22:42:45 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/Attic/s_lock.c,v 1.35 2001/03/22 03:59:44 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -43,16 +43,16 @@
|
||||
#define S_NSPINCYCLE 20
|
||||
|
||||
int s_spincycle[S_NSPINCYCLE] =
|
||||
{ 1, 10, 100, 1000,
|
||||
10000, 1000, 1000, 1000,
|
||||
10000, 1000, 1000, 10000,
|
||||
1000, 1000, 10000, 1000,
|
||||
10000, 1000, 10000, 30000
|
||||
{1, 10, 100, 1000,
|
||||
10000, 1000, 1000, 1000,
|
||||
10000, 1000, 1000, 10000,
|
||||
1000, 1000, 10000, 1000,
|
||||
10000, 1000, 10000, 30000
|
||||
};
|
||||
|
||||
#define AVG_SPINCYCLE 5000 /* average entry in microsec: 100ms / 20 */
|
||||
|
||||
#define DEFAULT_TIMEOUT (100*1000000) /* default timeout: 100 sec */
|
||||
#define DEFAULT_TIMEOUT (100*1000000) /* default timeout: 100 sec */
|
||||
|
||||
|
||||
/*
|
||||
@@ -74,10 +74,10 @@ s_lock_stuck(volatile slock_t *lock, const char *file, const int line)
|
||||
/*
|
||||
* s_lock_sleep() - sleep a pseudo-random amount of time, check for timeout
|
||||
*
|
||||
* The 'timeout' is given in microsec, or may be 0 for "infinity". Note that
|
||||
* The 'timeout' is given in microsec, or may be 0 for "infinity". Note that
|
||||
* this will be a lower bound (a fairly loose lower bound, on most platforms).
|
||||
*
|
||||
* 'microsec' is the number of microsec to delay per loop. Normally
|
||||
* 'microsec' is the number of microsec to delay per loop. Normally
|
||||
* 'microsec' is 0, specifying to use the next s_spincycle[] value.
|
||||
* Some callers may pass a nonzero interval, specifying to use exactly that
|
||||
* delay value rather than a pseudo-random delay.
|
||||
@@ -98,7 +98,7 @@ s_lock_sleep(unsigned spins, int timeout, int microsec,
|
||||
{
|
||||
delay.tv_sec = 0;
|
||||
delay.tv_usec = s_spincycle[spins % S_NSPINCYCLE];
|
||||
microsec = AVG_SPINCYCLE; /* use average to figure timeout */
|
||||
microsec = AVG_SPINCYCLE; /* use average to figure timeout */
|
||||
}
|
||||
|
||||
if (timeout > 0)
|
||||
@@ -125,10 +125,11 @@ s_lock(volatile slock_t *lock, const char *file, const int line)
|
||||
* If you are thinking of changing this code, be careful. This same
|
||||
* loop logic is used in other places that call TAS() directly.
|
||||
*
|
||||
* While waiting for a lock, we check for cancel/die interrupts (which
|
||||
* is a no-op if we are inside a critical section). The interrupt check
|
||||
* can be omitted in places that know they are inside a critical section.
|
||||
* Note that an interrupt must NOT be accepted after acquiring the lock.
|
||||
* While waiting for a lock, we check for cancel/die interrupts (which is
|
||||
* a no-op if we are inside a critical section). The interrupt check
|
||||
* can be omitted in places that know they are inside a critical
|
||||
* section. Note that an interrupt must NOT be accepted after
|
||||
* acquiring the lock.
|
||||
*/
|
||||
while (TAS(lock))
|
||||
{
|
||||
@@ -155,8 +156,8 @@ static void
|
||||
tas_dummy() /* really means: extern int tas(slock_t
|
||||
* **lock); */
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
"\
|
||||
__asm__ __volatile__(
|
||||
"\
|
||||
.global _tas \n\
|
||||
_tas: \n\
|
||||
movel sp@(0x4),a0 \n\
|
||||
@@ -180,8 +181,8 @@ _success: \n\
|
||||
static void
|
||||
tas_dummy()
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
"\
|
||||
__asm__ __volatile__(
|
||||
"\
|
||||
.globl tas \n\
|
||||
.globl _tas \n\
|
||||
_tas: \n\
|
||||
@@ -200,15 +201,15 @@ success: \n\
|
||||
");
|
||||
}
|
||||
|
||||
#endif /* __APPLE__ && __ppc__ */
|
||||
#endif /* __APPLE__ && __ppc__ */
|
||||
|
||||
#if defined(__powerpc__)
|
||||
/* Note: need a nice gcc constrained asm version so it can be inlined */
|
||||
static void
|
||||
tas_dummy()
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
"\
|
||||
__asm__ __volatile__(
|
||||
"\
|
||||
.global tas \n\
|
||||
tas: \n\
|
||||
lwarx 5,0,3 \n\
|
||||
@@ -231,8 +232,8 @@ success: \n\
|
||||
static void
|
||||
tas_dummy()
|
||||
{
|
||||
__asm__ _volatile__(
|
||||
"\
|
||||
__asm__ _volatile__(
|
||||
"\
|
||||
.global tas \n\
|
||||
tas: \n\
|
||||
.frame $sp, 0, $31 \n\
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/file/buffile.c,v 1.9 2001/01/24 19:43:06 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/file/buffile.c,v 1.10 2001/03/22 03:59:45 momjian Exp $
|
||||
*
|
||||
* NOTES:
|
||||
*
|
||||
@@ -163,6 +163,7 @@ BufFileCreate(File file)
|
||||
{
|
||||
return makeBufFile(file);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -574,5 +575,5 @@ BufFileTellBlock(BufFile *file)
|
||||
blknum += file->curFile * RELSEG_SIZE;
|
||||
return blknum;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/file/fd.c,v 1.73 2001/02/18 04:39:42 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/file/fd.c,v 1.74 2001/03/22 03:59:45 momjian Exp $
|
||||
*
|
||||
* NOTES:
|
||||
*
|
||||
@@ -243,7 +243,7 @@ pg_fdatasync(int fd)
|
||||
int
|
||||
BasicOpenFile(FileName fileName, int fileFlags, int fileMode)
|
||||
{
|
||||
int fd;
|
||||
int fd;
|
||||
|
||||
tryAgain:
|
||||
fd = open(fileName, fileFlags, fileMode);
|
||||
@@ -253,7 +253,7 @@ tryAgain:
|
||||
|
||||
if (errno == EMFILE || errno == ENFILE)
|
||||
{
|
||||
int save_errno = errno;
|
||||
int save_errno = errno;
|
||||
|
||||
DO_DB(elog(DEBUG, "BasicOpenFile: not enough descs, retry, er= %d",
|
||||
errno));
|
||||
@@ -414,7 +414,7 @@ LruInsert(File file)
|
||||
{
|
||||
while (nfile + numAllocatedFiles >= pg_nofile())
|
||||
{
|
||||
if (! ReleaseLruFile())
|
||||
if (!ReleaseLruFile())
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -460,6 +460,7 @@ ReleaseLruFile(void)
|
||||
|
||||
if (nfile > 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* There are opened files and so there should be at least one used
|
||||
* vfd in the ring.
|
||||
@@ -660,7 +661,7 @@ fileNameOpenFile(FileName fileName,
|
||||
|
||||
while (nfile + numAllocatedFiles >= pg_nofile())
|
||||
{
|
||||
if (! ReleaseLruFile())
|
||||
if (!ReleaseLruFile())
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -683,9 +684,10 @@ fileNameOpenFile(FileName fileName,
|
||||
vfdP->fileFlags = fileFlags & ~(O_TRUNC | O_EXCL);
|
||||
vfdP->fileMode = fileMode;
|
||||
vfdP->seekPos = 0;
|
||||
|
||||
/*
|
||||
* Have to fsync file on commit. Alternative way - log
|
||||
* file creation and fsync log before actual file creation.
|
||||
* Have to fsync file on commit. Alternative way - log file creation
|
||||
* and fsync log before actual file creation.
|
||||
*/
|
||||
if (fileFlags & O_CREAT)
|
||||
vfdP->fdstate = FD_DIRTY;
|
||||
@@ -1083,7 +1085,7 @@ TryAgain:
|
||||
|
||||
if (errno == EMFILE || errno == ENFILE)
|
||||
{
|
||||
int save_errno = errno;
|
||||
int save_errno = errno;
|
||||
|
||||
DO_DB(elog(DEBUG, "AllocateFile: not enough descs, retry, er= %d",
|
||||
errno));
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipc.c,v 1.63 2001/03/13 01:17:06 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipc.c,v 1.64 2001/03/22 03:59:45 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
*
|
||||
@@ -71,7 +71,7 @@ static IpcSemaphoreId InternalIpcSemaphoreCreate(IpcSemaphoreKey semKey,
|
||||
int semStartValue, bool removeOnExit);
|
||||
static void CallbackSemaphoreKill(int status, Datum semId);
|
||||
static void *InternalIpcMemoryCreate(IpcMemoryKey memKey, uint32 size,
|
||||
int permission);
|
||||
int permission);
|
||||
static void IpcMemoryDetach(int status, Datum shmaddr);
|
||||
static void IpcMemoryDelete(int status, Datum shmId);
|
||||
static void *PrivateMemoryCreate(uint32 size);
|
||||
@@ -101,6 +101,7 @@ static struct ONEXIT
|
||||
void (*function) ();
|
||||
Datum arg;
|
||||
} on_proc_exit_list[MAX_ON_EXITS],
|
||||
|
||||
on_shmem_exit_list[MAX_ON_EXITS];
|
||||
|
||||
static int on_proc_exit_index,
|
||||
@@ -127,9 +128,9 @@ proc_exit(int code)
|
||||
proc_exit_inprogress = true;
|
||||
|
||||
/*
|
||||
* Forget any pending cancel or die requests; we're doing our best
|
||||
* to close up shop already. Note that the signal handlers will not
|
||||
* set these flags again, now that proc_exit_inprogress is set.
|
||||
* Forget any pending cancel or die requests; we're doing our best to
|
||||
* close up shop already. Note that the signal handlers will not set
|
||||
* these flags again, now that proc_exit_inprogress is set.
|
||||
*/
|
||||
InterruptPending = false;
|
||||
ProcDiePending = false;
|
||||
@@ -198,7 +199,7 @@ shmem_exit(int code)
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
on_proc_exit(void (*function) (), Datum arg)
|
||||
on_proc_exit(void (*function) (), Datum arg)
|
||||
{
|
||||
if (on_proc_exit_index >= MAX_ON_EXITS)
|
||||
elog(FATAL, "Out of on_proc_exit slots");
|
||||
@@ -217,7 +218,7 @@ on_proc_exit(void (*function) (), Datum arg)
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
on_shmem_exit(void (*function) (), Datum arg)
|
||||
on_shmem_exit(void (*function) (), Datum arg)
|
||||
{
|
||||
if (on_shmem_exit_index >= MAX_ON_EXITS)
|
||||
elog(FATAL, "Out of on_shmem_exit slots");
|
||||
@@ -282,11 +283,13 @@ InternalIpcSemaphoreCreate(IpcSemaphoreKey semKey,
|
||||
|
||||
if (semId < 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* Fail quietly if error indicates a collision with existing set.
|
||||
* One would expect EEXIST, given that we said IPC_EXCL, but perhaps
|
||||
* we could get a permission violation instead? Also, EIDRM might
|
||||
* occur if an old set is slated for destruction but not gone yet.
|
||||
* One would expect EEXIST, given that we said IPC_EXCL, but
|
||||
* perhaps we could get a permission violation instead? Also,
|
||||
* EIDRM might occur if an old set is slated for destruction but
|
||||
* not gone yet.
|
||||
*/
|
||||
if (errno == EEXIST || errno == EACCES
|
||||
#ifdef EIDRM
|
||||
@@ -294,11 +297,12 @@ InternalIpcSemaphoreCreate(IpcSemaphoreKey semKey,
|
||||
#endif
|
||||
)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Else complain and abort
|
||||
*/
|
||||
fprintf(stderr, "IpcSemaphoreCreate: semget(key=%d, num=%d, 0%o) failed: %s\n",
|
||||
(int) semKey, numSems, (IPC_CREAT|IPC_EXCL|permission),
|
||||
(int) semKey, numSems, (IPC_CREAT | IPC_EXCL | permission),
|
||||
strerror(errno));
|
||||
|
||||
if (errno == ENOSPC)
|
||||
@@ -325,7 +329,7 @@ InternalIpcSemaphoreCreate(IpcSemaphoreKey semKey,
|
||||
if (errno == ERANGE)
|
||||
fprintf(stderr,
|
||||
"You possibly need to raise your kernel's SEMVMX value to be at least\n"
|
||||
"%d. Look into the PostgreSQL documentation for details.\n",
|
||||
"%d. Look into the PostgreSQL documentation for details.\n",
|
||||
semStartValue);
|
||||
|
||||
IpcSemaphoreKill(semId);
|
||||
@@ -348,12 +352,14 @@ IpcSemaphoreKill(IpcSemaphoreId semId)
|
||||
{
|
||||
union semun semun;
|
||||
|
||||
semun.val = 0; /* unused, but keep compiler quiet */
|
||||
semun.val = 0; /* unused, but keep compiler quiet */
|
||||
|
||||
if (semctl(semId, 0, IPC_RMID, semun) < 0)
|
||||
fprintf(stderr, "IpcSemaphoreKill: semctl(%d, 0, IPC_RMID, ...) failed: %s\n",
|
||||
semId, strerror(errno));
|
||||
/* We used to report a failure via elog(NOTICE), but that's pretty
|
||||
|
||||
/*
|
||||
* We used to report a failure via elog(NOTICE), but that's pretty
|
||||
* pointless considering any client has long since disconnected ...
|
||||
*/
|
||||
}
|
||||
@@ -393,13 +399,13 @@ IpcSemaphoreLock(IpcSemaphoreId semId, int sem, bool interruptOK)
|
||||
* section already).
|
||||
*
|
||||
* Once we acquire the lock, we do NOT check for an interrupt before
|
||||
* returning. The caller needs to be able to record ownership of
|
||||
* returning. The caller needs to be able to record ownership of
|
||||
* the lock before any interrupt can be accepted.
|
||||
*
|
||||
* There is a window of a few instructions between CHECK_FOR_INTERRUPTS
|
||||
* and entering the semop() call. If a cancel/die interrupt occurs in
|
||||
* and entering the semop() call. If a cancel/die interrupt occurs in
|
||||
* that window, we would fail to notice it until after we acquire the
|
||||
* lock (or get another interrupt to escape the semop()). We can avoid
|
||||
* lock (or get another interrupt to escape the semop()). We can avoid
|
||||
* this problem by temporarily setting ImmediateInterruptOK = true
|
||||
* before we do CHECK_FOR_INTERRUPTS; then, a die() interrupt in this
|
||||
* interval will execute directly. However, there is a huge pitfall:
|
||||
@@ -426,7 +432,7 @@ IpcSemaphoreLock(IpcSemaphoreId semId, int sem, bool interruptOK)
|
||||
|
||||
if (errStatus == -1)
|
||||
{
|
||||
fprintf(stderr, "IpcSemaphoreLock: semop(id=%d) failed: %s\n",
|
||||
fprintf(stderr, "IpcSemaphoreLock: semop(id=%d) failed: %s\n",
|
||||
semId, strerror(errno));
|
||||
proc_exit(255);
|
||||
}
|
||||
@@ -503,7 +509,7 @@ IpcSemaphoreTryLock(IpcSemaphoreId semId, int sem)
|
||||
return false; /* failed to lock it */
|
||||
#endif
|
||||
/* Otherwise we got trouble */
|
||||
fprintf(stderr, "IpcSemaphoreTryLock: semop(id=%d) failed: %s\n",
|
||||
fprintf(stderr, "IpcSemaphoreTryLock: semop(id=%d) failed: %s\n",
|
||||
semId, strerror(errno));
|
||||
proc_exit(255);
|
||||
}
|
||||
@@ -516,7 +522,8 @@ int
|
||||
IpcSemaphoreGetValue(IpcSemaphoreId semId, int sem)
|
||||
{
|
||||
union semun dummy; /* for Solaris */
|
||||
dummy.val = 0; /* unused */
|
||||
|
||||
dummy.val = 0; /* unused */
|
||||
|
||||
return semctl(semId, sem, GETVAL, dummy);
|
||||
}
|
||||
@@ -526,7 +533,8 @@ static pid_t
|
||||
IpcSemaphoreGetLastPID(IpcSemaphoreId semId, int sem)
|
||||
{
|
||||
union semun dummy; /* for Solaris */
|
||||
dummy.val = 0; /* unused */
|
||||
|
||||
dummy.val = 0; /* unused */
|
||||
|
||||
return semctl(semId, sem, GETPID, dummy);
|
||||
}
|
||||
@@ -563,11 +571,13 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, uint32 size, int permission)
|
||||
|
||||
if (shmid < 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* Fail quietly if error indicates a collision with existing segment.
|
||||
* One would expect EEXIST, given that we said IPC_EXCL, but perhaps
|
||||
* we could get a permission violation instead? Also, EIDRM might
|
||||
* occur if an old seg is slated for destruction but not gone yet.
|
||||
* Fail quietly if error indicates a collision with existing
|
||||
* segment. One would expect EEXIST, given that we said IPC_EXCL,
|
||||
* but perhaps we could get a permission violation instead? Also,
|
||||
* EIDRM might occur if an old seg is slated for destruction but
|
||||
* not gone yet.
|
||||
*/
|
||||
if (errno == EEXIST || errno == EACCES
|
||||
#ifdef EIDRM
|
||||
@@ -575,6 +585,7 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, uint32 size, int permission)
|
||||
#endif
|
||||
)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Else complain and abort
|
||||
*/
|
||||
@@ -584,7 +595,7 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, uint32 size, int permission)
|
||||
|
||||
if (errno == EINVAL)
|
||||
fprintf(stderr,
|
||||
"\nThis error can be caused by one of three things:\n\n"
|
||||
"\nThis error can be caused by one of three things:\n\n"
|
||||
"1. The maximum size for shared memory segments on your system was\n"
|
||||
" exceeded. You need to raise the SHMMAX parameter in your kernel\n"
|
||||
" to be at least %u bytes.\n\n"
|
||||
@@ -618,7 +629,7 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, uint32 size, int permission)
|
||||
|
||||
if (memAddress == (void *) -1)
|
||||
{
|
||||
fprintf(stderr, "IpcMemoryCreate: shmat(id=%d) failed: %s\n",
|
||||
fprintf(stderr, "IpcMemoryCreate: shmat(id=%d) failed: %s\n",
|
||||
shmid, strerror(errno));
|
||||
proc_exit(1);
|
||||
}
|
||||
@@ -643,7 +654,9 @@ IpcMemoryDetach(int status, Datum shmaddr)
|
||||
if (shmdt(DatumGetPointer(shmaddr)) < 0)
|
||||
fprintf(stderr, "IpcMemoryDetach: shmdt(%p) failed: %s\n",
|
||||
DatumGetPointer(shmaddr), strerror(errno));
|
||||
/* We used to report a failure via elog(NOTICE), but that's pretty
|
||||
|
||||
/*
|
||||
* We used to report a failure via elog(NOTICE), but that's pretty
|
||||
* pointless considering any client has long since disconnected ...
|
||||
*/
|
||||
}
|
||||
@@ -658,7 +671,9 @@ IpcMemoryDelete(int status, Datum shmId)
|
||||
if (shmctl(DatumGetInt32(shmId), IPC_RMID, (struct shmid_ds *) NULL) < 0)
|
||||
fprintf(stderr, "IpcMemoryDelete: shmctl(%d, %d, 0) failed: %s\n",
|
||||
DatumGetInt32(shmId), IPC_RMID, strerror(errno));
|
||||
/* We used to report a failure via elog(NOTICE), but that's pretty
|
||||
|
||||
/*
|
||||
* We used to report a failure via elog(NOTICE), but that's pretty
|
||||
* pointless considering any client has long since disconnected ...
|
||||
*/
|
||||
}
|
||||
@@ -669,22 +684,23 @@ IpcMemoryDelete(int status, Datum shmId)
|
||||
bool
|
||||
SharedMemoryIsInUse(IpcMemoryKey shmKey, IpcMemoryId shmId)
|
||||
{
|
||||
struct shmid_ds shmStat;
|
||||
struct shmid_ds shmStat;
|
||||
|
||||
/*
|
||||
* We detect whether a shared memory segment is in use by seeing whether
|
||||
* it (a) exists and (b) has any processes are attached to it.
|
||||
* We detect whether a shared memory segment is in use by seeing
|
||||
* whether it (a) exists and (b) has any processes are attached to it.
|
||||
*
|
||||
* If we are unable to perform the stat operation for a reason other than
|
||||
* nonexistence of the segment (most likely, because it doesn't belong to
|
||||
* our userid), assume it is in use.
|
||||
* nonexistence of the segment (most likely, because it doesn't belong
|
||||
* to our userid), assume it is in use.
|
||||
*/
|
||||
if (shmctl(shmId, IPC_STAT, &shmStat) < 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* EINVAL actually has multiple possible causes documented in the
|
||||
* shmctl man page, but we assume it must mean the segment no longer
|
||||
* exists.
|
||||
* shmctl man page, but we assume it must mean the segment no
|
||||
* longer exists.
|
||||
*/
|
||||
if (errno == EINVAL)
|
||||
return false;
|
||||
@@ -718,7 +734,7 @@ PrivateMemoryCreate(uint32 size)
|
||||
fprintf(stderr, "PrivateMemoryCreate: malloc(%u) failed\n", size);
|
||||
proc_exit(1);
|
||||
}
|
||||
MemSet(memAddress, 0, size); /* keep Purify quiet */
|
||||
MemSet(memAddress, 0, size);/* keep Purify quiet */
|
||||
|
||||
/* Register on-exit routine to release storage */
|
||||
on_shmem_exit(PrivateMemoryDelete, PointerGetDatum(memAddress));
|
||||
@@ -763,14 +779,14 @@ IpcInitKeyAssignment(int port)
|
||||
PGShmemHeader *
|
||||
IpcMemoryCreate(uint32 size, bool makePrivate, int permission)
|
||||
{
|
||||
void *memAddress;
|
||||
void *memAddress;
|
||||
PGShmemHeader *hdr;
|
||||
|
||||
/* Room for a header? */
|
||||
Assert(size > MAXALIGN(sizeof(PGShmemHeader)));
|
||||
|
||||
/* Loop till we find a free IPC key */
|
||||
for (NextShmemSegID++ ; ; NextShmemSegID++)
|
||||
for (NextShmemSegID++;; NextShmemSegID++)
|
||||
{
|
||||
IpcMemoryId shmid;
|
||||
|
||||
@@ -799,6 +815,7 @@ IpcMemoryCreate(uint32 size, bool makePrivate, int permission)
|
||||
shmdt(memAddress);
|
||||
continue; /* segment belongs to a non-Postgres app */
|
||||
}
|
||||
|
||||
/*
|
||||
* If the creator PID is my own PID or does not belong to any
|
||||
* extant process, it's safe to zap it.
|
||||
@@ -812,28 +829,32 @@ IpcMemoryCreate(uint32 size, bool makePrivate, int permission)
|
||||
continue; /* segment belongs to a live process */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The segment appears to be from a dead Postgres process, or
|
||||
* from a previous cycle of life in this same process. Zap it,
|
||||
* if possible. This probably shouldn't fail, but if it does,
|
||||
* assume the segment belongs to someone else after all,
|
||||
* and continue quietly.
|
||||
* The segment appears to be from a dead Postgres process, or from
|
||||
* a previous cycle of life in this same process. Zap it, if
|
||||
* possible. This probably shouldn't fail, but if it does, assume
|
||||
* the segment belongs to someone else after all, and continue
|
||||
* quietly.
|
||||
*/
|
||||
shmdt(memAddress);
|
||||
if (shmctl(shmid, IPC_RMID, (struct shmid_ds *) NULL) < 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Now try again to create the segment.
|
||||
*/
|
||||
memAddress = InternalIpcMemoryCreate(NextShmemSegID, size, permission);
|
||||
if (memAddress)
|
||||
break; /* successful create and attach */
|
||||
|
||||
/*
|
||||
* Can only get here if some other process managed to create the
|
||||
* same shmem key before we did. Let him have that one,
|
||||
* loop around to try next key.
|
||||
* same shmem key before we did. Let him have that one, loop
|
||||
* around to try next key.
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* OK, we created a new segment. Mark it as created by this process.
|
||||
* The order of assignments here is critical so that another Postgres
|
||||
@@ -843,6 +864,7 @@ IpcMemoryCreate(uint32 size, bool makePrivate, int permission)
|
||||
hdr = (PGShmemHeader *) memAddress;
|
||||
hdr->creatorPID = getpid();
|
||||
hdr->magic = PGShmemMagic;
|
||||
|
||||
/*
|
||||
* Initialize space allocation status for segment.
|
||||
*/
|
||||
@@ -862,27 +884,28 @@ IpcSemaphoreId
|
||||
IpcSemaphoreCreate(int numSems, int permission,
|
||||
int semStartValue, bool removeOnExit)
|
||||
{
|
||||
IpcSemaphoreId semId;
|
||||
IpcSemaphoreId semId;
|
||||
union semun semun;
|
||||
|
||||
/* Loop till we find a free IPC key */
|
||||
for (NextSemaID++ ; ; NextSemaID++)
|
||||
for (NextSemaID++;; NextSemaID++)
|
||||
{
|
||||
pid_t creatorPID;
|
||||
pid_t creatorPID;
|
||||
|
||||
/* Try to create new semaphore set */
|
||||
semId = InternalIpcSemaphoreCreate(NextSemaID, numSems+1,
|
||||
semId = InternalIpcSemaphoreCreate(NextSemaID, numSems + 1,
|
||||
permission, semStartValue,
|
||||
removeOnExit);
|
||||
if (semId >= 0)
|
||||
break; /* successful create */
|
||||
|
||||
/* See if it looks to be leftover from a dead Postgres process */
|
||||
semId = semget(NextSemaID, numSems+1, 0);
|
||||
semId = semget(NextSemaID, numSems + 1, 0);
|
||||
if (semId < 0)
|
||||
continue; /* failed: must be some other app's */
|
||||
if (IpcSemaphoreGetValue(semId, numSems) != PGSemaMagic)
|
||||
continue; /* sema belongs to a non-Postgres app */
|
||||
|
||||
/*
|
||||
* If the creator PID is my own PID or does not belong to any
|
||||
* extant process, it's safe to zap it.
|
||||
@@ -896,46 +919,50 @@ IpcSemaphoreCreate(int numSems, int permission,
|
||||
errno != ESRCH)
|
||||
continue; /* sema belongs to a live process */
|
||||
}
|
||||
|
||||
/*
|
||||
* The sema set appears to be from a dead Postgres process, or
|
||||
* from a previous cycle of life in this same process. Zap it,
|
||||
* if possible. This probably shouldn't fail, but if it does,
|
||||
* assume the sema set belongs to someone else after all,
|
||||
* and continue quietly.
|
||||
* from a previous cycle of life in this same process. Zap it, if
|
||||
* possible. This probably shouldn't fail, but if it does, assume
|
||||
* the sema set belongs to someone else after all, and continue
|
||||
* quietly.
|
||||
*/
|
||||
semun.val = 0; /* unused, but keep compiler quiet */
|
||||
if (semctl(semId, 0, IPC_RMID, semun) < 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Now try again to create the sema set.
|
||||
*/
|
||||
semId = InternalIpcSemaphoreCreate(NextSemaID, numSems+1,
|
||||
semId = InternalIpcSemaphoreCreate(NextSemaID, numSems + 1,
|
||||
permission, semStartValue,
|
||||
removeOnExit);
|
||||
if (semId >= 0)
|
||||
break; /* successful create */
|
||||
|
||||
/*
|
||||
* Can only get here if some other process managed to create the
|
||||
* same sema key before we did. Let him have that one,
|
||||
* loop around to try next key.
|
||||
* same sema key before we did. Let him have that one, loop
|
||||
* around to try next key.
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* OK, we created a new sema set. Mark it as created by this process.
|
||||
* We do this by setting the spare semaphore to PGSemaMagic-1 and then
|
||||
* incrementing it with semop(). That leaves it with value PGSemaMagic
|
||||
* and sempid referencing this process.
|
||||
* incrementing it with semop(). That leaves it with value
|
||||
* PGSemaMagic and sempid referencing this process.
|
||||
*/
|
||||
semun.val = PGSemaMagic-1;
|
||||
semun.val = PGSemaMagic - 1;
|
||||
if (semctl(semId, numSems, SETVAL, semun) < 0)
|
||||
{
|
||||
fprintf(stderr, "IpcSemaphoreCreate: semctl(id=%d, %d, SETVAL, %d) failed: %s\n",
|
||||
semId, numSems, PGSemaMagic-1, strerror(errno));
|
||||
semId, numSems, PGSemaMagic - 1, strerror(errno));
|
||||
|
||||
if (errno == ERANGE)
|
||||
fprintf(stderr,
|
||||
"You possibly need to raise your kernel's SEMVMX value to be at least\n"
|
||||
"%d. Look into the PostgreSQL documentation for details.\n",
|
||||
"%d. Look into the PostgreSQL documentation for details.\n",
|
||||
PGSemaMagic);
|
||||
|
||||
proc_exit(1);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.39 2001/01/24 19:43:07 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.40 2001/03/22 03:59:45 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -34,7 +34,7 @@
|
||||
* for such a backend, the shared memory is already ready-to-go.
|
||||
*
|
||||
* If "makePrivate" is true then we only need private memory, not shared
|
||||
* memory. This is true for a standalone backend, false for a postmaster.
|
||||
* memory. This is true for a standalone backend, false for a postmaster.
|
||||
*/
|
||||
void
|
||||
CreateSharedMemoryAndSemaphores(bool makePrivate, int maxBackends)
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.56 2001/01/24 19:43:07 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.57 2001/03/22 03:59:45 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
/*
|
||||
* POSTGRES processes share one or more regions of shared memory.
|
||||
* The shared memory is created by a postmaster and is inherited
|
||||
* by each backend via fork(). The routines in this file are used for
|
||||
* by each backend via fork(). The routines in this file are used for
|
||||
* allocating and binding to shared memory data structures.
|
||||
*
|
||||
* NOTES:
|
||||
@@ -65,7 +65,7 @@
|
||||
|
||||
/* shared memory global variables */
|
||||
|
||||
static PGShmemHeader *ShmemSegHdr; /* shared mem segment header */
|
||||
static PGShmemHeader *ShmemSegHdr; /* shared mem segment header */
|
||||
|
||||
SHMEM_OFFSET ShmemBase; /* start address of shared memory */
|
||||
|
||||
@@ -75,9 +75,9 @@ SPINLOCK ShmemLock; /* lock for shared memory allocation */
|
||||
|
||||
SPINLOCK ShmemIndexLock; /* lock for shmem index access */
|
||||
|
||||
static HTAB *ShmemIndex = NULL; /* primary index hashtable for shmem */
|
||||
static HTAB *ShmemIndex = NULL; /* primary index hashtable for shmem */
|
||||
|
||||
static bool ShmemBootstrap = false; /* bootstrapping shmem index? */
|
||||
static bool ShmemBootstrap = false; /* bootstrapping shmem index? */
|
||||
|
||||
|
||||
/*
|
||||
@@ -99,9 +99,9 @@ InitShmemAllocation(PGShmemHeader *seghdr)
|
||||
|
||||
/*
|
||||
* Since ShmemInitHash calls ShmemInitStruct, which expects the
|
||||
* ShmemIndex hashtable to exist already, we have a bit of a circularity
|
||||
* problem in initializing the ShmemIndex itself. We set ShmemBootstrap
|
||||
* to tell ShmemInitStruct to fake it.
|
||||
* ShmemIndex hashtable to exist already, we have a bit of a
|
||||
* circularity problem in initializing the ShmemIndex itself. We set
|
||||
* ShmemBootstrap to tell ShmemInitStruct to fake it.
|
||||
*/
|
||||
ShmemIndex = (HTAB *) NULL;
|
||||
ShmemBootstrap = true;
|
||||
@@ -373,6 +373,7 @@ ShmemInitStruct(char *name, Size size, bool *foundPtr)
|
||||
|
||||
if (!ShmemIndex)
|
||||
{
|
||||
|
||||
/*
|
||||
* If the shmem index doesn't exist, we are bootstrapping: we must
|
||||
* be trying to init the shmem index itself.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmqueue.c,v 1.15 2001/01/24 19:43:07 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmqueue.c,v 1.16 2001/03/22 03:59:45 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
*
|
||||
@@ -152,7 +152,8 @@ SHMQueueInsertAfter(SHM_QUEUE *queue, SHM_QUEUE *elem)
|
||||
dumpQ(queue, "in SHMQueueInsertAfter: end");
|
||||
#endif
|
||||
}
|
||||
#endif /* NOT_USED */
|
||||
|
||||
#endif /* NOT_USED */
|
||||
|
||||
/*--------------------
|
||||
* SHMQueueNext -- Get the next element from a queue
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.27 2001/03/18 20:18:59 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.28 2001/03/22 03:59:45 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -411,6 +411,7 @@ GetUndoRecPtr(void)
|
||||
if (pOffset != INVALID_OFFSET)
|
||||
{
|
||||
PROC *proc = (PROC *) MAKE_PTR(pOffset);
|
||||
|
||||
tempr = proc->logRec;
|
||||
if (tempr.xrecoff == 0)
|
||||
continue;
|
||||
@@ -422,5 +423,5 @@ GetUndoRecPtr(void)
|
||||
|
||||
SpinRelease(SInvalLock);
|
||||
|
||||
return(urec);
|
||||
return (urec);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.37 2001/01/24 19:43:07 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.38 2001/03/22 03:59:45 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -35,6 +35,7 @@ static void SISetProcStateInvalid(SISeg *segP);
|
||||
int
|
||||
SInvalShmemSize(int maxBackends)
|
||||
{
|
||||
|
||||
/*
|
||||
* Figure space needed. Note sizeof(SISeg) includes the first
|
||||
* ProcState entry.
|
||||
@@ -91,7 +92,7 @@ SIBackendInit(SISeg *segP)
|
||||
/* Look for a free entry in the procState array */
|
||||
for (index = 0; index < segP->lastBackend; index++)
|
||||
{
|
||||
if (segP->procState[index].nextMsgNum < 0) /* inactive slot? */
|
||||
if (segP->procState[index].nextMsgNum < 0) /* inactive slot? */
|
||||
{
|
||||
stateP = &segP->procState[index];
|
||||
break;
|
||||
@@ -108,9 +109,10 @@ SIBackendInit(SISeg *segP)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* elog() with spinlock held is probably not too cool, but this
|
||||
* condition should never happen anyway.
|
||||
* elog() with spinlock held is probably not too cool, but
|
||||
* this condition should never happen anyway.
|
||||
*/
|
||||
elog(NOTICE, "SIBackendInit: no free procState slot available");
|
||||
MyBackendId = InvalidBackendId;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/Attic/spin.c,v 1.31 2001/01/24 19:43:07 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/Attic/spin.c,v 1.32 2001/03/22 03:59:45 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -83,17 +83,18 @@ typedef struct slock
|
||||
} SLock;
|
||||
|
||||
#ifdef LOCK_DEBUG
|
||||
bool Trace_spinlocks = false;
|
||||
bool Trace_spinlocks = false;
|
||||
|
||||
inline static void
|
||||
PRINT_SLDEBUG(const char * where, SPINLOCK lockid, const SLock * lock)
|
||||
PRINT_SLDEBUG(const char *where, SPINLOCK lockid, const SLock *lock)
|
||||
{
|
||||
if (Trace_spinlocks)
|
||||
elog(DEBUG, "%s: id=%d", where, lockid);
|
||||
if (Trace_spinlocks)
|
||||
elog(DEBUG, "%s: id=%d", where, lockid);
|
||||
}
|
||||
#else /* not LOCK_DEBUG */
|
||||
|
||||
#else /* not LOCK_DEBUG */
|
||||
#define PRINT_SLDEBUG(a,b,c)
|
||||
#endif /* not LOCK_DEBUG */
|
||||
#endif /* not LOCK_DEBUG */
|
||||
|
||||
|
||||
static SLock *SLockArray = NULL;
|
||||
@@ -146,15 +147,17 @@ SpinAcquire(SPINLOCK lockid)
|
||||
SLock *slckP = &(SLockArray[lockid]);
|
||||
|
||||
PRINT_SLDEBUG("SpinAcquire", lockid, slckP);
|
||||
|
||||
/*
|
||||
* Acquire the lock, then record that we have done so (for recovery
|
||||
* in case of elog(ERROR) while holding the lock). Note we assume
|
||||
* here that S_LOCK will not accept cancel/die interrupts once it has
|
||||
* Acquire the lock, then record that we have done so (for recovery in
|
||||
* case of elog(ERROR) while holding the lock). Note we assume here
|
||||
* that S_LOCK will not accept cancel/die interrupts once it has
|
||||
* acquired the lock. However, interrupts should be accepted while
|
||||
* waiting, if InterruptHoldoffCount is zero.
|
||||
*/
|
||||
S_LOCK(&(slckP->shlock));
|
||||
PROC_INCR_SLOCK(lockid);
|
||||
|
||||
/*
|
||||
* Lock out cancel/die interrupts until we exit the code section
|
||||
* protected by the spinlock. This ensures that interrupts will not
|
||||
@@ -162,7 +165,7 @@ SpinAcquire(SPINLOCK lockid)
|
||||
*/
|
||||
HOLD_INTERRUPTS();
|
||||
|
||||
PRINT_SLDEBUG("SpinAcquire/done", lockid, slckP);
|
||||
PRINT_SLDEBUG("SpinAcquire/done", lockid, slckP);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -170,26 +173,29 @@ SpinRelease(SPINLOCK lockid)
|
||||
{
|
||||
SLock *slckP = &(SLockArray[lockid]);
|
||||
|
||||
PRINT_SLDEBUG("SpinRelease", lockid, slckP);
|
||||
PRINT_SLDEBUG("SpinRelease", lockid, slckP);
|
||||
|
||||
/*
|
||||
* Check that we are actually holding the lock we are releasing. This
|
||||
* can be done only after MyProc has been initialized.
|
||||
*/
|
||||
Assert(!MyProc || MyProc->sLocks[lockid] > 0);
|
||||
Assert(!MyProc || MyProc->sLocks[lockid] > 0);
|
||||
|
||||
/*
|
||||
* Record that we no longer hold the spinlock, and release it.
|
||||
*/
|
||||
PROC_DECR_SLOCK(lockid);
|
||||
S_UNLOCK(&(slckP->shlock));
|
||||
|
||||
/*
|
||||
* Exit the interrupt holdoff entered in SpinAcquire().
|
||||
*/
|
||||
RESUME_INTERRUPTS();
|
||||
|
||||
PRINT_SLDEBUG("SpinRelease/done", lockid, slckP);
|
||||
PRINT_SLDEBUG("SpinRelease/done", lockid, slckP);
|
||||
}
|
||||
|
||||
#else /* !HAS_TEST_AND_SET */
|
||||
#else /* !HAS_TEST_AND_SET */
|
||||
|
||||
/*
|
||||
* No TAS, so spinlocks are implemented using SysV semaphores.
|
||||
@@ -217,9 +223,9 @@ SpinRelease(SPINLOCK lockid)
|
||||
|
||||
static IpcSemaphoreId *SpinLockIds = NULL;
|
||||
|
||||
static int numSpinSets = 0; /* number of sema sets used */
|
||||
static int numSpinLocks = 0; /* total number of semas allocated */
|
||||
static int nextSpinLock = 0; /* next free spinlock index */
|
||||
static int numSpinSets = 0; /* number of sema sets used */
|
||||
static int numSpinLocks = 0; /* total number of semas allocated */
|
||||
static int nextSpinLock = 0; /* next free spinlock index */
|
||||
|
||||
static void SpinFreeAllSemaphores(void);
|
||||
|
||||
@@ -238,17 +244,18 @@ SLockShmemSize(void)
|
||||
void
|
||||
CreateSpinlocks(PGShmemHeader *seghdr)
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
|
||||
if (SpinLockIds == NULL)
|
||||
{
|
||||
|
||||
/*
|
||||
* Compute number of spinlocks needed. If this logic gets any more
|
||||
* complicated, it should be distributed into the affected modules,
|
||||
* similar to the way shmem space estimation is handled.
|
||||
* Compute number of spinlocks needed. If this logic gets any
|
||||
* more complicated, it should be distributed into the affected
|
||||
* modules, similar to the way shmem space estimation is handled.
|
||||
*
|
||||
* For now, though, we just need the fixed spinlocks (MAX_SPINS),
|
||||
* two spinlocks per shared disk buffer, and four spinlocks for XLOG.
|
||||
* For now, though, we just need the fixed spinlocks (MAX_SPINS), two
|
||||
* spinlocks per shared disk buffer, and four spinlocks for XLOG.
|
||||
*/
|
||||
numSpinLocks = (int) MAX_SPINS + 2 * NBuffers + 4;
|
||||
|
||||
@@ -265,11 +272,11 @@ CreateSpinlocks(PGShmemHeader *seghdr)
|
||||
SpinLockIds[i] = -1;
|
||||
|
||||
/*
|
||||
* Arrange to delete semas on exit --- set this up now so that we
|
||||
* will clean up if allocation fails. We use our own freeproc,
|
||||
* rather than IpcSemaphoreCreate's removeOnExit option, because
|
||||
* we don't want to fill up the on_shmem_exit list with a separate
|
||||
* entry for each semaphore set.
|
||||
* Arrange to delete semas on exit --- set this up now so that we will
|
||||
* clean up if allocation fails. We use our own freeproc, rather than
|
||||
* IpcSemaphoreCreate's removeOnExit option, because we don't want to
|
||||
* fill up the on_shmem_exit list with a separate entry for each
|
||||
* semaphore set.
|
||||
*/
|
||||
on_shmem_exit(SpinFreeAllSemaphores, 0);
|
||||
|
||||
@@ -320,12 +327,13 @@ SpinFreeAllSemaphores(void)
|
||||
void
|
||||
SpinAcquire(SPINLOCK lock)
|
||||
{
|
||||
|
||||
/*
|
||||
* See the TAS() version of this routine for primary commentary.
|
||||
*
|
||||
* NOTE we must pass interruptOK = false to IpcSemaphoreLock, to ensure
|
||||
* that a cancel/die interrupt cannot prevent us from recording ownership
|
||||
* of a lock we have just acquired.
|
||||
* that a cancel/die interrupt cannot prevent us from recording
|
||||
* ownership of a lock we have just acquired.
|
||||
*/
|
||||
IpcSemaphoreLock(SpinLockIds[0], lock, false);
|
||||
PROC_INCR_SLOCK(lock);
|
||||
@@ -348,7 +356,7 @@ SpinRelease(SPINLOCK lock)
|
||||
semval = IpcSemaphoreGetValue(SpinLockIds[0], lock);
|
||||
Assert(semval < 1);
|
||||
#endif
|
||||
Assert(!MyProc || MyProc->sLocks[lockid] > 0);
|
||||
Assert(!MyProc || MyProc->sLocks[lockid] > 0);
|
||||
PROC_DECR_SLOCK(lock);
|
||||
IpcSemaphoreUnlock(SpinLockIds[0], lock);
|
||||
RESUME_INTERRUPTS();
|
||||
@@ -384,7 +392,7 @@ int
|
||||
tas_sema(volatile slock_t *lock)
|
||||
{
|
||||
/* Note that TAS macros return 0 if *success* */
|
||||
return ! IpcSemaphoreTryLock(lock->semId, lock->sem);
|
||||
return !IpcSemaphoreTryLock(lock->semId, lock->sem);
|
||||
}
|
||||
|
||||
#endif /* !HAS_TEST_AND_SET */
|
||||
#endif /* !HAS_TEST_AND_SET */
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.85 2001/02/10 02:31:26 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.86 2001/03/22 03:59:45 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -44,7 +44,7 @@
|
||||
static int32
|
||||
getbytealen(bytea *data)
|
||||
{
|
||||
Assert(! VARATT_IS_EXTENDED(data));
|
||||
Assert(!VARATT_IS_EXTENDED(data));
|
||||
if (VARSIZE(data) < VARHDRSZ)
|
||||
elog(ERROR, "getbytealen: VARSIZE(data) < VARHDRSZ. This is internal error.");
|
||||
return (VARSIZE(data) - VARHDRSZ);
|
||||
@@ -75,7 +75,8 @@ inv_create(int flags)
|
||||
elog(ERROR, "inv_create: large object %u already exists. This is internal error.", file_oid);
|
||||
|
||||
/*
|
||||
* Create the LO by writing an empty first page for it in pg_largeobject
|
||||
* Create the LO by writing an empty first page for it in
|
||||
* pg_largeobject
|
||||
*/
|
||||
(void) LargeObjectCreate(file_oid);
|
||||
|
||||
@@ -93,13 +94,17 @@ inv_create(int flags)
|
||||
retval->id = file_oid;
|
||||
retval->offset = 0;
|
||||
|
||||
if (flags & INV_WRITE) {
|
||||
if (flags & INV_WRITE)
|
||||
{
|
||||
retval->flags = IFS_WRLOCK | IFS_RDLOCK;
|
||||
retval->heap_r = heap_openr(LargeObjectRelationName, RowExclusiveLock);
|
||||
} else if (flags & INV_READ) {
|
||||
}
|
||||
else if (flags & INV_READ)
|
||||
{
|
||||
retval->flags = IFS_RDLOCK;
|
||||
retval->heap_r = heap_openr(LargeObjectRelationName, AccessShareLock);
|
||||
} else
|
||||
}
|
||||
else
|
||||
elog(ERROR, "inv_create: invalid flags: %d", flags);
|
||||
|
||||
retval->index_r = index_openr(LargeObjectLOidPNIndex);
|
||||
@@ -118,21 +123,25 @@ inv_open(Oid lobjId, int flags)
|
||||
{
|
||||
LargeObjectDesc *retval;
|
||||
|
||||
if (! LargeObjectExists(lobjId))
|
||||
if (!LargeObjectExists(lobjId))
|
||||
elog(ERROR, "inv_open: large object %u not found", lobjId);
|
||||
|
||||
|
||||
retval = (LargeObjectDesc *) palloc(sizeof(LargeObjectDesc));
|
||||
|
||||
retval->id = lobjId;
|
||||
retval->offset = 0;
|
||||
|
||||
if (flags & INV_WRITE) {
|
||||
if (flags & INV_WRITE)
|
||||
{
|
||||
retval->flags = IFS_WRLOCK | IFS_RDLOCK;
|
||||
retval->heap_r = heap_openr(LargeObjectRelationName, RowExclusiveLock);
|
||||
} else if (flags & INV_READ) {
|
||||
}
|
||||
else if (flags & INV_READ)
|
||||
{
|
||||
retval->flags = IFS_RDLOCK;
|
||||
retval->heap_r = heap_openr(LargeObjectRelationName, AccessShareLock);
|
||||
} else
|
||||
}
|
||||
else
|
||||
elog(ERROR, "inv_open: invalid flags: %d", flags);
|
||||
|
||||
retval->index_r = index_openr(LargeObjectLOidPNIndex);
|
||||
@@ -185,16 +194,16 @@ inv_drop(Oid lobjId)
|
||||
static uint32
|
||||
inv_getsize(LargeObjectDesc *obj_desc)
|
||||
{
|
||||
bool found = false;
|
||||
uint32 lastbyte = 0;
|
||||
ScanKeyData skey[1];
|
||||
IndexScanDesc sd;
|
||||
RetrieveIndexResult indexRes;
|
||||
HeapTupleData tuple;
|
||||
Buffer buffer;
|
||||
Form_pg_largeobject data;
|
||||
bytea *datafield;
|
||||
bool pfreeit;
|
||||
bool found = false;
|
||||
uint32 lastbyte = 0;
|
||||
ScanKeyData skey[1];
|
||||
IndexScanDesc sd;
|
||||
RetrieveIndexResult indexRes;
|
||||
HeapTupleData tuple;
|
||||
Buffer buffer;
|
||||
Form_pg_largeobject data;
|
||||
bytea *datafield;
|
||||
bool pfreeit;
|
||||
|
||||
Assert(PointerIsValid(obj_desc));
|
||||
|
||||
@@ -210,10 +219,10 @@ inv_getsize(LargeObjectDesc *obj_desc)
|
||||
tuple.t_data = NULL;
|
||||
|
||||
/*
|
||||
* Because the pg_largeobject index is on both loid and pageno,
|
||||
* but we constrain only loid, a backwards scan should visit all
|
||||
* pages of the large object in reverse pageno order. So, it's
|
||||
* sufficient to examine the first valid tuple (== last valid page).
|
||||
* Because the pg_largeobject index is on both loid and pageno, but we
|
||||
* constrain only loid, a backwards scan should visit all pages of the
|
||||
* large object in reverse pageno order. So, it's sufficient to
|
||||
* examine the first valid tuple (== last valid page).
|
||||
*/
|
||||
while ((indexRes = index_getnext(sd, BackwardScanDirection)))
|
||||
{
|
||||
@@ -238,7 +247,7 @@ inv_getsize(LargeObjectDesc *obj_desc)
|
||||
ReleaseBuffer(buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
index_endscan(sd);
|
||||
|
||||
if (!found)
|
||||
@@ -259,15 +268,15 @@ inv_seek(LargeObjectDesc *obj_desc, int offset, int whence)
|
||||
obj_desc->offset = offset;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
if (offset < 0 && obj_desc->offset < ((uint32) (- offset)))
|
||||
if (offset < 0 && obj_desc->offset < ((uint32) (-offset)))
|
||||
elog(ERROR, "inv_seek: invalid offset: %d", offset);
|
||||
obj_desc->offset += offset;
|
||||
break;
|
||||
case SEEK_END:
|
||||
{
|
||||
uint32 size = inv_getsize(obj_desc);
|
||||
uint32 size = inv_getsize(obj_desc);
|
||||
|
||||
if (offset < 0 && size < ((uint32) (- offset)))
|
||||
if (offset < 0 && size < ((uint32) (-offset)))
|
||||
elog(ERROR, "inv_seek: invalid offset: %d", offset);
|
||||
obj_desc->offset = size + offset;
|
||||
}
|
||||
@@ -289,20 +298,20 @@ inv_tell(LargeObjectDesc *obj_desc)
|
||||
int
|
||||
inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes)
|
||||
{
|
||||
int nread = 0;
|
||||
int n;
|
||||
int off;
|
||||
int len;
|
||||
int32 pageno = (int32) (obj_desc->offset / LOBLKSIZE);
|
||||
uint32 pageoff;
|
||||
ScanKeyData skey[2];
|
||||
IndexScanDesc sd;
|
||||
RetrieveIndexResult indexRes;
|
||||
HeapTupleData tuple;
|
||||
Buffer buffer;
|
||||
Form_pg_largeobject data;
|
||||
bytea *datafield;
|
||||
bool pfreeit;
|
||||
int nread = 0;
|
||||
int n;
|
||||
int off;
|
||||
int len;
|
||||
int32 pageno = (int32) (obj_desc->offset / LOBLKSIZE);
|
||||
uint32 pageoff;
|
||||
ScanKeyData skey[2];
|
||||
IndexScanDesc sd;
|
||||
RetrieveIndexResult indexRes;
|
||||
HeapTupleData tuple;
|
||||
Buffer buffer;
|
||||
Form_pg_largeobject data;
|
||||
bytea *datafield;
|
||||
bool pfreeit;
|
||||
|
||||
Assert(PointerIsValid(obj_desc));
|
||||
Assert(buf != NULL);
|
||||
@@ -335,13 +344,13 @@ inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes)
|
||||
|
||||
if (tuple.t_data == NULL)
|
||||
continue;
|
||||
|
||||
|
||||
data = (Form_pg_largeobject) GETSTRUCT(&tuple);
|
||||
|
||||
/*
|
||||
* We assume the indexscan will deliver pages in order. However,
|
||||
* there may be missing pages if the LO contains unwritten "holes".
|
||||
* We want missing sections to read out as zeroes.
|
||||
* there may be missing pages if the LO contains unwritten
|
||||
* "holes". We want missing sections to read out as zeroes.
|
||||
*/
|
||||
pageoff = ((uint32) data->pageno) * LOBLKSIZE;
|
||||
if (pageoff > obj_desc->offset)
|
||||
@@ -393,28 +402,28 @@ inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes)
|
||||
int
|
||||
inv_write(LargeObjectDesc *obj_desc, char *buf, int nbytes)
|
||||
{
|
||||
int nwritten = 0;
|
||||
int n;
|
||||
int off;
|
||||
int len;
|
||||
int32 pageno = (int32) (obj_desc->offset / LOBLKSIZE);
|
||||
ScanKeyData skey[2];
|
||||
IndexScanDesc sd;
|
||||
RetrieveIndexResult indexRes;
|
||||
HeapTupleData oldtuple;
|
||||
Buffer buffer;
|
||||
Form_pg_largeobject olddata;
|
||||
bool neednextpage;
|
||||
bytea *datafield;
|
||||
bool pfreeit;
|
||||
char workbuf[LOBLKSIZE + VARHDRSZ];
|
||||
char *workb = VARATT_DATA(workbuf);
|
||||
HeapTuple newtup;
|
||||
Datum values[Natts_pg_largeobject];
|
||||
char nulls[Natts_pg_largeobject];
|
||||
char replace[Natts_pg_largeobject];
|
||||
bool write_indices;
|
||||
Relation idescs[Num_pg_largeobject_indices];
|
||||
int nwritten = 0;
|
||||
int n;
|
||||
int off;
|
||||
int len;
|
||||
int32 pageno = (int32) (obj_desc->offset / LOBLKSIZE);
|
||||
ScanKeyData skey[2];
|
||||
IndexScanDesc sd;
|
||||
RetrieveIndexResult indexRes;
|
||||
HeapTupleData oldtuple;
|
||||
Buffer buffer;
|
||||
Form_pg_largeobject olddata;
|
||||
bool neednextpage;
|
||||
bytea *datafield;
|
||||
bool pfreeit;
|
||||
char workbuf[LOBLKSIZE + VARHDRSZ];
|
||||
char *workb = VARATT_DATA(workbuf);
|
||||
HeapTuple newtup;
|
||||
Datum values[Natts_pg_largeobject];
|
||||
char nulls[Natts_pg_largeobject];
|
||||
char replace[Natts_pg_largeobject];
|
||||
bool write_indices;
|
||||
Relation idescs[Num_pg_largeobject_indices];
|
||||
|
||||
Assert(PointerIsValid(obj_desc));
|
||||
Assert(buf != NULL);
|
||||
@@ -422,7 +431,7 @@ inv_write(LargeObjectDesc *obj_desc, char *buf, int nbytes)
|
||||
if (nbytes <= 0)
|
||||
return 0;
|
||||
|
||||
write_indices = ! IsIgnoringSystemIndexes();
|
||||
write_indices = !IsIgnoringSystemIndexes();
|
||||
if (write_indices)
|
||||
CatalogOpenIndices(Num_pg_largeobject_indices,
|
||||
Name_pg_largeobject_indices,
|
||||
@@ -450,6 +459,7 @@ inv_write(LargeObjectDesc *obj_desc, char *buf, int nbytes)
|
||||
|
||||
while (nwritten < nbytes)
|
||||
{
|
||||
|
||||
/*
|
||||
* If possible, get next pre-existing page of the LO. We assume
|
||||
* the indexscan will deliver these in order --- but there may be
|
||||
@@ -471,12 +481,14 @@ inv_write(LargeObjectDesc *obj_desc, char *buf, int nbytes)
|
||||
}
|
||||
neednextpage = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have a pre-existing page, see if it is the page we want
|
||||
* to write, or a later one.
|
||||
*/
|
||||
if (olddata != NULL && olddata->pageno == pageno)
|
||||
{
|
||||
|
||||
/*
|
||||
* Update an existing page with fresh data.
|
||||
*
|
||||
@@ -495,12 +507,14 @@ inv_write(LargeObjectDesc *obj_desc, char *buf, int nbytes)
|
||||
memcpy(workb, VARDATA(datafield), len);
|
||||
if (pfreeit)
|
||||
pfree(datafield);
|
||||
|
||||
/*
|
||||
* Fill any hole
|
||||
*/
|
||||
off = (int) (obj_desc->offset % LOBLKSIZE);
|
||||
if (off > len)
|
||||
MemSet(workb + len, 0, off - len);
|
||||
|
||||
/*
|
||||
* Insert appropriate portion of new data
|
||||
*/
|
||||
@@ -513,6 +527,7 @@ inv_write(LargeObjectDesc *obj_desc, char *buf, int nbytes)
|
||||
/* compute valid length of new page */
|
||||
len = (len >= off) ? len : off;
|
||||
VARATT_SIZEP(workbuf) = len + VARHDRSZ;
|
||||
|
||||
/*
|
||||
* Form and insert updated tuple
|
||||
*/
|
||||
@@ -528,6 +543,7 @@ inv_write(LargeObjectDesc *obj_desc, char *buf, int nbytes)
|
||||
CatalogIndexInsert(idescs, Num_pg_largeobject_indices,
|
||||
obj_desc->heap_r, newtup);
|
||||
heap_freetuple(newtup);
|
||||
|
||||
/*
|
||||
* We're done with this old page.
|
||||
*/
|
||||
@@ -539,6 +555,7 @@ inv_write(LargeObjectDesc *obj_desc, char *buf, int nbytes)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Write a brand new page.
|
||||
*
|
||||
@@ -547,6 +564,7 @@ inv_write(LargeObjectDesc *obj_desc, char *buf, int nbytes)
|
||||
off = (int) (obj_desc->offset % LOBLKSIZE);
|
||||
if (off > 0)
|
||||
MemSet(workb, 0, off);
|
||||
|
||||
/*
|
||||
* Insert appropriate portion of new data
|
||||
*/
|
||||
@@ -558,6 +576,7 @@ inv_write(LargeObjectDesc *obj_desc, char *buf, int nbytes)
|
||||
/* compute valid length of new page */
|
||||
len = off + n;
|
||||
VARATT_SIZEP(workbuf) = len + VARHDRSZ;
|
||||
|
||||
/*
|
||||
* Form and insert updated tuple
|
||||
*/
|
||||
@@ -585,8 +604,8 @@ inv_write(LargeObjectDesc *obj_desc, char *buf, int nbytes)
|
||||
CatalogCloseIndices(Num_pg_largeobject_indices, idescs);
|
||||
|
||||
/*
|
||||
* Advance command counter so that my tuple updates will be seen by later
|
||||
* large-object operations in this transaction.
|
||||
* Advance command counter so that my tuple updates will be seen by
|
||||
* later large-object operations in this transaction.
|
||||
*/
|
||||
CommandCounterIncrement();
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/deadlock.c,v 1.2 2001/01/25 03:45:50 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/deadlock.c,v 1.3 2001/03/22 03:59:46 momjian Exp $
|
||||
*
|
||||
* Interface:
|
||||
*
|
||||
@@ -29,32 +29,36 @@
|
||||
|
||||
|
||||
/* One edge in the waits-for graph */
|
||||
typedef struct {
|
||||
PROC *waiter; /* the waiting process */
|
||||
PROC *blocker; /* the process it is waiting for */
|
||||
int pred; /* workspace for TopoSort */
|
||||
int link; /* workspace for TopoSort */
|
||||
typedef struct
|
||||
{
|
||||
PROC *waiter; /* the waiting process */
|
||||
PROC *blocker; /* the process it is waiting for */
|
||||
int pred; /* workspace for TopoSort */
|
||||
int link; /* workspace for TopoSort */
|
||||
} EDGE;
|
||||
|
||||
/* One potential reordering of a lock's wait queue */
|
||||
typedef struct {
|
||||
LOCK *lock; /* the lock whose wait queue is described */
|
||||
PROC **procs; /* array of PROC *'s in new wait order */
|
||||
int nProcs;
|
||||
typedef struct
|
||||
{
|
||||
LOCK *lock; /* the lock whose wait queue is described */
|
||||
PROC **procs; /* array of PROC *'s in new wait order */
|
||||
int nProcs;
|
||||
} WAIT_ORDER;
|
||||
|
||||
|
||||
static bool DeadLockCheckRecurse(PROC *proc);
|
||||
static bool TestConfiguration(PROC *startProc);
|
||||
static bool FindLockCycle(PROC *checkProc,
|
||||
EDGE *softEdges, int *nSoftEdges);
|
||||
EDGE *softEdges, int *nSoftEdges);
|
||||
static bool FindLockCycleRecurse(PROC *checkProc,
|
||||
EDGE *softEdges, int *nSoftEdges);
|
||||
EDGE *softEdges, int *nSoftEdges);
|
||||
static bool ExpandConstraints(EDGE *constraints, int nConstraints);
|
||||
static bool TopoSort(LOCK *lock, EDGE *constraints, int nConstraints,
|
||||
PROC **ordering);
|
||||
PROC **ordering);
|
||||
|
||||
#ifdef DEBUG_DEADLOCK
|
||||
static void PrintLockQueue(LOCK *lock, const char *info);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -64,30 +68,34 @@ static void PrintLockQueue(LOCK *lock, const char *info);
|
||||
|
||||
/* Workspace for FindLockCycle */
|
||||
static PROC **visitedProcs; /* Array of visited procs */
|
||||
static int nVisitedProcs;
|
||||
static int nVisitedProcs;
|
||||
|
||||
/* Workspace for TopoSort */
|
||||
static PROC **topoProcs; /* Array of not-yet-output procs */
|
||||
static int *beforeConstraints; /* Counts of remaining before-constraints */
|
||||
static int *afterConstraints; /* List head for after-constraints */
|
||||
|
||||
/* Output area for ExpandConstraints */
|
||||
static WAIT_ORDER *waitOrders; /* Array of proposed queue rearrangements */
|
||||
static int nWaitOrders;
|
||||
static int nWaitOrders;
|
||||
static PROC **waitOrderProcs; /* Space for waitOrders queue contents */
|
||||
|
||||
/* Current list of constraints being considered */
|
||||
static EDGE *curConstraints;
|
||||
static int nCurConstraints;
|
||||
static int maxCurConstraints;
|
||||
static int nCurConstraints;
|
||||
static int maxCurConstraints;
|
||||
|
||||
/* Storage space for results from FindLockCycle */
|
||||
static EDGE *possibleConstraints;
|
||||
static int nPossibleConstraints;
|
||||
static int maxPossibleConstraints;
|
||||
static int nPossibleConstraints;
|
||||
static int maxPossibleConstraints;
|
||||
|
||||
|
||||
/*
|
||||
* InitDeadLockChecking -- initialize deadlock checker during backend startup
|
||||
*
|
||||
* This does per-backend initialization of the deadlock checker; primarily,
|
||||
* allocation of working memory for DeadLockCheck. We do this per-backend
|
||||
* allocation of working memory for DeadLockCheck. We do this per-backend
|
||||
* since there's no percentage in making the kernel do copy-on-write
|
||||
* inheritance of workspace from the postmaster. We want to allocate the
|
||||
* space at startup because the deadlock checker might be invoked when there's
|
||||
@@ -96,7 +104,7 @@ static int maxPossibleConstraints;
|
||||
void
|
||||
InitDeadLockChecking(void)
|
||||
{
|
||||
MemoryContext oldcxt;
|
||||
MemoryContext oldcxt;
|
||||
|
||||
/* Make sure allocations are permanent */
|
||||
oldcxt = MemoryContextSwitchTo(TopMemoryContext);
|
||||
@@ -116,20 +124,21 @@ InitDeadLockChecking(void)
|
||||
|
||||
/*
|
||||
* We need to consider rearranging at most MaxBackends/2 wait queues
|
||||
* (since it takes at least two waiters in a queue to create a soft edge),
|
||||
* and the expanded form of the wait queues can't involve more than
|
||||
* MaxBackends total waiters.
|
||||
* (since it takes at least two waiters in a queue to create a soft
|
||||
* edge), and the expanded form of the wait queues can't involve more
|
||||
* than MaxBackends total waiters.
|
||||
*/
|
||||
waitOrders = (WAIT_ORDER *) palloc((MaxBackends/2) * sizeof(WAIT_ORDER));
|
||||
waitOrders = (WAIT_ORDER *) palloc((MaxBackends / 2) * sizeof(WAIT_ORDER));
|
||||
waitOrderProcs = (PROC **) palloc(MaxBackends * sizeof(PROC *));
|
||||
|
||||
/*
|
||||
* Allow at most MaxBackends distinct constraints in a configuration.
|
||||
* (Is this enough? In practice it seems it should be, but I don't quite
|
||||
* see how to prove it. If we run out, we might fail to find a workable
|
||||
* wait queue rearrangement even though one exists.) NOTE that this
|
||||
* number limits the maximum recursion depth of DeadLockCheckRecurse.
|
||||
* Making it really big might potentially allow a stack-overflow problem.
|
||||
* (Is this enough? In practice it seems it should be, but I don't
|
||||
* quite see how to prove it. If we run out, we might fail to find a
|
||||
* workable wait queue rearrangement even though one exists.) NOTE
|
||||
* that this number limits the maximum recursion depth of
|
||||
* DeadLockCheckRecurse. Making it really big might potentially allow
|
||||
* a stack-overflow problem.
|
||||
*/
|
||||
maxCurConstraints = MaxBackends;
|
||||
curConstraints = (EDGE *) palloc(maxCurConstraints * sizeof(EDGE));
|
||||
@@ -139,8 +148,8 @@ InitDeadLockChecking(void)
|
||||
* re-run TestConfiguration. (This is probably more than enough, but
|
||||
* we can survive if we run low on space by doing excess runs of
|
||||
* TestConfiguration to re-compute constraint lists each time needed.)
|
||||
* The last MaxBackends entries in possibleConstraints[] are reserved as
|
||||
* output workspace for FindLockCycle.
|
||||
* The last MaxBackends entries in possibleConstraints[] are reserved
|
||||
* as output workspace for FindLockCycle.
|
||||
*/
|
||||
maxPossibleConstraints = MaxBackends * 4;
|
||||
possibleConstraints =
|
||||
@@ -185,9 +194,9 @@ DeadLockCheck(PROC *proc)
|
||||
/* Apply any needed rearrangements of wait queues */
|
||||
for (i = 0; i < nWaitOrders; i++)
|
||||
{
|
||||
LOCK *lock = waitOrders[i].lock;
|
||||
PROC **procs = waitOrders[i].procs;
|
||||
int nProcs = waitOrders[i].nProcs;
|
||||
LOCK *lock = waitOrders[i].lock;
|
||||
PROC **procs = waitOrders[i].procs;
|
||||
int nProcs = waitOrders[i].nProcs;
|
||||
PROC_QUEUE *waitQueue = &(lock->waitProcs);
|
||||
|
||||
Assert(nProcs == waitQueue->size);
|
||||
@@ -218,10 +227,10 @@ DeadLockCheck(PROC *proc)
|
||||
* DeadLockCheckRecurse -- recursively search for valid orderings
|
||||
*
|
||||
* curConstraints[] holds the current set of constraints being considered
|
||||
* by an outer level of recursion. Add to this each possible solution
|
||||
* by an outer level of recursion. Add to this each possible solution
|
||||
* constraint for any cycle detected at this level.
|
||||
*
|
||||
* Returns TRUE if no solution exists. Returns FALSE if a deadlock-free
|
||||
* Returns TRUE if no solution exists. Returns FALSE if a deadlock-free
|
||||
* state is attainable, in which case waitOrders[] shows the required
|
||||
* rearrangements of lock wait queues (if any).
|
||||
*/
|
||||
@@ -252,6 +261,7 @@ DeadLockCheckRecurse(PROC *proc)
|
||||
/* Not room; will need to regenerate the edges on-the-fly */
|
||||
savedList = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try each available soft edge as an addition to the configuration.
|
||||
*/
|
||||
@@ -264,7 +274,7 @@ DeadLockCheckRecurse(PROC *proc)
|
||||
elog(FATAL, "DeadLockCheckRecurse: inconsistent results");
|
||||
}
|
||||
curConstraints[nCurConstraints] =
|
||||
possibleConstraints[oldPossibleConstraints+i];
|
||||
possibleConstraints[oldPossibleConstraints + i];
|
||||
nCurConstraints++;
|
||||
if (!DeadLockCheckRecurse(proc))
|
||||
return false; /* found a valid solution! */
|
||||
@@ -293,25 +303,27 @@ DeadLockCheckRecurse(PROC *proc)
|
||||
static bool
|
||||
TestConfiguration(PROC *startProc)
|
||||
{
|
||||
int softFound = 0;
|
||||
EDGE *softEdges = possibleConstraints + nPossibleConstraints;
|
||||
int nSoftEdges;
|
||||
int i;
|
||||
int softFound = 0;
|
||||
EDGE *softEdges = possibleConstraints + nPossibleConstraints;
|
||||
int nSoftEdges;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Make sure we have room for FindLockCycle's output.
|
||||
*/
|
||||
if (nPossibleConstraints + MaxBackends > maxPossibleConstraints)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Expand current constraint set into wait orderings. Fail if the
|
||||
* constraint set is not self-consistent.
|
||||
*/
|
||||
if (!ExpandConstraints(curConstraints, nCurConstraints))
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Check for cycles involving startProc or any of the procs mentioned
|
||||
* in constraints. We check startProc last because if it has a soft
|
||||
* in constraints. We check startProc last because if it has a soft
|
||||
* cycle still to be dealt with, we want to deal with that first.
|
||||
*/
|
||||
for (i = 0; i < nCurConstraints; i++)
|
||||
@@ -350,7 +362,7 @@ TestConfiguration(PROC *startProc)
|
||||
*
|
||||
* Since we need to be able to check hypothetical configurations that would
|
||||
* exist after wait queue rearrangement, the routine pays attention to the
|
||||
* table of hypothetical queue orders in waitOrders[]. These orders will
|
||||
* table of hypothetical queue orders in waitOrders[]. These orders will
|
||||
* be believed in preference to the actual ordering seen in the locktable.
|
||||
*/
|
||||
static bool
|
||||
@@ -391,9 +403,10 @@ FindLockCycleRecurse(PROC *checkProc,
|
||||
/* If we return to starting point, we have a deadlock cycle */
|
||||
if (i == 0)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Otherwise, we have a cycle but it does not include the start
|
||||
* point, so say "no deadlock".
|
||||
* Otherwise, we have a cycle but it does not include the
|
||||
* start point, so say "no deadlock".
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
@@ -401,6 +414,7 @@ FindLockCycleRecurse(PROC *checkProc,
|
||||
/* Mark proc as seen */
|
||||
Assert(nVisitedProcs < MaxBackends);
|
||||
visitedProcs[nVisitedProcs++] = checkProc;
|
||||
|
||||
/*
|
||||
* If the proc is not waiting, we have no outgoing waits-for edges.
|
||||
*/
|
||||
@@ -413,8 +427,9 @@ FindLockCycleRecurse(PROC *checkProc,
|
||||
lockctl = lockMethodTable->ctl;
|
||||
numLockModes = lockctl->numLockModes;
|
||||
conflictMask = lockctl->conflictTab[checkProc->waitLockMode];
|
||||
|
||||
/*
|
||||
* Scan for procs that already hold conflicting locks. These are
|
||||
* Scan for procs that already hold conflicting locks. These are
|
||||
* "hard" edges in the waits-for graph.
|
||||
*/
|
||||
lockHolders = &(lock->lockHolders);
|
||||
@@ -449,12 +464,13 @@ FindLockCycleRecurse(PROC *checkProc,
|
||||
|
||||
/*
|
||||
* Scan for procs that are ahead of this one in the lock's wait queue.
|
||||
* Those that have conflicting requests soft-block this one. This must
|
||||
* be done after the hard-block search, since if another proc both
|
||||
* hard- and soft-blocks this one, we want to call it a hard edge.
|
||||
* Those that have conflicting requests soft-block this one. This
|
||||
* must be done after the hard-block search, since if another proc
|
||||
* both hard- and soft-blocks this one, we want to call it a hard
|
||||
* edge.
|
||||
*
|
||||
* If there is a proposed re-ordering of the lock's wait order,
|
||||
* use that rather than the current wait order.
|
||||
* If there is a proposed re-ordering of the lock's wait order, use that
|
||||
* rather than the current wait order.
|
||||
*/
|
||||
for (i = 0; i < nWaitOrders; i++)
|
||||
{
|
||||
@@ -465,7 +481,7 @@ FindLockCycleRecurse(PROC *checkProc,
|
||||
if (i < nWaitOrders)
|
||||
{
|
||||
/* Use the given hypothetical wait queue order */
|
||||
PROC **procs = waitOrders[i].procs;
|
||||
PROC **procs = waitOrders[i].procs;
|
||||
|
||||
queue_size = waitOrders[i].nProcs;
|
||||
|
||||
@@ -483,7 +499,11 @@ FindLockCycleRecurse(PROC *checkProc,
|
||||
/* This proc soft-blocks checkProc */
|
||||
if (FindLockCycleRecurse(proc, softEdges, nSoftEdges))
|
||||
{
|
||||
/* Add this edge to the list of soft edges in the cycle */
|
||||
|
||||
/*
|
||||
* Add this edge to the list of soft edges in the
|
||||
* cycle
|
||||
*/
|
||||
Assert(*nSoftEdges < MaxBackends);
|
||||
softEdges[*nSoftEdges].waiter = checkProc;
|
||||
softEdges[*nSoftEdges].blocker = proc;
|
||||
@@ -513,7 +533,11 @@ FindLockCycleRecurse(PROC *checkProc,
|
||||
/* This proc soft-blocks checkProc */
|
||||
if (FindLockCycleRecurse(proc, softEdges, nSoftEdges))
|
||||
{
|
||||
/* Add this edge to the list of soft edges in the cycle */
|
||||
|
||||
/*
|
||||
* Add this edge to the list of soft edges in the
|
||||
* cycle
|
||||
*/
|
||||
Assert(*nSoftEdges < MaxBackends);
|
||||
softEdges[*nSoftEdges].waiter = checkProc;
|
||||
softEdges[*nSoftEdges].blocker = proc;
|
||||
@@ -553,18 +577,19 @@ ExpandConstraints(EDGE *constraints,
|
||||
j;
|
||||
|
||||
nWaitOrders = 0;
|
||||
|
||||
/*
|
||||
* Scan constraint list backwards. This is because the last-added
|
||||
* Scan constraint list backwards. This is because the last-added
|
||||
* constraint is the only one that could fail, and so we want to test
|
||||
* it for inconsistency first.
|
||||
*/
|
||||
for (i = nConstraints; --i >= 0; )
|
||||
for (i = nConstraints; --i >= 0;)
|
||||
{
|
||||
PROC *proc = constraints[i].waiter;
|
||||
LOCK *lock = proc->waitLock;
|
||||
PROC *proc = constraints[i].waiter;
|
||||
LOCK *lock = proc->waitLock;
|
||||
|
||||
/* Did we already make a list for this lock? */
|
||||
for (j = nWaitOrders; --j >= 0; )
|
||||
for (j = nWaitOrders; --j >= 0;)
|
||||
{
|
||||
if (waitOrders[j].lock == lock)
|
||||
break;
|
||||
@@ -577,11 +602,12 @@ ExpandConstraints(EDGE *constraints,
|
||||
waitOrders[nWaitOrders].nProcs = lock->waitProcs.size;
|
||||
nWaitOrderProcs += lock->waitProcs.size;
|
||||
Assert(nWaitOrderProcs <= MaxBackends);
|
||||
|
||||
/*
|
||||
* Do the topo sort. TopoSort need not examine constraints after
|
||||
* this one, since they must be for different locks.
|
||||
*/
|
||||
if (!TopoSort(lock, constraints, i+1,
|
||||
if (!TopoSort(lock, constraints, i + 1,
|
||||
waitOrders[nWaitOrders].procs))
|
||||
return false;
|
||||
nWaitOrders++;
|
||||
@@ -607,7 +633,7 @@ ExpandConstraints(EDGE *constraints,
|
||||
* The initial queue ordering is taken directly from the lock's wait queue.
|
||||
* The output is an array of PROC pointers, of length equal to the lock's
|
||||
* wait queue length (the caller is responsible for providing this space).
|
||||
* The partial order is specified by an array of EDGE structs. Each EDGE
|
||||
* The partial order is specified by an array of EDGE structs. Each EDGE
|
||||
* is one that we need to reverse, therefore the "waiter" must appear before
|
||||
* the "blocker" in the output array. The EDGE array may well contain
|
||||
* edges associated with other locks; these should be ignored.
|
||||
@@ -638,14 +664,15 @@ TopoSort(LOCK *lock,
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan the constraints, and for each proc in the array, generate a count
|
||||
* of the number of constraints that say it must be before something else,
|
||||
* plus a list of the constraints that say it must be after something else.
|
||||
* The count for the j'th proc is stored in beforeConstraints[j], and the
|
||||
* head of its list in afterConstraints[j]. Each constraint stores its
|
||||
* list link in constraints[i].link (note any constraint will be in
|
||||
* just one list). The array index for the before-proc of the i'th
|
||||
* constraint is remembered in constraints[i].pred.
|
||||
* Scan the constraints, and for each proc in the array, generate a
|
||||
* count of the number of constraints that say it must be before
|
||||
* something else, plus a list of the constraints that say it must be
|
||||
* after something else. The count for the j'th proc is stored in
|
||||
* beforeConstraints[j], and the head of its list in
|
||||
* afterConstraints[j]. Each constraint stores its list link in
|
||||
* constraints[i].link (note any constraint will be in just one list).
|
||||
* The array index for the before-proc of the i'th constraint is
|
||||
* remembered in constraints[i].pred.
|
||||
*/
|
||||
MemSet(beforeConstraints, 0, queue_size * sizeof(int));
|
||||
MemSet(afterConstraints, 0, queue_size * sizeof(int));
|
||||
@@ -656,7 +683,7 @@ TopoSort(LOCK *lock,
|
||||
if (proc->waitLock != lock)
|
||||
continue;
|
||||
/* Find the waiter proc in the array */
|
||||
for (j = queue_size; --j >= 0; )
|
||||
for (j = queue_size; --j >= 0;)
|
||||
{
|
||||
if (topoProcs[j] == proc)
|
||||
break;
|
||||
@@ -664,20 +691,20 @@ TopoSort(LOCK *lock,
|
||||
Assert(j >= 0); /* should have found a match */
|
||||
/* Find the blocker proc in the array */
|
||||
proc = constraints[i].blocker;
|
||||
for (k = queue_size; --k >= 0; )
|
||||
for (k = queue_size; --k >= 0;)
|
||||
{
|
||||
if (topoProcs[k] == proc)
|
||||
break;
|
||||
}
|
||||
Assert(k >= 0); /* should have found a match */
|
||||
beforeConstraints[j]++; /* waiter must come before */
|
||||
beforeConstraints[j]++; /* waiter must come before */
|
||||
/* add this constraint to list of after-constraints for blocker */
|
||||
constraints[i].pred = j;
|
||||
constraints[i].link = afterConstraints[k];
|
||||
afterConstraints[k] = i+1;
|
||||
afterConstraints[k] = i + 1;
|
||||
}
|
||||
/*--------------------
|
||||
* Now scan the topoProcs array backwards. At each step, output the
|
||||
* Now scan the topoProcs array backwards. At each step, output the
|
||||
* last proc that has no remaining before-constraints, and decrease
|
||||
* the beforeConstraints count of each of the procs it was constrained
|
||||
* against.
|
||||
@@ -687,8 +714,8 @@ TopoSort(LOCK *lock,
|
||||
* last = last non-null index in topoProcs (avoid redundant searches)
|
||||
*--------------------
|
||||
*/
|
||||
last = queue_size-1;
|
||||
for (i = queue_size; --i >= 0; )
|
||||
last = queue_size - 1;
|
||||
for (i = queue_size; --i >= 0;)
|
||||
{
|
||||
/* Find next candidate to output */
|
||||
while (topoProcs[last] == NULL)
|
||||
@@ -705,10 +732,8 @@ TopoSort(LOCK *lock,
|
||||
ordering[i] = topoProcs[j];
|
||||
topoProcs[j] = NULL;
|
||||
/* Update beforeConstraints counts of its predecessors */
|
||||
for (k = afterConstraints[j]; k > 0; k = constraints[k-1].link)
|
||||
{
|
||||
beforeConstraints[constraints[k-1].pred]--;
|
||||
}
|
||||
for (k = afterConstraints[j]; k > 0; k = constraints[k - 1].link)
|
||||
beforeConstraints[constraints[k - 1].pred]--;
|
||||
}
|
||||
|
||||
/* Done */
|
||||
@@ -734,4 +759,5 @@ PrintLockQueue(LOCK *lock, const char *info)
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lmgr.c,v 1.44 2001/01/24 19:43:07 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lmgr.c,v 1.45 2001/03/22 03:59:46 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -174,7 +174,7 @@ UnlockRelation(Relation relation, LOCKMODE lockmode)
|
||||
/*
|
||||
* LockRelationForSession
|
||||
*
|
||||
* This routine grabs a session-level lock on the target relation. The
|
||||
* This routine grabs a session-level lock on the target relation. The
|
||||
* session lock persists across transaction boundaries. It will be removed
|
||||
* when UnlockRelationForSession() is called, or if an elog(ERROR) occurs,
|
||||
* or if the backend exits.
|
||||
@@ -291,6 +291,7 @@ XactLockTableDelete(TransactionId xid)
|
||||
|
||||
LockRelease(LockTableId, &tag, xid, ExclusiveLock);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.87 2001/03/18 20:13:13 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.88 2001/03/22 03:59:46 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Outside modules can create a lock table and acquire/release
|
||||
@@ -40,10 +40,10 @@
|
||||
#include "utils/memutils.h"
|
||||
#include "utils/ps_status.h"
|
||||
|
||||
static int WaitOnLock(LOCKMETHOD lockmethod, LOCKMODE lockmode,
|
||||
LOCK *lock, HOLDER *holder);
|
||||
static int WaitOnLock(LOCKMETHOD lockmethod, LOCKMODE lockmode,
|
||||
LOCK *lock, HOLDER *holder);
|
||||
static void LockCountMyLocks(SHMEM_OFFSET lockOffset, PROC *proc,
|
||||
int *myHolding);
|
||||
int *myHolding);
|
||||
|
||||
static char *lock_mode_names[] =
|
||||
{
|
||||
@@ -65,40 +65,40 @@ static char *DeadLockMessage = "Deadlock detected.\n\tSee the lock(l) manual pag
|
||||
/*------
|
||||
* The following configuration options are available for lock debugging:
|
||||
*
|
||||
* TRACE_LOCKS -- give a bunch of output what's going on in this file
|
||||
* TRACE_USERLOCKS -- same but for user locks
|
||||
* TRACE_LOCK_OIDMIN-- do not trace locks for tables below this oid
|
||||
* (use to avoid output on system tables)
|
||||
* TRACE_LOCK_TABLE -- trace locks on this table (oid) unconditionally
|
||||
* DEBUG_DEADLOCKS -- currently dumps locks at untimely occasions ;)
|
||||
* TRACE_LOCKS -- give a bunch of output what's going on in this file
|
||||
* TRACE_USERLOCKS -- same but for user locks
|
||||
* TRACE_LOCK_OIDMIN-- do not trace locks for tables below this oid
|
||||
* (use to avoid output on system tables)
|
||||
* TRACE_LOCK_TABLE -- trace locks on this table (oid) unconditionally
|
||||
* DEBUG_DEADLOCKS -- currently dumps locks at untimely occasions ;)
|
||||
*
|
||||
* Furthermore, but in storage/ipc/spin.c:
|
||||
* TRACE_SPINLOCKS -- trace spinlocks (pretty useless)
|
||||
* TRACE_SPINLOCKS -- trace spinlocks (pretty useless)
|
||||
*
|
||||
* Define LOCK_DEBUG at compile time to get all these enabled.
|
||||
* --------
|
||||
*/
|
||||
|
||||
int Trace_lock_oidmin = BootstrapObjectIdData;
|
||||
bool Trace_locks = false;
|
||||
bool Trace_userlocks = false;
|
||||
int Trace_lock_table = 0;
|
||||
bool Debug_deadlocks = false;
|
||||
int Trace_lock_oidmin = BootstrapObjectIdData;
|
||||
bool Trace_locks = false;
|
||||
bool Trace_userlocks = false;
|
||||
int Trace_lock_table = 0;
|
||||
bool Debug_deadlocks = false;
|
||||
|
||||
|
||||
inline static bool
|
||||
LOCK_DEBUG_ENABLED(const LOCK * lock)
|
||||
LOCK_DEBUG_ENABLED(const LOCK *lock)
|
||||
{
|
||||
return
|
||||
(((LOCK_LOCKMETHOD(*lock) == DEFAULT_LOCKMETHOD && Trace_locks)
|
||||
|| (LOCK_LOCKMETHOD(*lock) == USER_LOCKMETHOD && Trace_userlocks))
|
||||
&& (lock->tag.relId >= (Oid) Trace_lock_oidmin))
|
||||
|| (Trace_lock_table && (lock->tag.relId == Trace_lock_table));
|
||||
(((LOCK_LOCKMETHOD(*lock) == DEFAULT_LOCKMETHOD && Trace_locks)
|
||||
|| (LOCK_LOCKMETHOD(*lock) == USER_LOCKMETHOD && Trace_userlocks))
|
||||
&& (lock->tag.relId >= (Oid) Trace_lock_oidmin))
|
||||
|| (Trace_lock_table && (lock->tag.relId == Trace_lock_table));
|
||||
}
|
||||
|
||||
|
||||
inline static void
|
||||
LOCK_PRINT(const char * where, const LOCK * lock, LOCKMODE type)
|
||||
LOCK_PRINT(const char *where, const LOCK *lock, LOCKMODE type)
|
||||
{
|
||||
if (LOCK_DEBUG_ENABLED(lock))
|
||||
elog(DEBUG,
|
||||
@@ -119,30 +119,30 @@ LOCK_PRINT(const char * where, const LOCK * lock, LOCKMODE type)
|
||||
|
||||
|
||||
inline static void
|
||||
HOLDER_PRINT(const char * where, const HOLDER * holderP)
|
||||
HOLDER_PRINT(const char *where, const HOLDER *holderP)
|
||||
{
|
||||
if (
|
||||
(((HOLDER_LOCKMETHOD(*holderP) == DEFAULT_LOCKMETHOD && Trace_locks)
|
||||
|| (HOLDER_LOCKMETHOD(*holderP) == USER_LOCKMETHOD && Trace_userlocks))
|
||||
&& (((LOCK *)MAKE_PTR(holderP->tag.lock))->tag.relId >= (Oid) Trace_lock_oidmin))
|
||||
|| (Trace_lock_table && (((LOCK *)MAKE_PTR(holderP->tag.lock))->tag.relId == Trace_lock_table))
|
||||
)
|
||||
(((HOLDER_LOCKMETHOD(*holderP) == DEFAULT_LOCKMETHOD && Trace_locks)
|
||||
|| (HOLDER_LOCKMETHOD(*holderP) == USER_LOCKMETHOD && Trace_userlocks))
|
||||
&& (((LOCK *) MAKE_PTR(holderP->tag.lock))->tag.relId >= (Oid) Trace_lock_oidmin))
|
||||
|| (Trace_lock_table && (((LOCK *) MAKE_PTR(holderP->tag.lock))->tag.relId == Trace_lock_table))
|
||||
)
|
||||
elog(DEBUG,
|
||||
"%s: holder(%lx) lock(%lx) tbl(%d) proc(%lx) xid(%u) hold(%d,%d,%d,%d,%d,%d,%d)=%d",
|
||||
where, MAKE_OFFSET(holderP), holderP->tag.lock,
|
||||
HOLDER_LOCKMETHOD(*(holderP)),
|
||||
holderP->tag.proc, holderP->tag.xid,
|
||||
holderP->holding[1], holderP->holding[2], holderP->holding[3],
|
||||
holderP->holding[4], holderP->holding[5], holderP->holding[6],
|
||||
holderP->holding[1], holderP->holding[2], holderP->holding[3],
|
||||
holderP->holding[4], holderP->holding[5], holderP->holding[6],
|
||||
holderP->holding[7], holderP->nHolding);
|
||||
}
|
||||
|
||||
#else /* not LOCK_DEBUG */
|
||||
#else /* not LOCK_DEBUG */
|
||||
|
||||
#define LOCK_PRINT(where, lock, type)
|
||||
#define HOLDER_PRINT(where, holderP)
|
||||
|
||||
#endif /* not LOCK_DEBUG */
|
||||
#endif /* not LOCK_DEBUG */
|
||||
|
||||
|
||||
|
||||
@@ -218,7 +218,7 @@ LockingDisabled(void)
|
||||
LOCKMETHODTABLE *
|
||||
GetLocksMethodTable(LOCK *lock)
|
||||
{
|
||||
LOCKMETHOD lockmethod = LOCK_LOCKMETHOD(*lock);
|
||||
LOCKMETHOD lockmethod = LOCK_LOCKMETHOD(*lock);
|
||||
|
||||
Assert(lockmethod > 0 && lockmethod < NumLockMethods);
|
||||
return LockMethodTable[lockmethod];
|
||||
@@ -258,7 +258,7 @@ LockMethodInit(LOCKMETHODTABLE *lockMethodTable,
|
||||
* is wasteful, in this case, but not much space is involved.
|
||||
*
|
||||
* NOTE: data structures allocated here are allocated permanently, using
|
||||
* TopMemoryContext and shared memory. We don't ever release them anyway,
|
||||
* TopMemoryContext and shared memory. We don't ever release them anyway,
|
||||
* and in normal multi-backend operation the lock table structures set up
|
||||
* by the postmaster are inherited by each backend, so they must be in
|
||||
* TopMemoryContext.
|
||||
@@ -304,8 +304,8 @@ LockMethodTableInit(char *tabName,
|
||||
SpinAcquire(LockMgrLock);
|
||||
|
||||
/*
|
||||
* allocate a control structure from shared memory or attach to it
|
||||
* if it already exists.
|
||||
* allocate a control structure from shared memory or attach to it if
|
||||
* it already exists.
|
||||
*
|
||||
*/
|
||||
sprintf(shmemName, "%s (ctl)", tabName);
|
||||
@@ -341,8 +341,8 @@ LockMethodTableInit(char *tabName,
|
||||
Assert(NumLockMethods <= MAX_LOCK_METHODS);
|
||||
|
||||
/*
|
||||
* allocate a hash table for LOCK structs. This is used
|
||||
* to store per-locked-object information.
|
||||
* allocate a hash table for LOCK structs. This is used to store
|
||||
* per-locked-object information.
|
||||
*
|
||||
*/
|
||||
info.keysize = SHMEM_LOCKTAB_KEYSIZE;
|
||||
@@ -362,8 +362,8 @@ LockMethodTableInit(char *tabName,
|
||||
Assert(lockMethodTable->lockHash->hash == tag_hash);
|
||||
|
||||
/*
|
||||
* allocate a hash table for HOLDER structs. This is used
|
||||
* to store per-lock-holder information.
|
||||
* allocate a hash table for HOLDER structs. This is used to store
|
||||
* per-lock-holder information.
|
||||
*
|
||||
*/
|
||||
info.keysize = SHMEM_HOLDERTAB_KEYSIZE;
|
||||
@@ -558,7 +558,8 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
||||
* Create the hash key for the holder table.
|
||||
*
|
||||
*/
|
||||
MemSet(&holdertag, 0, sizeof(HOLDERTAG)); /* must clear padding, needed */
|
||||
MemSet(&holdertag, 0, sizeof(HOLDERTAG)); /* must clear padding,
|
||||
* needed */
|
||||
holdertag.lock = MAKE_OFFSET(lock);
|
||||
holdertag.proc = MAKE_OFFSET(MyProc);
|
||||
TransactionIdStore(xid, &holdertag.xid);
|
||||
@@ -595,6 +596,7 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
||||
Assert(holder->nHolding <= lock->nGranted);
|
||||
|
||||
#ifdef CHECK_DEADLOCK_RISK
|
||||
|
||||
/*
|
||||
* Issue warning if we already hold a lower-level lock on this
|
||||
* object and do not hold a lock of the requested level or higher.
|
||||
@@ -602,12 +604,13 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
||||
* a deadlock if another backend were following the same code path
|
||||
* at about the same time).
|
||||
*
|
||||
* This is not enabled by default, because it may generate log entries
|
||||
* about user-level coding practices that are in fact safe in context.
|
||||
* It can be enabled to help find system-level problems.
|
||||
* This is not enabled by default, because it may generate log
|
||||
* entries about user-level coding practices that are in fact safe
|
||||
* in context. It can be enabled to help find system-level
|
||||
* problems.
|
||||
*
|
||||
* XXX Doing numeric comparison on the lockmodes is a hack;
|
||||
* it'd be better to use a table. For now, though, this works.
|
||||
* XXX Doing numeric comparison on the lockmodes is a hack; it'd be
|
||||
* better to use a table. For now, though, this works.
|
||||
*/
|
||||
for (i = lockMethodTable->ctl->numLockModes; i > 0; i--)
|
||||
{
|
||||
@@ -618,17 +621,17 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
||||
elog(DEBUG, "Deadlock risk: raising lock level"
|
||||
" from %s to %s on object %u/%u/%u",
|
||||
lock_mode_names[i], lock_mode_names[lockmode],
|
||||
lock->tag.relId, lock->tag.dbId, lock->tag.objId.blkno);
|
||||
lock->tag.relId, lock->tag.dbId, lock->tag.objId.blkno);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* CHECK_DEADLOCK_RISK */
|
||||
#endif /* CHECK_DEADLOCK_RISK */
|
||||
}
|
||||
|
||||
/*
|
||||
* lock->nRequested and lock->requested[] count the total number of
|
||||
* requests, whether granted or waiting, so increment those immediately.
|
||||
* The other counts don't increment till we get the lock.
|
||||
* requests, whether granted or waiting, so increment those
|
||||
* immediately. The other counts don't increment till we get the lock.
|
||||
*
|
||||
*/
|
||||
lock->nRequested++;
|
||||
@@ -636,8 +639,8 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
||||
Assert((lock->nRequested > 0) && (lock->requested[lockmode] > 0));
|
||||
|
||||
/*
|
||||
* If I already hold one or more locks of the requested type,
|
||||
* just grant myself another one without blocking.
|
||||
* If I already hold one or more locks of the requested type, just
|
||||
* grant myself another one without blocking.
|
||||
*
|
||||
*/
|
||||
if (holder->holding[lockmode] > 0)
|
||||
@@ -649,8 +652,8 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
||||
}
|
||||
|
||||
/*
|
||||
* If this process (under any XID) is a holder of the lock,
|
||||
* also grant myself another one without blocking.
|
||||
* If this process (under any XID) is a holder of the lock, also grant
|
||||
* myself another one without blocking.
|
||||
*
|
||||
*/
|
||||
LockCountMyLocks(holder->tag.lock, MyProc, myHolding);
|
||||
@@ -663,9 +666,9 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
||||
}
|
||||
|
||||
/*
|
||||
* If lock requested conflicts with locks requested by waiters,
|
||||
* must join wait queue. Otherwise, check for conflict with
|
||||
* already-held locks. (That's last because most complex check.)
|
||||
* If lock requested conflicts with locks requested by waiters, must
|
||||
* join wait queue. Otherwise, check for conflict with already-held
|
||||
* locks. (That's last because most complex check.)
|
||||
*
|
||||
*/
|
||||
if (lockMethodTable->ctl->conflictTab[lockmode] & lock->waitMask)
|
||||
@@ -711,7 +714,7 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
||||
SpinRelease(masterLock);
|
||||
return FALSE;
|
||||
}
|
||||
#endif /* USER_LOCKS */
|
||||
#endif /* USER_LOCKS */
|
||||
|
||||
/*
|
||||
* Construct bitmask of locks this process holds on this object.
|
||||
@@ -737,8 +740,9 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
||||
|
||||
/*
|
||||
* NOTE: do not do any material change of state between here and
|
||||
* return. All required changes in locktable state must have been
|
||||
* done when the lock was granted to us --- see notes in WaitOnLock.
|
||||
* return. All required changes in locktable state must have been
|
||||
* done when the lock was granted to us --- see notes in
|
||||
* WaitOnLock.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -795,13 +799,13 @@ LockCheckConflicts(LOCKMETHODTABLE *lockMethodTable,
|
||||
int localHolding[MAX_LOCKMODES];
|
||||
|
||||
/*
|
||||
* first check for global conflicts: If no locks conflict
|
||||
* with my request, then I get the lock.
|
||||
* first check for global conflicts: If no locks conflict with my
|
||||
* request, then I get the lock.
|
||||
*
|
||||
* Checking for conflict: lock->grantMask represents the types of
|
||||
* currently held locks. conflictTable[lockmode] has a bit
|
||||
* set for each type of lock that conflicts with request. Bitwise
|
||||
* compare tells if there is a conflict.
|
||||
* currently held locks. conflictTable[lockmode] has a bit set for
|
||||
* each type of lock that conflicts with request. Bitwise compare
|
||||
* tells if there is a conflict.
|
||||
*
|
||||
*/
|
||||
if (!(lockctl->conflictTab[lockmode] & lock->grantMask))
|
||||
@@ -811,10 +815,10 @@ LockCheckConflicts(LOCKMETHODTABLE *lockMethodTable,
|
||||
}
|
||||
|
||||
/*
|
||||
* Rats. Something conflicts. But it could still be my own
|
||||
* lock. We have to construct a conflict mask
|
||||
* that does not reflect our own locks. Locks held by the current
|
||||
* process under another XID also count as "our own locks".
|
||||
* Rats. Something conflicts. But it could still be my own lock. We
|
||||
* have to construct a conflict mask that does not reflect our own
|
||||
* locks. Locks held by the current process under another XID also
|
||||
* count as "our own locks".
|
||||
*
|
||||
*/
|
||||
if (myHolding == NULL)
|
||||
@@ -834,10 +838,9 @@ LockCheckConflicts(LOCKMETHODTABLE *lockMethodTable,
|
||||
}
|
||||
|
||||
/*
|
||||
* now check again for conflicts. 'bitmask' describes the types
|
||||
* of locks held by other processes. If one of these
|
||||
* conflicts with the kind of lock that I want, there is a
|
||||
* conflict and I have to sleep.
|
||||
* now check again for conflicts. 'bitmask' describes the types of
|
||||
* locks held by other processes. If one of these conflicts with the
|
||||
* kind of lock that I want, there is a conflict and I have to sleep.
|
||||
*
|
||||
*/
|
||||
if (!(lockctl->conflictTab[lockmode] & bitmask))
|
||||
@@ -878,9 +881,7 @@ LockCountMyLocks(SHMEM_OFFSET lockOffset, PROC *proc, int *myHolding)
|
||||
if (lockOffset == holder->tag.lock)
|
||||
{
|
||||
for (i = 1; i < MAX_LOCKMODES; i++)
|
||||
{
|
||||
myHolding[i] += holder->holding[i];
|
||||
}
|
||||
}
|
||||
|
||||
holder = (HOLDER *) SHMQueueNext(procHolders, &holder->procLink,
|
||||
@@ -947,8 +948,8 @@ WaitOnLock(LOCKMETHOD lockmethod, LOCKMODE lockmode,
|
||||
* Hence, after granting, the locktable state must fully reflect the
|
||||
* fact that we own the lock; we can't do additional work on return.
|
||||
* Contrariwise, if we fail, any cleanup must happen in xact abort
|
||||
* processing, not here, to ensure it will also happen in the cancel/die
|
||||
* case.
|
||||
* processing, not here, to ensure it will also happen in the
|
||||
* cancel/die case.
|
||||
*/
|
||||
|
||||
if (ProcSleep(lockMethodTable,
|
||||
@@ -956,9 +957,10 @@ WaitOnLock(LOCKMETHOD lockmethod, LOCKMODE lockmode,
|
||||
lock,
|
||||
holder) != STATUS_OK)
|
||||
{
|
||||
|
||||
/*
|
||||
* We failed as a result of a deadlock, see HandleDeadLock().
|
||||
* Quit now. Removal of the holder and lock objects, if no longer
|
||||
* We failed as a result of a deadlock, see HandleDeadLock(). Quit
|
||||
* now. Removal of the holder and lock objects, if no longer
|
||||
* needed, will happen in xact cleanup (see above for motivation).
|
||||
*/
|
||||
LOCK_PRINT("WaitOnLock: aborting on lock", lock, lockmode);
|
||||
@@ -984,15 +986,15 @@ WaitOnLock(LOCKMETHOD lockmethod, LOCKMODE lockmode,
|
||||
* NB: this does not remove the process' holder object, nor the lock object,
|
||||
* even though their counts might now have gone to zero. That will happen
|
||||
* during a subsequent LockReleaseAll call, which we expect will happen
|
||||
* during transaction cleanup. (Removal of a proc from its wait queue by
|
||||
* during transaction cleanup. (Removal of a proc from its wait queue by
|
||||
* this routine can only happen if we are aborting the transaction.)
|
||||
*--------------------
|
||||
*/
|
||||
void
|
||||
RemoveFromWaitQueue(PROC *proc)
|
||||
{
|
||||
LOCK *waitLock = proc->waitLock;
|
||||
LOCKMODE lockmode = proc->waitLockMode;
|
||||
LOCK *waitLock = proc->waitLock;
|
||||
LOCKMODE lockmode = proc->waitLockMode;
|
||||
|
||||
/* Make sure proc is waiting */
|
||||
Assert(proc->links.next != INVALID_OFFSET);
|
||||
@@ -1095,7 +1097,8 @@ LockRelease(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
||||
/*
|
||||
* Find the holder entry for this holder.
|
||||
*/
|
||||
MemSet(&holdertag, 0, sizeof(HOLDERTAG)); /* must clear padding, needed */
|
||||
MemSet(&holdertag, 0, sizeof(HOLDERTAG)); /* must clear padding,
|
||||
* needed */
|
||||
holdertag.lock = MAKE_OFFSET(lock);
|
||||
holdertag.proc = MAKE_OFFSET(MyProc);
|
||||
TransactionIdStore(xid, &holdertag.xid);
|
||||
@@ -1156,11 +1159,11 @@ LockRelease(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
||||
/*
|
||||
* We need only run ProcLockWakeup if the released lock conflicts with
|
||||
* at least one of the lock types requested by waiter(s). Otherwise
|
||||
* whatever conflict made them wait must still exist. NOTE: before MVCC,
|
||||
* we could skip wakeup if lock->granted[lockmode] was still positive.
|
||||
* But that's not true anymore, because the remaining granted locks might
|
||||
* belong to some waiter, who could now be awakened because he doesn't
|
||||
* conflict with his own locks.
|
||||
* whatever conflict made them wait must still exist. NOTE: before
|
||||
* MVCC, we could skip wakeup if lock->granted[lockmode] was still
|
||||
* positive. But that's not true anymore, because the remaining
|
||||
* granted locks might belong to some waiter, who could now be
|
||||
* awakened because he doesn't conflict with his own locks.
|
||||
*
|
||||
*/
|
||||
if (lockMethodTable->ctl->conflictTab[lockmode] & lock->waitMask)
|
||||
@@ -1168,10 +1171,10 @@ LockRelease(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
||||
|
||||
if (lock->nRequested == 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* if there's no one waiting in the queue,
|
||||
* we just released the last lock on this object.
|
||||
* Delete it from the lock table.
|
||||
* if there's no one waiting in the queue, we just released the
|
||||
* last lock on this object. Delete it from the lock table.
|
||||
*
|
||||
*/
|
||||
Assert(lockMethodTable->lockHash->hash == tag_hash);
|
||||
@@ -1197,8 +1200,8 @@ LockRelease(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
||||
Assert((holder->nHolding >= 0) && (holder->holding[lockmode] >= 0));
|
||||
|
||||
/*
|
||||
* If this was my last hold on this lock, delete my entry in the holder
|
||||
* table.
|
||||
* If this was my last hold on this lock, delete my entry in the
|
||||
* holder table.
|
||||
*/
|
||||
if (holder->nHolding == 0)
|
||||
{
|
||||
@@ -1316,11 +1319,12 @@ LockReleaseAll(LOCKMETHOD lockmethod, PROC *proc,
|
||||
Assert(lock->requested[i] >= 0 && lock->granted[i] >= 0);
|
||||
if (lock->granted[i] == 0)
|
||||
lock->grantMask &= BITS_OFF[i];
|
||||
|
||||
/*
|
||||
* Read comments in LockRelease
|
||||
*/
|
||||
if (!wakeupNeeded &&
|
||||
lockMethodTable->ctl->conflictTab[i] & lock->waitMask)
|
||||
lockMethodTable->ctl->conflictTab[i] & lock->waitMask)
|
||||
wakeupNeeded = true;
|
||||
}
|
||||
}
|
||||
@@ -1331,9 +1335,10 @@ LockReleaseAll(LOCKMETHOD lockmethod, PROC *proc,
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* This holder accounts for all the requested locks on the object,
|
||||
* so we can be lazy and just zero things out.
|
||||
* This holder accounts for all the requested locks on the
|
||||
* object, so we can be lazy and just zero things out.
|
||||
*
|
||||
*/
|
||||
lock->nRequested = 0;
|
||||
@@ -1371,6 +1376,7 @@ LockReleaseAll(LOCKMETHOD lockmethod, PROC *proc,
|
||||
|
||||
if (lock->nRequested == 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* We've just released the last lock, so garbage-collect the
|
||||
* lock object.
|
||||
@@ -1412,7 +1418,8 @@ LockShmemSize(int maxBackends)
|
||||
|
||||
size += MAXALIGN(sizeof(PROC_HDR)); /* ProcGlobal */
|
||||
size += maxBackends * MAXALIGN(sizeof(PROC)); /* each MyProc */
|
||||
size += MAX_LOCK_METHODS * MAXALIGN(sizeof(LOCKMETHODCTL)); /* each lockMethodTable->ctl */
|
||||
size += MAX_LOCK_METHODS * MAXALIGN(sizeof(LOCKMETHODCTL)); /* each
|
||||
* lockMethodTable->ctl */
|
||||
|
||||
/* lockHash table */
|
||||
size += hash_estimate_size(NLOCKENTS(maxBackends),
|
||||
@@ -1534,4 +1541,4 @@ DumpAllLocks(void)
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* LOCK_DEBUG */
|
||||
#endif /* LOCK_DEBUG */
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.98 2001/01/26 18:23:12 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.99 2001/03/22 03:59:46 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -76,7 +76,7 @@
|
||||
#include "storage/proc.h"
|
||||
|
||||
|
||||
int DeadlockTimeout = 1000;
|
||||
int DeadlockTimeout = 1000;
|
||||
|
||||
/* --------------------
|
||||
* Spin lock for manipulating the shared process data structure:
|
||||
@@ -147,10 +147,10 @@ InitProcGlobal(int maxBackends)
|
||||
|
||||
/*
|
||||
* Arrange to delete semas on exit --- set this up now so that we
|
||||
* will clean up if pre-allocation fails. We use our own freeproc,
|
||||
* rather than IpcSemaphoreCreate's removeOnExit option, because
|
||||
* we don't want to fill up the on_shmem_exit list with a separate
|
||||
* entry for each semaphore set.
|
||||
* will clean up if pre-allocation fails. We use our own
|
||||
* freeproc, rather than IpcSemaphoreCreate's removeOnExit option,
|
||||
* because we don't want to fill up the on_shmem_exit list with a
|
||||
* separate entry for each semaphore set.
|
||||
*/
|
||||
on_shmem_exit(ProcFreeAllSemaphores, 0);
|
||||
|
||||
@@ -159,9 +159,9 @@ InitProcGlobal(int maxBackends)
|
||||
*/
|
||||
Assert(maxBackends > 0 && maxBackends <= MAXBACKENDS);
|
||||
|
||||
for (i = 0; i < ((maxBackends-1)/PROC_NSEMS_PER_SET+1); i++)
|
||||
for (i = 0; i < ((maxBackends - 1) / PROC_NSEMS_PER_SET + 1); i++)
|
||||
{
|
||||
IpcSemaphoreId semId;
|
||||
IpcSemaphoreId semId;
|
||||
|
||||
semId = IpcSemaphoreCreate(PROC_NSEMS_PER_SET,
|
||||
IPCProtection,
|
||||
@@ -242,6 +242,7 @@ InitProcess(void)
|
||||
if (IsUnderPostmaster)
|
||||
{
|
||||
ProcGetNewSemIdAndNum(&MyProc->sem.semId, &MyProc->sem.semNum);
|
||||
|
||||
/*
|
||||
* we might be reusing a semaphore that belongs to a dead backend.
|
||||
* So be careful and reinitialize its value here.
|
||||
@@ -288,8 +289,8 @@ InitProcess(void)
|
||||
on_shmem_exit(ProcKill, 0);
|
||||
|
||||
/*
|
||||
* Now that we have a PROC, we could try to acquire locks,
|
||||
* so initialize the deadlock checker.
|
||||
* Now that we have a PROC, we could try to acquire locks, so
|
||||
* initialize the deadlock checker.
|
||||
*/
|
||||
InitDeadLockChecking();
|
||||
}
|
||||
@@ -300,7 +301,7 @@ InitProcess(void)
|
||||
static void
|
||||
ZeroProcSemaphore(PROC *proc)
|
||||
{
|
||||
union semun semun;
|
||||
union semun semun;
|
||||
|
||||
semun.val = 0;
|
||||
if (semctl(proc->sem.semId, proc->sem.semNum, SETVAL, semun) < 0)
|
||||
@@ -333,15 +334,15 @@ LockWaitCancel(void)
|
||||
#ifndef __BEOS__
|
||||
{
|
||||
struct itimerval timeval,
|
||||
dummy;
|
||||
dummy;
|
||||
|
||||
MemSet(&timeval, 0, sizeof(struct itimerval));
|
||||
setitimer(ITIMER_REAL, &timeval, &dummy);
|
||||
}
|
||||
#else
|
||||
/* BeOS doesn't have setitimer, but has set_alarm */
|
||||
set_alarm(B_INFINITE_TIMEOUT, B_PERIODIC_ALARM);
|
||||
#endif /* __BEOS__ */
|
||||
set_alarm(B_INFINITE_TIMEOUT, B_PERIODIC_ALARM);
|
||||
#endif /* __BEOS__ */
|
||||
|
||||
/* Unlink myself from the wait queue, if on it (might not be anymore!) */
|
||||
LockLockTable();
|
||||
@@ -352,17 +353,17 @@ LockWaitCancel(void)
|
||||
/*
|
||||
* Reset the proc wait semaphore to zero. This is necessary in the
|
||||
* scenario where someone else granted us the lock we wanted before we
|
||||
* were able to remove ourselves from the wait-list. The semaphore will
|
||||
* have been bumped to 1 by the would-be grantor, and since we are no
|
||||
* longer going to wait on the sema, we have to force it back to zero.
|
||||
* Otherwise, our next attempt to wait for a lock will fall through
|
||||
* prematurely.
|
||||
* were able to remove ourselves from the wait-list. The semaphore
|
||||
* will have been bumped to 1 by the would-be grantor, and since we
|
||||
* are no longer going to wait on the sema, we have to force it back
|
||||
* to zero. Otherwise, our next attempt to wait for a lock will fall
|
||||
* through prematurely.
|
||||
*/
|
||||
ZeroProcSemaphore(MyProc);
|
||||
|
||||
/*
|
||||
* Return true even if we were kicked off the lock before we were
|
||||
* able to remove ourselves.
|
||||
* Return true even if we were kicked off the lock before we were able
|
||||
* to remove ourselves.
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
@@ -467,7 +468,7 @@ ProcQueueAlloc(char *name)
|
||||
{
|
||||
bool found;
|
||||
PROC_QUEUE *queue = (PROC_QUEUE *)
|
||||
ShmemInitStruct(name, sizeof(PROC_QUEUE), &found);
|
||||
ShmemInitStruct(name, sizeof(PROC_QUEUE), &found);
|
||||
|
||||
if (!queue)
|
||||
return NULL;
|
||||
@@ -520,11 +521,14 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
|
||||
int myHeldLocks = MyProc->heldLocks;
|
||||
PROC *proc;
|
||||
int i;
|
||||
|
||||
#ifndef __BEOS__
|
||||
struct itimerval timeval,
|
||||
dummy;
|
||||
|
||||
#else
|
||||
bigtime_t time_interval;
|
||||
bigtime_t time_interval;
|
||||
|
||||
#endif
|
||||
|
||||
/* ----------------------
|
||||
@@ -582,6 +586,7 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
|
||||
aheadRequests |= (1 << proc->waitLockMode);
|
||||
proc = (PROC *) MAKE_PTR(proc->links.next);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we fall out of loop normally, proc points to waitQueue head,
|
||||
* so we will insert at tail of queue as desired.
|
||||
@@ -607,7 +612,7 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
|
||||
MyProc->waitHolder = holder;
|
||||
MyProc->waitLockMode = lockmode;
|
||||
|
||||
MyProc->errType = STATUS_OK; /* initialize result for success */
|
||||
MyProc->errType = STATUS_OK;/* initialize result for success */
|
||||
|
||||
/* mark that we are waiting for a lock */
|
||||
waitingForLock = true;
|
||||
@@ -643,7 +648,7 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
|
||||
if (setitimer(ITIMER_REAL, &timeval, &dummy))
|
||||
elog(FATAL, "ProcSleep: Unable to set timer for process wakeup");
|
||||
#else
|
||||
time_interval = DeadlockTimeout * 1000000; /* usecs */
|
||||
time_interval = DeadlockTimeout * 1000000; /* usecs */
|
||||
if (set_alarm(time_interval, B_ONE_SHOT_RELATIVE_ALARM) < 0)
|
||||
elog(FATAL, "ProcSleep: Unable to set timer for process wakeup");
|
||||
#endif
|
||||
@@ -674,7 +679,7 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
|
||||
if (setitimer(ITIMER_REAL, &timeval, &dummy))
|
||||
elog(FATAL, "ProcSleep: Unable to disable timer for process wakeup");
|
||||
#else
|
||||
if (set_alarm(B_INFINITE_TIMEOUT, B_PERIODIC_ALARM) < 0)
|
||||
if (set_alarm(B_INFINITE_TIMEOUT, B_PERIODIC_ALARM) < 0)
|
||||
elog(FATAL, "ProcSleep: Unable to disable timer for process wakeup");
|
||||
#endif
|
||||
|
||||
@@ -759,7 +764,7 @@ ProcLockWakeup(LOCKMETHODTABLE *lockMethodTable, LOCK *lock)
|
||||
|
||||
while (queue_size-- > 0)
|
||||
{
|
||||
LOCKMODE lockmode = proc->waitLockMode;
|
||||
LOCKMODE lockmode = proc->waitLockMode;
|
||||
|
||||
/*
|
||||
* Waken if (a) doesn't conflict with requests of earlier waiters,
|
||||
@@ -776,15 +781,20 @@ ProcLockWakeup(LOCKMETHODTABLE *lockMethodTable, LOCK *lock)
|
||||
/* OK to waken */
|
||||
GrantLock(lock, proc->waitHolder, lockmode);
|
||||
proc = ProcWakeup(proc, STATUS_OK);
|
||||
|
||||
/*
|
||||
* ProcWakeup removes proc from the lock's waiting process queue
|
||||
* and returns the next proc in chain; don't use proc's next-link,
|
||||
* because it's been cleared.
|
||||
* ProcWakeup removes proc from the lock's waiting process
|
||||
* queue and returns the next proc in chain; don't use proc's
|
||||
* next-link, because it's been cleared.
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Cannot wake this guy. Remember his request for later checks. */
|
||||
|
||||
/*
|
||||
* Cannot wake this guy. Remember his request for later
|
||||
* checks.
|
||||
*/
|
||||
aheadRequests |= (1 << lockmode);
|
||||
proc = (PROC *) MAKE_PTR(proc->links.next);
|
||||
}
|
||||
@@ -807,11 +817,11 @@ HandleDeadLock(SIGNAL_ARGS)
|
||||
int save_errno = errno;
|
||||
|
||||
/*
|
||||
* Acquire locktable lock. Note that the SIGALRM interrupt had better
|
||||
* not be enabled anywhere that this process itself holds the locktable
|
||||
* lock, else this will wait forever. Also note that this calls
|
||||
* SpinAcquire which creates a critical section, so that this routine
|
||||
* cannot be interrupted by cancel/die interrupts.
|
||||
* Acquire locktable lock. Note that the SIGALRM interrupt had better
|
||||
* not be enabled anywhere that this process itself holds the
|
||||
* locktable lock, else this will wait forever. Also note that this
|
||||
* calls SpinAcquire which creates a critical section, so that this
|
||||
* routine cannot be interrupted by cancel/die interrupts.
|
||||
*/
|
||||
LockLockTable();
|
||||
|
||||
@@ -836,8 +846,8 @@ HandleDeadLock(SIGNAL_ARGS)
|
||||
}
|
||||
|
||||
#ifdef LOCK_DEBUG
|
||||
if (Debug_deadlocks)
|
||||
DumpAllLocks();
|
||||
if (Debug_deadlocks)
|
||||
DumpAllLocks();
|
||||
#endif
|
||||
|
||||
if (!DeadLockCheck(MyProc))
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/page/bufpage.c,v 1.36 2001/02/06 06:24:00 vadim Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/page/bufpage.c,v 1.37 2001/03/22 03:59:47 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -59,14 +59,14 @@ PageInit(Page page, Size pageSize, Size specialSize)
|
||||
void
|
||||
PageZero(Page page)
|
||||
{
|
||||
MemSet((char*)page + ((PageHeader)page)->pd_lower, 0,
|
||||
((PageHeader)page)->pd_special - ((PageHeader)page)->pd_lower);
|
||||
MemSet((char *) page + ((PageHeader) page)->pd_lower, 0,
|
||||
((PageHeader) page)->pd_special - ((PageHeader) page)->pd_lower);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* PageAddItem
|
||||
*
|
||||
* Add an item to a page. Return value is offset at which it was
|
||||
* Add an item to a page. Return value is offset at which it was
|
||||
* inserted, or InvalidOffsetNumber if there's not room to insert.
|
||||
*
|
||||
* If offsetNumber is valid and <= current max offset in the page,
|
||||
@@ -75,7 +75,7 @@ PageZero(Page page)
|
||||
* If offsetNumber is not valid, then assign one by finding the first
|
||||
* one that is both unused and deallocated.
|
||||
*
|
||||
* !!! ELOG(ERROR) IS DISALLOWED HERE !!!
|
||||
* !!! ELOG(ERROR) IS DISALLOWED HERE !!!
|
||||
*
|
||||
* ----------------
|
||||
*/
|
||||
@@ -125,10 +125,12 @@ PageAddItem(Page page,
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Don't actually do the shuffle till we've checked free space!
|
||||
* Don't actually do the shuffle till we've checked free
|
||||
* space!
|
||||
*/
|
||||
needshuffle = true; /* need to increase "lower" */
|
||||
needshuffle = true; /* need to increase "lower" */
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -162,7 +164,8 @@ PageAddItem(Page page,
|
||||
return InvalidOffsetNumber;
|
||||
|
||||
/*
|
||||
* OK to insert the item. First, shuffle the existing pointers if needed.
|
||||
* OK to insert the item. First, shuffle the existing pointers if
|
||||
* needed.
|
||||
*/
|
||||
if (needshuffle)
|
||||
{
|
||||
@@ -284,12 +287,12 @@ PageRepairFragmentation(Page page, OffsetNumber *unused)
|
||||
for (i = 0; i < nline; i++)
|
||||
{
|
||||
lp = ((PageHeader) page)->pd_linp + i;
|
||||
if ((*lp).lp_flags & LP_DELETE) /* marked for deletion */
|
||||
if ((*lp).lp_flags & LP_DELETE) /* marked for deletion */
|
||||
(*lp).lp_flags &= ~(LP_USED | LP_DELETE);
|
||||
if ((*lp).lp_flags & LP_USED)
|
||||
nused++;
|
||||
else if (unused)
|
||||
unused[i - nused] = (OffsetNumber)i;
|
||||
unused[i - nused] = (OffsetNumber) i;
|
||||
}
|
||||
|
||||
if (nused == 0)
|
||||
@@ -347,7 +350,7 @@ PageRepairFragmentation(Page page, OffsetNumber *unused)
|
||||
pfree(itemidbase);
|
||||
}
|
||||
|
||||
return(nline - nused);
|
||||
return (nline - nused);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -377,16 +380,16 @@ PageGetFreeSpace(Page page)
|
||||
void
|
||||
IndexPageCleanup(Buffer buffer)
|
||||
{
|
||||
Page page = (Page) BufferGetPage(buffer);
|
||||
ItemId lp;
|
||||
OffsetNumber maxoff;
|
||||
OffsetNumber i;
|
||||
Page page = (Page) BufferGetPage(buffer);
|
||||
ItemId lp;
|
||||
OffsetNumber maxoff;
|
||||
OffsetNumber i;
|
||||
|
||||
maxoff = PageGetMaxOffsetNumber(page);
|
||||
for (i = 0; i < maxoff; i++)
|
||||
{
|
||||
lp = ((PageHeader) page)->pd_linp + i;
|
||||
if ((*lp).lp_flags & LP_DELETE) /* marked for deletion */
|
||||
if ((*lp).lp_flags & LP_DELETE) /* marked for deletion */
|
||||
{
|
||||
PageIndexTupleDelete(page, i + 1);
|
||||
maxoff--;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.81 2001/01/24 19:43:08 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.82 2001/03/22 03:59:47 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -76,7 +76,7 @@ static int _mdfd_getrelnfd(Relation reln);
|
||||
static MdfdVec *_mdfd_openseg(Relation reln, int segno, int oflags);
|
||||
static MdfdVec *_mdfd_getseg(Relation reln, int blkno);
|
||||
|
||||
static int _mdfd_blind_getseg(RelFileNode rnode, int blkno);
|
||||
static int _mdfd_blind_getseg(RelFileNode rnode, int blkno);
|
||||
|
||||
static int _fdvec_alloc(void);
|
||||
static void _fdvec_free(int);
|
||||
@@ -135,13 +135,14 @@ mdcreate(Relation reln)
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
int save_errno = errno;
|
||||
int save_errno = errno;
|
||||
|
||||
/*
|
||||
* During bootstrap, there are cases where a system relation will be
|
||||
* accessed (by internal backend processes) before the bootstrap
|
||||
* script nominally creates it. Therefore, allow the file to exist
|
||||
* already, but in bootstrap mode only. (See also mdopen)
|
||||
* During bootstrap, there are cases where a system relation will
|
||||
* be accessed (by internal backend processes) before the
|
||||
* bootstrap script nominally creates it. Therefore, allow the
|
||||
* file to exist already, but in bootstrap mode only. (See also
|
||||
* mdopen)
|
||||
*/
|
||||
if (IsBootstrapProcessingMode())
|
||||
fd = FileNameOpenFile(path, O_RDWR | PG_BINARY, 0600);
|
||||
@@ -197,7 +198,7 @@ mdunlink(RelFileNode rnode)
|
||||
char *segpath = (char *) palloc(strlen(path) + 12);
|
||||
int segno;
|
||||
|
||||
for (segno = 1; ; segno++)
|
||||
for (segno = 1;; segno++)
|
||||
{
|
||||
sprintf(segpath, "%s.%d", path, segno);
|
||||
if (unlink(segpath) < 0)
|
||||
@@ -293,11 +294,13 @@ mdopen(Relation reln)
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* During bootstrap, there are cases where a system relation will be
|
||||
* accessed (by internal backend processes) before the bootstrap
|
||||
* script nominally creates it. Therefore, accept mdopen() as a
|
||||
* substitute for mdcreate() in bootstrap mode only. (See mdcreate)
|
||||
* During bootstrap, there are cases where a system relation will
|
||||
* be accessed (by internal backend processes) before the
|
||||
* bootstrap script nominally creates it. Therefore, accept
|
||||
* mdopen() as a substitute for mdcreate() in bootstrap mode only.
|
||||
* (See mdcreate)
|
||||
*/
|
||||
if (IsBootstrapProcessingMode())
|
||||
fd = FileNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, 0600);
|
||||
@@ -666,12 +669,13 @@ mdnblocks(Relation reln)
|
||||
|
||||
if (v->mdfd_chain == (MdfdVec *) NULL)
|
||||
{
|
||||
|
||||
/*
|
||||
* Because we pass O_CREAT, we will create the next segment
|
||||
* (with zero length) immediately, if the last segment is of
|
||||
* length REL_SEGSIZE. This is unnecessary but harmless, and
|
||||
* testing for the case would take more cycles than it seems
|
||||
* worth.
|
||||
* Because we pass O_CREAT, we will create the next
|
||||
* segment (with zero length) immediately, if the last
|
||||
* segment is of length REL_SEGSIZE. This is unnecessary
|
||||
* but harmless, and testing for the case would take more
|
||||
* cycles than it seems worth.
|
||||
*/
|
||||
v->mdfd_chain = _mdfd_openseg(reln, segno, O_CREAT);
|
||||
if (v->mdfd_chain == (MdfdVec *) NULL)
|
||||
@@ -700,8 +704,10 @@ mdtruncate(Relation reln, int nblocks)
|
||||
int curnblk;
|
||||
int fd;
|
||||
MdfdVec *v;
|
||||
|
||||
#ifndef LET_OS_MANAGE_FILESIZE
|
||||
int priorblocks;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -1004,14 +1010,16 @@ _mdfd_getseg(Relation reln, int blkno)
|
||||
|
||||
if (v->mdfd_chain == (MdfdVec *) NULL)
|
||||
{
|
||||
|
||||
/*
|
||||
* We will create the next segment only if the target block
|
||||
* is within it. This prevents Sorcerer's Apprentice syndrome
|
||||
* if a bug at higher levels causes us to be handed a ridiculously
|
||||
* large blkno --- otherwise we could create many thousands of
|
||||
* empty segment files before reaching the "target" block. We
|
||||
* should never need to create more than one new segment per call,
|
||||
* so this restriction seems reasonable.
|
||||
* We will create the next segment only if the target block is
|
||||
* within it. This prevents Sorcerer's Apprentice syndrome if
|
||||
* a bug at higher levels causes us to be handed a
|
||||
* ridiculously large blkno --- otherwise we could create many
|
||||
* thousands of empty segment files before reaching the
|
||||
* "target" block. We should never need to create more than
|
||||
* one new segment per call, so this restriction seems
|
||||
* reasonable.
|
||||
*/
|
||||
v->mdfd_chain = _mdfd_openseg(reln, i, (segno == 1) ? O_CREAT : 0);
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/smgr.c,v 1.47 2001/01/24 19:43:08 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/smgr.c,v 1.48 2001/03/22 03:59:47 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -39,8 +39,8 @@ typedef struct f_smgr
|
||||
char *buffer);
|
||||
int (*smgr_flush) (Relation reln, BlockNumber blocknum,
|
||||
char *buffer);
|
||||
int (*smgr_blindwrt) (RelFileNode rnode, BlockNumber blkno,
|
||||
char *buffer, bool dofsync);
|
||||
int (*smgr_blindwrt) (RelFileNode rnode, BlockNumber blkno,
|
||||
char *buffer, bool dofsync);
|
||||
int (*smgr_markdirty) (Relation reln, BlockNumber blkno);
|
||||
int (*smgr_blindmarkdirty) (RelFileNode, BlockNumber blkno);
|
||||
int (*smgr_nblocks) (Relation reln);
|
||||
@@ -60,7 +60,7 @@ static f_smgr smgrsw[] = {
|
||||
/* magnetic disk */
|
||||
{mdinit, NULL, mdcreate, mdunlink, mdextend, mdopen, mdclose,
|
||||
mdread, mdwrite, mdflush, mdblindwrt, mdmarkdirty, mdblindmarkdirty,
|
||||
mdnblocks, mdtruncate, mdcommit, mdabort, mdsync
|
||||
mdnblocks, mdtruncate, mdcommit, mdabort, mdsync
|
||||
},
|
||||
|
||||
#ifdef STABLE_MEMORY_STORAGE
|
||||
@@ -96,7 +96,7 @@ static int NSmgr = lengthof(smgrsw);
|
||||
* that have been created or deleted in the current transaction. When
|
||||
* a relation is created, we create the physical file immediately, but
|
||||
* remember it so that we can delete the file again if the current
|
||||
* transaction is aborted. Conversely, a deletion request is NOT
|
||||
* transaction is aborted. Conversely, a deletion request is NOT
|
||||
* executed immediately, but is just entered in the list. When and if
|
||||
* the transaction commits, we can delete the physical file.
|
||||
*
|
||||
@@ -108,12 +108,12 @@ static int NSmgr = lengthof(smgrsw);
|
||||
typedef struct PendingRelDelete
|
||||
{
|
||||
RelFileNode relnode; /* relation that may need to be deleted */
|
||||
int16 which; /* which storage manager? */
|
||||
bool atCommit; /* T=delete at commit; F=delete at abort */
|
||||
struct PendingRelDelete *next; /* linked-list link */
|
||||
int16 which; /* which storage manager? */
|
||||
bool atCommit; /* T=delete at commit; F=delete at abort */
|
||||
struct PendingRelDelete *next; /* linked-list link */
|
||||
} PendingRelDelete;
|
||||
|
||||
static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */
|
||||
static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */
|
||||
|
||||
|
||||
/*
|
||||
@@ -133,7 +133,7 @@ smgrinit()
|
||||
if ((*(smgrsw[i].smgr_init)) () == SM_FAIL)
|
||||
elog(FATAL, "initialization failed on %s: %m",
|
||||
DatumGetCString(DirectFunctionCall1(smgrout,
|
||||
Int16GetDatum(i))));
|
||||
Int16GetDatum(i))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ smgrshutdown(void)
|
||||
if ((*(smgrsw[i].smgr_shutdown)) () == SM_FAIL)
|
||||
elog(FATAL, "shutdown failed on %s: %m",
|
||||
DatumGetCString(DirectFunctionCall1(smgrout,
|
||||
Int16GetDatum(i))));
|
||||
Int16GetDatum(i))));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -213,11 +213,11 @@ smgrunlink(int16 which, Relation reln)
|
||||
|
||||
/*
|
||||
* NOTE: if the relation was created in this transaction, it will now
|
||||
* be present in the pending-delete list twice, once with atCommit true
|
||||
* and once with atCommit false. Hence, it will be physically deleted
|
||||
* at end of xact in either case (and the other entry will be ignored
|
||||
* by smgrDoPendingDeletes, so no error will occur). We could instead
|
||||
* remove the existing list entry and delete the physical file
|
||||
* be present in the pending-delete list twice, once with atCommit
|
||||
* true and once with atCommit false. Hence, it will be physically
|
||||
* deleted at end of xact in either case (and the other entry will be
|
||||
* ignored by smgrDoPendingDeletes, so no error will occur). We could
|
||||
* instead remove the existing list entry and delete the physical file
|
||||
* immediately, but for now I'll keep the logic simple.
|
||||
*/
|
||||
|
||||
@@ -259,7 +259,7 @@ smgropen(int16 which, Relation reln, bool failOK)
|
||||
if (reln->rd_rel->relkind == RELKIND_VIEW)
|
||||
return -1;
|
||||
if ((fd = (*(smgrsw[which].smgr_open)) (reln)) < 0)
|
||||
if (! failOK)
|
||||
if (!failOK)
|
||||
elog(ERROR, "cannot open %s: %m", RelationGetRelationName(reln));
|
||||
|
||||
return fd;
|
||||
@@ -475,17 +475,20 @@ smgrDoPendingDeletes(bool isCommit)
|
||||
pendingDeletes = pending->next;
|
||||
if (pending->atCommit == isCommit)
|
||||
{
|
||||
|
||||
/*
|
||||
* Get rid of any leftover buffers for the rel (shouldn't be
|
||||
* any in the commit case, but there can be in the abort case).
|
||||
* any in the commit case, but there can be in the abort
|
||||
* case).
|
||||
*/
|
||||
DropRelFileNodeBuffers(pending->relnode);
|
||||
|
||||
/*
|
||||
* And delete the physical files.
|
||||
*
|
||||
* Note: we treat deletion failure as a NOTICE, not an error,
|
||||
* because we've already decided to commit or abort the current
|
||||
* xact.
|
||||
* because we've already decided to commit or abort the
|
||||
* current xact.
|
||||
*/
|
||||
if ((*(smgrsw[pending->which].smgr_unlink)) (pending->relnode) == SM_FAIL)
|
||||
elog(NOTICE, "cannot unlink %u/%u: %m",
|
||||
@@ -513,7 +516,7 @@ smgrcommit()
|
||||
if ((*(smgrsw[i].smgr_commit)) () == SM_FAIL)
|
||||
elog(FATAL, "transaction commit failed on %s: %m",
|
||||
DatumGetCString(DirectFunctionCall1(smgrout,
|
||||
Int16GetDatum(i))));
|
||||
Int16GetDatum(i))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,7 +535,7 @@ smgrabort()
|
||||
if ((*(smgrsw[i].smgr_abort)) () == SM_FAIL)
|
||||
elog(FATAL, "transaction abort failed on %s: %m",
|
||||
DatumGetCString(DirectFunctionCall1(smgrout,
|
||||
Int16GetDatum(i))));
|
||||
Int16GetDatum(i))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -551,7 +554,7 @@ smgrsync()
|
||||
if ((*(smgrsw[i].smgr_sync)) () == SM_FAIL)
|
||||
elog(STOP, "storage sync failed on %s: %m",
|
||||
DatumGetCString(DirectFunctionCall1(smgrout,
|
||||
Int16GetDatum(i))));
|
||||
Int16GetDatum(i))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -579,8 +582,8 @@ void
|
||||
smgr_undo(XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
smgr_desc(char *buf, uint8 xl_info, char* rec)
|
||||
smgr_desc(char *buf, uint8 xl_info, char *rec)
|
||||
{
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user