cdbvars.c 32.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*-------------------------------------------------------------------------
 *
 * cdbvars.c
 *	  Provides storage areas and processing routines for Greenplum Database variables
 *	  managed by GUC.
 *
 * Copyright (c) 2003-2010, Greenplum inc
 *
 *
 * NOTES
 *	  See src/backend/utils/misc/guc.c for variable external specification.
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"
#include "miscadmin.h"
#include "utils/guc.h"
#include "catalog/gp_segment_config.h"
#include "cdb/cdbvars.h"
#include "cdb/cdbfts.h"
22
#include "cdb/cdbdisp.h"
23
#include "cdb/cdbutil.h"
24
#include "cdb/cdbdisp.h"
25 26 27 28
#include "lib/stringinfo.h"
#include "libpq/libpq-be.h"
#include "utils/memutils.h"
#include "storage/bfz.h"
29
#include "storage/proc.h"
30 31 32 33 34 35 36 37 38 39 40 41 42
#include "cdb/memquota.h"

/*
 * ----------------
 *		GUC/global variables
 *
 *	Initial values are set by guc.c function "InitializeGUCOptions" called
 *	*very* early during postmaster, postgres, or bootstrap initialization.
 * ----------------
 */



43 44 45 46
GpRoleValue Gp_role;			/* Role paid by this Greenplum Database
								 * backend */
char	   *gp_role_string;		/* Staging area for guc.c */
char	   *gp_fault_action_string;		/* Staging area for guc.c */
47 48
bool		gp_set_read_only;	/* Staging area for guc.c */

49 50 51
GpRoleValue Gp_session_role;	/* Role paid by this Greenplum Database
								 * backend */
char	   *gp_session_role_string;		/* Staging area for guc.c */
52

53
bool		Gp_is_writer;		/* is this qExec a "writer" process. */
54

55
int			gp_session_id;		/* global unique id for session. */
56

57 58
char	   *qdHostname;			/* QD hostname */
int			qdPostmasterPort;	/* Master Segment Postmaster port. */
59

60
int			gp_command_count;	/* num of commands from client */
61

62
bool		gp_debug_pgproc;	/* print debug info for PGPROC */
63 64 65 66 67
bool		Debug_print_prelim_plan;	/* Shall we log argument of
										 * cdbparallelize? */

bool		Debug_print_slice_table;	/* Shall we log the slice table? */

68
bool		gp_backup_directIO = false; /* disable\enable direct I/O dump */
69

70 71 72
int			gp_backup_directIO_read_chunk_mb = 20;		/* size of readChunk
														 * buffer for directIO
														 * dump */
73

74 75
bool		gp_external_enable_exec = true;		/* allow ext tables with
												 * EXECUTE */
76

77 78 79
bool		gp_external_grant_privileges = false;		/* allow creating
														 * http/gpfdist/gpfdists
														 * for non-su */
80

81
int			gp_external_max_segs;		/* max segdbs per gpfdist/gpfdists URI */
82

83
int			gp_safefswritesize; /* set for safe AO writes in non-mature fs */
84

85
int			gp_connections_per_thread;	/* How many libpq connections are
86 87
										 * handled in each thread */

88 89
int			gp_cached_gang_threshold;	/* How many gangs to keep around from
										 * stmt to stmt. */
90

91
int			Gp_segment = UNDEF_SEGMENT; /* What content this QE is handling. */
92 93 94 95

bool		Gp_write_shared_snapshot;	/* tell the writer QE to write the
										 * shared snapshot */

96 97
bool		gp_reraise_signal = false;	/* try to dump core when we get
										 * SIGABRT & SIGSEGV */
98

99 100
bool		gp_set_proc_affinity = false;		/* set processor affinity (if
												 * platform supports it) */
101

102 103 104
int			gp_reject_percent_threshold;		/* SREH reject % kicks off
												 * only after * <num> records
												 * have been processed	*/
105

106 107
int			gp_max_csv_line_length;		/* max allowed len for csv data line
										 * in bytes */
108

109 110
bool		gp_select_invisible = false;		/* debug mode to allow select
												 * to see "invisible" rows */
111

112 113 114 115
int			pgstat_track_activity_query_size = INT_MAX; /* max allowed len for
														 * displaying the query
														 * in pg_stat_activity
														 * table */
116 117 118 119 120

/*
 * Configurable timeout for snapshot add: exceptionally busy systems may take
 * longer than our old hard-coded version -- so here is a tuneable version.
 */
121
int			gp_snapshotadd_timeout = 10;
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137


/*
 * Probe retry count for fts prober.
 */
int			gp_fts_probe_retries = 5;

/*
 * Probe timeout for fts prober.
 */
int			gp_fts_probe_timeout = 20;

/*
 * Polling interval for the fts prober. A scan of the entire system starts
 * every time this expires.
 */
138
int			gp_fts_probe_interval = 60;
139 140 141 142 143

/*
 * Number of threads to use for probe of segments (it is a good idea to have this
 * larger than the number of segments per host.
 */
144
int			gp_fts_probe_threadcount = 16;
145 146 147 148 149 150 151

/*
 * Controls parallel segment transition (failover).
 */
bool		gp_fts_transition_parallel = true;

/* The number of retries to request a segment state transition. */
152
int			gp_fts_transition_retries = 5;
153 154

/* Timeout to request a segment state transition. */
155
int			gp_fts_transition_timeout = 3600;
156 157 158 159 160 161


/*
 * When we have certain types of failures during gang creation which indicate
 * that a segment is in recovery mode we may be able to retry.
 */
