1 /*-------------------------------------------------------------------------
4 * local buffer manager. Fast buffer manager for temporary tables
5 * or special cases when the operation is not visible to other backends.
7 * When a relation is being created, the descriptor will have rd_islocal
8 * set to indicate that the local buffer manager should be used. During
9 * the same transaction the relation is being created, any inserts or
10 * selects from the newly created relation will use the local buffer
11 * pool. rd_islocal is reset at the end of a transaction (commit/abort).
12 * This is useful for queries like SELECT INTO TABLE and create index.
14 * Copyright (c) 1994-5, Regents of the University of California
18 * $Header: /cvsroot/pgsql/src/backend/storage/buffer/localbuf.c,v 1.6 1997/04/18 02:53:37 vadim Exp $
20 *-------------------------------------------------------------------------
30 /* declarations split between these three files */
31 #include "storage/buf.h"
32 #include "storage/buf_internals.h"
33 #include "storage/bufmgr.h"
35 #include "storage/fd.h"
36 #include "storage/ipc.h"
37 #include "storage/shmem.h"
38 #include "storage/spin.h"
39 #include "storage/smgr.h"
40 #include "storage/lmgr.h"
41 #include "storage/buf_internals.h"
42 #include "miscadmin.h"
43 #include "utils/builtins.h"
44 #include "utils/hsearch.h"
45 #include "utils/memutils.h"
46 #include "utils/relcache.h"
47 #include "executor/execdebug.h" /* for NDirectFileRead */
48 #include "catalog/catalog.h"
50 extern long int LocalBufferFlushCount;
53 BufferDesc *LocalBufferDescriptors = NULL;
54 long *LocalRefCount = NULL;
56 static int nextFreeLocalBuf = 0;
62 * allocate a local buffer. We do round robin allocation for now.
65 LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
68 BufferDesc *bufHdr = (BufferDesc *) NULL;
70 if (blockNum == P_NEW) {
71 blockNum = reln->rd_nblocks;
75 /* a low tech search for now -- not optimized for scans */
76 for (i=0; i < NLocBuffer; i++) {
77 if (LocalBufferDescriptors[i].tag.relId.relId == reln->rd_id &&
78 LocalBufferDescriptors[i].tag.blockNum == blockNum) {
81 fprintf(stderr, "LB ALLOC (%d,%d) %d\n",
82 reln->rd_id, blockNum, -i-1);
86 return &LocalBufferDescriptors[i];
91 fprintf(stderr, "LB ALLOC (%d,%d) %d\n",
92 reln->rd_id, blockNum, -nextFreeLocalBuf-1);
95 /* need to get a new buffer (round robin for now) */
96 for(i=0; i < NLocBuffer; i++) {
97 int b = (nextFreeLocalBuf + i) % NLocBuffer;
99 if (LocalRefCount[b]==0) {
100 bufHdr = &LocalBufferDescriptors[b];
102 nextFreeLocalBuf = (b + 1) % NLocBuffer;
107 elog(WARN, "no empty local buffer.");
110 * this buffer is not referenced but it might still be dirty (the
111 * last transaction to touch it doesn't need its contents but has
112 * not flushed it). if that's the case, write it out before
115 if (bufHdr->flags & BM_DIRTY) {
116 Relation bufrel = RelationIdCacheGetRelation(bufHdr->tag.relId.relId);
118 Assert(bufrel != NULL);
120 /* flush this page */
121 smgrwrite(bufrel->rd_rel->relsmgr, bufrel, bufHdr->tag.blockNum,
122 (char *) MAKE_PTR(bufHdr->data));
123 LocalBufferFlushCount++;
129 bufHdr->tag.relId.relId = reln->rd_id;
130 bufHdr->tag.blockNum = blockNum;
131 bufHdr->flags &= ~BM_DIRTY;
134 * lazy memory allocation. (see MAKE_PTR for why we need to do
137 if (bufHdr->data == (SHMEM_OFFSET)0) {
138 char *data = (char *)malloc(BLCKSZ);
140 bufHdr->data = MAKE_OFFSET(data);
149 * writes out a local buffer
152 WriteLocalBuffer(Buffer buffer, bool release)
156 Assert(BufferIsLocal(buffer));
159 fprintf(stderr, "LB WRITE %d\n", buffer);
162 bufid = - (buffer + 1);
163 LocalBufferDescriptors[bufid].flags |= BM_DIRTY;
166 Assert(LocalRefCount[bufid] > 0);
167 LocalRefCount[bufid]--;
175 * flushes a local buffer
178 FlushLocalBuffer(Buffer buffer, bool release)
184 Assert(BufferIsLocal(buffer));
187 fprintf(stderr, "LB FLUSH %d\n", buffer);
190 bufid = - (buffer + 1);
191 bufHdr = &LocalBufferDescriptors[bufid];
192 bufHdr->flags &= ~BM_DIRTY;
193 bufrel = RelationIdCacheGetRelation(bufHdr->tag.relId.relId);
195 Assert(bufrel != NULL);
196 smgrflush(bufrel->rd_rel->relsmgr, bufrel, bufHdr->tag.blockNum,
197 (char *) MAKE_PTR(bufHdr->data));
198 LocalBufferFlushCount++;
200 Assert(LocalRefCount[bufid] > 0);
202 LocalRefCount[bufid]--;
209 * init the local buffer cache. Since most queries (esp. multi-user ones)
210 * don't involve local buffers, we delay allocating memory for actual the
211 * buffer until we need it.
214 InitLocalBuffer(void)
219 * these aren't going away. I'm not gonna use palloc.
221 LocalBufferDescriptors =
222 (BufferDesc *)malloc(sizeof(BufferDesc) * NLocBuffer);
223 memset(LocalBufferDescriptors, 0, sizeof(BufferDesc) * NLocBuffer);
224 nextFreeLocalBuf = 0;
226 for (i = 0; i < NLocBuffer; i++) {
227 BufferDesc *buf = &LocalBufferDescriptors[i];
230 * negative to indicate local buffer. This is tricky: shared buffers
231 * start with 0. We have to start with -2. (Note that the routine
232 * BufferDescriptorGetBuffer adds 1 to buf_id so our first buffer id
235 buf->buf_id = - i - 2;
239 (long *)malloc(sizeof(long) * NLocBuffer);
240 memset(LocalRefCount, 0, sizeof(long) * NLocBuffer);
245 * flush all dirty buffers in the local buffer cache. Since the buffer
246 * cache is only used for keeping relations visible during a transaction,
247 * we will not need these buffers again.
250 LocalBufferSync(void)
254 for (i = 0; i < NLocBuffer; i++) {
255 BufferDesc *buf = &LocalBufferDescriptors[i];
258 if (buf->flags & BM_DIRTY) {
260 fprintf(stderr, "LB SYNC %d\n", -i-1);
262 bufrel = RelationIdCacheGetRelation(buf->tag.relId.relId);
264 Assert(bufrel != NULL);
266 smgrwrite(bufrel->rd_rel->relsmgr, bufrel, buf->tag.blockNum,
267 (char *) MAKE_PTR(buf->data));
268 LocalBufferFlushCount++;
270 buf->tag.relId.relId = InvalidOid;
271 buf->flags &= ~BM_DIRTY;
275 memset(LocalRefCount, 0, sizeof(long) * NLocBuffer);
279 ResetLocalBufferPool(void)
283 memset(LocalBufferDescriptors, 0, sizeof(BufferDesc) * NLocBuffer);
284 nextFreeLocalBuf = 0;
286 for (i = 0; i < NLocBuffer; i++) {
287 BufferDesc *buf = &LocalBufferDescriptors[i];
289 /* just like InitLocalBuffer() */
290 buf->buf_id = - i - 2;
293 memset(LocalRefCount, 0, sizeof(long) * NLocBuffer);