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-2026, 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 :
26 : /* entry for buffer lookup hashtable */
27 : typedef struct
28 : {
29 : BufferTag key; /* Tag of a disk page */
30 : int id; /* Associated buffer ID */
31 : } BufferLookupEnt;
32 :
33 : static HTAB *SharedBufHash;
34 :
35 :
36 : /*
37 : * Estimate space needed for mapping hashtable
38 : * size is the desired hash table size (possibly more than NBuffers)
39 : */
40 : Size
41 2165 : BufTableShmemSize(int size)
42 : {
43 2165 : return hash_estimate_size(size, sizeof(BufferLookupEnt));
44 : }
45 :
46 : /*
47 : * Initialize shmem hash table for mapping buffers
48 : * size is the desired hash table size (possibly more than NBuffers)
49 : */
50 : void
51 1159 : InitBufTable(int size)
52 : {
53 : HASHCTL info;
54 :
55 : /* assume no locking is needed yet */
56 :
57 : /* BufferTag maps to Buffer */
58 1159 : info.keysize = sizeof(BufferTag);
59 1159 : info.entrysize = sizeof(BufferLookupEnt);
60 1159 : info.num_partitions = NUM_BUFFER_PARTITIONS;
61 :
62 1159 : SharedBufHash = ShmemInitHash("Shared Buffer Lookup Table",
63 : size, size,
64 : &info,
65 : HASH_ELEM | HASH_BLOBS | HASH_PARTITION | HASH_FIXED_SIZE);
66 1159 : }
67 :
68 : /*
69 : * BufTableHashCode
70 : * Compute the hash code associated with a BufferTag
71 : *
72 : * This must be passed to the lookup/insert/delete routines along with the
73 : * tag. We do it like this because the callers need to know the hash code
74 : * in order to determine which buffer partition to lock, and we don't want
75 : * to do the hash computation twice (hash_any is a bit slow).
76 : */
77 : uint32
78 67976045 : BufTableHashCode(BufferTag *tagPtr)
79 : {
80 67976045 : return get_hash_value(SharedBufHash, tagPtr);
81 : }
82 :
83 : /*
84 : * BufTableLookup
85 : * Lookup the given BufferTag; return buffer ID, or -1 if not found
86 : *
87 : * Caller must hold at least share lock on BufMappingLock for tag's partition
88 : */
89 : int
90 66389972 : BufTableLookup(BufferTag *tagPtr, uint32 hashcode)
91 : {
92 : BufferLookupEnt *result;
93 :
94 : result = (BufferLookupEnt *)
95 66389972 : hash_search_with_hash_value(SharedBufHash,
96 : tagPtr,
97 : hashcode,
98 : HASH_FIND,
99 : NULL);
100 :
101 66389972 : if (!result)
102 1787343 : return -1;
103 :
104 64602629 : return result->id;
105 : }
106 :
107 : /*
108 : * BufTableInsert
109 : * Insert a hashtable entry for given tag and buffer ID,
110 : * unless an entry already exists for that tag
111 : *
112 : * Returns -1 on successful insertion. If a conflicting entry exists
113 : * already, returns the buffer ID in that entry.
114 : *
115 : * Caller must hold exclusive lock on BufMappingLock for tag's partition
116 : */
117 : int
118 2007885 : BufTableInsert(BufferTag *tagPtr, uint32 hashcode, int buf_id)
119 : {
120 : BufferLookupEnt *result;
121 : bool found;
122 :
123 : Assert(buf_id >= 0); /* -1 is reserved for not-in-table */
124 : Assert(tagPtr->blockNum != P_NEW); /* invalid tag */
125 :
126 : result = (BufferLookupEnt *)
127 2007885 : hash_search_with_hash_value(SharedBufHash,
128 : tagPtr,
129 : hashcode,
130 : HASH_ENTER,
131 : &found);
132 :
133 2007885 : if (found) /* found something already in the table */
134 744 : return result->id;
135 :
136 2007141 : result->id = buf_id;
137 :
138 2007141 : return -1;
139 : }
140 :
141 : /*
142 : * BufTableDelete
143 : * Delete the hashtable entry for given tag (which must exist)
144 : *
145 : * Caller must hold exclusive lock on BufMappingLock for tag's partition
146 : */
147 : void
148 1355702 : BufTableDelete(BufferTag *tagPtr, uint32 hashcode)
149 : {
150 : BufferLookupEnt *result;
151 :
152 : result = (BufferLookupEnt *)
153 1355702 : hash_search_with_hash_value(SharedBufHash,
154 : tagPtr,
155 : hashcode,
156 : HASH_REMOVE,
157 : NULL);
158 :
159 1355702 : if (!result) /* shouldn't happen */
160 0 : elog(ERROR, "shared buffer hash table corrupted");
161 1355702 : }
|