Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * spccache.c
4 : : * Tablespace cache management.
5 : : *
6 : : * We cache the parsed version of spcoptions for each tablespace to avoid
7 : : * needing to reparse on every lookup. Right now, there doesn't appear to
8 : : * be a measurable performance gain from doing this, but that might change
9 : : * in the future as we add more options.
10 : : *
11 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
12 : : * Portions Copyright (c) 1994, Regents of the University of California
13 : : *
14 : : * IDENTIFICATION
15 : : * src/backend/utils/cache/spccache.c
16 : : *
17 : : *-------------------------------------------------------------------------
18 : : */
19 : : #include "postgres.h"
20 : :
21 : : #include "access/reloptions.h"
22 : : #include "catalog/pg_tablespace.h"
23 : : #include "commands/tablespace.h"
24 : : #include "miscadmin.h"
25 : : #include "optimizer/optimizer.h"
26 : : #include "storage/bufmgr.h"
27 : : #include "utils/catcache.h"
28 : : #include "utils/hsearch.h"
29 : : #include "utils/inval.h"
30 : : #include "utils/spccache.h"
31 : : #include "utils/syscache.h"
32 : : #include "varatt.h"
33 : :
34 : :
35 : : /* Hash table for information about each tablespace */
36 : : static HTAB *TableSpaceCacheHash = NULL;
37 : :
38 : : typedef struct
39 : : {
40 : : Oid oid; /* lookup key - must be first */
41 : : TableSpaceOpts *opts; /* options, or NULL if none */
42 : : } TableSpaceCacheEntry;
43 : :
44 : :
45 : : /*
46 : : * InvalidateTableSpaceCacheCallback
47 : : * Flush all cache entries when pg_tablespace is updated.
48 : : *
49 : : * When pg_tablespace is updated, we must flush the cache entry at least
50 : : * for that tablespace. Currently, we just flush them all. This is quick
51 : : * and easy and doesn't cost much, since there shouldn't be terribly many
52 : : * tablespaces, nor do we expect them to be frequently modified.
53 : : */
54 : : static void
25 michael@paquier.xyz 55 :GNC 428 : InvalidateTableSpaceCacheCallback(Datum arg, SysCacheIdentifier cacheid,
56 : : uint32 hashvalue)
57 : : {
58 : : HASH_SEQ_STATUS status;
59 : : TableSpaceCacheEntry *spc;
60 : :
5913 rhaas@postgresql.org 61 :CBC 428 : hash_seq_init(&status, TableSpaceCacheHash);
5912 tgl@sss.pgh.pa.us 62 [ + + ]: 619 : while ((spc = (TableSpaceCacheEntry *) hash_seq_search(&status)) != NULL)
63 : : {
5913 rhaas@postgresql.org 64 [ - + ]: 191 : if (spc->opts)
5913 rhaas@postgresql.org 65 :UBC 0 : pfree(spc->opts);
5912 tgl@sss.pgh.pa.us 66 [ - + ]:CBC 191 : if (hash_search(TableSpaceCacheHash,
1133 peter@eisentraut.org 67 : 191 : &spc->oid,
68 : : HASH_REMOVE,
69 : : NULL) == NULL)
5912 tgl@sss.pgh.pa.us 70 [ # # ]:UBC 0 : elog(ERROR, "hash table corrupted");
71 : : }
5913 rhaas@postgresql.org 72 :CBC 428 : }
73 : :
74 : : /*
75 : : * InitializeTableSpaceCache
76 : : * Initialize the tablespace cache.
77 : : */
78 : : static void
79 : 7170 : InitializeTableSpaceCache(void)
80 : : {
81 : : HASHCTL ctl;
82 : :
83 : : /* Initialize the hash table. */
84 : 7170 : ctl.keysize = sizeof(Oid);
5912 tgl@sss.pgh.pa.us 85 : 7170 : ctl.entrysize = sizeof(TableSpaceCacheEntry);
5913 rhaas@postgresql.org 86 : 7170 : TableSpaceCacheHash =
87 : 7170 : hash_create("TableSpace cache", 16, &ctl,
88 : : HASH_ELEM | HASH_BLOBS);
89 : :
90 : : /* Make sure we've initialized CacheMemoryContext. */
91 [ - + ]: 7170 : if (!CacheMemoryContext)
5913 rhaas@postgresql.org 92 :UBC 0 : CreateCacheMemoryContext();
93 : :
94 : : /* Watch for invalidation events. */
5913 rhaas@postgresql.org 95 :CBC 7170 : CacheRegisterSyscacheCallback(TABLESPACEOID,
96 : : InvalidateTableSpaceCacheCallback,
97 : : (Datum) 0);
98 : 7170 : }
99 : :
100 : : /*
101 : : * get_tablespace
102 : : * Fetch TableSpaceCacheEntry structure for a specified table OID.
103 : : *
104 : : * Pointers returned by this function should not be stored, since a cache
105 : : * flush will invalidate them.
106 : : */
107 : : static TableSpaceCacheEntry *
108 : 1937687 : get_tablespace(Oid spcid)
109 : : {
110 : : TableSpaceCacheEntry *spc;
111 : : HeapTuple tp;
112 : : TableSpaceOpts *opts;
113 : :
114 : : /*
115 : : * Since spcid is always from a pg_class tuple, InvalidOid implies the
116 : : * default.
117 : : */
118 [ + + ]: 1937687 : if (spcid == InvalidOid)
119 : 1478238 : spcid = MyDatabaseTableSpace;
120 : :
121 : : /* Find existing cache entry, if any. */
122 [ + + ]: 1937687 : if (!TableSpaceCacheHash)
123 : 7170 : InitializeTableSpaceCache();
5912 tgl@sss.pgh.pa.us 124 : 1937687 : spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
125 : : &spcid,
126 : : HASH_FIND,
127 : : NULL);
128 [ + + ]: 1937687 : if (spc)
5913 rhaas@postgresql.org 129 : 1929596 : return spc;
130 : :
131 : : /*
132 : : * Not found in TableSpace cache. Check catcache. If we don't find a
133 : : * valid HeapTuple, it must mean someone has managed to request tablespace
134 : : * details for a non-existent tablespace. We'll just treat that case as
135 : : * if no options were specified.
136 : : */
5873 137 : 8091 : tp = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spcid));
5913 138 [ - + ]: 8091 : if (!HeapTupleIsValid(tp))
5912 tgl@sss.pgh.pa.us 139 :UBC 0 : opts = NULL;
140 : : else
141 : : {
142 : : Datum datum;
143 : : bool isNull;
144 : :
5913 rhaas@postgresql.org 145 :CBC 8091 : datum = SysCacheGetAttr(TABLESPACEOID,
146 : : tp,
147 : : Anum_pg_tablespace_spcoptions,
148 : : &isNull);
149 [ + + ]: 8091 : if (isNull)
5912 tgl@sss.pgh.pa.us 150 : 8088 : opts = NULL;
151 : : else
152 : : {
5861 bruce@momjian.us 153 : 3 : bytea *bytea_opts = tablespace_reloptions(datum, false);
154 : :
5911 rhaas@postgresql.org 155 : 3 : opts = MemoryContextAlloc(CacheMemoryContext, VARSIZE(bytea_opts));
156 : 3 : memcpy(opts, bytea_opts, VARSIZE(bytea_opts));
157 : : }
5913 158 : 8091 : ReleaseSysCache(tp);
159 : : }
160 : :
161 : : /*
162 : : * Now create the cache entry. It's important to do this only after
163 : : * reading the pg_tablespace entry, since doing so could cause a cache
164 : : * flush.
165 : : */
5912 tgl@sss.pgh.pa.us 166 : 8091 : spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
167 : : &spcid,
168 : : HASH_ENTER,
169 : : NULL);
170 : 8091 : spc->opts = opts;
5913 rhaas@postgresql.org 171 : 8091 : return spc;
172 : : }
173 : :
174 : : /*
175 : : * get_tablespace_page_costs
176 : : * Return random and/or sequential page costs for a given tablespace.
177 : : *
178 : : * This value is not locked by the transaction, so this value may
179 : : * be changed while a SELECT that has used these values for planning
180 : : * is still executing.
181 : : */
182 : : void
5912 tgl@sss.pgh.pa.us 183 : 1542505 : get_tablespace_page_costs(Oid spcid,
184 : : double *spc_random_page_cost,
185 : : double *spc_seq_page_cost)
186 : : {
187 : 1542505 : TableSpaceCacheEntry *spc = get_tablespace(spcid);
188 : :
5913 rhaas@postgresql.org 189 [ - + ]: 1542505 : Assert(spc != NULL);
190 : :
191 [ + + ]: 1542505 : if (spc_random_page_cost)
192 : : {
193 [ + + + - ]: 1298095 : if (!spc->opts || spc->opts->random_page_cost < 0)
194 : 1298095 : *spc_random_page_cost = random_page_cost;
195 : : else
5913 rhaas@postgresql.org 196 :UBC 0 : *spc_random_page_cost = spc->opts->random_page_cost;
197 : : }
198 : :
5913 rhaas@postgresql.org 199 [ + + ]:CBC 1542505 : if (spc_seq_page_cost)
200 : : {
201 [ + + - + ]: 1063419 : if (!spc->opts || spc->opts->seq_page_cost < 0)
202 : 1063290 : *spc_seq_page_cost = seq_page_cost;
203 : : else
204 : 129 : *spc_seq_page_cost = spc->opts->seq_page_cost;
205 : : }
206 : 1542505 : }
207 : :
208 : : /*
209 : : * get_tablespace_io_concurrency
210 : : *
211 : : * This value is not locked by the transaction, so this value may
212 : : * be changed while a SELECT that has used these values for planning
213 : : * is still executing.
214 : : */
215 : : int
3841 alvherre@alvh.no-ip. 216 : 386792 : get_tablespace_io_concurrency(Oid spcid)
217 : : {
218 : 386792 : TableSpaceCacheEntry *spc = get_tablespace(spcid);
219 : :
220 [ + + + - ]: 386792 : if (!spc->opts || spc->opts->effective_io_concurrency < 0)
221 : 386792 : return effective_io_concurrency;
222 : : else
3841 alvherre@alvh.no-ip. 223 :UBC 0 : return spc->opts->effective_io_concurrency;
224 : : }
225 : :
226 : : /*
227 : : * get_tablespace_maintenance_io_concurrency
228 : : */
229 : : int
2190 tmunro@postgresql.or 230 :CBC 8390 : get_tablespace_maintenance_io_concurrency(Oid spcid)
231 : : {
232 : 8390 : TableSpaceCacheEntry *spc = get_tablespace(spcid);
233 : :
234 [ + + + - ]: 8390 : if (!spc->opts || spc->opts->maintenance_io_concurrency < 0)
235 : 8390 : return maintenance_io_concurrency;
236 : : else
2190 tmunro@postgresql.or 237 :UBC 0 : return spc->opts->maintenance_io_concurrency;
238 : : }
|