Age Owner Branch data TLA 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 : : #include "storage/subsystems.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 : : static void BufTableShmemRequest(void *arg);
37 : :
38 : : const ShmemCallbacks BufTableShmemCallbacks = {
39 : : .request_fn = BufTableShmemRequest,
40 : : /* no special initialization needed, the hash table will start empty */
41 : : };
42 : :
43 : : /*
44 : : * Register shmem hash table for mapping buffers.
45 : : * size is the desired hash table size (possibly more than NBuffers)
46 : : */
47 : : void
29 heikki.linnakangas@i 48 :GNC 1244 : BufTableShmemRequest(void *arg)
49 : : {
50 : : int size;
51 : :
52 : : /*
53 : : * Request the shared buffer lookup hashtable.
54 : : *
55 : : * Since we can't tolerate running out of lookup table entries, we must be
56 : : * sure to specify an adequate table size here. The maximum steady-state
57 : : * usage is of course NBuffers entries, but BufferAlloc() tries to insert
58 : : * a new entry before deleting the old. In principle this could be
59 : : * happening in each partition concurrently, so we could need as many as
60 : : * NBuffers + NUM_BUFFER_PARTITIONS entries.
61 : : */
62 : 1244 : size = NBuffers + NUM_BUFFER_PARTITIONS;
63 : :
64 : 1244 : ShmemRequestHash(.name = "Shared Buffer Lookup Table",
65 : : .nelems = size,
66 : : .ptr = &SharedBufHash,
67 : : .hash_info.keysize = sizeof(BufferTag),
68 : : .hash_info.entrysize = sizeof(BufferLookupEnt),
69 : : .hash_info.num_partitions = NUM_BUFFER_PARTITIONS,
70 : : .hash_flags = HASH_ELEM | HASH_BLOBS | HASH_PARTITION | HASH_FIXED_SIZE,
71 : : );
10892 scrappy@hub.org 72 :CBC 1244 : }
73 : :
74 : : /*
75 : : * BufTableHashCode
76 : : * Compute the hash code associated with a BufferTag
77 : : *
78 : : * This must be passed to the lookup/insert/delete routines along with the
79 : : * tag. We do it like this because the callers need to know the hash code
80 : : * in order to determine which buffer partition to lock, and we don't want
81 : : * to do the hash computation twice (hash_any is a bit slow).
82 : : */
83 : : uint32
7226 tgl@sss.pgh.pa.us 84 : 84565725 : BufTableHashCode(BufferTag *tagPtr)
85 : : {
523 peter@eisentraut.org 86 : 84565725 : return get_hash_value(SharedBufHash, tagPtr);
87 : : }
88 : :
89 : : /*
90 : : * BufTableLookup
91 : : * Lookup the given BufferTag; return buffer ID, or -1 if not found
92 : : *
93 : : * Caller must hold at least share lock on BufMappingLock for tag's partition
94 : : */
95 : : int
7226 tgl@sss.pgh.pa.us 96 : 82750810 : BufTableLookup(BufferTag *tagPtr, uint32 hashcode)
97 : : {
98 : : BufferLookupEnt *result;
99 : :
100 : : result = (BufferLookupEnt *)
101 : 82750810 : hash_search_with_hash_value(SharedBufHash,
102 : : tagPtr,
103 : : hashcode,
104 : : HASH_FIND,
105 : : NULL);
106 : :
10467 bruce@momjian.us 107 [ + + ]: 82750810 : if (!result)
8209 JanWieck@Yahoo.com 108 : 1971816 : return -1;
109 : :
110 : 80778994 : return result->id;
111 : : }
112 : :
113 : : /*
114 : : * BufTableInsert
115 : : * Insert a hashtable entry for given tag and buffer ID,
116 : : * unless an entry already exists for that tag
117 : : *
118 : : * Returns -1 on successful insertion. If a conflicting entry exists
119 : : * already, returns the buffer ID in that entry.
120 : : *
121 : : * Caller must hold exclusive lock on BufMappingLock for tag's partition
122 : : */
123 : : int
7226 tgl@sss.pgh.pa.us 124 : 2241587 : BufTableInsert(BufferTag *tagPtr, uint32 hashcode, int buf_id)
125 : : {
126 : : BufferLookupEnt *result;
127 : : bool found;
128 : :
7732 129 [ - + ]: 2241587 : Assert(buf_id >= 0); /* -1 is reserved for not-in-table */
7507 bruce@momjian.us 130 [ - + ]: 2241587 : Assert(tagPtr->blockNum != P_NEW); /* invalid tag */
131 : :
132 : : result = (BufferLookupEnt *)
7226 tgl@sss.pgh.pa.us 133 : 2241587 : hash_search_with_hash_value(SharedBufHash,
134 : : tagPtr,
135 : : hashcode,
136 : : HASH_ENTER,
137 : : &found);
138 : :
7732 139 [ + + ]: 2241587 : if (found) /* found something already in the table */
140 : 701 : return result->id;
141 : :
7761 142 : 2240886 : result->id = buf_id;
143 : :
7732 144 : 2240886 : return -1;
145 : : }
146 : :
147 : : /*
148 : : * BufTableDelete
149 : : * Delete the hashtable entry for given tag (which must exist)
150 : : *
151 : : * Caller must hold exclusive lock on BufMappingLock for tag's partition
152 : : */
153 : : void
7226 154 : 1535132 : BufTableDelete(BufferTag *tagPtr, uint32 hashcode)
155 : : {
156 : : BufferLookupEnt *result;
157 : :
158 : : result = (BufferLookupEnt *)
159 : 1535132 : hash_search_with_hash_value(SharedBufHash,
160 : : tagPtr,
161 : : hashcode,
162 : : HASH_REMOVE,
163 : : NULL);
164 : :
8209 JanWieck@Yahoo.com 165 [ - + ]: 1535132 : if (!result) /* shouldn't happen */
8321 tgl@sss.pgh.pa.us 166 [ # # ]:UBC 0 : elog(ERROR, "shared buffer hash table corrupted");
10892 scrappy@hub.org 167 :CBC 1535132 : }
|