162 163
int			gp_gang_creation_retry_count = 5;	/* disable by default */
int			gp_gang_creation_retry_timer = 2000;		/* 2000ms */
164 165 166 167 168 169 170

/*
 * gp_enable_slow_writer_testmode
 *
 * In order facilitate testing of reader-gang/writer-gang synchronization,
 * this inserts a pg_usleep call at the start of writer-gang processing.
 */
171
bool		gp_enable_slow_writer_testmode = false;
172 173 174 175 176 177 178

/*
 * gp_enable_slow_cursor_testmode
 *
 * In order facilitate testing of reader-gang/writer-gang synchronization,
 * this inserts a pg_usleep call at the start of cursor-gang processing.
 */
179
bool		gp_enable_slow_cursor_testmode = false;
180 181 182 183

/**
 * Hash-join node releases hash table when it returns last tuple.
 */
184
bool		gp_eager_hashtable_release = true;
185

186
int			Gp_max_packet_size; /* max Interconnect packet size */
187

188 189 190 191 192 193 194 195 196 197 198
int			Gp_interconnect_queue_depth = 4;	/* max number of messages
												 * waiting in rx-queue before
												 * we drop. */
int			Gp_interconnect_snd_queue_depth = 2;
int			Gp_interconnect_timer_period = 5;
int			Gp_interconnect_timer_checking_period = 20;
int			Gp_interconnect_default_rtt = 20;
int			Gp_interconnect_min_rto = 20;
int			Gp_interconnect_fc_method = INTERCONNECT_FC_METHOD_LOSS;
int			Gp_interconnect_transmit_timeout = 3600;
int			Gp_interconnect_min_retries_before_timeout = 100;
199

200 201 202
int			Gp_interconnect_hash_multiplier = 2;		/* sets the size of the
														 * hash table used by
														 * the UDP-IC */
203

204
int			interconnect_setup_timeout = 7200;
205

206
int			Gp_interconnect_type = INTERCONNECT_TYPE_UDPIFC;
207

208
bool		gp_interconnect_full_crc = false;	/* sanity check UDP data. */
209

210
bool		gp_interconnect_log_stats = false;	/* emit stats at log-level */
211

212
bool		gp_interconnect_cache_future_packets = true;
213

214
int			Gp_udp_bufsize_k;	/* UPD recv buf size, in KB */
215 216 217 218 219 220 221

#ifdef USE_ASSERT_CHECKING
/*
 * UDP-IC Test hooks (for fault injection).
 *
 * Dropseg: specifies which segment to apply the drop_percent to.
 */
222 223 224 225 226 227
int			gp_udpic_dropseg = UNDEF_SEGMENT;
int			gp_udpic_dropxmit_percent = 0;
int			gp_udpic_dropacks_percent = 0;
int			gp_udpic_fault_inject_percent = 0;
int			gp_udpic_fault_inject_bitmap = 0;
int			gp_udpic_network_disable_ipv6 = 0;
228 229 230 231 232 233
#endif

/*
 * Each slice table has a unique ID (certain commands like "vacuum analyze"
 * run many many slice-tables for each gp_command_id).
 */
234
uint32		gp_interconnect_id = 0;
235 236 237 238 239

/* --------------------------------------------------------------------------------------------------
 * Resource management
 */

240
double		gp_hashagg_respill_bias = 1;
241 242 243 244 245

/* --------------------------------------------------------------------------------------------------
 * Greenplum Optimizer GUCs
 */

246 247
double		gp_motion_cost_per_row = 0;
int			gp_segments_for_planner = 0;
248

249
int			gp_hashagg_default_nbatches = 32;
250 251 252 253 254 255 256 257 258 259 260 261 262

bool		gp_adjust_selectivity_for_outerjoins = TRUE;
bool		gp_selectivity_damping_for_scans = false;
bool		gp_selectivity_damping_for_joins = false;
double		gp_selectivity_damping_factor = 1;
bool		gp_selectivity_damping_sigsort = true;

int			gp_hashjoin_tuples_per_bucket = 5;
int			gp_hashagg_groups_per_bucket = 5;
int			gp_hashjoin_metadata_memory_percent = 20;


/* default value to 0, which means we do not try to control number of spill batches */
263 264
int			gp_hashagg_spillbatch_min = 0;
int			gp_hashagg_spillbatch_max = 0;
265 266

/* hash join to use bloom filter: default to 0, means not used */
267
int			gp_hashjoin_bloomfilter = 0;
268 269

/* Analyzing aid */
270
int			gp_motion_slice_noop = 0;
271
#ifdef ENABLE_LTRACE
272
int			gp_ltrace_flag = 0;
273 274 275 276 277 278 279 280 281
#endif

/* Internal Features */
bool		gp_enable_alter_table_inherit_cols = false;

/* During insertion in a table with parquet partitions, require tuples to be sorted by partition key */
bool		gp_parquet_insert_sort = true;

/* Greenplum Database Experimental Feature GUCs */
282
int			gp_distinct_grouping_sets_threshold = 32;
283
bool		gp_enable_explain_allstat = FALSE;
284 285
bool		gp_enable_motion_deadlock_sanity = FALSE;	/* planning time sanity
														 * check */
286 287 288 289 290 291

#ifdef USE_ASSERT_CHECKING
bool		gp_mk_sort_check = false;
#endif
int			gp_sort_flags = 0;
int			gp_dbg_flags = 0;
292
int			gp_sort_max_distinct = 20000;
293 294 295 296 297 298 299 300 301 302

bool		gp_enable_hash_partitioned_tables = FALSE;
bool		gp_setwith_alter_storage = FALSE;

