PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
relfilenodemap.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * relfilenodemap.c
4  * relfilenode to oid mapping cache.
5  *
6  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * IDENTIFICATION
10  * src/backend/utils/cache/relfilenode.c
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include "postgres.h"
15 
16 #include "access/genam.h"
17 #include "access/heapam.h"
18 #include "access/htup_details.h"
19 #include "catalog/indexing.h"
20 #include "catalog/pg_class.h"
21 #include "catalog/pg_tablespace.h"
22 #include "miscadmin.h"
23 #include "utils/builtins.h"
24 #include "utils/catcache.h"
25 #include "utils/hsearch.h"
26 #include "utils/inval.h"
27 #include "utils/fmgroids.h"
28 #include "utils/rel.h"
29 #include "utils/relfilenodemap.h"
30 #include "utils/relmapper.h"
31 
32 /* Hash table for informations about each relfilenode <-> oid pair */
34 
35 /* built first time through in InitializeRelfilenodeMap */
37 
38 typedef struct
39 {
43 
44 typedef struct
45 {
46  RelfilenodeMapKey key; /* lookup key - must be first */
47  Oid relid; /* pg_class.oid */
49 
50 /*
51  * RelfilenodeMapInvalidateCallback
52  * Flush mapping entries when pg_class is updated in a relevant fashion.
53  */
54 static void
56 {
58  RelfilenodeMapEntry *entry;
59 
60  /* callback only gets registered after creating the hash */
61  Assert(RelfilenodeMapHash != NULL);
62 
63  hash_seq_init(&status, RelfilenodeMapHash);
64  while ((entry = (RelfilenodeMapEntry *) hash_seq_search(&status)) != NULL)
65  {
66  /*
67  * If relid is InvalidOid, signalling a complete reset, we must remove
68  * all entries, otherwise just remove the specific relation's entry.
69  * Always remove negative cache entries.
70  */
71  if (relid == InvalidOid || /* complete reset */
72  entry->relid == InvalidOid || /* negative cache entry */
73  entry->relid == relid) /* individual flushed relation */
74  {
75  if (hash_search(RelfilenodeMapHash,
76  (void *) &entry->key,
78  NULL) == NULL)
79  elog(ERROR, "hash table corrupted");
80  }
81  }
82 }
83 
84 /*
85  * RelfilenodeMapInvalidateCallback
86  * Initialize cache, either on first use or after a reset.
87  */
88 static void
90 {
91  HASHCTL ctl;
92  int i;
93 
94  /* Make sure we've initialized CacheMemoryContext. */
95  if (CacheMemoryContext == NULL)
97 
98  /* build skey */
99  MemSet(&relfilenode_skey, 0, sizeof(relfilenode_skey));
100 
101  for (i = 0; i < 2; i++)
102  {
103  fmgr_info_cxt(F_OIDEQ,
104  &relfilenode_skey[i].sk_func,
106  relfilenode_skey[i].sk_strategy = BTEqualStrategyNumber;
107  relfilenode_skey[i].sk_subtype = InvalidOid;
108  relfilenode_skey[i].sk_collation = InvalidOid;
109  }
110 
111  relfilenode_skey[0].sk_attno = Anum_pg_class_reltablespace;
112  relfilenode_skey[1].sk_attno = Anum_pg_class_relfilenode;
113 
114  /* Initialize the hash table. */
115  MemSet(&ctl, 0, sizeof(ctl));
116  ctl.keysize = sizeof(RelfilenodeMapKey);
117  ctl.entrysize = sizeof(RelfilenodeMapEntry);
118  ctl.hcxt = CacheMemoryContext;
119 
120  /*
121  * Only create the RelfilenodeMapHash now, so we don't end up partially
122  * initialized when fmgr_info_cxt() above ERRORs out with an out of memory
123  * error.
124  */
125  RelfilenodeMapHash =
126  hash_create("RelfilenodeMap cache", 64, &ctl,
128 
129  /* Watch for invalidation events. */
131  (Datum) 0);
132 }
133 
134 /*
135  * Map a relation's (tablespace, filenode) to a relation's oid and cache the
136  * result.
137  *
138  * Returns InvalidOid if no relation matching the criteria could be found.
139  */
140 Oid
141 RelidByRelfilenode(Oid reltablespace, Oid relfilenode)
142 {
143  RelfilenodeMapKey key;
144  RelfilenodeMapEntry *entry;
145  bool found;
146  SysScanDesc scandesc;
147  Relation relation;
148  HeapTuple ntp;
149  ScanKeyData skey[2];
150  Oid relid;
151 
152  if (RelfilenodeMapHash == NULL)
154 
155  /* pg_class will show 0 when the value is actually MyDatabaseTableSpace */
156  if (reltablespace == MyDatabaseTableSpace)
157  reltablespace = 0;
158 
159  MemSet(&key, 0, sizeof(key));
160  key.reltablespace = reltablespace;
161  key.relfilenode = relfilenode;
162 
163  /*
164  * Check cache and return entry if one is found. Even if no target
165  * relation can be found later on we store the negative match and return a
166  * InvalidOid from cache. That's not really necessary for performance
167  * since querying invalid values isn't supposed to be a frequent thing,
168  * but it's basically free.
169  */
170  entry = hash_search(RelfilenodeMapHash, (void *) &key, HASH_FIND, &found);
171 
172  if (found)
173  return entry->relid;
174 
175  /* ok, no previous cache entry, do it the hard way */
176 
177  /* initialize empty/negative cache entry before doing the actual lookups */
178  relid = InvalidOid;
179 
180  if (reltablespace == GLOBALTABLESPACE_OID)
181  {
182  /*
183  * Ok, shared table, check relmapper.
184  */
185  relid = RelationMapFilenodeToOid(relfilenode, true);
186  }
187  else
188  {
189  /*
190  * Not a shared table, could either be a plain relation or a
191  * non-shared, nailed one, like e.g. pg_class.
192  */
193 
194  /* check for plain relations by looking in pg_class */
196 
197  /* copy scankey to local copy, it will be modified during the scan */
198  memcpy(skey, relfilenode_skey, sizeof(skey));
199 
200  /* set scan arguments */
201  skey[0].sk_argument = ObjectIdGetDatum(reltablespace);
202  skey[1].sk_argument = ObjectIdGetDatum(relfilenode);
203 
204  scandesc = systable_beginscan(relation,
206  true,
207  NULL,
208  2,
209  skey);
210 
211  found = false;
212 
213  while (HeapTupleIsValid(ntp = systable_getnext(scandesc)))
214  {
215  if (found)
216  elog(ERROR,
217  "unexpected duplicate for tablespace %u, relfilenode %u",
218  reltablespace, relfilenode);
219  found = true;
220 
221 #ifdef USE_ASSERT_CHECKING
222  {
223  bool isnull;
224  Oid check;
225 
227  RelationGetDescr(relation),
228  &isnull);
229  Assert(!isnull && check == reltablespace);
230 
232  RelationGetDescr(relation),
233  &isnull);
234  Assert(!isnull && check == relfilenode);
235  }
236 #endif
237  relid = HeapTupleGetOid(ntp);
238  }
239 
240  systable_endscan(scandesc);
241  heap_close(relation, AccessShareLock);
242 
243  /* check for tables that are mapped but not shared */
244  if (!found)
245  relid = RelationMapFilenodeToOid(relfilenode, false);
246  }
247 
248  /*
249  * Only enter entry into cache now, our opening of pg_class could have
250  * caused cache invalidations to be executed which would have deleted a
251  * new entry if we had entered it above.
252  */
253  entry = hash_search(RelfilenodeMapHash, (void *) &key, HASH_ENTER, &found);
254  if (found)
255  elog(ERROR, "corrupted hashtable");
256  entry->relid = relid;
257 
258  return relid;
259 }
Oid sk_subtype
Definition: skey.h:69
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define fastgetattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:719
#define HASH_CONTEXT
Definition: hsearch.h:93
#define HASH_ELEM
Definition: hsearch.h:87
MemoryContext hcxt
Definition: hsearch.h:78
#define RelationGetDescr(relation)
Definition: rel.h:429
RelfilenodeMapKey key
#define RelationRelationId
Definition: pg_class.h:29
#define Anum_pg_class_reltablespace
Definition: pg_class.h:110
Oid RelidByRelfilenode(Oid reltablespace, Oid relfilenode)
#define AccessShareLock
Definition: lockdefs.h:36
#define GLOBALTABLESPACE_OID
Definition: pg_tablespace.h:64
Size entrysize
Definition: hsearch.h:73
#define MemSet(start, val, len)
Definition: c.h:857
#define heap_close(r, l)
Definition: heapam.h:97
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:885
unsigned int Oid
Definition: postgres_ext.h:31
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
#define Anum_pg_class_relfilenode
Definition: pg_class.h:109
Oid MyDatabaseTableSpace
Definition: globals.c:78
void CacheRegisterRelcacheCallback(RelcacheCallbackFunction func, Datum arg)
Definition: inval.c:1431
Definition: dynahash.c:193
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
static HTAB * RelfilenodeMapHash
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
StrategyNumber sk_strategy
Definition: skey.h:68
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:137
static void RelfilenodeMapInvalidateCallback(Datum arg, Oid relid)
static ScanKeyData relfilenode_skey[2]
#define HASH_BLOBS
Definition: hsearch.h:88
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:301
uintptr_t Datum
Definition: postgres.h:372
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
Size keysize
Definition: hsearch.h:72
#define InvalidOid
Definition: postgres_ext.h:36
Oid RelationMapFilenodeToOid(Oid filenode, bool shared)
Definition: relmapper.c:199
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
void CreateCacheMemoryContext(void)
Definition: catcache.c:511
static void InitializeRelfilenodeMap(void)
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1351
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1341
Oid sk_collation
Definition: skey.h:70
int i
void * arg
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:224
Datum sk_argument
Definition: skey.h:72
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define ClassTblspcRelfilenodeIndexId
Definition: indexing.h:116
AttrNumber sk_attno
Definition: skey.h:67
MemoryContext CacheMemoryContext
Definition: mcxt.c:46