cdbvars.c 33.2 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
#include "lib/stringinfo.h"
#include "libpq/libpq-be.h"
#include "utils/memutils.h"
28
#include "utils/resource_manager.h"
29
#include "storage/bfz.h"
30
#include "storage/proc.h"
31 32 33 34 35 36 37 38 39 40 41 42 43
#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.
 * ----------------
 */



44 45 46 47
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 */
48 49
bool		gp_set_read_only;	/* Staging area for guc.c */

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

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

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

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

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

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

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

69 70
bool		Debug_resource_group;	/* Shall we log the resource group? */

71
bool		gp_backup_directIO = false; /* disable\enable direct I/O dump */
72

73 74 75
int			gp_backup_directIO_read_chunk_mb = 20;		/* size of readChunk
														 * buffer for directIO
														 * dump */
76

77 78
bool		gp_external_enable_exec = true;		/* allow ext tables with
												 * EXECUTE */
79

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

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

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

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

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

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

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

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

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

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

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

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

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


/*
 * 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.
 */
137
int			gp_fts_probe_interval = 60;
138 139 140 141 142

/*
 * 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.
 */
143
int			gp_fts_probe_threadcount = 16;
144 145 146 147 148 149 150

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

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

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


/*
 * 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.
 */
161 162
int			gp_gang_creation_retry_count = 5;	/* disable by default */
int			gp_gang_creation_retry_timer = 2000;		/* 2000ms */
163 164 165 166 167 168 169

/*
 * 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.
 */
170
bool		gp_enable_slow_writer_testmode = false;
171 172 173 174 175 176 177

/*
 * 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.
 */
178
bool		gp_enable_slow_cursor_testmode = false;
179

180
int			Gp_max_packet_size; /* max Interconnect packet size */
181

182 183 184 185 186 187 188 189 190 191 192
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;
193

194 195 196
int			Gp_interconnect_hash_multiplier = 2;		/* sets the size of the
														 * hash table used by
														 * the UDP-IC */
197

198
int			interconnect_setup_timeout = 7200;
199

200
int			Gp_interconnect_type = INTERCONNECT_TYPE_UDPIFC;
201

202
bool		gp_interconnect_full_crc = false;	/* sanity check UDP data. */
203

204
bool		gp_interconnect_log_stats = false;	/* emit stats at log-level */
205

206
bool		gp_interconnect_cache_future_packets = true;
207

208
int			Gp_udp_bufsize_k;	/* UPD recv buf size, in KB */
209 210 211 212 213 214 215

#ifdef USE_ASSERT_CHECKING
/*
 * UDP-IC Test hooks (for fault injection).
 *
 * Dropseg: specifies which segment to apply the drop_percent to.
 */
216 217 218 219 220 221
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;
222 223 224 225 226 227
#endif

/*
 * Each slice table has a unique ID (certain commands like "vacuum analyze"
 * run many many slice-tables for each gp_command_id).
 */
228
uint32		gp_interconnect_id = 0;
229 230 231 232 233

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

234
double		gp_hashagg_respill_bias = 1;
235 236 237 238 239

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

240 241
double		gp_motion_cost_per_row = 0;
int			gp_segments_for_planner = 0;
242

243
int			gp_hashagg_default_nbatches = 32;
244 245 246 247 248 249 250 251 252 253 254 255 256

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 */
257 258
int			gp_hashagg_spillbatch_min = 0;
int			gp_hashagg_spillbatch_max = 0;
259 260

/* hash join to use bloom filter: default to 0, means not used */
261
int			gp_hashjoin_bloomfilter = 0;
262 263

/* Analyzing aid */
264
int			gp_motion_slice_noop = 0;
265
#ifdef ENABLE_LTRACE
266
int			gp_ltrace_flag = 0;
267 268 269 270 271 272
#endif

/* 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 */
273
int			gp_distinct_grouping_sets_threshold = 32;
274
bool		gp_enable_explain_allstat = FALSE;
275 276
bool		gp_enable_motion_deadlock_sanity = FALSE;	/* planning time sanity
														 * check */
277 278 279 280 281 282