bool		gp_enable_tablespace_auto_mkdir = FALSE;

/* MPP-9772, MPP-9773: remove support for CREATE INDEX CONCURRENTLY */
bool		gp_create_index_concurrently = FALSE;

/* Enable check for compatibility of encoding and locale in createdb */
303
bool		gp_encoding_check_locale_compatibility = true;
304 305

/* Priority for the segworkers relative to the postmaster's priority */
306
int			gp_segworker_relative_priority = PRIO_MAX;
307 308 309 310 311 312

/* Max size of dispatched plans; 0 if no limit */
int			gp_max_plan_size = 0;

/* Disable setting of tuple hints while reading */
bool		gp_disable_tuple_hints = false;
313 314 315 316 317 318
int			gp_hashagg_compress_spill_files = 0;

int			gp_workfile_compress_algorithm = 0;
bool		gp_workfile_checksumming = false;
int			gp_workfile_caching_loglevel = DEBUG1;
int			gp_sessionstate_loglevel = DEBUG1;
319 320

/* Maximum disk space to use for workfiles on a segment, in kilobytes */
321 322
double		gp_workfile_limit_per_segment = 0;

323
/* Maximum disk space to use for workfiles per query on a segment, in kilobytes */
324 325
double		gp_workfile_limit_per_query = 0;

326
/* Maximum number of workfiles to be created by a query */
327 328 329
int			gp_workfile_limit_files_per_query = 0;
bool		gp_workfile_faultinject = false;
int			gp_workfile_bytes_to_checksum = 16;
330 331

/* The type of work files that HashJoin should use */
332
int			gp_workfile_type_hashjoin = 0;
333 334

/* Gpmon */
335 336
bool		gp_enable_gpperfmon = false;
int			gp_gpperfmon_send_interval = 1;
337 338 339
GpperfmonLogAlertLevel gpperfmon_log_alert_level = GPPERFMON_LOG_ALERT_LEVEL_NONE;

/* Enable single-slice single-row inserts ?*/
340
bool		gp_enable_fast_sri = true;
341 342

/* Enable single-mirror pair dispatch. */
343
bool		gp_enable_direct_dispatch = true;
344 345

/* Disable logging while creating mapreduce objects */
346
bool		gp_mapreduce_define = false;
347 348

/* request fault-prober pause */
349
bool		gp_fts_probe_pause = false;
350 351

/* Force core dump on memory context error */
352
bool		coredump_on_memerror = false;
353 354 355

/* Experimental feature for MPP-4082. Please read doc before setting this guc */
GpAutoStatsModeValue gp_autostats_mode;
356
char	   *gp_autostats_mode_string;
357
GpAutoStatsModeValue gp_autostats_mode_in_functions;
358 359 360 361
char	   *gp_autostats_mode_in_functions_string;
int			gp_autostats_on_change_threshold = 100000;
bool		log_autostats = true;

362 363 364 365
/* --------------------------------------------------------------------------------------------------
 * Miscellaneous developer use
 */

366
bool		gp_dev_notice_agg_cost = false;
367 368 369 370 371 372 373 374 375 376 377 378

/* --------------------------------------------------------------------------------------------------
 * Server debugging
 */

/*
 * gp_debug_linger (integer)
 *
 * Upon an error with severity FATAL and error code ERRCODE_INTERNAL_ERROR,
 * errfinish() will sleep() for the specified number of seconds before
 * termination, to let the user attach a debugger.
 */
379
int			gp_debug_linger = 30;
380 381 382 383 384 385 386 387 388 389 390

/* ----------------
 * Non-GUC globals
 */

int			currentSliceId = UNSET_SLICE_ID;	/* used by elog to show the
												 * current slice the process
												 * is executing. */
SeqServerControlBlock *seqServerCtl;

/* Segment id where singleton gangs are to be dispatched. */
391
int			gp_singleton_segindex;
392

393
bool		gp_cost_hashjoin_chainwalk = false;
394 395 396 397 398 399 400

/* ----------------
 * This variable is initialized by the postmaster from command line arguments
 *
 * Any code needing the "numsegments"
 * can simply #include cdbvars.h, and use GpIdentity.numsegments
 */
401
GpId		GpIdentity = {UNINITIALIZED_GP_IDENTITY_VALUE, UNINITIALIZED_GP_IDENTITY_VALUE, UNINITIALIZED_GP_IDENTITY_VALUE};
402 403 404 405 406 407 408 409

/*
 * This has to be int because of guc.c stupidity :(
 * The value is supposed to be passed through postmaster command line
 * and go to XLogCtlData for mmxlog purpose.  We'd like to fetch the value
 * from the catalog but the value is too fundamental and accessed too early
 * to fetch it from catalog.
 */
410
int			GpStandbyDbid = InvalidDbid;
411

412 413
void
verifyGpIdentityIsSet(void)
414
{
415 416 417 418 419 420
	if (GpIdentity.numsegments == UNINITIALIZED_GP_IDENTITY_VALUE ||
		GpIdentity.dbid == UNINITIALIZED_GP_IDENTITY_VALUE ||
		GpIdentity.segindex == UNINITIALIZED_GP_IDENTITY_VALUE)
	{
		elog(ERROR, "GpIdentity is not set");
	}
421 422 423 424 425
}

/*
 * Keep track of a few dispatch-related  statistics:
 */
426 427 428
int			cdb_total_slices = 0;
int			cdb_total_plans = 0;
int			cdb_max_slices = 0;
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499

/*
 * Local macro to provide string values of numeric defines.
 */
#define CppNumericAsString(s) CppAsString(s)

