postgresql/src/backend/storage/buffer/buf_table.c

163 lines
4.0 KiB
C

/*-------------------------------------------------------------------------
*
* 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-2023, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* src/backend/storage/buffer/buf_table.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "storage/buf_internals.h"
#include "storage/bufmgr.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.num_partitions = NUM_BUFFER_PARTITIONS;
SharedBufHash = ShmemInitHash("Shared Buffer Lookup Table",
size, size,
&info,
HASH_ELEM | HASH_BLOBS | HASH_PARTITION);
}
/*
* 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,
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,
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,
tagPtr,
hashcode,
HASH_REMOVE,
NULL);
if (!result) /* shouldn't happen */
elog(ERROR, "shared buffer hash table corrupted");
}