buf_init.c 7.19 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * buf_init.c
4
 *	  buffer manager initialization routines
5
 *
Bruce Momjian's avatar
Bruce Momjian committed
6
 * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
Bruce Momjian's avatar
Add:  
Bruce Momjian committed
7
 * Portions Copyright (c) 1994, Regents of the University of California
8 9 10
 *
 *
 * IDENTIFICATION
Jan Wieck's avatar
Jan Wieck committed
11
 *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.57 2003/11/13 14:57:15 wieck Exp $
12 13 14
 *
 *-------------------------------------------------------------------------
 */
15 16
#include "postgres.h"

17 18 19 20
#include <sys/file.h>
#include <math.h>
#include <signal.h>

Bruce Momjian's avatar
Bruce Momjian committed
21 22 23
#include "catalog/catalog.h"
#include "executor/execdebug.h"
#include "miscadmin.h"
24 25 26 27 28
#include "storage/buf.h"
#include "storage/buf_internals.h"
#include "storage/bufmgr.h"
#include "storage/fd.h"
#include "storage/ipc.h"
Bruce Momjian's avatar
Bruce Momjian committed
29
#include "storage/lmgr.h"
30 31
#include "storage/shmem.h"
#include "storage/smgr.h"
32
#include "storage/lwlock.h"
33 34 35 36
#include "utils/builtins.h"
#include "utils/hsearch.h"
#include "utils/memutils.h"

37

38
/*
39 40
 *	if BMTRACE is defined, we trace the last 200 buffer allocations and
 *	deallocations in a circular buffer in shared memory.
41 42
 */
#ifdef	BMTRACE
43 44
bmtrace    *TraceBuf;
long	   *CurTraceBuf;
45 46

#define BMT_LIMIT		200
47
#endif   /* BMTRACE */
48
int			ShowPinTrace = 0;
49

50
int			Data_Descriptors;
51

52
BufferDesc *BufferDescriptors;
53
Block	   *BufferBlockPointers;
54

55
long	   *PrivateRefCount;	/* also used in freelist.c */
56 57
bits8	   *BufferLocks;		/* flag bits showing locks I have set */

58 59 60

/*
 * Data Structures:
61 62
 *		buffers live in a freelist and a lookup data structure.
 *
63 64
 *
 * Buffer Lookup:
65 66 67
 *		Two important notes.  First, the buffer has to be
 *		available for lookup BEFORE an IO begins.  Otherwise
 *		a second process trying to read the buffer will
68
 *		allocate its own copy and the buffer pool will
69
 *		become inconsistent.
70 71
 *
 * Buffer Replacement:
72 73
 *		see freelist.c.  A buffer cannot be replaced while in
 *		use either by data manager or during IO.
74 75
 *
 * WriteBufferBack:
76 77 78 79
 *		currently, a buffer is only written back at the time
 *		it is selected for replacement.  It should
 *		be done sooner if possible to reduce latency of
 *		BufferAlloc().	Maybe there should be a daemon process.
80 81 82
 *
 * Synchronization/Locking:
 *
83 84 85
 * BufMgrLock lock -- must be acquired before manipulating the
 *		buffer queues (lookup/freelist).  Must be released
 *		before exit and before doing any IO.
86 87
 *
 * IO_IN_PROGRESS -- this is a flag in the buffer descriptor.
88 89 90 91
 *		It must be set when an IO is initiated and cleared at
 *		the end of	the IO.  It is there to make sure that one
 *		process doesn't start to use a buffer while another is
 *		faulting it in.  see IOWait/IOSignal.
92
 *
93 94 95 96 97
 * refcount --	A buffer is pinned during IO and immediately
 *		after a BufferAlloc().	A buffer is always either pinned
 *		or on the freelist but never both.	The buffer must be
 *		released, written, or flushed before the end of
 *		transaction.
98 99
 *
 * PrivateRefCount -- Each buffer also has a private refcount the keeps
100 101 102 103 104 105 106
 *		track of the number of times the buffer is pinned in the current
 *		processes.	This is used for two purposes, first, if we pin a
 *		a buffer more than once, we only need to change the shared refcount
 *		once, thus only lock the buffer pool once, second, when a transaction
 *		aborts, it should only unpin the buffers exactly the number of times it
 *		has pinned them, so that it will not blow away buffers of another
 *		backend.
107 108 109
 *
 */

110 111 112 113 114 115
long int	ReadBufferCount;
long int	ReadLocalBufferCount;
long int	BufferHitCount;
long int	LocalBufferHitCount;
long int	BufferFlushCount;
long int	LocalBufferFlushCount;
116 117 118


/*
119
 * Initialize shared buffer pool
120
 *
121 122
 * This is called once during shared-memory initialization (either in the
 * postmaster, or in a standalone backend).
123 124
 */