/*
 *	Forward declarations of local function.
 */
GpRoleValue string_to_role(const char *string);
const char *role_to_string(GpRoleValue role);


/*
 * Convert a Greenplum Database role string (as for gp_session_role or gp_role) to an
 * enum value of type GpRoleValue. Return GP_ROLE_UNDEFINED in case the
 * string is unrecognized.
 */
GpRoleValue
string_to_role(const char *string)
{
	GpRoleValue role = GP_ROLE_UNDEFINED;

	if (pg_strcasecmp(string, "dispatch") == 0 || pg_strcasecmp(string, "") == 0)
	{
		role = GP_ROLE_DISPATCH;
	}
	else if (pg_strcasecmp(string, "execute") == 0)
	{
		role = GP_ROLE_EXECUTE;
	}
	else if (pg_strcasecmp(string, "utility") == 0)
	{
		role = GP_ROLE_UTILITY;
	}

	return role;
}

/*
 * Convert a GpRoleValue to a role string (as for gp_session_role or
 * gp_role).  Return eyecatcher in the unexpected event that the value
 * is unknown or undefined.
 */
const char *
role_to_string(GpRoleValue role)
{
	switch (role)
	{
		case GP_ROLE_DISPATCH:
			return "dispatch";
		case GP_ROLE_EXECUTE:
			return "execute";
		case GP_ROLE_UTILITY:
			return "utility";
		case GP_ROLE_UNDEFINED:
		default:
			return "*undefined*";
	}
}


/*
 * Assign hook routine for "gp_session_role" option.  Because this variable
 * has context PGC_BACKEND, we expect this assigment to happen only during
 * setup of a BACKEND, e.g., based on the role value specified on the connect
 * request.
 *
 * See src/backend/util/misc/guc.c for option definition.
 */
const char *
500
assign_gp_session_role(const char *newval, bool doit, GucSource source __attribute__((unused)))
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520
{
#if FALSE
	elog(DEBUG1, "assign_gp_session_role: gp_session_role=%s, newval=%s, doit=%s",
		 show_gp_session_role(), newval, (doit ? "true" : "false"));
#endif

	GpRoleValue newrole = string_to_role(newval);

	if (newrole == GP_ROLE_UNDEFINED)
	{
		return NULL;
	}

	if (doit)
	{
		Gp_session_role = newrole;
		Gp_role = Gp_session_role;

		if (Gp_role == GP_ROLE_DISPATCH)
			Gp_segment = -1;
521 522 523

		if (Gp_role == GP_ROLE_UTILITY && MyProc != NULL)
			MyProc->mppIsWriter = false;
524 525 526 527 528 529 530
	}
	return newval;
}



/*
T
Tristan Su 已提交
531
 * Assign hook routine for "gp_role" option.  This variable has context
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
 * PGC_SUSET so that is can only be set by a superuser via the SET command.
 * (It can also be set using an option on postmaster start, but this isn't
 * interesting beccause the derived global CdbRole is always set (along with
 * CdbSessionRole) on backend startup for a new connection.
 *
 * See src/backend/util/misc/guc.c for option definition.
 */
const char *
assign_gp_role(const char *newval, bool doit, GucSource source)
{
#if FALSE
	elog(DEBUG1, "assign_gp_role: gp_role=%s, newval=%s, doit=%s",
		 show_gp_role(), newval, (doit ? "true" : "false"));
#endif


	GpRoleValue newrole = string_to_role(newval);
	GpRoleValue oldrole = Gp_role;

	if (newrole == GP_ROLE_UNDEFINED)
	{
		return NULL;
	}

	if (doit)
	{
		/*
559 560
		 * When changing between roles, we must call cdb_cleanup and then
		 * cdb_setup to get setup and connections appropriate to the new role.
561 562 563 564 565 566 567 568 569 570 571 572 573 574
		 */
		bool		do_disconnect = false;
		bool		do_connect = false;

		if (Gp_role != newrole && IsUnderPostmaster)
		{
			if (Gp_role != GP_ROLE_UTILITY)
				do_disconnect = true;

			if (newrole != GP_ROLE_UTILITY)
				do_connect = true;
		}

		if (do_disconnect)
575
			cdb_cleanup(0, 0);
576 577 578 579 580 581 582 583

		Gp_role = newrole;

		if (source != PGC_S_DEFAULT)
		{
			if (do_connect)
			{
				/*
584 585 586 587 588
				 * In case there are problems with the Greenplum Database
				 * tables or data, we catch any error coming out of
				 * cdblink_setup so we can set the gp_role back to what it
				 * was.  Otherwise we may be left with inappropriate
				 * connections for the new role.
589 590 591 592 593 594 595
				 */
				PG_TRY();
				{
					cdb_setup();
				}
				PG_CATCH();
				{
596
					cdb_cleanup(0, 0);
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
					Gp_role = oldrole;
					if (Gp_role != GP_ROLE_UTILITY)
						cdb_setup();
					PG_RE_THROW();
				}
				PG_END_TRY();
			}
		}
	}

	return newval;
}


/*
T
Tristan Su 已提交
612
 * Assign hook routine for "gp_connections_per_thread" option.  This variable has context
613 614 615 616 617 618
 * PGC_SUSET so that is can only be set by a superuser via the SET command.
 * (It can also be set in config file, but not inside of PGOPTIONS.)
 *
 * See src/backend/util/misc/guc.c for option definition.
 */
