Line data Source code
1 : /*------------------------------------------------------------------------- 2 : * 3 : * buf_table.c 4 : * routines for mapping BufferTags to buffer indexes. 5 : * 6 : * Note: the routines in this file do no locking of their own. The caller 7 : * must hold a suitable lock on the appropriate BufMappingLock, as specified 8 : * in the comments. We can't do the locking inside these functions because 9 : * in most cases the caller needs to adjust the buffer header contents 10 : * before the lock is released (see notes in README). 11 : * 12 : * 13 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group 14 : * Portions Copyright (c) 1994, Regents of the University of California 15 : * 16 : * 17 : * IDENTIFICATION 18 : * src/backend/storage/buffer/buf_table.c 19 : * 20 : *------------------------------------------------------------------------- 21 : */ 22 : #include "postgres.h" 23 : 24 : #include "storage/buf_internals.h" 25 : #include "storage/bufmgr.h" 26 : 27 : /* entry for buffer lookup hashtable */ 28 : typedef struct 29 : { 30 : BufferTag key; /* Tag of a disk page */ 31 : int id; /* Associated buffer ID */ 32 : } BufferLookupEnt; 33 : 34 : static HTAB *SharedBufHash; 35 : 36 : 37 : /* 38 : * Estimate space needed for mapping hashtable 39 : * size is the desired hash table size (possibly more than NBuffers) 40 : */ 41 : Size 42 5456 : BufTableShmemSize(int size) 43 : { 44 5456 : return hash_estimate_size(size, sizeof(BufferLookupEnt)); 45 : } 46 : 47 : /* 48 : * Initialize shmem hash table for mapping buffers 49 : * size is the desired hash table size (possibly more than NBuffers) 50 : */ 51 : void 52 3636 : InitBufTable(int size) 53 : { 54 : HASHCTL info; 55 : 56 : /* assume no locking is needed yet */ 57 : 58 : /* BufferTag maps to Buffer */ 59 3636 : info.keysize = sizeof(BufferTag); 60 3636 : info.entrysize = sizeof(BufferLookupEnt); 61 3636 : info.num_partitions = NUM_BUFFER_PARTITIONS; 62 : 63 3636 : SharedBufHash = ShmemInitHash("Shared Buffer Lookup Table", 64 : size, size, 65 : &info, 66 : HASH_ELEM | HASH_BLOBS | HASH_PARTITION); 67 3636 : } 68 : 69 : /* 70 : * BufTableHashCode 71 : * Compute the hash code associated with a BufferTag 72 : * 73 : * This must be passed to the lookup/insert/delete routines along with the 74 : * tag. We do it like this because the callers need to know the hash code 75 : * in order to determine which buffer partition to lock, and we don't want 76 : * to do the hash computation twice (hash_any is a bit slow). 77 : */ 78 : uint32 79 137604542 : BufTableHashCode(BufferTag *tagPtr) 80 : { 81 137604542 : return get_hash_value(SharedBufHash, (void *) tagPtr); 82 : } 83 : 84 : /* 85 : * BufTableLookup 86 : * Lookup the given BufferTag; return buffer ID, or -1 if not found 87 : * 88 : * Caller must hold at least share lock on BufMappingLock for tag's partition 89 : */ 90 : int 91 134675148 : BufTableLookup(BufferTag *tagPtr, uint32 hashcode) 92 : { 93 : BufferLookupEnt *result; 94 : 95 : result = (BufferLookupEnt *) 96 134675148 : hash_search_with_hash_value(SharedBufHash, 97 : tagPtr, 98 : hashcode, 99 : HASH_FIND, 100 : NULL); 101 : 102 134675148 : if (!result) 103 3333410 : return -1; 104 : 105 131341738 : return result->id; 106 : } 107 : 108 : /* 109 : * BufTableInsert 110 : * Insert a hashtable entry for given tag and buffer ID, 111 : * unless an entry already exists for that tag 112 : * 113 : * Returns -1 on successful insertion. If a conflicting entry exists 114 : * already, returns the buffer ID in that entry. 115 : * 116 : * Caller must hold exclusive lock on BufMappingLock for tag's partition 117 : */ 118 : int 119 3641766 : BufTableInsert(BufferTag *tagPtr, uint32 hashcode, int buf_id) 120 : { 121 : BufferLookupEnt *result; 122 : bool found; 123 : 124 : Assert(buf_id >= 0); /* -1 is reserved for not-in-table */ 125 : Assert(tagPtr->blockNum != P_NEW); /* invalid tag */ 126 : 127 : result = (BufferLookupEnt *) 128 3641766 : hash_search_with_hash_value(SharedBufHash, 129 : tagPtr, 130 : hashcode, 131 : HASH_ENTER, 132 : &found); 133 : 134 3641766 : if (found) /* found something already in the table */ 135 250 : return result->id; 136 : 137 3641516 : result->id = buf_id; 138 : 139 3641516 : return -1; 140 : } 141 : 142 : /* 143 : * BufTableDelete 144 : * Delete the hashtable entry for given tag (which must exist) 145 : * 146 : * Caller must hold exclusive lock on BufMappingLock for tag's partition 147 : */ 148 : void 149 2204376 : BufTableDelete(BufferTag *tagPtr, uint32 hashcode) 150 : { 151 : BufferLookupEnt *result; 152 : 153 : result = (BufferLookupEnt *) 154 2204376 : hash_search_with_hash_value(SharedBufHash, 155 : tagPtr, 156 : hashcode, 157 : HASH_REMOVE, 158 : NULL); 159 : 160 2204376 : if (!result) /* shouldn't happen */ 161 0 : elog(ERROR, "shared buffer hash table corrupted"); 162 2204376 : }