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-2024, 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
4625 tgl@sss.pgh.pa.us 55 :CBC 399 : InvalidateTableSpaceCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
56 : : {
57 : : HASH_SEQ_STATUS status;
58 : : TableSpaceCacheEntry *spc;
59 : :
5213 rhaas@postgresql.org 60 : 399 : hash_seq_init(&status, TableSpaceCacheHash);
5212 tgl@sss.pgh.pa.us 61 [ + + ]: 578 : while ((spc = (TableSpaceCacheEntry *) hash_seq_search(&status)) != NULL)
62 : : {
5213 rhaas@postgresql.org 63 [ + + ]: 179 : if (spc->opts)
64 : 3 : pfree(spc->opts);
5212 tgl@sss.pgh.pa.us 65 [ - + ]: 179 : if (hash_search(TableSpaceCacheHash,
433 peter@eisentraut.org 66 : 179 : &spc->oid,
67 : : HASH_REMOVE,
68 : : NULL) == NULL)
5212 tgl@sss.pgh.pa.us 69 [ # # ]:UBC 0 : elog(ERROR, "hash table corrupted");
70 : : }
5213 rhaas@postgresql.org 71 :CBC 399 : }
72 : :
73 : : /*
74 : : * InitializeTableSpaceCache
75 : : * Initialize the tablespace cache.
76 : : */
77 : : static void
78 : 5415 : InitializeTableSpaceCache(void)
79 : : {
80 : : HASHCTL ctl;
81 : :
82 : : /* Initialize the hash table. */
83 : 5415 : ctl.keysize = sizeof(Oid);
5212 tgl@sss.pgh.pa.us 84 : 5415 : ctl.entrysize = sizeof(TableSpaceCacheEntry);
5213 rhaas@postgresql.org 85 : 5415 : TableSpaceCacheHash =
86 : 5415 : hash_create("TableSpace cache", 16, &ctl,
87 : : HASH_ELEM | HASH_BLOBS);
88 : :
89 : : /* Make sure we've initialized CacheMemoryContext. */
90 [ - + ]: 5415 : if (!CacheMemoryContext)
5213 rhaas@postgresql.org 91 :UBC 0 : CreateCacheMemoryContext();
92 : :
93 : : /* Watch for invalidation events. */
5213 rhaas@postgresql.org 94 :CBC 5415 : CacheRegisterSyscacheCallback(TABLESPACEOID,
95 : : InvalidateTableSpaceCacheCallback,
96 : : (Datum) 0);
97 : 5415 : }
98 : :
99 : : /*
100 : : * get_tablespace
101 : : * Fetch TableSpaceCacheEntry structure for a specified table OID.
102 : : *
103 : : * Pointers returned by this function should not be stored, since a cache
104 : : * flush will invalidate them.
105 : : */
106 : : static TableSpaceCacheEntry *
107 : 1127612 : get_tablespace(Oid spcid)
108 : : {
109 : : TableSpaceCacheEntry *spc;
110 : : HeapTuple tp;
111 : : TableSpaceOpts *opts;
112 : :
113 : : /*
114 : : * Since spcid is always from a pg_class tuple, InvalidOid implies the
115 : : * default.
116 : : */
117 [ + + ]: 1127612 : if (spcid == InvalidOid)
118 : 1026689 : spcid = MyDatabaseTableSpace;
119 : :
120 : : /* Find existing cache entry, if any. */
121 [ + + ]: 1127612 : if (!TableSpaceCacheHash)
122 : 5415 : InitializeTableSpaceCache();
5212 tgl@sss.pgh.pa.us 123 : 1127612 : spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
124 : : &spcid,
125 : : HASH_FIND,
126 : : NULL);
127 [ + + ]: 1127612 : if (spc)
5213 rhaas@postgresql.org 128 : 1121563 : return spc;
129 : :
130 : : /*
131 : : * Not found in TableSpace cache. Check catcache. If we don't find a
132 : : * valid HeapTuple, it must mean someone has managed to request tablespace
133 : : * details for a non-existent tablespace. We'll just treat that case as
134 : : * if no options were specified.
135 : : */
5173 136 : 6049 : tp = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spcid));
5213 137 [ - + ]: 6049 : if (!HeapTupleIsValid(tp))
5212 tgl@sss.pgh.pa.us 138 :UBC 0 : opts = NULL;
139 : : else
140 : : {
141 : : Datum datum;
142 : : bool isNull;
143 : :
5213 rhaas@postgresql.org 144 :CBC 6049 : datum = SysCacheGetAttr(TABLESPACEOID,
145 : : tp,
146 : : Anum_pg_tablespace_spcoptions,
147 : : &isNull);
148 [ + + ]: 6049 : if (isNull)
5212 tgl@sss.pgh.pa.us 149 : 6046 : opts = NULL;
150 : : else
151 : : {
5161 bruce@momjian.us 152 : 3 : bytea *bytea_opts = tablespace_reloptions(datum, false);
153 : :
5211 rhaas@postgresql.org 154 : 3 : opts = MemoryContextAlloc(CacheMemoryContext, VARSIZE(bytea_opts));
155 : 3 : memcpy(opts, bytea_opts, VARSIZE(bytea_opts));
156 : : }
5213 157 : 6049 : ReleaseSysCache(tp);
158 : : }
159 : :
160 : : /*
161 : : * Now create the cache entry. It's important to do this only after
162 : : * reading the pg_tablespace entry, since doing so could cause a cache
163 : : * flush.
164 : : */
5212 tgl@sss.pgh.pa.us 165 : 6049 : spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
166 : : &spcid,
167 : : HASH_ENTER,
168 : : NULL);
169 : 6049 : spc->opts = opts;
5213 rhaas@postgresql.org 170 : 6049 : return spc;
171 : : }
172 : :
173 : : /*
174 : : * get_tablespace_page_costs
175 : : * Return random and/or sequential page costs for a given tablespace.
176 : : *
177 : : * This value is not locked by the transaction, so this value may
178 : : * be changed while a SELECT that has used these values for planning
179 : : * is still executing.
180 : : */
181 : : void
5212 tgl@sss.pgh.pa.us 182 : 1046794 : get_tablespace_page_costs(Oid spcid,
183 : : double *spc_random_page_cost,
184 : : double *spc_seq_page_cost)
185 : : {
186 : 1046794 : TableSpaceCacheEntry *spc = get_tablespace(spcid);
187 : :
5213 rhaas@postgresql.org 188 [ - + ]: 1046794 : Assert(spc != NULL);
189 : :
190 [ + + ]: 1046794 : if (spc_random_page_cost)
191 : : {
192 [ + + + - ]: 860296 : if (!spc->opts || spc->opts->random_page_cost < 0)
193 : 860296 : *spc_random_page_cost = random_page_cost;
194 : : else
5213 rhaas@postgresql.org 195 :UBC 0 : *spc_random_page_cost = spc->opts->random_page_cost;
196 : : }
197 : :
5213 rhaas@postgresql.org 198 [ + + ]:CBC 1046794 : if (spc_seq_page_cost)
199 : : {
200 [ + + - + ]: 729161 : if (!spc->opts || spc->opts->seq_page_cost < 0)
201 : 729032 : *spc_seq_page_cost = seq_page_cost;
202 : : else
203 : 129 : *spc_seq_page_cost = spc->opts->seq_page_cost;
204 : : }
205 : 1046794 : }
206 : :
207 : : /*
208 : : * get_tablespace_io_concurrency
209 : : *
210 : : * This value is not locked by the transaction, so this value may
211 : : * be changed while a SELECT that has used these values for planning
212 : : * is still executing.
213 : : */
214 : : int
3141 alvherre@alvh.no-ip. 215 : 76289 : get_tablespace_io_concurrency(Oid spcid)
216 : : {
217 : 76289 : TableSpaceCacheEntry *spc = get_tablespace(spcid);
218 : :
219 [ + + + - ]: 76289 : if (!spc->opts || spc->opts->effective_io_concurrency < 0)
220 : 76289 : return effective_io_concurrency;
221 : : else
3141 alvherre@alvh.no-ip. 222 :UBC 0 : return spc->opts->effective_io_concurrency;
223 : : }
224 : :
225 : : /*
226 : : * get_tablespace_maintenance_io_concurrency
227 : : */
228 : : int
1490 tmunro@postgresql.or 229 :CBC 4529 : get_tablespace_maintenance_io_concurrency(Oid spcid)
230 : : {
231 : 4529 : TableSpaceCacheEntry *spc = get_tablespace(spcid);
232 : :
233 [ - + - - ]: 4529 : if (!spc->opts || spc->opts->maintenance_io_concurrency < 0)
234 : 4529 : return maintenance_io_concurrency;
235 : : else
1490 tmunro@postgresql.or 236 :UBC 0 : return spc->opts->maintenance_io_concurrency;
237 : : }
|