bool
619
assign_gp_connections_per_thread(int newval, bool doit, GucSource source __attribute__((unused)))
620 621 622
{
#if FALSE
	elog(DEBUG1, "assign_gp_connections_per_thread: gp_connections_per_thread=%s, newval=%d, doit=%s",
623
		 show_gp_connections_per_thread(), newval, (doit ? "true" : "false"));
624 625 626 627
#endif

	if (doit)
	{
628
		if (newval < 0)
629 630
			return false;

631 632
		cdbdisp_setAsync(newval == 0);
		cdbgang_setAsync(newval == 0);
633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
		gp_connections_per_thread = newval;
	}

	return true;
}

/*
 * Show hook routine for "gp_session_role" option.
 *
 * See src/backend/util/misc/guc.c for option definition.
 */
const char *
show_gp_session_role(void)
{
	return role_to_string(Gp_session_role);
}


/*
 * Show hook routine for "gp_role" option.
 *
 * See src/backend/util/misc/guc.c for option definition.
 */
const char *
show_gp_role(void)
{
	return role_to_string(Gp_role);
}

/*
 * Show hook routine for "gp_connections_per_thread" option.
 *
 * See src/backend/util/misc/guc.c for option definition.
 */
const char *
show_gp_connections_per_thread(void)
{
	/*
	 * We rely on the fact that the memory context will clean up the memory
	 * for the buffer.data.
	 */
	StringInfoData buffer;

	initStringInfo(&buffer);

	appendStringInfo(&buffer, "%d", gp_connections_per_thread);

	return buffer.data;
}



/* --------------------------------------------------------------------------------------------------
 * Logging
 */


/*
 * gp_log_gangs (string)
 *
 * Should creation, reallocation and cleanup of gangs of QE processes be logged?
694 695
 * "OFF"	 -> only errors are logged
 * "TERSE"	 -> terse logging of routine events, e.g. creation of new qExecs
696
 * "VERBOSE" -> gang allocation per command is logged
697
 * "DEBUG"	 -> additional events are logged at severity level DEBUG1 to DEBUG5
698 699 700 701
 *
 * The messages that are enabled by the TERSE and VERBOSE settings are
 * written with a severity level of LOG.
 */
702
GpVars_Verbosity gp_log_gang;
703 704 705 706 707

/*
 * gp_log_fts (string)
 *
 * What kind of messages should the fault-prober log ?
708 709
 * "OFF"	 -> only errors are logged
 * "TERSE"	 -> terse logging of routine events
710
 * "VERBOSE" -> gang allocation per command is logged
711
 * "DEBUG"	 -> additional events are logged at severity level DEBUG1 to DEBUG5
712 713 714 715
 *
 * The messages that are enabled by the TERSE and VERBOSE settings are
 * written with a severity level of LOG.
 */
716
GpVars_Verbosity gp_log_fts;
717 718 719 720 721

/*
 * gp_log_interconnect (string)
 *
 * Should connections between internal processes be logged?  (qDisp/qExec/etc)
722 723
 * "OFF"	 -> connection errors are logged
 * "TERSE"	 -> terse logging of routine events, e.g. successful connections
724
 * "VERBOSE" -> most interconnect setup events are logged
725
 * "DEBUG"	 -> additional events are logged at severity level DEBUG1 to DEBUG5.
726 727 728 729
 *
 * The messages that are enabled by the TERSE and VERBOSE settings are
 * written with a severity level of LOG.
 */
730
GpVars_Verbosity gp_log_interconnect;
731 732 733 734

/*
 * gpvars_string_to_verbosity
 */
H
Heikki Linnakangas 已提交
735
static GpVars_Verbosity
736 737 738 739 740
gpvars_string_to_verbosity(const char *s)
{
	GpVars_Verbosity result;

	if (!s ||
741 742
		!s[0] ||
		!pg_strcasecmp("terse", s))
743 744 745 746 747 748 749
		result = GPVARS_VERBOSITY_TERSE;
	else if (!pg_strcasecmp("off", s))
		result = GPVARS_VERBOSITY_OFF;
	else if (!pg_strcasecmp("verbose", s))
		result = GPVARS_VERBOSITY_VERBOSE;
	else if (!pg_strcasecmp("debug", s))
		result = GPVARS_VERBOSITY_DEBUG;
750 751
	else
		result = GPVARS_VERBOSITY_UNDEFINED;
752
	return result;
753
}	/* gpvars_string_to_verbosity */
754 755 756 757

/*
 * gpvars_verbosity_to_string
 */
H
Heikki Linnakangas 已提交
758
static const char *
759 760 761 762 763 764 765 766 767 768 769 770 771 772 773
gpvars_verbosity_to_string(GpVars_Verbosity verbosity)
{
	switch (verbosity)
	{
		case GPVARS_VERBOSITY_OFF:
			return "off";
		case GPVARS_VERBOSITY_TERSE:
			return "terse";
		case GPVARS_VERBOSITY_VERBOSE:
			return "verbose";
		case GPVARS_VERBOSITY_DEBUG:
			return "debug";
		default:
			return "*undefined*";
	}
774
}	/* gpvars_verbosity_to_string */
775 776

/*
777
 * gpperfmon_log_alert_level_to_string
778 779 780 781 782 783
 */
const char *
gpperfmon_log_alert_level_to_string(GpperfmonLogAlertLevel level)
{
	switch (level)
	{
784
		case GPPERFMON_LOG_ALERT_LEVEL_NONE:
785
			return "none";
786
		case GPPERFMON_LOG_ALERT_LEVEL_WARNING:
787
			return "warning";
788
		case GPPERFMON_LOG_ALERT_LEVEL_ERROR:
789
			return "error";
790
		case GPPERFMON_LOG_ALERT_LEVEL_FATAL:
791
			return "fatal";
792
		case GPPERFMON_LOG_ALERT_LEVEL_PANIC:
793 794
			return "panic";
		default:
795
			return "*undefined*";
796
	}
797
}
798 799 800 801 802