#ifdef USE_ASSERT_CHECKING
bool		gp_mk_sort_check = false;
#endif
int			gp_sort_flags = 0;
int			gp_dbg_flags = 0;
283
int			gp_sort_max_distinct = 20000;
284 285 286 287 288 289 290 291 292 293

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 */
294
bool		gp_encoding_check_locale_compatibility = true;
295 296

/* Priority for the segworkers relative to the postmaster's priority */
297
int			gp_segworker_relative_priority = PRIO_MAX;
298 299 300 301 302 303

/* 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;
304 305 306 307 308

int			gp_workfile_compress_algorithm = 0;
bool		gp_workfile_checksumming = false;
int			gp_workfile_caching_loglevel = DEBUG1;
int			gp_sessionstate_loglevel = DEBUG1;
309 310

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

313
/* Maximum disk space to use for workfiles per query on a segment, in kilobytes */
314 315
double		gp_workfile_limit_per_query = 0;

316
/* Maximum number of workfiles to be created by a query */
317 318 319
int			gp_workfile_limit_files_per_query = 0;
bool		gp_workfile_faultinject = false;
int			gp_workfile_bytes_to_checksum = 16;
320 321

/* The type of work files that HashJoin should use */
322
int			gp_workfile_type_hashjoin = 0;
323 324

/* Gpmon */
325 326
bool		gp_enable_gpperfmon = false;
int			gp_gpperfmon_send_interval = 1;
327 328 329
GpperfmonLogAlertLevel gpperfmon_log_alert_level = GPPERFMON_LOG_ALERT_LEVEL_NONE;

/* Enable single-slice single-row inserts ?*/
330
bool		gp_enable_fast_sri = true;
331 332

/* Enable single-mirror pair dispatch. */
333
bool		gp_enable_direct_dispatch = true;
334 335

/* Disable logging while creating mapreduce objects */
336
bool		gp_mapreduce_define = false;
337 338

/* request fault-prober pause */
339
bool		gp_fts_probe_pause = false;
340 341

/* Force core dump on memory context error */
342
bool		coredump_on_memerror = false;
343 344 345

/* Experimental feature for MPP-4082. Please read doc before setting this guc */
GpAutoStatsModeValue gp_autostats_mode;
346
char	   *gp_autostats_mode_string;
347
GpAutoStatsModeValue gp_autostats_mode_in_functions;
348 349 350 351
char	   *gp_autostats_mode_in_functions_string;
int			gp_autostats_on_change_threshold = 100000;
bool		log_autostats = true;

352 353 354 355
/* --------------------------------------------------------------------------------------------------
 * Miscellaneous developer use
 */

356
bool		gp_dev_notice_agg_cost = false;
357 358 359 360 361 362 363 364 365 366 367 368

/* --------------------------------------------------------------------------------------------------
 * 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.
 */
369
int			gp_debug_linger = 30;
370 371 372 373 374 375 376 377 378 379 380

/* ----------------
 * 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. */
381
int			gp_singleton_segindex;
382

383
bool		gp_cost_hashjoin_chainwalk = false;
384 385 386 387 388 389 390

/* ----------------
 * 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
 */
391
GpId		GpIdentity = {UNINITIALIZED_GP_IDENTITY_VALUE, UNINITIALIZED_GP_IDENTITY_VALUE, UNINITIALIZED_GP_IDENTITY_VALUE};
392 393 394 395 396 397 398 399

/*
 * 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.
 */
400
int			GpStandbyDbid = InvalidDbid;
401

402 403
void
verifyGpIdentityIsSet(void)
404
{
405 406 407 408 409 410
	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");
	}
411 412 413 414 415
}

/*
 * Keep track of a few dispatch-related  statistics:
 */
416 417 418
int			cdb_total_slices = 0;
int			cdb_total_plans = 0;
int			cdb_max_slices = 0;
419 420 421 422 423 424 425 426 427 428 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

/*
 * 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 *
490
assign_gp_session_role(const char *newval, bool doit, GucSource source __attribute__((unused)))
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
{
#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;
511 512 513

		if (Gp_role == GP_ROLE_UTILITY && MyProc != NULL)
			MyProc->mppIsWriter = false;
514 515 516 517 518 519 520
	}
	return newval;
}



/*
T
Tristan Su 已提交
521
 * Assign hook routine for "gp_role" option.  This variable has context
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
 * 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)
	{
		/*
549 550
		 * When changing between roles, we must call cdb_cleanup and then
		 * cdb_setup to get setup and connections appropriate to the new role.
551 552 553 554 555 556 557 558 559 560 561 562 563 564
		 */
		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)
