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 }