/*
 * gpperfmon_log_alert_level_from_string
 */
GpperfmonLogAlertLevel
803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821
gpperfmon_log_alert_level_from_string(const char *level_string)
{
	if (strcasecmp(level_string, "warning") == 0)
	{
		return GPPERFMON_LOG_ALERT_LEVEL_WARNING;
	}
	if (strcasecmp(level_string, "error") == 0)
	{
		return GPPERFMON_LOG_ALERT_LEVEL_ERROR;
	}
	if (strcasecmp(level_string, "fatal") == 0)
	{
		return GPPERFMON_LOG_ALERT_LEVEL_FATAL;
	}
	if (strcasecmp(level_string, "panic") == 0)
	{
		return GPPERFMON_LOG_ALERT_LEVEL_PANIC;
	}
	return GPPERFMON_LOG_ALERT_LEVEL_NONE;
822 823 824 825 826 827 828
}

/*
 * gpvars_assign_gp_log_gangs
 * gpvars_show_gp_log_gangs
 */
const char *
829
gpvars_assign_gp_log_gang(const char *newval, bool doit, GucSource source __attribute__((unused)))
830 831 832 833
{
	GpVars_Verbosity v = gpvars_string_to_verbosity(newval);

	if (v == GPVARS_VERBOSITY_UNDEFINED)
834
		return NULL;
835 836 837
	if (doit)
		gp_log_gang = v;
	return newval;
838
}	/* gpvars_assign_gp_log_gangs */
839 840 841 842 843

const char *
gpvars_show_gp_log_gang(void)
{
	return gpvars_verbosity_to_string(gp_log_gang);
844
}	/* gpvars_show_gp_log_gangs */
845 846 847 848 849 850

/*
 * gpvars_assign_gp_log_fts
 * gpvars_show_gp_log_fts
 */
const char *
851
gpvars_assign_gp_log_fts(const char *newval, bool doit, GucSource source __attribute__((unused)))
852 853 854 855
{
	GpVars_Verbosity v = gpvars_string_to_verbosity(newval);

	if (v == GPVARS_VERBOSITY_UNDEFINED)
856
		return NULL;
857 858 859
	if (doit)
		gp_log_fts = v;
	return newval;
860
}	/* gpvars_assign_gp_log_fts */
861 862 863 864 865

const char *
gpvars_show_gp_log_fts(void)
{
	return gpvars_verbosity_to_string(gp_log_fts);
866
}	/* gpvars_show_gp_log_fts */
867 868 869 870 871 872

/*
 * gpvars_assign_gp_log_interconnect
 * gpvars_show_gp_log_interconnect
 */
const char *
873
gpvars_assign_gp_log_interconnect(const char *newval, bool doit, GucSource source __attribute__((unused)))
874 875 876 877
{
	GpVars_Verbosity v = gpvars_string_to_verbosity(newval);

	if (v == GPVARS_VERBOSITY_UNDEFINED)
878
		return NULL;
879 880 881
	if (doit)
		gp_log_interconnect = v;
	return newval;
882
}	/* gpvars_assign_gp_log_interconnect */
883 884 885 886 887

const char *
gpvars_show_gp_log_interconnect(void)
{
	return gpvars_verbosity_to_string(gp_log_interconnect);
888
}	/* gpvars_show_gp_log_interconnect */
889 890 891 892 893 894 895


/*
 * gpvars_assign_gp_interconnect_type
 * gpvars_show_gp_interconnect_type
 */
const char *
896
gpvars_assign_gp_interconnect_type(const char *newval, bool doit, GucSource source __attribute__((unused)))
897
{
898
	int			newtype = 0;
899

900 901
	if (newval == NULL || newval[0] == 0)
		newtype = INTERCONNECT_TYPE_UDPIFC;
902 903 904
	else if (!pg_strcasecmp("udpifc", newval))
		newtype = INTERCONNECT_TYPE_UDPIFC;
	else
905
		elog(ERROR, "Only support UDPIFC, (current type is '%s')", gpvars_show_gp_interconnect_type());
906 907 908 909 910 911 912

	if (doit)
	{
		Gp_interconnect_type = newtype;
	}

	return newval;
913
}	/* gpvars_assign_gp_log_interconnect */
914 915 916 917

const char *
gpvars_show_gp_interconnect_type(void)
{
918
	return "UDPIFC";
919
}	/* gpvars_show_gp_log_interconnect */
920 921 922 923 924 925

/*
 * gpvars_assign_gp_interconnect_fc_method
 * gpvars_show_gp_interconnect_fc_method
 */
const char *
926
gpvars_assign_gp_interconnect_fc_method(const char *newval, bool doit, GucSource source __attribute__((unused)))
927
{
928
	int			newmethod = 0;
929 930 931 932 933 934 935 936 937 938 939 940 941 942 943

	if (newval == NULL || newval[0] == 0 ||
		!pg_strcasecmp("capacity", newval))
		newmethod = INTERCONNECT_FC_METHOD_CAPACITY;
	else if (!pg_strcasecmp("loss", newval))
		newmethod = INTERCONNECT_FC_METHOD_LOSS;
	else
		elog(ERROR, "Unknown interconnect flow control method. (current method is '%s')", gpvars_show_gp_interconnect_fc_method());

	if (doit)
	{
		Gp_interconnect_fc_method = newmethod;
	}

	return newval;
944
}	/* gpvars_assign_gp_interconnect_fc_method */
945 946 947 948