565
			cdb_cleanup(0, 0);
566 567 568 569 570 571 572 573

		Gp_role = newrole;

		if (source != PGC_S_DEFAULT)
		{
			if (do_connect)
			{
				/*
574 575 576 577 578
				 * 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.
579 580 581 582 583 584 585
				 */
				PG_TRY();
				{
					cdb_setup();
				}
				PG_CATCH();
				{
586
					cdb_cleanup(0, 0);
587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
					Gp_role = oldrole;
					if (Gp_role != GP_ROLE_UTILITY)
						cdb_setup();
					PG_RE_THROW();
				}
				PG_END_TRY();
			}
		}
	}

	return newval;
}


/*
T
Tristan Su 已提交
602
 * Assign hook routine for "gp_connections_per_thread" option.  This variable has context
603 604 605 606 607 608
 * 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
609
assign_gp_connections_per_thread(int newval, bool doit, GucSource source __attribute__((unused)))
610 611 612
{
#if FALSE
	elog(DEBUG1, "assign_gp_connections_per_thread: gp_connections_per_thread=%s, newval=%d, doit=%s",
613
		 show_gp_connections_per_thread(), newval, (doit ? "true" : "false"));
614 615 616 617
#endif

	if (doit)
	{
618
		if (newval < 0)
619 620
			return false;

621 622
		cdbdisp_setAsync(newval == 0);
		cdbgang_setAsync(newval == 0);
623 624 625 626 627 628 629 630 631 632 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
		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?
684 685
 * "OFF"	 -> only errors are logged
 * "TERSE"	 -> terse logging of routine events, e.g. creation of new qExecs
686
 * "VERBOSE" -> gang allocation per command is logged
687
 * "DEBUG"	 -> additional events are logged at severity level DEBUG1 to DEBUG5
688 689 690 691
 *
 * The messages that are enabled by the TERSE and VERBOSE settings are
 * written with a severity level of LOG.
 */
692
GpVars_Verbosity gp_log_gang;
693 694 695 696 697

/*
 * gp_log_fts (string)
 *
 * What kind of messages should the fault-prober log ?
698 699
 * "OFF"	 -> only errors are logged
 * "TERSE"	 -> terse logging of routine events
700
 * "VERBOSE" -> gang allocation per command is logged
701
 * "DEBUG"	 -> additional events are logged at severity level DEBUG1 to DEBUG5
702 703 704 705
 *
 * The messages that are enabled by the TERSE and VERBOSE settings are
 * written with a severity level of LOG.
 */
706
GpVars_Verbosity gp_log_fts;
707 708 709 710 711

/*
 * gp_log_interconnect (string)
 *
 * Should connections between internal processes be logged?  (qDisp/qExec/etc)
712 713
 * "OFF"	 -> connection errors are logged
 * "TERSE"	 -> terse logging of routine events, e.g. successful connections
714
 * "VERBOSE" -> most interconnect setup events are logged
715
 * "DEBUG"	 -> additional events are logged at severity level DEBUG1 to DEBUG5.
716 717 718 719
 *
 * The messages that are enabled by the TERSE and VERBOSE settings are
 * written with a severity level of LOG.
 */
720
GpVars_Verbosity gp_log_interconnect;
721 722 723 724

/*
 * gpvars_string_to_verbosity
 */
H
Heikki Linnakangas 已提交
725
static GpVars_Verbosity
726 727 728 729 730
gpvars_string_to_verbosity(const char *s)
{
	GpVars_Verbosity result;

	if (!s ||
731 732
		!s[0] ||
		!pg_strcasecmp("terse", s))
733 734 735 736 737 738 739
		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;
740 741
	else
		result = GPVARS_VERBOSITY_UNDEFINED;
742
	return result;
743
}	/* gpvars_string_to_verbosity */
744 745 746 747

/*
 * gpvars_verbosity_to_string
 */
H
Heikki Linnakangas 已提交
748
static const char *
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763
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*";
	}
764
}	/* gpvars_verbosity_to_string */
765 766

