PostgreSQL Source Code git master
Loading...
Searching...
No Matches
pg_stash_advice.h File Reference
#include "lib/dshash.h"
#include "storage/lwlock.h"
#include "lib/simplehash.h"
Include dependency graph for pg_stash_advice.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  pgsa_entry_key
 
struct  pgsa_entry
 
struct  pgsa_stash
 
struct  pgsa_shared_state
 
struct  pgsa_stash_name
 

Macros

#define SH_PREFIX   pgsa_stash_name_table
 
#define SH_ELEMENT_TYPE   pgsa_stash_name
 
#define SH_KEY_TYPE   uint64
 
#define SH_SCOPE   extern
 
#define SH_DECLARE
 

Typedefs

typedef struct pgsa_entry_key pgsa_entry_key
 
typedef struct pgsa_entry pgsa_entry
 
typedef struct pgsa_stash pgsa_stash
 
typedef struct pgsa_shared_state pgsa_shared_state
 
typedef struct pgsa_stash_name pgsa_stash_name
 

Functions

void pgsa_attach (void)
 
void pgsa_check_stash_name (char *stash_name)
 
void pgsa_clear_advice_string (char *stash_name, int64 queryId)
 
void pgsa_create_stash (char *stash_name)
 
void pgsa_drop_stash (char *stash_name)
 
uint64 pgsa_lookup_stash_id (char *stash_name)
 
void pgsa_set_advice_string (char *stash_name, int64 queryId, char *advice_string)
 

Variables

pgsa_shared_statepgsa_state
 
dsa_areapgsa_dsa_area
 
dshash_tablepgsa_stash_dshash
 
dshash_tablepgsa_entry_dshash
 

Macro Definition Documentation

◆ SH_DECLARE

#define SH_DECLARE

Definition at line 80 of file pg_stash_advice.h.

◆ SH_ELEMENT_TYPE

#define SH_ELEMENT_TYPE   pgsa_stash_name

Definition at line 77 of file pg_stash_advice.h.

◆ SH_KEY_TYPE

#define SH_KEY_TYPE   uint64

Definition at line 78 of file pg_stash_advice.h.

◆ SH_PREFIX

#define SH_PREFIX   pgsa_stash_name_table

Definition at line 76 of file pg_stash_advice.h.

◆ SH_SCOPE

#define SH_SCOPE   extern

Definition at line 79 of file pg_stash_advice.h.

Typedef Documentation

◆ pgsa_entry

◆ pgsa_entry_key

◆ pgsa_shared_state

◆ pgsa_stash

◆ pgsa_stash_name

Function Documentation

◆ pgsa_attach()

void pgsa_attach ( void  )
extern

Definition at line 182 of file pg_stash_advice.c.

