Age Owner 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-2023, 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
4254 tgl 55 GIC 166 : InvalidateTableSpaceCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
4842 rhaas 56 ECB : {
57 : HASH_SEQ_STATUS status;
58 : TableSpaceCacheEntry *spc;
59 :
4842 rhaas 60 GIC 166 : hash_seq_init(&status, TableSpaceCacheHash);
4841 tgl 61 CBC 262 : while ((spc = (TableSpaceCacheEntry *) hash_seq_search(&status)) != NULL)
4842 rhaas 62 ECB : {
4842 rhaas 63 GIC 96 : if (spc->opts)
4842 rhaas 64 CBC 3 : pfree(spc->opts);
4841 tgl 65 96 : if (hash_search(TableSpaceCacheHash,
62 peter 66 GNC 96 : &spc->oid,
4841 tgl 67 ECB : HASH_REMOVE,
68 : NULL) == NULL)
4841 tgl 69 UIC 0 : elog(ERROR, "hash table corrupted");
4842 rhaas 70 EUB : }
4842 rhaas 71 GIC 166 : }
4842 rhaas 72 ECB :
73 : /*
74 : * InitializeTableSpaceCache
75 : * Initialize the tablespace cache.
76 : */
77 : static void
4842 rhaas 78 GIC 3590 : InitializeTableSpaceCache(void)
4842 rhaas 79 ECB : {
80 : HASHCTL ctl;
81 :
82 : /* Initialize the hash table. */
4842 rhaas 83 GIC 3590 : ctl.keysize = sizeof(Oid);
4841 tgl 84 CBC 3590 : ctl.entrysize = sizeof(TableSpaceCacheEntry);
4842 rhaas 85 3590 : TableSpaceCacheHash =
86 3590 : hash_create("TableSpace cache", 16, &ctl,
3034 tgl 87 ECB : HASH_ELEM | HASH_BLOBS);
88 :
89 : /* Make sure we've initialized CacheMemoryContext. */
4842 rhaas 90 GIC 3590 : if (!CacheMemoryContext)
4842 rhaas 91 LBC 0 : CreateCacheMemoryContext();
4842 rhaas 92 EUB :
93 : /* Watch for invalidation events. */
4842 rhaas 94 GIC 3590 : CacheRegisterSyscacheCallback(TABLESPACEOID,
4842 rhaas 95 ECB : InvalidateTableSpaceCacheCallback,
96 : (Datum) 0);
4842 rhaas 97 GIC 3590 : }
4842 rhaas 98 ECB :
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 *
4842 rhaas 107 GIC 925360 : get_tablespace(Oid spcid)
4842 rhaas 108 ECB : {
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 : */
4842 rhaas 117 GIC 925360 : if (spcid == InvalidOid)
4842 rhaas 118 CBC 893268 : spcid = MyDatabaseTableSpace;
4842 rhaas 119 ECB :
120 : /* Find existing cache entry, if any. */
4842 rhaas 121 GIC 925360 : if (!TableSpaceCacheHash)
4842 rhaas 122 CBC 3590 : InitializeTableSpaceCache();
4841 tgl 123 925360 : spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
124 : &spcid,
125 : HASH_FIND,
126 : NULL);
4841 tgl 127 GIC 925360 : if (spc)
4842 rhaas 128 CBC 921021 : return spc;
4842 rhaas 129 ECB :
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 : */
4802 rhaas 136 GIC 4339 : tp = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spcid));
4842 rhaas 137 CBC 4339 : if (!HeapTupleIsValid(tp))
4841 tgl 138 LBC 0 : opts = NULL;
4842 rhaas 139 EUB : else
140 : {
141 : Datum datum;
142 : bool isNull;
143 :
4842 rhaas 144 GIC 4339 : datum = SysCacheGetAttr(TABLESPACEOID,
4842 rhaas 145 ECB : tp,
146 : Anum_pg_tablespace_spcoptions,
147 : &isNull);
4842 rhaas 148 GIC 4339 : if (isNull)
4841 tgl 149 CBC 4336 : opts = NULL;
4842 rhaas 150 ECB : else
151 : {
4790 bruce 152 GIC 3 : bytea *bytea_opts = tablespace_reloptions(datum, false);
4790 bruce 153 ECB :
4840 rhaas 154 GIC 3 : opts = MemoryContextAlloc(CacheMemoryContext, VARSIZE(bytea_opts));
4840 rhaas 155 CBC 3 : memcpy(opts, bytea_opts, VARSIZE(bytea_opts));
4842 rhaas 156 ECB : }
4842 rhaas 157 GIC 4339 : ReleaseSysCache(tp);
4842 rhaas 158 ECB : }
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 : */
4841 tgl 165 GIC 4339 : spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
166 : &spcid,
167 : HASH_ENTER,
168 : NULL);
169 4339 : spc->opts = opts;
4842 rhaas 170 CBC 4339 : return spc;
4842 rhaas 171 ECB : }
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
4841 tgl 182 GIC 888690 : get_tablespace_page_costs(Oid spcid,
4841 tgl 183 ECB : double *spc_random_page_cost,
184 : double *spc_seq_page_cost)
185 : {
4841 tgl 186 GIC 888690 : TableSpaceCacheEntry *spc = get_tablespace(spcid);
4842 rhaas 187 ECB :
4842 rhaas 188 GIC 888690 : Assert(spc != NULL);
4842 rhaas 189 ECB :
4842 rhaas 190 GIC 888690 : if (spc_random_page_cost)
4842 rhaas 191 ECB : {
4842 rhaas 192 GIC 718659 : if (!spc->opts || spc->opts->random_page_cost < 0)
4842 rhaas 193 CBC 718659 : *spc_random_page_cost = random_page_cost;
4842 rhaas 194 ECB : else
4842 rhaas 195 UIC 0 : *spc_random_page_cost = spc->opts->random_page_cost;
4842 rhaas 196 EUB : }
197 :
4842 rhaas 198 GIC 888690 : if (spc_seq_page_cost)
4842 rhaas 199 ECB : {
4842 rhaas 200 GIC 625731 : if (!spc->opts || spc->opts->seq_page_cost < 0)
4842 rhaas 201 CBC 625602 : *spc_seq_page_cost = seq_page_cost;
4842 rhaas 202 ECB : else
4842 rhaas 203 GIC 129 : *spc_seq_page_cost = spc->opts->seq_page_cost;
4842 rhaas 204 ECB : }
4842 rhaas 205 GIC 888690 : }
2770 alvherre 206 ECB :
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
2770 alvherre 215 GIC 10598 : get_tablespace_io_concurrency(Oid spcid)
2770 alvherre 216 ECB : {
2770 alvherre 217 GIC 10598 : TableSpaceCacheEntry *spc = get_tablespace(spcid);
2770 alvherre 218 ECB :
2770 alvherre 219 GIC 10598 : if (!spc->opts || spc->opts->effective_io_concurrency < 0)
2770 alvherre 220 CBC 10598 : return effective_io_concurrency;
2770 alvherre 221 ECB : else
2770 alvherre 222 UIC 0 : return spc->opts->effective_io_concurrency;
2770 alvherre 223 EUB : }
224 :
225 : /*
226 : * get_tablespace_maintenance_io_concurrency
227 : */
228 : int
1119 tmunro 229 GIC 26072 : get_tablespace_maintenance_io_concurrency(Oid spcid)
1119 tmunro 230 ECB : {
1119 tmunro 231 GIC 26072 : TableSpaceCacheEntry *spc = get_tablespace(spcid);
1119 tmunro 232 ECB :
1119 tmunro 233 GIC 26072 : if (!spc->opts || spc->opts->maintenance_io_concurrency < 0)
1119 tmunro 234 CBC 26072 : return maintenance_io_concurrency;
1119 tmunro 235 ECB : else
1119 tmunro 236 UIC 0 : return spc->opts->maintenance_io_concurrency;
1119 tmunro 237 EUB : }
|