/*
767
 * gpperfmon_log_alert_level_to_string
768 769 770 771 772 773
 */
const char *
gpperfmon_log_alert_level_to_string(GpperfmonLogAlertLevel level)
{
	switch (level)
	{
774
		case GPPERFMON_LOG_ALERT_LEVEL_NONE:
775
			return "none";
776
		case GPPERFMON_LOG_ALERT_LEVEL_WARNING:
777
			return "warning";
778
		case GPPERFMON_LOG_ALERT_LEVEL_ERROR:
779
			return "error";
780
		case GPPERFMON_LOG_ALERT_LEVEL_FATAL:
781
			return "fatal";
782
		case GPPERFMON_LOG_ALERT_LEVEL_PANIC:
783 784
			return "panic";
		default:
785
			return "*undefined*";
786
	}
787
}
788 789 790 791 792

/*
 * gpperfmon_log_alert_level_from_string
 */
GpperfmonLogAlertLevel
793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811
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;
812 813 814 815 816 817 818
}

/*
 * gpvars_assign_gp_log_gangs
 * gpvars_show_gp_log_gangs
 */
const char *
819
gpvars_assign_gp_log_gang(const char *newval, bool doit, GucSource source __attribute__((unused)))
820 821 822 823
{
	GpVars_Verbosity v = gpvars_string_to_verbosity(newval);

	if (v == GPVARS_VERBOSITY_UNDEFINED)
824
		return NULL;
825 826 827
	if (doit)
		gp_log_gang = v;
	return newval;
828
}	/* gpvars_assign_gp_log_gangs */
829 830 831 832 833

const char *
gpvars_show_gp_log_gang(void)
{
	return gpvars_verbosity_to_string(gp_log_gang);
834
}	/* gpvars_show_gp_log_gangs */
835 836 837 838 839 840

/*
 * gpvars_assign_gp_log_fts
 * gpvars_show_gp_log_fts
 */
const char *
841
gpvars_assign_gp_log_fts(const char *newval, bool doit, GucSource source __attribute__((unused)))
842 843 844 845
{
	GpVars_Verbosity v = gpvars_string_to_verbosity(newval);

	if (v == GPVARS_VERBOSITY_UNDEFINED)
846
		return NULL;
847 848 849
	if (doit)
		gp_log_fts = v;
	return newval;
850
}	/* gpvars_assign_gp_log_fts */
851 852 853 854 855

const char *
gpvars_show_gp_log_fts(void)
{
	return gpvars_verbosity_to_string(gp_log_fts);
856
}	/* gpvars_show_gp_log_fts */
857 858 859 860 861 862

/*
 * gpvars_assign_gp_log_interconnect
 * gpvars_show_gp_log_interconnect
 */
const char *
863
gpvars_assign_gp_log_interconnect(const char *newval, bool doit, GucSource source __attribute__((unused)))
864 865 866 867
{
	GpVars_Verbosity v = gpvars_string_to_verbosity(newval);

	if (v == GPVARS_VERBOSITY_UNDEFINED)
868
		return NULL;
869 870 871
	if (doit)
		gp_log_interconnect = v;
	return newval;
872
}	/* gpvars_assign_gp_log_interconnect */
873 874 875 876 877

const char *
gpvars_show_gp_log_interconnect(void)
{
	return gpvars_verbosity_to_string(gp_log_interconnect);
878
}	/* gpvars_show_gp_log_interconnect */
879 880 881 882 883 884 885


/*
 * gpvars_assign_gp_interconnect_type
 * gpvars_show_gp_interconnect_type
 */
const char *
886
gpvars_assign_gp_interconnect_type(const char *newval, bool doit, GucSource source __attribute__((unused)))
887
{
888
	int			newtype = 0;
889

890 891
	if (newval == NULL || newval[0] == 0)
		newtype = INTERCONNECT_TYPE_UDPIFC;
892 893 894
	else if (!pg_strcasecmp("udpifc", newval))
		newtype = INTERCONNECT_TYPE_UDPIFC;
	else
895
		elog(ERROR, "Only support UDPIFC, (current type is '%s')", gpvars_show_gp_interconnect_type());
896 897 898 899 900 901 902

	if (doit)
	{
		Gp_interconnect_type = newtype;
	}

	return newval;
903
}	/* gpvars_assign_gp_log_interconnect */
904 905 906 907