183{
184 bool found;
185 MemoryContext oldcontext;
186
187 /*
188 * Create a memory context to make sure that any control structures
189 * allocated in local memory are sufficiently persistent.
190 */
193 "pg_stash_advice",
196
197 /* Attach to the fixed-size state object if not already done. */
198 if (pgsa_state == NULL)
199 pgsa_state = GetNamedDSMSegment("pg_stash_advice",
200 sizeof(pgsa_shared_state),
202 &found, NULL);
203
204 /* Attach to the DSA area if not already done. */
205 if (pgsa_dsa_area == NULL)
206 {
208
212 {
217 }
218 else
219 {
222 }
224 }
225
226 /* Attach to the stash_name->stash_id hash table if not already done. */
227 if (pgsa_stash_dshash == NULL)
228 {
230
235 {
238 NULL);
242 }
243 else
244 {
249 }
250 }
251
252 /* Attach to the entry hash table if not already done. */
253 if (pgsa_entry_dshash == NULL)
254 {
256
261 {
264 NULL);
268 }
269 else
270 {
275 }
276 }
277
278 /* Restore previous memory context. */
279 MemoryContextSwitchTo(oldcontext);
280}
dsa_area * dsa_attach(dsa_handle handle)
Definition dsa.c:510
void dsa_pin_mapping(dsa_area *area)
Definition dsa.c:650
dsa_handle dsa_get_handle(dsa_area *area)
Definition dsa.c:498
void dsa_pin(dsa_area *area)
Definition dsa.c:990
#define dsa_create(tranche_id)
Definition dsa.h:117
dsm_handle dsa_handle
Definition dsa.h:136
#define DSA_HANDLE_INVALID
Definition dsa.h:139
dshash_table_handle dshash_get_hash_table_handle(dshash_table *hash_table)
Definition dshash.c:371
dshash_table * dshash_attach(dsa_area *area, const dshash_parameters *params, dshash_table_handle handle, void *arg)
Definition dshash.c:274
dshash_table * dshash_create(dsa_area *area, const dshash_parameters *params, void *arg)
Definition dshash.c:210
#define DSHASH_HANDLE_INVALID
Definition dshash.h:27
dsa_pointer dshash_table_handle
Definition dshash.h:24
void * GetNamedDSMSegment(const char *name, size_t size, void(*init_callback)(void *ptr, void *arg), bool *found, void *arg)
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1150
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1767
@ LW_EXCLUSIVE
Definition lwlock.h:104
MemoryContext TopMemoryContext
Definition mcxt.c:166
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
dshash_table * pgsa_entry_dshash
dshash_table * pgsa_stash_dshash
static MemoryContext pg_stash_advice_mcxt
dsa_area * pgsa_dsa_area
static dshash_parameters pgsa_stash_dshash_parameters
pgsa_shared_state * pgsa_state
static dshash_parameters pgsa_entry_dshash_parameters
static void pgsa_init_shared_state(void *ptr, void *arg)
static int fb(int x)
dshash_table_handle entry_hash
dshash_table_handle stash_hash

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, pgsa_shared_state::area, dsa_attach(), dsa_create, dsa_get_handle(), DSA_HANDLE_INVALID, dsa_pin(), dsa_pin_mapping(), pgsa_shared_state::dsa_tranche, dshash_attach(), dshash_create(), dshash_get_hash_table_handle(), DSHASH_HANDLE_INVALID, pgsa_shared_state::entry_hash, pgsa_shared_state::entry_tranche, fb(), GetNamedDSMSegment(), pgsa_shared_state::lock, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MemoryContextSwitchTo(), pg_stash_advice_mcxt, pgsa_dsa_area, pgsa_entry_dshash, pgsa_entry_dshash_parameters, pgsa_init_shared_state(), pgsa_stash_dshash, pgsa_stash_dshash_parameters, pgsa_state, pgsa_shared_state::stash_hash, pgsa_shared_state::stash_tranche, TopMemoryContext, and dshash_parameters::tranche_id.

Referenced by pg_create_advice_stash(), pg_drop_advice_stash(), pg_get_advice_stash_contents(), pg_get_advice_stashes(), pg_set_stashed_advice(), and pgsa_advisor().

◆ pgsa_check_stash_name()

void pgsa_check_stash_name ( char stash_name)
extern

Definition at line 288 of file pg_stash_advice.c.

289{
290 /* Reject empty advice stash name. */
291 if (stash_name[0] == '\0')
294 errmsg("advice stash name may not be zero length"));
295
296 /* Reject overlong advice stash names. */
297 if (strlen(stash_name) + 1 > NAMEDATALEN)
300 errmsg("advice stash names may not be longer than %d bytes",
301 NAMEDATALEN - 1));
302
303 /*
304 * Reject non-ASCII advice stash names, since advice stashes are visible
305 * across all databases and the encodings of those databases might differ.
306 */
310 errmsg("advice stash name must not contain non-ASCII characters"));
311
312 /*
313 * Reject things that do not look like identifiers, since the ability to
314 * create an advice stash with non-printable characters or weird symbols
315 * in the name is not likely to be useful to anyone.
316 */
320 errmsg("advice stash name must begin with a letter or underscore and contain only letters, digits, and underscores"));
321}
int errcode(int sqlerrcode)
Definition elog.c:874
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:151
static char * errmsg
#define NAMEDATALEN
static bool pgsa_is_identifier(char *str)
bool pg_is_ascii(const char *str)
Definition string.c:132

References ereport, errcode(), errmsg, ERROR, fb(), NAMEDATALEN, pg_is_ascii(), and pgsa_is_identifier().

Referenced by pg_create_advice_stash(), pg_drop_advice_stash(), pg_get_advice_stash_contents(), and pg_set_stashed_advice().

◆ pgsa_clear_advice_string()

void pgsa_clear_advice_string ( char stash_name,
int64  queryId 
)
extern

Definition at line 392 of file pg_stash_advice.c.