const char *
gpvars_show_gp_interconnect_fc_method(void)
{
949
	switch (Gp_interconnect_fc_method)
950 951 952 953 954 955 956 957
	{
		case INTERCONNECT_FC_METHOD_CAPACITY:
			return "CAPACITY";
		case INTERCONNECT_FC_METHOD_LOSS:
			return "LOSS";
		default:
			return "CAPACITY";
	}
958
}	/* gpvars_show_gp_interconnect_fc_method */
959 960 961 962 963 964 965

/*
 * Parse the string value of gp_autostats_mode and gp_autostats_mode_in_functions
 */
static int
gpvars_parse_gp_autostats_mode(const char *newval, bool inFunctions)
{
966
	int			newtype = 0;
967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983

	if (newval == NULL || newval[0] == 0 ||
		!pg_strcasecmp("none", newval))
	{
		newtype = GP_AUTOSTATS_NONE;
	}
	else if (!pg_strcasecmp("on_change", newval) || !pg_strcasecmp("onchange", newval))
	{
		newtype = GP_AUTOSTATS_ON_CHANGE;
	}
	else if (!pg_strcasecmp("on_no_stats", newval))
	{
		newtype = GP_AUTOSTATS_ON_NO_STATS;
	}
	else
	{
		const char *autostats_mode_string;
984

985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003
		if (inFunctions)
		{
			autostats_mode_string = gpvars_show_gp_autostats_mode_in_functions();
		}
		else
		{
			autostats_mode_string = gpvars_show_gp_autostats_mode();
		}
		elog(ERROR, "Unknown autostats mode. (current type is '%s')", autostats_mode_string);
	}

	return newtype;
}

/*
 * gpvars_assign_gp_autostats_mode
 * gpvars_show_gp_autostats_mode
 */
const char *
1004
gpvars_assign_gp_autostats_mode(const char *newval, bool doit, GucSource source __attribute__((unused)))
1005
{
1006
	int			newtype = gpvars_parse_gp_autostats_mode(newval, false /* inFunctions */ );
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023

	if (doit)
	{
		gp_autostats_mode = newtype;
	}

	return newval;
}

/*
 * Common function to show the value of the gp_autostats_mode
 * and gp_autostats_mode_in_functions GUCs
 */
static const char *
gpvars_show_gp_autostats_mode_common(bool inFunctions)
{
	GpAutoStatsModeValue autostats_mode;
1024

1025 1026 1027 1028 1029 1030 1031 1032
	if (inFunctions)
	{
		autostats_mode = gp_autostats_mode_in_functions;
	}
	else
	{
		autostats_mode = gp_autostats_mode;
	}
1033
	switch (autostats_mode)
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
	{
		case GP_AUTOSTATS_NONE:
			return "NONE";
		case GP_AUTOSTATS_ON_CHANGE:
			return "ON_CHANGE";
		case GP_AUTOSTATS_ON_NO_STATS:
			return "ON_NO_STATS";
		default:
			return "NONE";
	}
}

const char *
gpvars_show_gp_autostats_mode(void)
{
1049
	return gpvars_show_gp_autostats_mode_common(false /* inFunctions */ );
1050 1051 1052 1053 1054 1055 1056 1057
}

/*
 * gpvars_assign_gp_autostats_mode_in_functions
 * gpvars_show_gp_autostats_mode_in_functions
 */

const char *
1058
gpvars_assign_gp_autostats_mode_in_functions(const char *newval, bool doit, GucSource source __attribute__((unused)))
1059
{
1060 1061
	bool		inFunctions = true;
	int			newtype = gpvars_parse_gp_autostats_mode(newval, inFunctions);
1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074

	if (doit)
	{
		gp_autostats_mode_in_functions = newtype;
	}

	return newval;
}


const char *
gpvars_show_gp_autostats_mode_in_functions(void)
{
1075
	return gpvars_show_gp_autostats_mode_common(true /* inFunctions */ );
1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
}

/* gp_enable_gpperfmon and gp_gpperfmon_send_interval are GUCs that we'd like
 * to have propagate from master to segments but we don't want non-super users
 * to be able to set it.  Unfortunately, as long as we use libpq to connect to
 * the segments its hard to create a clean way of doing this.
 *
 * Here we check and enforce that if the value is being set on the master its being
 * done as superuser and not a regular user.
 *
 */
bool
gpvars_assign_gp_enable_gpperfmon(bool newval, bool doit, GucSource source)
{
	if (doit)
	{

		if (Gp_role == GP_ROLE_DISPATCH && IsUnderPostmaster && GetCurrentRoleId() != InvalidOid && !superuser())
		{
			ereport(ERROR,
1096 1097
					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
					 errmsg("must be superuser to set gp_enable_gpperfmon")));
1098 1099 1100
		}
		else
		{
1101
			gp_enable_gpperfmon = newval;
1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116
		}
	}

	return true;
}

bool
gpvars_assign_gp_gpperfmon_send_interval(int newval, bool doit, GucSource source)
{
	if (doit)
	{
		if (Gp_role == GP_ROLE_DISPATCH && IsUnderPostmaster && GetCurrentRoleId() != InvalidOid && !superuser())
		{
			ereport(ERROR,
					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1117
			 errmsg("must be superuser to set gp_gpperfmon_send_interval")));
1118 1119 1120
		}
		else
		{
1121
			gp_gpperfmon_send_interval = newval;
1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132
		}
	}

	return true;
}