const char *
gpvars_show_gp_interconnect_type(void)
{
908
	return "UDPIFC";
909
}	/* gpvars_show_gp_log_interconnect */
910 911 912 913 914 915

/*
 * gpvars_assign_gp_interconnect_fc_method
 * gpvars_show_gp_interconnect_fc_method
 */
const char *
916
gpvars_assign_gp_interconnect_fc_method(const char *newval, bool doit, GucSource source __attribute__((unused)))
917
{
918
	int			newmethod = 0;
919 920 921 922 923 924 925 926 927 928 929 930 931 932 933

	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;
934
}	/* gpvars_assign_gp_interconnect_fc_method */
935 936 937 938

const char *
gpvars_show_gp_interconnect_fc_method(void)
{
939
	switch (Gp_interconnect_fc_method)
940 941 942 943 944 945 946 947
	{
		case INTERCONNECT_FC_METHOD_CAPACITY:
			return "CAPACITY";
		case INTERCONNECT_FC_METHOD_LOSS:
			return "LOSS";
		default:
			return "CAPACITY";
	}
948
}	/* gpvars_show_gp_interconnect_fc_method */
949 950 951 952 953 954 955

/*
 * 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)
{
956
	int			newtype = 0;
957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973

	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;
974

975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993
		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 *
994
gpvars_assign_gp_autostats_mode(const char *newval, bool doit, GucSource source __attribute__((unused)))
995
{
996
	int			newtype = gpvars_parse_gp_autostats_mode(newval, false /* inFunctions */ );
997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013

	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;
1014

1015 1016 1017 1018 1019 1020 1021 1022
	if (inFunctions)
	{
		autostats_mode = gp_autostats_mode_in_functions;
	}
	else
	{
		autostats_mode = gp_autostats_mode;
	}
1023
	switch (autostats_mode)
1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038
	{
		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)
{
1039
	return gpvars_show_gp_autostats_mode_common(false /* inFunctions */ );
1040 1041 1042 1043 1044 1045 1046 1047
}

/*
 * gpvars_assign_gp_autostats_mode_in_functions
 * gpvars_show_gp_autostats_mode_in_functions
 */

const char *
1048
gpvars_assign_gp_autostats_mode_in_functions(const char *newval, bool doit, GucSource source __attribute__((unused)))
1049
{
1050 1051
	bool		inFunctions = true;
	int			newtype = gpvars_parse_gp_autostats_mode(newval, inFunctions);
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064

	if (doit)
	{
		gp_autostats_mode_in_functions = newtype;
	}

	return newval;
}


const char *
gpvars_show_gp_autostats_mode_in_functions(void)
{
1065
	return gpvars_show_gp_autostats_mode_common(true /* inFunctions */ );
1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085
}

