PostgreSQL Source Code: src/backend/utils/cache/relfilenumbermap.c Source File

PostgreSQL Source Code git master
relfilenumbermap.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * relfilenumbermap.c
4 * relfilenumber to oid mapping cache.
5 *
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 * IDENTIFICATION
10 * src/backend/utils/cache/relfilenumbermap.c
11 *
12 *-------------------------------------------------------------------------
13 */
14#include "postgres.h"
15
16#include "access/genam.h"
17#include "access/htup_details.h"
18#include "access/table.h"
19#include "catalog/pg_class.h"
20#include "catalog/pg_tablespace.h"
21#include "miscadmin.h"
22#include "utils/catcache.h"
23#include "utils/fmgroids.h"
24#include "utils/hsearch.h"
25#include "utils/inval.h"
26#include "utils/relfilenumbermap.h"
27#include "utils/relmapper.h"
28
29/* Hash table for information about each relfilenumber <-> oid pair */
30 static HTAB *RelfilenumberMapHash = NULL;
31
32/* built first time through in InitializeRelfilenumberMap */
33 static ScanKeyData relfilenumber_skey[2];
34
35 typedef struct
36{
37 Oid reltablespace;
38 RelFileNumber relfilenumber;
39} RelfilenumberMapKey;
40
41 typedef struct
42{
43 RelfilenumberMapKey key; /* lookup key - must be first */
44 Oid relid; /* pg_class.oid */
45} RelfilenumberMapEntry;
46
47/*
48 * RelfilenumberMapInvalidateCallback
49 * Flush mapping entries when pg_class is updated in a relevant fashion.
50 */
51static void
52 RelfilenumberMapInvalidateCallback(Datum arg, Oid relid)
53{
54 HASH_SEQ_STATUS status;
55 RelfilenumberMapEntry *entry;
56
57 /* callback only gets registered after creating the hash */
58 Assert(RelfilenumberMapHash != NULL);
59
60 hash_seq_init(&status, RelfilenumberMapHash);
61 while ((entry = (RelfilenumberMapEntry *) hash_seq_search(&status)) != NULL)
62 {
63 /*
64 * If relid is InvalidOid, signaling a complete reset, we must remove
65 * all entries, otherwise just remove the specific relation's entry.
66 * Always remove negative cache entries.
67 */
68 if (relid == InvalidOid || /* complete reset */
69 entry->relid == InvalidOid || /* negative cache entry */
70 entry->relid == relid) /* individual flushed relation */
71 {
72 if (hash_search(RelfilenumberMapHash,
73 &entry->key,
74 HASH_REMOVE,
75 NULL) == NULL)
76 elog(ERROR, "hash table corrupted");
77 }
78 }
79}
80
81/*
82 * InitializeRelfilenumberMap
83 * Initialize cache, either on first use or after a reset.
84 */
85static void
86 InitializeRelfilenumberMap(void)
87{
88 HASHCTL ctl;
89 int i;
90
91 /* Make sure we've initialized CacheMemoryContext. */
92 if (CacheMemoryContext == NULL)
93 CreateCacheMemoryContext();
94
95 /* build skey */
96 MemSet(&relfilenumber_skey, 0, sizeof(relfilenumber_skey));
97
98 for (i = 0; i < 2; i++)
99 {
100 fmgr_info_cxt(F_OIDEQ,
101 &relfilenumber_skey[i].sk_func,
102 CacheMemoryContext);
103 relfilenumber_skey[i].sk_strategy = BTEqualStrategyNumber;
104 relfilenumber_skey[i].sk_subtype = InvalidOid;
105 relfilenumber_skey[i].sk_collation = InvalidOid;
106 }
107
108 relfilenumber_skey[0].sk_attno = Anum_pg_class_reltablespace;
109 relfilenumber_skey[1].sk_attno = Anum_pg_class_relfilenode;
110
111 /*
112 * Only create the RelfilenumberMapHash now, so we don't end up partially
113 * initialized when fmgr_info_cxt() above ERRORs out with an out of memory
114 * error.
115 */
116 ctl.keysize = sizeof(RelfilenumberMapKey);
117 ctl.entrysize = sizeof(RelfilenumberMapEntry);
118 ctl.hcxt = CacheMemoryContext;
119
120 RelfilenumberMapHash =
121 hash_create("RelfilenumberMap cache", 64, &ctl,
122 HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
123
124 /* Watch for invalidation events. */
125 CacheRegisterRelcacheCallback(RelfilenumberMapInvalidateCallback,
126 (Datum) 0);
127}
128
129/*
130 * Map a relation's (tablespace, relfilenumber) to a relation's oid and cache
131 * the result.
132 *
133 * A temporary relation may share its relfilenumber with a permanent relation
134 * or temporary relations created in other backends. Being able to uniquely
135 * identify a temporary relation would require a backend's proc number, which
136 * we do not know about. Hence, this function ignores this case.
137 *
138 * Returns InvalidOid if no relation matching the criteria could be found.
139 */
140Oid
141 RelidByRelfilenumber(Oid reltablespace, RelFileNumber relfilenumber)
142{
143 RelfilenumberMapKey key;
144 RelfilenumberMapEntry *entry;
145 bool found;
146 SysScanDesc scandesc;
147 Relation relation;
148 HeapTuple ntp;
149 Oid relid;
150
151 if (RelfilenumberMapHash == NULL)
152 InitializeRelfilenumberMap();
153
154 /* pg_class will show 0 when the value is actually MyDatabaseTableSpace */
155 if (reltablespace == MyDatabaseTableSpace)
156 reltablespace = 0;
157
158 MemSet(&key, 0, sizeof(key));
159 key.reltablespace = reltablespace;
160 key.relfilenumber = relfilenumber;
161
162 /*
163 * Check cache and return entry if one is found. Even if no target
164 * relation can be found later on we store the negative match and return a
165 * InvalidOid from cache. That's not really necessary for performance
166 * since querying invalid values isn't supposed to be a frequent thing,
167 * but it's basically free.
168 */
169 entry = hash_search(RelfilenumberMapHash, &key, HASH_FIND, &found);
170
171 if (found)
172 return entry->relid;
173
174 /* ok, no previous cache entry, do it the hard way */
175
176 /* initialize empty/negative cache entry before doing the actual lookups */
177 relid = InvalidOid;
178
179 if (reltablespace == GLOBALTABLESPACE_OID)
180 {
181 /*
182 * Ok, shared table, check relmapper.
183 */
184 relid = RelationMapFilenumberToOid(relfilenumber, true);
185 }
186 else
187 {
188 ScanKeyData skey[2];
189
190 /*
191 * Not a shared table, could either be a plain relation or a
192 * non-shared, nailed one, like e.g. pg_class.
193 */
194
195 /* check for plain relations by looking in pg_class */
196 relation = table_open(RelationRelationId, AccessShareLock);
197
198 /* copy scankey to local copy and set scan arguments */
199 memcpy(skey, relfilenumber_skey, sizeof(skey));
200 skey[0].sk_argument = ObjectIdGetDatum(reltablespace);
201 skey[1].sk_argument = ObjectIdGetDatum(relfilenumber);
202
203 scandesc = systable_beginscan(relation,
204 ClassTblspcRelfilenodeIndexId,
205 true,
206 NULL,
207 2,
208 skey);
209
210 found = false;
211
212 while (HeapTupleIsValid(ntp = systable_getnext(scandesc)))
213 {
214 Form_pg_class classform = (Form_pg_class) GETSTRUCT(ntp);
215
216 if (classform->relpersistence == RELPERSISTENCE_TEMP)
217 continue;
218
219 if (found)
220 elog(ERROR,
221 "unexpected duplicate for tablespace %u, relfilenumber %u",
222 reltablespace, relfilenumber);
223 found = true;
224
225 Assert(classform->reltablespace == reltablespace);
226 Assert(classform->relfilenode == relfilenumber);
227 relid = classform->oid;
228 }
229
230 systable_endscan(scandesc);
231 table_close(relation, AccessShareLock);
232
233 /* check for tables that are mapped but not shared */
234 if (!found)
235 relid = RelationMapFilenumberToOid(relfilenumber, false);
236 }
237
238 /*
239 * Only enter entry into cache now, our opening of pg_class could have
240 * caused cache invalidations to be executed which would have deleted a
241 * new entry if we had entered it above.
242 */
243 entry = hash_search(RelfilenumberMapHash, &key, HASH_ENTER, &found);
244 if (found)
245 elog(ERROR, "corrupted hashtable");
246 entry->relid = relid;
247
248 return relid;
249}
#define MemSet(start, val, len)
Definition: c.h:1019
void CreateCacheMemoryContext(void)
Definition: catcache.c:709
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:952
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:358
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1415
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1380
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:138
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:603
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:514
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:388
Oid MyDatabaseTableSpace
Definition: globals.c:96
Assert(PointerIsAligned(start, uint64))
@ HASH_FIND
Definition: hsearch.h:113
@ HASH_REMOVE
Definition: hsearch.h:115
@ HASH_ENTER
Definition: hsearch.h:114
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
void CacheRegisterRelcacheCallback(RelcacheCallbackFunction func, Datum arg)
Definition: inval.c:1854
i
int i
Definition: isn.c:77
#define AccessShareLock
Definition: lockdefs.h:36
MemoryContext CacheMemoryContext
Definition: mcxt.c:169
void * arg
FormData_pg_class * Form_pg_class
Definition: pg_class.h:156
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:262
uint64_t Datum
Definition: postgres.h:70
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
tree ctl
Definition: radixtree.h:1838
static ScanKeyData relfilenumber_skey[2]
static void RelfilenumberMapInvalidateCallback(Datum arg, Oid relid)
static void InitializeRelfilenumberMap(void)
static HTAB * RelfilenumberMapHash
Oid RelidByRelfilenumber(Oid reltablespace, RelFileNumber relfilenumber)
Oid RelationMapFilenumberToOid(RelFileNumber filenumber, bool shared)
Definition: relmapper.c:218
Oid RelFileNumber
Definition: relpath.h:25
#define BTEqualStrategyNumber
Definition: stratnum.h:31
Definition: hsearch.h:66
Definition: dynahash.c:222
Definition: rel.h:56
RelfilenumberMapKey key
RelFileNumber relfilenumber
Definition: skey.h:65
Datum sk_argument
Definition: skey.h:72
Oid sk_subtype
Definition: skey.h:69
Oid sk_collation
Definition: skey.h:70
StrategyNumber sk_strategy
Definition: skey.h:68
AttrNumber sk_attno
Definition: skey.h:67
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

AltStyle によって変換されたページ (->オリジナル) /