| /*------------------------------------------------------------------------- |
| * |
| * buf_table.c |
| * routines for mapping BufferTags to buffer indexes. |
| * |
| * Note: the routines in this file do no locking of their own. The caller |
| * must hold a suitable lock on the appropriate BufMappingLock, as specified |
| * in the comments. We can't do the locking inside these functions because |
| * in most cases the caller needs to adjust the buffer header contents |
| * before the lock is released (see notes in README). |
| * |
| * |
| * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group |
| * Portions Copyright (c) 1994, Regents of the University of California |
| * |
| * |
| * IDENTIFICATION |
| * $PostgreSQL: pgsql/src/backend/storage/buffer/buf_table.c,v 1.47 2006/07/23 03:07:58 tgl Exp $ |
| * |
| *------------------------------------------------------------------------- |
| */ |
| #include "postgres.h" |
| |
| #include "storage/bufmgr.h" |
| #include "storage/buf_internals.h" |
| |
| |
| /* entry for buffer lookup hashtable */ |
| typedef struct |
| { |
| BufferTag key; /* Tag of a disk page */ |
| int id; /* Associated buffer ID */ |
| } BufferLookupEnt; |
| |
| static HTAB *SharedBufHash; |
| |
| |
| /* |
| * Estimate space needed for mapping hashtable |
| * size is the desired hash table size (possibly more than NBuffers) |
| */ |
| Size |
| BufTableShmemSize(int size) |
| { |
| return hash_estimate_size(size, sizeof(BufferLookupEnt)); |
| } |
| |
| /* |
| * Initialize shmem hash table for mapping buffers |
| * size is the desired hash table size (possibly more than NBuffers) |
| */ |
| void |
| InitBufTable(int size) |
| { |
| HASHCTL info; |
| |
| /* assume no locking is needed yet */ |
| |
| /* BufferTag maps to Buffer */ |
| info.keysize = sizeof(BufferTag); |
| info.entrysize = sizeof(BufferLookupEnt); |
| info.hash = tag_hash; |
| info.num_partitions = NUM_BUFFER_PARTITIONS; |
| |
| SharedBufHash = ShmemInitHash("Shared Buffer Lookup Table", |
| size, size, |
| &info, |
| HASH_ELEM | HASH_FUNCTION | HASH_PARTITION); |
| |
| if (!SharedBufHash) |
| elog(FATAL, "could not initialize shared buffer hash table"); |
| } |
| |
| /* |
| * BufTableHashCode |
| * Compute the hash code associated with a BufferTag |
| * |
| * This must be passed to the lookup/insert/delete routines along with the |
| * tag. We do it like this because the callers need to know the hash code |
| * in order to determine which buffer partition to lock, and we don't want |
| * to do the hash computation twice (hash_any is a bit slow). |
| */ |
| uint32 |
| BufTableHashCode(BufferTag *tagPtr) |
| { |
| return get_hash_value(SharedBufHash, (void *) tagPtr); |
| } |
| |
| /* |
| * BufTableLookup |
| * Lookup the given BufferTag; return buffer ID, or -1 if not found |
| * |
| * Caller must hold at least share lock on BufMappingLock for tag's partition |
| */ |
| int |
| BufTableLookup(BufferTag *tagPtr, uint32 hashcode) |
| { |
| BufferLookupEnt *result; |
| |
| result = (BufferLookupEnt *) |
| hash_search_with_hash_value(SharedBufHash, |
| (void *) tagPtr, |
| hashcode, |
| HASH_FIND, |
| NULL); |
| |
| if (!result) |
| return -1; |
| |
| return result->id; |
| } |
| |
| /* |
| * BufTableInsert |
| * Insert a hashtable entry for given tag and buffer ID, |
| * unless an entry already exists for that tag |
| * |
| * Returns -1 on successful insertion. If a conflicting entry exists |
| * already, returns the buffer ID in that entry. |
| * |
| * Caller must hold exclusive lock on BufMappingLock for tag's partition |
| */ |
| int |
| BufTableInsert(BufferTag *tagPtr, uint32 hashcode, int buf_id) |
| { |
| BufferLookupEnt *result; |
| bool found; |
| |
| Assert(buf_id >= 0); /* -1 is reserved for not-in-table */ |
| Assert(tagPtr->blockNum != P_NEW); /* invalid tag */ |
| |
| result = (BufferLookupEnt *) |
| hash_search_with_hash_value(SharedBufHash, |
| (void *) tagPtr, |
| hashcode, |
| HASH_ENTER, |
| &found); |
| |
| if (found) /* found something already in the table */ |
| return result->id; |
| |
| result->id = buf_id; |
| |
| return -1; |
| } |
| |
| /* |
| * BufTableDelete |
| * Delete the hashtable entry for given tag (which must exist) |
| * |
| * Caller must hold exclusive lock on BufMappingLock for tag's partition |
| */ |
| void |
| BufTableDelete(BufferTag *tagPtr, uint32 hashcode) |
| { |
| BufferLookupEnt *result; |
| |
| result = (BufferLookupEnt *) |
| hash_search_with_hash_value(SharedBufHash, |
| (void *) tagPtr, |
| hashcode, |
| HASH_REMOVE, |
| NULL); |
| |
| if (!result) /* shouldn't happen */ |
| elog(ERROR, "shared buffer hash table corrupted"); |
| } |