/* 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,
1086 1087
					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
					 errmsg("must be superuser to set gp_enable_gpperfmon")));
1088 1089 1090
		}
		else
		{
1091
			gp_enable_gpperfmon = newval;
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106
		}
	}

	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),
1107
			 errmsg("must be superuser to set gp_gpperfmon_send_interval")));
1108 1109 1110
		}
		else
		{
1111
			gp_gpperfmon_send_interval = newval;
1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122
		}
	}

	return true;
}

const char *
gpvars_assign_gp_gpperfmon_log_alert_level(const char *newval, bool doit, GucSource source)
{
	if (doit)
	{
1123
		if (!pg_strcasecmp(newval, "none"))
1124 1125 1126
		{
			gpperfmon_log_alert_level = GPPERFMON_LOG_ALERT_LEVEL_NONE;
		}
1127
		else if (!pg_strcasecmp(newval, "warning"))
1128 1129 1130
		{
			gpperfmon_log_alert_level = GPPERFMON_LOG_ALERT_LEVEL_WARNING;
		}
1131
		else if (!pg_strcasecmp(newval, "error"))
1132 1133 1134
		{
			gpperfmon_log_alert_level = GPPERFMON_LOG_ALERT_LEVEL_ERROR;
		}
1135
		else if (!pg_strcasecmp(newval, "fatal"))
1136 1137 1138
		{
			gpperfmon_log_alert_level = GPPERFMON_LOG_ALERT_LEVEL_FATAL;
		}
1139
		else if (!pg_strcasecmp(newval, "panic"))
1140 1141 1142 1143 1144
		{
			gpperfmon_log_alert_level = GPPERFMON_LOG_ALERT_LEVEL_PANIC;
		}
		else
		{
1145
			elog(ERROR, "Unknown log alert level '%s'. (current value is '%s')", newval, gpperfmon_log_alert_level_to_string(gpperfmon_log_alert_level));
1146 1147 1148 1149 1150 1151 1152 1153 1154
		}
	}

	return newval;
}

const char *
gpvars_show_gp_gpperfmon_log_alert_level(void)
{
1155
	return gpperfmon_log_alert_level_to_string(gpperfmon_log_alert_level);
1156
}
1157

1158 1159 1160 1161 1162 1163 1164 1165 1166 1167
/*
 * 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)
	{
		/*
1168 1169
		 * We only want to do fancy stuff on the master (where we have a
		 * prober).
1170 1171 1172 1173
		 */
		if (ftsProbeInfo && Gp_segment == -1)
		{
			/*
1174 1175
			 * fts_pauseProbes is externally set/cleared; fts_cancelProbes is
			 * externally set and cleared by FTS
1176 1177 1178 1179 1180 1181 1182
			 */
			ftsLock();
			ftsProbeInfo->fts_pauseProbes = newval;
			ftsProbeInfo->fts_discardResults = ftsProbeInfo->fts_discardResults || newval;
			ftsUnlock();

			/*
1183 1184
			 * If we're unpausing, we want to force the prober to re-read
			 * everything. (we want FtsNotifyProber()).
1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196
			 */
			if (!newval)
			{
				FtsNotifyProber();
			}
		}
		gp_fts_probe_pause = newval;
	}

	return true;
}

1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236
/*
 * gpvars_assign_gp_resource_manager_policy
 * gpvars_show_gp_resource_manager_policy
 */
const char *
gpvars_assign_gp_resource_manager_policy(const char *newval, bool doit, GucSource source __attribute__((unused)))
{
	ResourceManagerPolicy newtype = RESOURCE_MANAGER_POLICY_QUEUE;

	if (newval == NULL || newval[0] == 0 )
		newtype = RESOURCE_MANAGER_POLICY_QUEUE;
	else if (!pg_strcasecmp("queue", newval))
		newtype = RESOURCE_MANAGER_POLICY_QUEUE;
	else if (!pg_strcasecmp("group", newval))
		newtype = RESOURCE_MANAGER_POLICY_GROUP;
	else
		elog(ERROR, "unknown resource manager policy: current policy is '%s'", gpvars_show_gp_resource_manager_policy());

	if (doit)
	{
		Gp_resource_manager_policy = newtype;
	}

	return newval;
}

const char *
gpvars_show_gp_resource_manager_policy(void)
{
	switch (Gp_resource_manager_policy)
	{
		case RESOURCE_MANAGER_POLICY_QUEUE:
			return "queue";
		case RESOURCE_MANAGER_POLICY_GROUP:
			return "group";
		default:
			Assert(!"unexpected resource manager policy");
			return "unknown";
	}
}
1237 1238 1239 1240 1241
/*
 * gpvars_assign_gp_resqueue_memory_policy
 * gpvars_show_gp_resqueue_memory_policy
 */
const char *
1242
gpvars_assign_gp_resqueue_memory_policy(const char *newval, bool doit, GucSource source __attribute__((unused)))
1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266
{
	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)
{
1267
	switch (gp_resqueue_memory_policy)
1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283
	{
		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
1284
gpvars_assign_statement_mem(int newval, bool doit, GucSource source __attribute__((unused)))
1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300
{
	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
1301
 *	  Increment gp_command_count. If the new command count is 0 or a negative number, reset it to 1.
1302 1303 1304 1305 1306 1307 1308 1309
 */
void
increment_command_count()
{
	if (gp_cancel_query_print_log)
	{
		ereport(LOG,
				(errmsg("Incrementing command count from %d to %d",
1310 1311
						gp_command_count, gp_command_count + 1),
				 errprintstack(true)));
1312 1313 1314 1315 1316 1317 1318 1319
	}

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