blob: e77e21a2b57b0635829668bae0fdd8b0ea52bfed [file] [log] [blame]
/*-------------------------------------------------------------------------
*
* bufmgr.h
* POSTGRES buffer manager definitions.
*
*
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/storage/bufmgr.h,v 1.101 2006/07/13 16:49:20 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef BUFMGR_H
#define BUFMGR_H
#include "storage/buf.h"
#include "storage/buf_internals.h"
#include "storage/bufpage.h"
#include "storage/relfilenode.h"
#include "storage/smgr.h"
#include "utils/relcache.h"
#include "utils/rel.h"
typedef void *Block;
/* in globals.c ... this duplicates miscadmin.h */
extern PGDLLIMPORT int NBuffers;
/* in bufmgr.c */
/* should not be accessed directly. Use ShouldMemoryProtectBufferPool() instead */
extern bool memory_protect_buffer_pool;
extern bool flush_buffer_pages_when_evicted;
extern bool zero_damaged_pages;
extern double bgwriter_lru_percent;
extern double bgwriter_all_percent;
extern int bgwriter_lru_maxpages;
extern int bgwriter_all_maxpages;
extern PGDLLIMPORT bool IsUnderPostmaster; /* from utils/init/globals.c */
#define ShouldMemoryProtectBufferPool() (memory_protect_buffer_pool && IsUnderPostmaster)
/* in buf_init.c */
extern PGDLLIMPORT char *BufferBlocks;
extern PGDLLIMPORT int32 *PrivateRefCount;
/* in localbuf.c */
extern PGDLLIMPORT int NLocBuffer;
extern PGDLLIMPORT Block *LocalBufferBlockPointers;
extern PGDLLIMPORT int32 *LocalRefCount;
/* special block number for ReadBuffer() */
#define P_NEW InvalidBlockNumber /* grow the file to get a new page */
/*
* Buffer content lock modes (mode argument for LockBuffer())
*/
#define BUFFER_LOCK_UNLOCK 0
#define BUFFER_LOCK_SHARE 1
#define BUFFER_LOCK_EXCLUSIVE 2
/*
* These routines are beaten on quite heavily, hence the macroization.
*/
/*
* BufferIsValid
* True iff the given buffer number is valid (either as a shared
* or local buffer).
*
* This is not quite the inverse of the BufferIsInvalid() macro, since this
* adds sanity rangechecks on the buffer number.
*
* Note: For a long time this was defined the same as BufferIsPinned,
* that is it would say False if you didn't hold a pin on the buffer.
* I believe this was bogus and served only to mask logic errors.
* Code should always know whether it has a buffer reference,
* independently of the pin state.
*/
#define BufferIsValid(bufnum) \
( \
(bufnum) != InvalidBuffer && \
(bufnum) >= -NLocBuffer && \
(bufnum) <= NBuffers \
)
/*
* BufferIsPinned
* True iff the buffer is pinned (also checks for valid buffer number).
*
* NOTE: what we check here is that *this* backend holds a pin on
* the buffer. We do not care whether some other backend does.
*/
#define BufferIsPinned(bufnum) \
( \
!BufferIsValid(bufnum) ? \
false \
: \
BufferIsLocal(bufnum) ? \
(LocalRefCount[-(bufnum) - 1] > 0) \
: \
(PrivateRefCount[(bufnum) - 1] > 0) \
)
/*
* BufferGetBlock
* Returns a reference to a disk page image associated with a buffer.
*
* Note:
* Assumes buffer is valid.
*/
#define BufferGetBlock(buffer) \
( \
AssertMacro(BufferIsValid(buffer)), \
BufferIsLocal(buffer) ? \
LocalBufferBlockPointers[-(buffer) - 1] \
: \
(Block) (BufferBlocks + ((Size) ((buffer) - 1)) * BLCKSZ) \
)
// Helper DEFINEs for MirroredLock within Buffer Pool Manager ONLY.
#ifdef USE_ASSERT_CHECKING
typedef struct MirroredLockBufMgrLocalVars
{
bool mirroredLockIsHeldByMe;
bool specialResyncManagerFlag;
bool mirroredVariablesSet;
} MirroredLockBufMgrLocalVars;
#define MIRROREDLOCK_BUFMGR_DECLARE \
MirroredLockBufMgrLocalVars mirroredLockBufMgrLocalVars = {false, false, false};
#else
typedef struct MirroredLockBufMgrLocalVars
{
bool mirroredLockIsHeldByMe;
bool specialResyncManagerFlag;
} MirroredLockBufMgrLocalVars;
#define MIRROREDLOCK_BUFMGR_DECLARE \
MirroredLockBufMgrLocalVars mirroredLockBufMgrLocalVars = {false, false};
#endif
#ifdef USE_ASSERT_CHECKING
#define MIRROREDLOCK_BUFMGR_LOCK \
{ \
mirroredLockBufMgrLocalVars.mirroredLockIsHeldByMe = LWLockHeldByMe(MirroredLock); \
mirroredLockBufMgrLocalVars.specialResyncManagerFlag = false; \
mirroredLockBufMgrLocalVars.mirroredVariablesSet = true; \
\
if (!mirroredLockBufMgrLocalVars.mirroredLockIsHeldByMe) \
{ \
if (!mirroredLockBufMgrLocalVars.specialResyncManagerFlag) \
{ \
LWLockAcquire(MirroredLock , LW_SHARED); \
} \
else \
{ \
HOLD_INTERRUPTS(); \
} \
} \
\
Assert(InterruptHoldoffCount > 0); \
}
#else
#define MIRROREDLOCK_BUFMGR_LOCK \
{ \
mirroredLockBufMgrLocalVars.mirroredLockIsHeldByMe = LWLockHeldByMe(MirroredLock); \
mirroredLockBufMgrLocalVars.specialResyncManagerFlag = false; \
\
if (!mirroredLockBufMgrLocalVars.mirroredLockIsHeldByMe) \
{ \
if (!mirroredLockBufMgrLocalVars.specialResyncManagerFlag) \
{ \
LWLockAcquire(MirroredLock , LW_SHARED); \
} \
else \
{ \
HOLD_INTERRUPTS(); \
} \
} \
}
#endif
#ifdef USE_ASSERT_CHECKING
#define MIRROREDLOCK_BUFMGR_UNLOCK \
{ \
Assert(mirroredLockBufMgrLocalVars.mirroredVariablesSet); \
Assert(InterruptHoldoffCount > 0); \
\
if (!mirroredLockBufMgrLocalVars.mirroredLockIsHeldByMe) \
{ \
if (!mirroredLockBufMgrLocalVars.specialResyncManagerFlag) \
{ \
LWLockRelease(MirroredLock); \
} \
else \
{ \
RESUME_INTERRUPTS(); \
} \
} \
}
#else
#define MIRROREDLOCK_BUFMGR_UNLOCK \
{ \
if (!mirroredLockBufMgrLocalVars.mirroredLockIsHeldByMe) \
{ \
if (!mirroredLockBufMgrLocalVars.specialResyncManagerFlag) \
{ \
LWLockRelease(MirroredLock); \
} \
else \
{ \
RESUME_INTERRUPTS(); \
} \
} \
}
#endif
#define MIRROREDLOCK_BUFMGR_MUST_ALREADY_BE_HELD \
{ \
bool alreadyMirroredLockIsHeldByMe; \
bool alreadySpecialResyncManagerFlag; \
\
alreadyMirroredLockIsHeldByMe = LWLockHeldByMe(MirroredLock); \
alreadySpecialResyncManagerFlag = false; \
if (!alreadyMirroredLockIsHeldByMe && !alreadySpecialResyncManagerFlag) \
elog(ERROR, "Mirrored lock must already be held"); \
}
#ifdef USE_ASSERT_CHECKING
#define MIRROREDLOCK_BUFMGR_VERIFY_NO_LOCK_LEAK_DECLARE \
bool verifyMirroredLockIsHeldByMe = false; \
bool verifyMirroredVariablesSet = false;
#else
#define MIRROREDLOCK_BUFMGR_VERIFY_NO_LOCK_LEAK_DECLARE \
bool verifyMirroredLockIsHeldByMe = false;
#endif
#ifdef USE_ASSERT_CHECKING
#define MIRROREDLOCK_BUFMGR_VERIFY_NO_LOCK_LEAK_ENTER \
{ \
verifyMirroredLockIsHeldByMe = LWLockHeldByMe(MirroredLock); \
verifyMirroredVariablesSet = true; \
}
#else
#define MIRROREDLOCK_BUFMGR_VERIFY_NO_LOCK_LEAK_ENTER \
{ \
verifyMirroredLockIsHeldByMe = LWLockHeldByMe(MirroredLock); \
}
#endif
#ifdef USE_ASSERT_CHECKING
#define MIRROREDLOCK_BUFMGR_VERIFY_NO_LOCK_LEAK_EXIT \
{ \
bool currentMirroredLockIsHeldByMe; \
\
Assert(verifyMirroredVariablesSet); \
currentMirroredLockIsHeldByMe = LWLockHeldByMe(MirroredLock); \
if (verifyMirroredLockIsHeldByMe != currentMirroredLockIsHeldByMe) \
elog(ERROR, "Exiting with mirrored lock held / not held different (enter %s, exit %s)", \
(verifyMirroredLockIsHeldByMe ? "true" : "false"), \
(currentMirroredLockIsHeldByMe ? "true" : "false")); \
}
#else
#define MIRROREDLOCK_BUFMGR_VERIFY_NO_LOCK_LEAK_EXIT \
{ \
bool currentMirroredLockIsHeldByMe; \
\
currentMirroredLockIsHeldByMe = LWLockHeldByMe(MirroredLock); \
if (verifyMirroredLockIsHeldByMe != currentMirroredLockIsHeldByMe) \
elog(ERROR, "Exiting with mirrored lock held / not held different (enter %s, exit %s)", \
(verifyMirroredLockIsHeldByMe ? "true" : "false"), \
(currentMirroredLockIsHeldByMe ? "true" : "false")); \
}
#endif
/*
* prototypes for functions in bufmgr.c
*/
extern Buffer
ReadBuffer_ResyncEx(SMgrRelation reln,
BlockNumber blockNum);
extern Buffer ReadBuffer(Relation reln, BlockNumber blockNum);
extern Buffer ReadBuffer_Ex_SMgr(SMgrRelation smgr, BlockNumber blockNum, volatile BufferDesc* availBufHdr, bool isLocalBuf, bool isTemp);
extern void ReleaseBuffer(Buffer buffer);
extern void ReleaseBuffer_Ex(Buffer buffer, bool flushIfDirty);
extern void UnlockReleaseBuffer(Buffer buffer);
extern void MarkBufferDirty(Buffer buffer);
extern void IncrBufferRefCount(Buffer buffer);
extern Buffer ReleaseAndReadBuffer(Buffer buffer, Relation relation,
BlockNumber blockNum);
extern Buffer KillAndReadBuffer(Buffer buffer, Relation relation,
BlockNumber blockNum);
extern void InitBufferPool(void);
extern void InitBufferPoolAccess(void);
extern void InitBufferPoolBackend(void);
extern char *ShowBufferUsage(void);
extern void ResetBufferUsage(void);
extern void AtEOXact_Buffers(bool isCommit);
extern void PrintBufferLeakWarning(Buffer buffer);
extern void FlushBufferPool(void);
extern BlockNumber BufferGetBlockNumber(Buffer buffer);
extern BlockNumber RelationGetNumberOfBlocks(Relation relation);
extern void RelationTruncate(Relation rel, BlockNumber nblocks, bool markPersistentAsPhysicallyTruncated);
extern void FlushRelationBuffers(Relation rel);
extern void DropRelFileNodeBuffers(RelFileNode rnode, bool istemp,
BlockNumber firstDelBlock);
extern void DropDatabaseBuffers(Oid tbpoid, Oid dbid);
#ifdef NOT_USED
extern void PrintPinnedBufs(void);
#endif
extern Size BufferShmemSize(void);
extern RelFileNode BufferGetFileNode(Buffer buffer);
extern void SetBufferCommitInfoNeedsSave(Buffer buffer);
extern void UnlockBuffers(void);
extern void LockBuffer(Buffer buffer, int mode);
extern bool ConditionalLockBuffer(Buffer buffer);
extern void LockBufferForCleanup(Buffer buffer);
extern void AbortBufferIO(void);
extern void BufmgrCommit(void);
extern void BufferSync(void);
extern void BgBufferSync(void);
extern void AtProcExit_LocalBuffers(void);
/* in freelist.c */
extern void StrategyHintVacuum(bool vacuum_active);
#endif