const char *
gpvars_assign_gp_gpperfmon_log_alert_level(const char *newval, bool doit, GucSource source)
{
	if (doit)
	{
1133
		if (!pg_strcasecmp(newval, "none"))
1134 1135 1136
		{
			gpperfmon_log_alert_level = GPPERFMON_LOG_ALERT_LEVEL_NONE;
		}
1137
		else if (!pg_strcasecmp(newval, "warning"))
1138 1139 1140
		{
			gpperfmon_log_alert_level = GPPERFMON_LOG_ALERT_LEVEL_WARNING;
		}
1141
		else if (!pg_strcasecmp(newval, "error"))
1142 1143 1144
		{
			gpperfmon_log_alert_level = GPPERFMON_LOG_ALERT_LEVEL_ERROR;
		}
1145
		else if (!pg_strcasecmp(newval, "fatal"))
1146 1147 1148
		{
			gpperfmon_log_alert_level = GPPERFMON_LOG_ALERT_LEVEL_FATAL;
		}
1149
		else if (!pg_strcasecmp(newval, "panic"))
1150 1151 1152 1153 1154
		{
			gpperfmon_log_alert_level = GPPERFMON_LOG_ALERT_LEVEL_PANIC;
		}
		else
		{
1155
			elog(ERROR, "Unknown log alert level '%s'. (current value is '%s')", newval, gpperfmon_log_alert_level_to_string(gpperfmon_log_alert_level));
1156 1157 1158 1159 1160 1161 1162 1163 1164
		}
	}

	return newval;
}

const char *
gpvars_show_gp_gpperfmon_log_alert_level(void)
{
1165
	return gpperfmon_log_alert_level_to_string(gpperfmon_log_alert_level);
1166
}
1167

1168 1169 1170 1171 1172 1173 1174 1175 1176 1177
/*
 * Request the fault-prober to suspend probes -- no fault actions will
 * be taken based on in-flight probes until the prober is unpaused.
 */
bool
gpvars_assign_gp_fts_probe_pause(bool newval, bool doit, GucSource source)
{
	if (doit)
	{
		/*
1178 1179
		 * We only want to do fancy stuff on the master (where we have a
		 * prober).
1180 1181 1182 1183
		 */
		if (ftsProbeInfo && Gp_segment == -1)
		{
			/*
1184 1185
			 * fts_pauseProbes is externally set/cleared; fts_cancelProbes is
			 * externally set and cleared by FTS
1186 1187 1188 1189 1190 1191 1192
			 */
			ftsLock();
			ftsProbeInfo->fts_pauseProbes = newval;
			ftsProbeInfo->fts_discardResults = ftsProbeInfo->fts_discardResults || newval;
			ftsUnlock();

			/*
1193 1194
			 * If we're unpausing, we want to force the prober to re-read
			 * everything. (we want FtsNotifyProber()).
1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211
			 */
			if (!newval)
			{
				FtsNotifyProber();
			}
		}
		gp_fts_probe_pause = newval;
	}

	return true;
}

/*
 * gpvars_assign_gp_resqueue_memory_policy
 * gpvars_show_gp_resqueue_memory_policy
 */
const char *
1212
gpvars_assign_gp_resqueue_memory_policy(const char *newval, bool doit, GucSource source __attribute__((unused)))
1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236
{
	ResQueueMemoryPolicy newtype = RESQUEUE_MEMORY_POLICY_NONE;

	if (newval == NULL || newval[0] == 0 ||
		!pg_strcasecmp("none", newval))
		newtype = RESQUEUE_MEMORY_POLICY_NONE;
	else if (!pg_strcasecmp("auto", newval))
		newtype = RESQUEUE_MEMORY_POLICY_AUTO;
	else if (!pg_strcasecmp("eager_free", newval))
		newtype = RESQUEUE_MEMORY_POLICY_EAGER_FREE;
	else
		elog(ERROR, "unknown resource queue memory policy: current policy is '%s'", gpvars_show_gp_resqueue_memory_policy());

	if (doit)
	{
		gp_resqueue_memory_policy = newtype;
	}

	return newval;
}

const char *
gpvars_show_gp_resqueue_memory_policy(void)
{
1237
	switch (gp_resqueue_memory_policy)
1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253
	{
		case RESQUEUE_MEMORY_POLICY_NONE:
			return "none";
		case RESQUEUE_MEMORY_POLICY_AUTO:
			return "auto";
		case RESQUEUE_MEMORY_POLICY_EAGER_FREE:
			return "eager_free";
		default:
			return "none";
	}
}

/*
 * gpvars_assign_statement_mem
 */
bool
1254
gpvars_assign_statement_mem(int newval, bool doit, GucSource source __attribute__((unused)))
1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270
{
	if (newval >= max_statement_mem)
	{
		elog(ERROR, "Invalid input for statement_mem. Must be less than max_statement_mem (%d kB).", max_statement_mem);
	}

	if (doit)
	{
		statement_mem = newval;
	}

	return true;
}

/*
 * increment_command_count
1271
 *	  Increment gp_command_count. If the new command count is 0 or a negative number, reset it to 1.
1272 1273 1274 1275 1276 1277 1278 1279
 */
void
increment_command_count()
{
	if (gp_cancel_query_print_log)
	{
		ereport(LOG,
				(errmsg("Incrementing command count from %d to %d",
1280 1281
						gp_command_count, gp_command_count + 1),
				 errprintstack(true)));
1282 1283 1284 1285 1286 1287 1288 1289
	}

	gp_command_count++;
	if (gp_command_count <= 0)
	{
		gp_command_count = 1;
	}
}