void
125
InitBufferPool(void)
126
{
127
	char	   *BufferBlocks;
128 129 130
	bool		foundBufs,
				foundDescs;
	int			i;
131 132 133

	Data_Descriptors = NBuffers;

134 135
	/*
	 * It's probably not really necessary to grab the lock --- if there's
136 137
	 * anyone else attached to the shmem at this point, we've got
	 * problems.
138
	 */
139
	LWLockAcquire(BufMgrLock, LW_EXCLUSIVE);
140

141
#ifdef BMTRACE
142 143 144 145
	CurTraceBuf = (long *) ShmemInitStruct("Buffer trace",
							(BMT_LIMIT * sizeof(bmtrace)) + sizeof(long),
										   &foundDescs);
	if (!foundDescs)
Bruce Momjian's avatar
Bruce Momjian committed
146
		MemSet(CurTraceBuf, 0, (BMT_LIMIT * sizeof(bmtrace)) + sizeof(long));
147 148

	TraceBuf = (bmtrace *) & (CurTraceBuf[1]);
149
#endif
150 151 152

	BufferDescriptors = (BufferDesc *)
		ShmemInitStruct("Buffer Descriptors",
Jan Wieck's avatar
Jan Wieck committed
153
					  Data_Descriptors * sizeof(BufferDesc), &foundDescs);
154

155
	BufferBlocks = (char *)
156 157 158 159 160 161 162 163 164 165
		ShmemInitStruct("Buffer Blocks",
						NBuffers * BLCKSZ, &foundBufs);

	if (foundDescs || foundBufs)
	{
		/* both should be present or neither */
		Assert(foundDescs && foundBufs);
	}
	else
	{
166
		BufferDesc *buf;
167
		char	   *block;
168 169

		buf = BufferDescriptors;
170
		block = BufferBlocks;
171 172

		/*
Jan Wieck's avatar
Jan Wieck committed
173 174
		 * link the buffers into a single linked list. This will become the
		 * LiFo list of unused buffers returned by StragegyGetBuffer().
175 176 177 178 179
		 */
		for (i = 0; i < Data_Descriptors; block += BLCKSZ, buf++, i++)
		{
			Assert(ShmemIsValid((unsigned long) block));

Jan Wieck's avatar
Jan Wieck committed
180
			buf->bufNext = i + 1;
181 182

			CLEAR_BUFFERTAG(&(buf->tag));
183 184
			buf->buf_id = i;

185 186 187
			buf->data = MAKE_OFFSET(block);
			buf->flags = (BM_DELETED | BM_FREE | BM_VALID);
			buf->refcount = 0;
188 189 190 191
			buf->io_in_progress_lock = LWLockAssign();
			buf->cntx_lock = LWLockAssign();
			buf->cntxDirty = false;
			buf->wait_backend_id = 0;
192 193
		}

Jan Wieck's avatar
Jan Wieck committed
194 195
		/* Correct last entry */
		BufferDescriptors[Data_Descriptors - 1].bufNext = -1;
196
	}
197

198
	/* Init other shared buffer-management stuff */
Jan Wieck's avatar
Jan Wieck committed
199
	StrategyInitialize(!foundDescs);
200

201
	LWLockRelease(BufMgrLock);
202 203 204 205 206 207 208 209
}

/*
 * Initialize access to shared buffer pool
 *
 * This is called during backend startup (whether standalone or under the
 * postmaster).  It sets up for this backend's access to the already-existing
 * buffer pool.
210 211 212 213
 *
 * NB: this is called before InitProcess(), so we do not have a PGPROC and
 * cannot do LWLockAcquire; hence we can't actually access the bufmgr's
 * shared memory yet.  We are only initializing local data here.
214 215 216 217 218
 */
void
InitBufferPoolAccess(void)
{
	int			i;
219

220 221 222
	/*
	 * Allocate and zero local arrays of per-buffer info.
	 */
223
	BufferBlockPointers = (Block *) calloc(NBuffers, sizeof(Block));
224
	PrivateRefCount = (long *) calloc(NBuffers, sizeof(long));
Bruce Momjian's avatar
Bruce Momjian committed
225
	BufferLocks = (bits8 *) calloc(NBuffers, sizeof(bits8));
Bruce Momjian's avatar
Bruce Momjian committed
226

227
	/*
228 229
	 * Convert shmem offsets into addresses as seen by this process. This
	 * is just to speed up the BufferGetBlock() macro.
230 231 232
	 */
	for (i = 0; i < NBuffers; i++)
		BufferBlockPointers[i] = (Block) MAKE_PTR(BufferDescriptors[i].data);
233 234 235 236 237 238 239 240 241 242
}

/* -----------------------------------------------------
 * BufferShmemSize
 *
 * compute the size of shared memory for the buffer pool including
 * data pages, buffer descriptors, hash tables, etc.
 * ----------------------------------------------------
 */
int
243
BufferShmemSize(void)
244
{
245
	int			size = 0;
246 247

	/* size of shmem index hash table */
248
	size += hash_estimate_size(SHMEM_INDEX_SIZE, sizeof(ShmemIndexEnt));
249 250 251 252 253 254 255 256

	/* size of buffer descriptors */
	size += MAXALIGN((NBuffers + 1) * sizeof(BufferDesc));

	/* size of data pages */
	size += NBuffers * MAXALIGN(BLCKSZ);

	/* size of buffer hash table */
257
	size += hash_estimate_size(NBuffers, sizeof(BufferLookupEnt));
258

259
#ifdef BMTRACE
260
	size += (BMT_LIMIT * sizeof(bmtrace)) + sizeof(long);
261
#endif
262

263
	return size;
264
}