OSDN Git Service

Added SCO support, from Daniel Harris.
[pg-rex/syncrep.git] / src / backend / storage / buffer / localbuf.c
1 /*-------------------------------------------------------------------------
2  *
3  * localbuf.c--
4  *    local buffer manager. Fast buffer manager for temporary tables
5  *    or special cases when the operation is not visible to other backends.
6  *
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.
13  *
14  * Copyright (c) 1994-5, Regents of the University of California
15  *
16  *
17  * IDENTIFICATION
18  *    $Header: /cvsroot/pgsql/src/backend/storage/buffer/localbuf.c,v 1.8 1997/07/28 00:54:48 momjian Exp $
19  *
20  *-------------------------------------------------------------------------
21  */
22 #include <sys/types.h>
23 #include <sys/file.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <math.h>
27 #include <signal.h>
28
29 #include "postgres.h"
30
31 /* declarations split between these three files */
32 #include "storage/buf.h"
33 #include "storage/buf_internals.h"
34 #include "storage/bufmgr.h"
35
36 #include "storage/fd.h"
37 #include "storage/ipc.h"
38 #include "storage/shmem.h"
39 #include "storage/spin.h"
40 #include "storage/smgr.h"
41 #include "storage/lmgr.h"
42 #include "storage/buf_internals.h"
43 #include "miscadmin.h"
44 #include "utils/builtins.h"
45 #include "utils/hsearch.h"
46 #include "utils/memutils.h"
47 #include "utils/relcache.h"
48 #include "executor/execdebug.h" /* for NDirectFileRead */
49 #include "catalog/catalog.h"
50
51 extern long int LocalBufferFlushCount;
52
53 int NLocBuffer = 64;
54 BufferDesc *LocalBufferDescriptors = NULL;
55 long *LocalRefCount = NULL;
56
57 static int nextFreeLocalBuf = 0;
58
59 /*#define LBDEBUG*/
60
61 /*
62  * LocalBufferAlloc -
63  *    allocate a local buffer. We do round robin allocation for now.
64  */
65 BufferDesc *
66 LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
67 {
68     int i;
69     BufferDesc *bufHdr = (BufferDesc *) NULL;
70
71     if (blockNum == P_NEW) {
72         blockNum = reln->rd_nblocks;
73         reln->rd_nblocks++;
74     } 
75
76     /* a low tech search for now -- not optimized for scans */
77     for (i=0; i < NLocBuffer; i++) {
78         if (LocalBufferDescriptors[i].tag.relId.relId == reln->rd_id &&
79             LocalBufferDescriptors[i].tag.blockNum == blockNum) {
80
81 #ifdef LBDEBUG
82             fprintf(stderr, "LB ALLOC (%d,%d) %d\n",
83                     reln->rd_id, blockNum, -i-1);
84 #endif    
85             LocalRefCount[i]++;
86             *foundPtr = TRUE;
87             return &LocalBufferDescriptors[i];
88         }
89     }
90
91 #ifdef LBDEBUG
92     fprintf(stderr, "LB ALLOC (%d,%d) %d\n",
93             reln->rd_id, blockNum, -nextFreeLocalBuf-1);
94 #endif    
95     
96     /* need to get a new buffer (round robin for now) */
97     for(i=0; i < NLocBuffer; i++) {
98         int b = (nextFreeLocalBuf + i) % NLocBuffer;
99
100         if (LocalRefCount[b]==0) {
101             bufHdr = &LocalBufferDescriptors[b];
102             LocalRefCount[b]++;
103             nextFreeLocalBuf = (b + 1) % NLocBuffer;
104             break;
105         }
106     }
107     if (bufHdr==NULL)
108         elog(WARN, "no empty local buffer.");
109
110     /*
111      * this buffer is not referenced but it might still be dirty (the
112      * last transaction to touch it doesn't need its contents but has
113      * not flushed it).  if that's the case, write it out before
114      * reusing it!
115      */
116     if (bufHdr->flags & BM_DIRTY) {
117         Relation bufrel = RelationIdCacheGetRelation(bufHdr->tag.relId.relId);
118
119         Assert(bufrel != NULL);
120         
121         /* flush this page */
122         smgrwrite(bufrel->rd_rel->relsmgr, bufrel, bufHdr->tag.blockNum,
123                   (char *) MAKE_PTR(bufHdr->data));
124         LocalBufferFlushCount++;
125     }
126
127     /*
128      * it's all ours now.
129      */
130     bufHdr->tag.relId.relId = reln->rd_id;
131     bufHdr->tag.blockNum = blockNum;
132     bufHdr->flags &= ~BM_DIRTY;
133
134     /*
135      * lazy memory allocation. (see MAKE_PTR for why we need to do 
136      * MAKE_OFFSET.)
137      */
138     if (bufHdr->data == (SHMEM_OFFSET)0) {
139         char *data = (char *)malloc(BLCKSZ);
140
141         bufHdr->data = MAKE_OFFSET(data);
142     }
143     
144     *foundPtr = FALSE;
145     return bufHdr;
146 }
147
148 /*
149  * WriteLocalBuffer -
150  *    writes out a local buffer
151  */
152 int
153 WriteLocalBuffer(Buffer buffer, bool release)
154 {
155     int bufid;
156
157     Assert(BufferIsLocal(buffer));
158
159 #ifdef LBDEBUG
160     fprintf(stderr, "LB WRITE %d\n", buffer);
161 #endif    
162     
163     bufid = - (buffer + 1);
164     LocalBufferDescriptors[bufid].flags |= BM_DIRTY;
165
166     if (release) {
167         Assert(LocalRefCount[bufid] > 0);
168         LocalRefCount[bufid]--;
169     }
170
171     return true;
172 }
173
174 /*
175  * FlushLocalBuffer -
176  *    flushes a local buffer
177  */
178 int
179 FlushLocalBuffer(Buffer buffer, bool release)
180 {
181     int bufid;
182     Relation bufrel;
183     BufferDesc *bufHdr;
184
185     Assert(BufferIsLocal(buffer));
186
187 #ifdef LBDEBUG
188     fprintf(stderr, "LB FLUSH %d\n", buffer);
189 #endif    
190
191     bufid = - (buffer + 1);
192     bufHdr = &LocalBufferDescriptors[bufid];
193     bufHdr->flags &= ~BM_DIRTY;
194     bufrel = RelationIdCacheGetRelation(bufHdr->tag.relId.relId);
195
196     Assert(bufrel != NULL);
197     smgrflush(bufrel->rd_rel->relsmgr, bufrel, bufHdr->tag.blockNum,
198               (char *) MAKE_PTR(bufHdr->data));
199     LocalBufferFlushCount++;
200
201     Assert(LocalRefCount[bufid] > 0);
202     if ( release )
203         LocalRefCount[bufid]--;
204     
205     return true;
206 }
207
208 /*
209  * InitLocalBuffer -
210  *    init the local buffer cache. Since most queries (esp. multi-user ones)
211  *    don't involve local buffers, we delay allocating memory for actual the
212  *    buffer until we need it.
213  */
214 void
215 InitLocalBuffer(void)
216 {
217     int i;
218     
219     /*
220      * these aren't going away. I'm not gonna use palloc.
221      */
222     LocalBufferDescriptors =
223         (BufferDesc *)malloc(sizeof(BufferDesc) * NLocBuffer);
224     memset(LocalBufferDescriptors, 0, sizeof(BufferDesc) * NLocBuffer);
225     nextFreeLocalBuf = 0;
226
227     for (i = 0; i < NLocBuffer; i++) {
228         BufferDesc *buf = &LocalBufferDescriptors[i];
229
230         /*
231          * negative to indicate local buffer. This is tricky: shared buffers
232          * start with 0. We have to start with -2. (Note that the routine
233          * BufferDescriptorGetBuffer adds 1 to buf_id so our first buffer id
234          * is -1.)
235          */
236         buf->buf_id = - i - 2;  
237     }
238
239     LocalRefCount =
240         (long *)malloc(sizeof(long) * NLocBuffer);
241     memset(LocalRefCount, 0, sizeof(long) * NLocBuffer);
242 }
243
244 /*
245  * LocalBufferSync -
246  *    flush all dirty buffers in the local buffer cache. Since the buffer
247  *    cache is only used for keeping relations visible during a transaction,
248  *    we will not need these buffers again.
249  */
250 void
251 LocalBufferSync(void)
252 {
253     int i;
254     
255     for (i = 0; i < NLocBuffer; i++) {
256         BufferDesc *buf = &LocalBufferDescriptors[i];
257         Relation bufrel;
258
259         if (buf->flags & BM_DIRTY) {
260 #ifdef LBDEBUG
261             fprintf(stderr, "LB SYNC %d\n", -i-1);
262 #endif      
263             bufrel = RelationIdCacheGetRelation(buf->tag.relId.relId);
264
265             Assert(bufrel != NULL);
266             
267             smgrwrite(bufrel->rd_rel->relsmgr, bufrel, buf->tag.blockNum,
268                       (char *) MAKE_PTR(buf->data));
269             LocalBufferFlushCount++;
270
271             buf->tag.relId.relId = InvalidOid;
272             buf->flags &= ~BM_DIRTY;
273         }
274     }
275
276     memset(LocalRefCount, 0, sizeof(long) * NLocBuffer);
277     nextFreeLocalBuf = 0;
278 }
279
280 void
281 ResetLocalBufferPool(void)
282 {
283     int i;
284
285     for (i = 0; i < NLocBuffer; i++)
286     {
287         BufferDesc *buf = &LocalBufferDescriptors[i];
288
289         buf->tag.relId.relId = InvalidOid;
290         buf->flags &= ~BM_DIRTY;
291         buf->buf_id = - i - 2;  
292     }
293
294     memset(LocalRefCount, 0, sizeof(long) * NLocBuffer);
295     nextFreeLocalBuf = 0;
296 }