]> granicus.if.org Git - postgresql/blob - src/backend/storage/buffer/buf_table.c
Improve hash_create's API for selecting simple-binary-key hash functions.
[postgresql] / src / backend / storage / buffer / buf_table.c
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-2014, 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 BufTableShmemSize(int size)
44 {
45         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 InitBufTable(int size)
54 {
55         HASHCTL         info;
56
57         /* assume no locking is needed yet */
58
59         /* BufferTag maps to Buffer */
60         info.keysize = sizeof(BufferTag);
61         info.entrysize = sizeof(BufferLookupEnt);
62         info.num_partitions = NUM_BUFFER_PARTITIONS;
63
64         SharedBufHash = ShmemInitHash("Shared Buffer Lookup Table",
65                                                                   size, size,
66                                                                   &info,
67                                                                   HASH_ELEM | HASH_BLOBS | HASH_PARTITION);
68 }
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 BufTableHashCode(BufferTag *tagPtr)
81 {
82         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 BufTableLookup(BufferTag *tagPtr, uint32 hashcode)
93 {
94         BufferLookupEnt *result;
95
96         result = (BufferLookupEnt *)
97                 hash_search_with_hash_value(SharedBufHash,
98                                                                         (void *) tagPtr,
99                                                                         hashcode,
100                                                                         HASH_FIND,
101                                                                         NULL);
102
103         if (!result)
104                 return -1;
105
106         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 BufTableInsert(BufferTag *tagPtr, uint32 hashcode, int buf_id)
121 {
122         BufferLookupEnt *result;
123         bool            found;
124
125         Assert(buf_id >= 0);            /* -1 is reserved for not-in-table */
126         Assert(tagPtr->blockNum != P_NEW);      /* invalid tag */
127
128         result = (BufferLookupEnt *)
129                 hash_search_with_hash_value(SharedBufHash,
130                                                                         (void *) tagPtr,
131                                                                         hashcode,
132                                                                         HASH_ENTER,
133                                                                         &found);
134
135         if (found)                                      /* found something already in the table */
136                 return result->id;
137
138         result->id = buf_id;
139
140         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 BufTableDelete(BufferTag *tagPtr, uint32 hashcode)
151 {
152         BufferLookupEnt *result;
153
154         result = (BufferLookupEnt *)
155                 hash_search_with_hash_value(SharedBufHash,
156                                                                         (void *) tagPtr,
157                                                                         hashcode,
158                                                                         HASH_REMOVE,
159                                                                         NULL);
160
161         if (!result)                            /* shouldn't happen */
162                 elog(ERROR, "shared buffer hash table corrupted");
163 }