393{
394 pgsa_entry *entry;
398
400
401 /* Translate the stash name to an integer ID. */
405 errmsg("advice stash \"%s\" does not exist", stash_name));
406
407 /*
408 * Look for an existing entry, and free it. But, be sure to save the
409 * pointer to the associated advice string, if any.
410 */
411 memset(&key, 0, sizeof(pgsa_entry_key));
412 key.pgsa_stash_id = stash_id;
413 key.queryId = queryId;
414 entry = dshash_find(pgsa_entry_dshash, &key, true);
415 if (entry == NULL)
417 else
418 {
419 old_dp = entry->advice_string;
421 }
422
423 /* Now we free the advice string as well, if there was one. */
426}
#define Assert(condition)
Definition c.h:943
uint64_t uint64
Definition c.h:625
void dsa_free(dsa_area *area, dsa_pointer dp)
Definition dsa.c:841
uint64 dsa_pointer
Definition dsa.h:62
#define InvalidDsaPointer
Definition dsa.h:78
void dshash_delete_entry(dshash_table *hash_table, void *entry)
Definition dshash.c:562
void * dshash_find(dshash_table *hash_table, const void *key, bool exclusive)
Definition dshash.c:394
bool LWLockHeldByMe(LWLock *lock)
Definition lwlock.c:1885
uint64 pgsa_lookup_stash_id(char *stash_name)
dsa_pointer advice_string

References pgsa_entry::advice_string, Assert, dsa_free(), dshash_delete_entry(), dshash_find(), ereport, errcode(), errmsg, ERROR, fb(), InvalidDsaPointer, pgsa_shared_state::lock, LWLockHeldByMe(), pgsa_dsa_area, pgsa_entry_dshash, pgsa_lookup_stash_id(), and pgsa_state.

Referenced by pg_set_stashed_advice().

◆ pgsa_create_stash()

void pgsa_create_stash ( char stash_name)
extern

Definition at line 371 of file pg_stash_advice.c.

372{
374 bool found;
375
377
378 /* Create a stash with this name, unless one already exists. */
380 if (found)
383 errmsg("advice stash \"%s\" already exists", stash_name));
384 stash->pgsa_stash_id = pgsa_state->next_stash_id++;
386}
void dshash_release_lock(dshash_table *hash_table, void *entry)
Definition dshash.c:579
#define dshash_find_or_insert(hash_table, key, found)
Definition dshash.h:109
bool LWLockHeldByMeInMode(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1929

References Assert, dshash_find_or_insert, dshash_release_lock(), ereport, errcode(), errmsg, ERROR, fb(), pgsa_shared_state::lock, LW_EXCLUSIVE, LWLockHeldByMeInMode(), pgsa_shared_state::next_stash_id, pgsa_stash_dshash, and pgsa_state.

Referenced by pg_create_advice_stash().

◆ pgsa_drop_stash()

void pgsa_drop_stash ( char stash_name)
extern

Definition at line 432 of file pg_stash_advice.c.

433{
434 pgsa_entry *entry;
438
440
441 /* Remove the entry for this advice stash. */
443 if (stash == NULL)
446 errmsg("advice stash \"%s\" does not exist", stash_name));
447 stash_id = stash->pgsa_stash_id;
449
450 /*
451 * Now remove all the entries. Since pgsa_state->lock must be held at
452 * least in shared mode to insert entries into pgsa_entry_dshash, it
453 * doesn't matter whether we do this before or after deleting the entry
454 * from pgsa_stash_dshash.
455 */
457 while ((entry = dshash_seq_next(&iterator)) != NULL)
458 {
459 if (stash_id == entry->key.pgsa_stash_id)
460 {
461 if (entry->advice_string != InvalidDsaPointer)
464 }
465 }
467}
void dshash_seq_init(dshash_seq_status *status, dshash_table *hash_table, bool exclusive)
Definition dshash.c:659
void dshash_seq_term(dshash_seq_status *status)
Definition dshash.c:768
void * dshash_seq_next(dshash_seq_status *status)
Definition dshash.c:678
void dshash_delete_current(dshash_seq_status *status)
Definition dshash.c:778
uint64 pgsa_stash_id
pgsa_entry_key key

