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