99 *
1010 *
1111 * IDENTIFICATION
12- * $PostgreSQL: pgsql/src/backend/storage/buffer/localbuf.c,v 1.64 2005/03/18 16:16:09 tgl Exp $
12+ * $PostgreSQL: pgsql/src/backend/storage/buffer/localbuf.c,v 1.65 2005/03/19 17:39:43 tgl Exp $
1313 *
1414 *-------------------------------------------------------------------------
1515 */
1818#include "storage/buf_internals.h"
1919#include "storage/bufmgr.h"
2020#include "storage/smgr.h"
21- #include "utils/relcache .h"
21+ #include "utils/memutils .h"
2222#include "utils/resowner.h"
2323
2424
2525/*#define LBDEBUG*/
2626
27+ /* entry for buffer lookup hashtable */
28+ typedef struct
29+ {
30+ BufferTag key ; /* Tag of a disk page */
31+ int id ; /* Associated local buffer's index */
32+ } LocalBufferLookupEnt ;
33+
2734/* Note: this macro only works on local buffers, not shared ones! */
2835#define LocalBufHdrGetBlock (bufHdr ) \
2936 LocalBufferBlockPointers[-((bufHdr)->buf_id + 2)]
3037
31- /* should be a GUC parameter some day */
32- int NLocBuffer = 64 ;
38+ int NLocBuffer = 0 ; /* until buffers are initialized */
3339
3440BufferDesc * LocalBufferDescriptors = NULL ;
3541Block * LocalBufferBlockPointers = NULL ;
3642int32 * LocalRefCount = NULL ;
3743
3844static int nextFreeLocalBuf = 0 ;
3945
46+ static HTAB * LocalBufHash = NULL ;
47+
4048
4149/*
4250 * LocalBufferAlloc -
43- * allocate a local buffer. We do round robin allocation for now .
51+ * Find or create a local buffer for the given page of the given relation .
4452 *
4553 * API is similar to bufmgr.c's BufferAlloc, except that we do not need
4654 * to do any locking since this is all local. Also, IO_IN_PROGRESS
@@ -50,35 +58,39 @@ BufferDesc *
5058LocalBufferAlloc (Relation reln , BlockNumber blockNum , bool * foundPtr )
5159{
5260 BufferTag newTag ; /* identity of requested block */
53- int i ;
54- int trycounter ;
61+ LocalBufferLookupEnt * hresult ;
5562 BufferDesc * bufHdr ;
63+ int b ;
64+ int trycounter ;
65+ bool found ;
5666
5767 INIT_BUFFERTAG (newTag , reln , blockNum );
5868
59- /* a low tech search for now -- should use a hashtable */
60- for (i = 0 ; i < NLocBuffer ; i ++ )
69+ /* See if the desired buffer already exists */
70+ hresult = (LocalBufferLookupEnt * )
71+ hash_search (LocalBufHash , (void * ) & newTag , HASH_FIND , NULL );
72+
73+ if (hresult )
6174 {
62- bufHdr = & LocalBufferDescriptors [ i ] ;
63- if ( BUFFERTAGS_EQUAL ( bufHdr -> tag , newTag ))
64- {
75+ b = hresult -> id ;
76+ bufHdr = & LocalBufferDescriptors [ b ];
77+ Assert ( BUFFERTAGS_EQUAL ( bufHdr -> tag , newTag ));
6578#ifdef LBDEBUG
66- fprintf (stderr , "LB ALLOC (%u,%d) %d\n" ,
67- RelationGetRelid (reln ), blockNum , - i - 1 );
79+ fprintf (stderr , "LB ALLOC (%u,%d) %d\n" ,
80+ RelationGetRelid (reln ), blockNum , - b - 1 );
6881#endif
6982
70- LocalRefCount [i ]++ ;
71- ResourceOwnerRememberBuffer (CurrentResourceOwner ,
72- BufferDescriptorGetBuffer (bufHdr ));
73- if (bufHdr -> flags & BM_VALID )
74- * foundPtr = TRUE;
75- else
76- {
77- /* Previous read attempt must have failed; try again */
78- * foundPtr = FALSE;
79- }
80- return bufHdr ;
83+ LocalRefCount [b ]++ ;
84+ ResourceOwnerRememberBuffer (CurrentResourceOwner ,
85+ BufferDescriptorGetBuffer (bufHdr ));
86+ if (bufHdr -> flags & BM_VALID )
87+ * foundPtr = TRUE;
88+ else
89+ {
90+ /* Previous read attempt must have failed; try again */
91+ * foundPtr = FALSE;
8192 }
93+ return bufHdr ;
8294 }
8395
8496#ifdef LBDEBUG
@@ -93,7 +105,7 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
93105 trycounter = NLocBuffer ;
94106 for (;;)
95107 {
96- int b = nextFreeLocalBuf ;
108+ b = nextFreeLocalBuf ;
97109
98110 if (++ nextFreeLocalBuf >= NLocBuffer )
99111 nextFreeLocalBuf = 0 ;
@@ -136,31 +148,50 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
136148 (char * ) LocalBufHdrGetBlock (bufHdr ),
137149 true);
138150
151+ /* Mark not-dirty now in case we error out below */
152+ bufHdr -> flags &= ~BM_DIRTY ;
153+
139154 LocalBufferFlushCount ++ ;
140155 }
141156
142157 /*
143158 * lazy memory allocation: allocate space on first use of a buffer.
144- *
145- * Note this path cannot be taken for a buffer that was previously in
146- * use, so it's okay to do it (and possibly error out) before marking
147- * the buffer as not dirty.
148159 */
149160 if (LocalBufHdrGetBlock (bufHdr ) == NULL )
150161 {
151- char * data = ( char * ) malloc ( BLCKSZ ) ;
162+ char * data ;
152163
153- if (data == NULL )
154- ereport (ERROR ,
155- (errcode (ERRCODE_OUT_OF_MEMORY ),
156- errmsg ("out of memory" )));
164+ data = (char * ) MemoryContextAlloc (TopMemoryContext , BLCKSZ );
157165
158- /*
159- * Set pointer for use by BufferGetBlock() macro.
160- */
166+ /* Set pointer for use by BufferGetBlock() macro */
161167 LocalBufHdrGetBlock (bufHdr ) = (Block ) data ;
162168 }
163169
170+ /*
171+ * Update the hash table: remove old entry, if any, and make new one.
172+ */
173+ if (bufHdr -> flags & BM_TAG_VALID )
174+ {
175+ hresult = (LocalBufferLookupEnt * )
176+ hash_search (LocalBufHash , (void * ) & bufHdr -> tag ,
177+ HASH_REMOVE , NULL );
178+ if (!hresult ) /* shouldn't happen */
179+ elog (ERROR , "local buffer hash table corrupted" );
180+ /* mark buffer invalid just in case hash insert fails */
181+ CLEAR_BUFFERTAG (bufHdr -> tag );
182+ bufHdr -> flags &= ~(BM_VALID | BM_TAG_VALID );
183+ }
184+
185+ hresult = (LocalBufferLookupEnt * )
186+ hash_search (LocalBufHash , (void * ) & newTag , HASH_ENTER , & found );
187+ if (!hresult )
188+ ereport (ERROR ,
189+ (errcode (ERRCODE_OUT_OF_MEMORY ),
190+ errmsg ("out of memory" )));
191+ if (found ) /* shouldn't happen */
192+ elog (ERROR , "local buffer hash table corrupted" );
193+ hresult -> id = b ;
194+
164195 /*
165196 * it's all ours now.
166197 */
@@ -215,20 +246,39 @@ WriteLocalBuffer(Buffer buffer, bool release)
215246void
216247InitLocalBuffer (void )
217248{
249+ int nbufs = 64 ; /* should be from a GUC var */
250+ HASHCTL info ;
218251 int i ;
219252
220- /*
221- * these aren't going away. I'm not gonna use palloc.
222- */
253+ /* Create the lookup hash table */
254+ MemSet (& info , 0 , sizeof (info ));
255+ info .keysize = sizeof (BufferTag );
256+ info .entrysize = sizeof (LocalBufferLookupEnt );
257+ info .hash = tag_hash ;
258+
259+ LocalBufHash = hash_create ("Local Buffer Lookup Table" ,
260+ nbufs ,
261+ & info ,
262+ HASH_ELEM | HASH_FUNCTION );
263+
264+ if (!LocalBufHash )
265+ elog (ERROR , "could not initialize local buffer hash table" );
266+
267+ /* Allocate and zero buffer headers and auxiliary arrays */
223268 LocalBufferDescriptors = (BufferDesc * )
224- calloc (NLocBuffer , sizeof (* LocalBufferDescriptors ));
269+ MemoryContextAllocZero (TopMemoryContext ,
270+ nbufs * sizeof (BufferDesc ));
225271 LocalBufferBlockPointers = (Block * )
226- calloc (NLocBuffer , sizeof (* LocalBufferBlockPointers ));
272+ MemoryContextAllocZero (TopMemoryContext ,
273+ nbufs * sizeof (Block ));
227274 LocalRefCount = (int32 * )
228- calloc (NLocBuffer , sizeof (* LocalRefCount ));
275+ MemoryContextAllocZero (TopMemoryContext ,
276+ nbufs * sizeof (int32 ));
277+
229278 nextFreeLocalBuf = 0 ;
230279
231- for (i = 0 ; i < NLocBuffer ; i ++ )
280+ /* initialize fields that need to start off nonzero */
281+ for (i = 0 ; i < nbufs ; i ++ )
232282 {
233283 BufferDesc * buf = & LocalBufferDescriptors [i ];
234284
@@ -240,6 +290,9 @@ InitLocalBuffer(void)
240290 */
241291 buf -> buf_id = - i - 2 ;
242292 }
293+
294+ /* Initialization done, mark buffers allocated */
295+ NLocBuffer = nbufs ;
243296}
244297
245298/*
271324AtProcExit_LocalBuffers (void )
272325{
273326 /* just zero the refcounts ... */
274- MemSet (LocalRefCount , 0 , NLocBuffer * sizeof (* LocalRefCount ));
327+ if (LocalRefCount )
328+ MemSet (LocalRefCount , 0 , NLocBuffer * sizeof (* LocalRefCount ));
275329}
0 commit comments