References pgsa_entry::advice_string, Assert, dsa_free(), dshash_delete_current(), dshash_delete_entry(), dshash_find(), dshash_seq_init(), dshash_seq_next(), dshash_seq_term(), ereport, errcode(), errmsg, ERROR, fb(), InvalidDsaPointer, pgsa_entry::key, pgsa_shared_state::lock, LW_EXCLUSIVE, LWLockHeldByMeInMode(), pgsa_dsa_area, pgsa_entry_dshash, pgsa_stash_dshash, pgsa_entry_key::pgsa_stash_id, and pgsa_state.

Referenced by pg_drop_advice_stash().

◆ pgsa_lookup_stash_id()

uint64 pgsa_lookup_stash_id ( char stash_name)
extern

Definition at line 516 of file pg_stash_advice.c.

517{
520
521 /* Search the shared hash table. */
523 if (stash == NULL)
524 return 0;
525 stash_id = stash->pgsa_stash_id;
527
528 return stash_id;
529}

References dshash_find(), dshash_release_lock(), fb(), and pgsa_stash_dshash.

Referenced by pg_get_advice_stash_contents(), pgsa_advisor(), pgsa_clear_advice_string(), and pgsa_set_advice_string().

◆ pgsa_set_advice_string()

void pgsa_set_advice_string ( char stash_name,
int64  queryId,
char advice_string 
)
extern

Definition at line 535 of file pg_stash_advice.c.

536{
537 pgsa_entry *entry;
538 bool found;
543
544 /*
545 * The caller must hold our lock, at least in shared mode. This is
546 * important for two reasons.
547 *
548 * First, it holds off interrupts, so that we can't bail out of this code
549 * after allocating DSA memory for the advice string and before storing
550 * the resulting pointer somewhere that others can find it.
551 *
552 * Second, we need to avoid a race against pgsa_drop_stash(). That
553 * function removes a stash_name->stash_id mapping and all the entries for
554 * that stash_id. Without the lock, there's a race condition no matter
555 * which of those things it does first, because as soon as we've looked up
556 * the stash ID, that whole function can execute before we do the rest of
557 * our work, which would result in us adding an entry for a stash that no
558 * longer exists.
559 */
561
562 /* Look up the stash ID. */
566 errmsg("advice stash \"%s\" does not exist", stash_name));
567
568 /* Allocate space for the advice string. */
569 new_dp = dsa_allocate(pgsa_dsa_area, strlen(advice_string) + 1);
570 strcpy(dsa_get_address(pgsa_dsa_area, new_dp), advice_string);
571
572 /* Attempt to insert an entry into the hash table. */
573 memset(&key, 0, sizeof(pgsa_entry_key));
574 key.pgsa_stash_id = stash_id;
575 key.queryId = queryId;
578
579 /*
580 * If it didn't work, bail out, being careful to free the shared memory
581 * we've already allocated before, since error cleanup will not do so.
582 */
583 if (entry == NULL)
584 {
588 errmsg("out of memory"),
589 errdetail("could not insert advice string into shared hash table"));
590 }
591
592 /* Update the entry and release the lock. */
593 old_dp = found ? entry->advice_string : InvalidDsaPointer;
594 entry->advice_string = new_dp;
596
597 /*
598 * We're not safe from leaks yet!
599 *
600 * There's now a pointer to new_dp in the entry that we just updated, but
601 * that means that there's no longer anything pointing to old_dp.
602 */
605}
void * dsa_get_address(dsa_area *area, dsa_pointer dp)
Definition dsa.c:957
#define dsa_allocate(area, size)
Definition dsa.h:109
#define DsaPointerIsValid(x)
Definition dsa.h:106
void * dshash_find_or_insert_extended(dshash_table *hash_table, const void *key, bool *found, int flags)
Definition dshash.c:442
#define DSHASH_INSERT_NO_OOM
Definition dshash.h:96
int errdetail(const char *fmt,...) pg_attribute_printf(1

References pgsa_entry::advice_string, Assert, dsa_allocate, dsa_free(), dsa_get_address(), DsaPointerIsValid, dshash_find_or_insert_extended(), DSHASH_INSERT_NO_OOM, dshash_release_lock(), ereport, errcode(), errdetail(), errmsg, ERROR, fb(), InvalidDsaPointer, pgsa_shared_state::lock, LWLockHeldByMe(), pgsa_dsa_area, pgsa_entry_dshash, pgsa_lookup_stash_id(), and pgsa_state.

Referenced by pg_set_stashed_advice().

Variable Documentation

◆ pgsa_dsa_area

◆ pgsa_entry_dshash

◆ pgsa_stash_dshash

◆ pgsa_state