Header And Logo

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

buf_table.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * buf_table.c
00004  *    routines for mapping BufferTags to buffer indexes.
00005  *
00006  * Note: the routines in this file do no locking of their own.  The caller
00007  * must hold a suitable lock on the appropriate BufMappingLock, as specified
00008  * in the comments.  We can't do the locking inside these functions because
00009  * in most cases the caller needs to adjust the buffer header contents
00010  * before the lock is released (see notes in README).
00011  *
00012  *
00013  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00014  * Portions Copyright (c) 1994, Regents of the University of California
00015  *
00016  *
00017  * IDENTIFICATION
00018  *    src/backend/storage/buffer/buf_table.c
00019  *
00020  *-------------------------------------------------------------------------
00021  */
00022 #include "postgres.h"
00023 
00024 #include "storage/bufmgr.h"
00025 #include "storage/buf_internals.h"
00026 
00027 
00028 /* entry for buffer lookup hashtable */
00029 typedef struct
00030 {
00031     BufferTag   key;            /* Tag of a disk page */
00032     int         id;             /* Associated buffer ID */
00033 } BufferLookupEnt;
00034 
00035 static HTAB *SharedBufHash;
00036 
00037 
00038 /*
00039  * Estimate space needed for mapping hashtable
00040  *      size is the desired hash table size (possibly more than NBuffers)
00041  */
00042 Size
00043 BufTableShmemSize(int size)
00044 {
00045     return hash_estimate_size(size, sizeof(BufferLookupEnt));
00046 }
00047 
00048 /*
00049  * Initialize shmem hash table for mapping buffers
00050  *      size is the desired hash table size (possibly more than NBuffers)
00051  */
00052 void
00053 InitBufTable(int size)
00054 {
00055     HASHCTL     info;
00056 
00057     /* assume no locking is needed yet */
00058 
00059     /* BufferTag maps to Buffer */
00060     info.keysize = sizeof(BufferTag);
00061     info.entrysize = sizeof(BufferLookupEnt);
00062     info.hash = tag_hash;
00063     info.num_partitions = NUM_BUFFER_PARTITIONS;
00064 
00065     SharedBufHash = ShmemInitHash("Shared Buffer Lookup Table",
00066                                   size, size,
00067                                   &info,
00068                                   HASH_ELEM | HASH_FUNCTION | HASH_PARTITION);
00069 }
00070 
00071 /*
00072  * BufTableHashCode
00073  *      Compute the hash code associated with a BufferTag
00074  *
00075  * This must be passed to the lookup/insert/delete routines along with the
00076  * tag.  We do it like this because the callers need to know the hash code
00077  * in order to determine which buffer partition to lock, and we don't want
00078  * to do the hash computation twice (hash_any is a bit slow).
00079  */
00080 uint32
00081 BufTableHashCode(BufferTag *tagPtr)
00082 {
00083     return get_hash_value(SharedBufHash, (void *) tagPtr);
00084 }
00085 
00086 /*
00087  * BufTableLookup
00088  *      Lookup the given BufferTag; return buffer ID, or -1 if not found
00089  *
00090  * Caller must hold at least share lock on BufMappingLock for tag's partition
00091  */
00092 int
00093 BufTableLookup(BufferTag *tagPtr, uint32 hashcode)
00094 {
00095     BufferLookupEnt *result;
00096 
00097     result = (BufferLookupEnt *)
00098         hash_search_with_hash_value(SharedBufHash,
00099                                     (void *) tagPtr,
00100                                     hashcode,
00101                                     HASH_FIND,
00102                                     NULL);
00103 
00104     if (!result)
00105         return -1;
00106 
00107     return result->id;
00108 }
00109 
00110 /*
00111  * BufTableInsert
00112  *      Insert a hashtable entry for given tag and buffer ID,
00113  *      unless an entry already exists for that tag
00114  *
00115  * Returns -1 on successful insertion.  If a conflicting entry exists
00116  * already, returns the buffer ID in that entry.
00117  *
00118  * Caller must hold exclusive lock on BufMappingLock for tag's partition
00119  */
00120 int
00121 BufTableInsert(BufferTag *tagPtr, uint32 hashcode, int buf_id)
00122 {
00123     BufferLookupEnt *result;
00124     bool        found;
00125 
00126     Assert(buf_id >= 0);        /* -1 is reserved for not-in-table */
00127     Assert(tagPtr->blockNum != P_NEW);  /* invalid tag */
00128 
00129     result = (BufferLookupEnt *)
00130         hash_search_with_hash_value(SharedBufHash,
00131                                     (void *) tagPtr,
00132                                     hashcode,
00133                                     HASH_ENTER,
00134                                     &found);
00135 
00136     if (found)                  /* found something already in the table */
00137         return result->id;
00138 
00139     result->id = buf_id;
00140 
00141     return -1;
00142 }
00143 
00144 /*
00145  * BufTableDelete
00146  *      Delete the hashtable entry for given tag (which must exist)
00147  *
00148  * Caller must hold exclusive lock on BufMappingLock for tag's partition
00149  */
00150 void
00151 BufTableDelete(BufferTag *tagPtr, uint32 hashcode)
00152 {
00153     BufferLookupEnt *result;
00154 
00155     result = (BufferLookupEnt *)
00156         hash_search_with_hash_value(SharedBufHash,
00157                                     (void *) tagPtr,
00158                                     hashcode,
00159                                     HASH_REMOVE,
00160                                     NULL);
00161 
00162     if (!result)                /* shouldn't happen */
00163         elog(ERROR, "shared buffer hash table corrupted");
00164 }