Header And Logo

PostgreSQL
| The world's most advanced open source database.

buf_init.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * buf_init.c
00004  *    buffer manager initialization routines
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/storage/buffer/buf_init.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 #include "postgres.h"
00016 
00017 #include "storage/bufmgr.h"
00018 #include "storage/buf_internals.h"
00019 
00020 
00021 BufferDesc *BufferDescriptors;
00022 char       *BufferBlocks;
00023 int32      *PrivateRefCount;
00024 
00025 
00026 /*
00027  * Data Structures:
00028  *      buffers live in a freelist and a lookup data structure.
00029  *
00030  *
00031  * Buffer Lookup:
00032  *      Two important notes.  First, the buffer has to be
00033  *      available for lookup BEFORE an IO begins.  Otherwise
00034  *      a second process trying to read the buffer will
00035  *      allocate its own copy and the buffer pool will
00036  *      become inconsistent.
00037  *
00038  * Buffer Replacement:
00039  *      see freelist.c.  A buffer cannot be replaced while in
00040  *      use either by data manager or during IO.
00041  *
00042  *
00043  * Synchronization/Locking:
00044  *
00045  * IO_IN_PROGRESS -- this is a flag in the buffer descriptor.
00046  *      It must be set when an IO is initiated and cleared at
00047  *      the end of the IO.  It is there to make sure that one
00048  *      process doesn't start to use a buffer while another is
00049  *      faulting it in.  see WaitIO and related routines.
00050  *
00051  * refcount --  Counts the number of processes holding pins on a buffer.
00052  *      A buffer is pinned during IO and immediately after a BufferAlloc().
00053  *      Pins must be released before end of transaction.
00054  *
00055  * PrivateRefCount -- Each buffer also has a private refcount that keeps
00056  *      track of the number of times the buffer is pinned in the current
00057  *      process.    This is used for two purposes: first, if we pin a
00058  *      a buffer more than once, we only need to change the shared refcount
00059  *      once, thus only lock the shared state once; second, when a transaction
00060  *      aborts, it should only unpin the buffers exactly the number of times it
00061  *      has pinned them, so that it will not blow away buffers of another
00062  *      backend.
00063  */
00064 
00065 
00066 /*
00067  * Initialize shared buffer pool
00068  *
00069  * This is called once during shared-memory initialization (either in the
00070  * postmaster, or in a standalone backend).
00071  */
00072 void
00073 InitBufferPool(void)
00074 {
00075     bool        foundBufs,
00076                 foundDescs;
00077 
00078     BufferDescriptors = (BufferDesc *)
00079         ShmemInitStruct("Buffer Descriptors",
00080                         NBuffers * sizeof(BufferDesc), &foundDescs);
00081 
00082     BufferBlocks = (char *)
00083         ShmemInitStruct("Buffer Blocks",
00084                         NBuffers * (Size) BLCKSZ, &foundBufs);
00085 
00086     if (foundDescs || foundBufs)
00087     {
00088         /* both should be present or neither */
00089         Assert(foundDescs && foundBufs);
00090         /* note: this path is only taken in EXEC_BACKEND case */
00091     }
00092     else
00093     {
00094         BufferDesc *buf;
00095         int         i;
00096 
00097         buf = BufferDescriptors;
00098 
00099         /*
00100          * Initialize all the buffer headers.
00101          */
00102         for (i = 0; i < NBuffers; buf++, i++)
00103         {
00104             CLEAR_BUFFERTAG(buf->tag);
00105             buf->flags = 0;
00106             buf->usage_count = 0;
00107             buf->refcount = 0;
00108             buf->wait_backend_pid = 0;
00109 
00110             SpinLockInit(&buf->buf_hdr_lock);
00111 
00112             buf->buf_id = i;
00113 
00114             /*
00115              * Initially link all the buffers together as unused. Subsequent
00116              * management of this list is done by freelist.c.
00117              */
00118             buf->freeNext = i + 1;
00119 
00120             buf->io_in_progress_lock = LWLockAssign();
00121             buf->content_lock = LWLockAssign();
00122         }
00123 
00124         /* Correct last entry of linked list */
00125         BufferDescriptors[NBuffers - 1].freeNext = FREENEXT_END_OF_LIST;
00126     }
00127 
00128     /* Init other shared buffer-management stuff */
00129     StrategyInitialize(!foundDescs);
00130 }
00131 
00132 /*
00133  * Initialize access to shared buffer pool
00134  *
00135  * This is called during backend startup (whether standalone or under the
00136  * postmaster).  It sets up for this backend's access to the already-existing
00137  * buffer pool.
00138  *
00139  * NB: this is called before InitProcess(), so we do not have a PGPROC and
00140  * cannot do LWLockAcquire; hence we can't actually access stuff in
00141  * shared memory yet.  We are only initializing local data here.
00142  * (See also InitBufferPoolBackend, over in bufmgr.c.)
00143  */
00144 void
00145 InitBufferPoolAccess(void)
00146 {
00147     /*
00148      * Allocate and zero local arrays of per-buffer info.
00149      */
00150     PrivateRefCount = (int32 *) calloc(NBuffers, sizeof(int32));
00151     if (!PrivateRefCount)
00152         ereport(FATAL,
00153                 (errcode(ERRCODE_OUT_OF_MEMORY),
00154                  errmsg("out of memory")));
00155 }
00156 
00157 /*
00158  * BufferShmemSize
00159  *
00160  * compute the size of shared memory for the buffer pool including
00161  * data pages, buffer descriptors, hash tables, etc.
00162  */
00163 Size
00164 BufferShmemSize(void)
00165 {
00166     Size        size = 0;
00167 
00168     /* size of buffer descriptors */
00169     size = add_size(size, mul_size(NBuffers, sizeof(BufferDesc)));
00170 
00171     /* size of data pages */
00172     size = add_size(size, mul_size(NBuffers, BLCKSZ));
00173 
00174     /* size of stuff controlled by freelist.c */
00175     size = add_size(size, StrategyShmemSize());
00176 
00177     return size;
00178 }