|
97 | 97 | #include "storage/smgr.h"
|
98 | 98 | #include "storage/spin.h"
|
99 | 99 | #include "storage/sync.h"
|
100 |
| -#include "utils/guc.h" |
| 100 | +#include "utils/guc_hooks.h" |
| 101 | +#include "utils/guc_tables.h" |
101 | 102 | #include "utils/memutils.h"
|
102 | 103 | #include "utils/ps_status.h"
|
103 | 104 | #include "utils/relmapper.h"
|
104 | 105 | #include "utils/pg_rusage.h"
|
105 | 106 | #include "utils/snapmgr.h"
|
106 | 107 | #include "utils/timeout.h"
|
107 | 108 | #include "utils/timestamp.h"
|
| 109 | +#include "utils/varlena.h" |
108 | 110 |
|
109 | 111 | extern uint32 bootstrap_data_checksum_version;
|
110 | 112 |
|
@@ -160,6 +162,12 @@ int CheckPointSegments;
|
160 | 162 | static double CheckPointDistanceEstimate = 0;
|
161 | 163 | static double PrevCheckPointDistance = 0;
|
162 | 164 |
|
| 165 | +/* |
| 166 | + * Track whether there were any deferred checks for custom resource managers |
| 167 | + * specified in wal_consistency_checking. |
| 168 | + */ |
| 169 | +static bool check_wal_consistency_checking_deferred = false; |
| 170 | + |
163 | 171 | /*
|
164 | 172 | * GUC support
|
165 | 173 | */
|
@@ -4304,6 +4312,172 @@ check_wal_buffers(int *newval, void **extra, GucSource source)
|
4304 | 4312 | return true;
|
4305 | 4313 | }
|
4306 | 4314 |
|
| 4315 | +/* |
| 4316 | + * GUC check_hook for wal_consistency_checking |
| 4317 | + */ |
| 4318 | +bool |
| 4319 | +check_wal_consistency_checking(char **newval, void **extra, GucSource source) |
| 4320 | +{ |
| 4321 | + char *rawstring; |
| 4322 | + List *elemlist; |
| 4323 | + ListCell *l; |
| 4324 | + bool newwalconsistency[RM_MAX_ID + 1]; |
| 4325 | + |
| 4326 | + /* Initialize the array */ |
| 4327 | + MemSet(newwalconsistency, 0, (RM_MAX_ID + 1) * sizeof(bool)); |
| 4328 | + |
| 4329 | + /* Need a modifiable copy of string */ |
| 4330 | + rawstring = pstrdup(*newval); |
| 4331 | + |
| 4332 | + /* Parse string into list of identifiers */ |
| 4333 | + if (!SplitIdentifierString(rawstring, ',', &elemlist)) |
| 4334 | + { |
| 4335 | + /* syntax error in list */ |
| 4336 | + GUC_check_errdetail("List syntax is invalid."); |
| 4337 | + pfree(rawstring); |
| 4338 | + list_free(elemlist); |
| 4339 | + return false; |
| 4340 | + } |
| 4341 | + |
| 4342 | + foreach(l, elemlist) |
| 4343 | + { |
| 4344 | + char *tok = (char *) lfirst(l); |
| 4345 | + int rmid; |
| 4346 | + |
| 4347 | + /* Check for 'all'. */ |
| 4348 | + if (pg_strcasecmp(tok, "all") == 0) |
| 4349 | + { |
| 4350 | + for (rmid = 0; rmid <= RM_MAX_ID; rmid++) |
| 4351 | + if (RmgrIdExists(rmid) && GetRmgr(rmid).rm_mask != NULL) |
| 4352 | + newwalconsistency[rmid] = true; |
| 4353 | + } |
| 4354 | + else |
| 4355 | + { |
| 4356 | + /* Check if the token matches any known resource manager. */ |
| 4357 | + bool found = false; |
| 4358 | + |
| 4359 | + for (rmid = 0; rmid <= RM_MAX_ID; rmid++) |
| 4360 | + { |
| 4361 | + if (RmgrIdExists(rmid) && GetRmgr(rmid).rm_mask != NULL && |
| 4362 | + pg_strcasecmp(tok, GetRmgr(rmid).rm_name) == 0) |
| 4363 | + { |
| 4364 | + newwalconsistency[rmid] = true; |
| 4365 | + found = true; |
| 4366 | + break; |
| 4367 | + } |
| 4368 | + } |
| 4369 | + if (!found) |
| 4370 | + { |
| 4371 | + /* |
| 4372 | + * During startup, it might be a not-yet-loaded custom |
| 4373 | + * resource manager. Defer checking until |
| 4374 | + * InitializeWalConsistencyChecking(). |
| 4375 | + */ |
| 4376 | + if (!process_shared_preload_libraries_done) |
| 4377 | + { |
| 4378 | + check_wal_consistency_checking_deferred = true; |
| 4379 | + } |
| 4380 | + else |
| 4381 | + { |
| 4382 | + GUC_check_errdetail("Unrecognized key word: \"%s\".", tok); |
| 4383 | + pfree(rawstring); |
| 4384 | + list_free(elemlist); |
| 4385 | + return false; |
| 4386 | + } |
| 4387 | + } |
| 4388 | + } |
| 4389 | + } |
| 4390 | + |
| 4391 | + pfree(rawstring); |
| 4392 | + list_free(elemlist); |
| 4393 | + |
| 4394 | + /* assign new value */ |
| 4395 | + *extra = guc_malloc(ERROR, (RM_MAX_ID + 1) * sizeof(bool)); |
| 4396 | + memcpy(*extra, newwalconsistency, (RM_MAX_ID + 1) * sizeof(bool)); |
| 4397 | + return true; |
| 4398 | +} |
| 4399 | + |
| 4400 | +/* |
| 4401 | + * GUC assign_hook for wal_consistency_checking |
| 4402 | + */ |
| 4403 | +void |
| 4404 | +assign_wal_consistency_checking(const char *newval, void *extra) |
| 4405 | +{ |
| 4406 | + /* |
| 4407 | + * If some checks were deferred, it's possible that the checks will fail |
| 4408 | + * later during InitializeWalConsistencyChecking(). But in that case, the |
| 4409 | + * postmaster will exit anyway, so it's safe to proceed with the |
| 4410 | + * assignment. |
| 4411 | + * |
| 4412 | + * Any built-in resource managers specified are assigned immediately, |
| 4413 | + * which affects WAL created before shared_preload_libraries are |
| 4414 | + * processed. Any custom resource managers specified won't be assigned |
| 4415 | + * until after shared_preload_libraries are processed, but that's OK |
| 4416 | + * because WAL for a custom resource manager can't be written before the |
| 4417 | + * module is loaded anyway. |
| 4418 | + */ |
| 4419 | + wal_consistency_checking = extra; |
| 4420 | +} |
| 4421 | + |
| 4422 | +/* |
| 4423 | + * InitializeWalConsistencyChecking: run after loading custom resource managers |
| 4424 | + * |
| 4425 | + * If any unknown resource managers were specified in the |
| 4426 | + * wal_consistency_checking GUC, processing was deferred. Now that |
| 4427 | + * shared_preload_libraries have been loaded, process wal_consistency_checking |
| 4428 | + * again. |
| 4429 | + */ |
| 4430 | +void |
| 4431 | +InitializeWalConsistencyChecking(void) |
| 4432 | +{ |
| 4433 | + Assert(process_shared_preload_libraries_done); |
| 4434 | + |
| 4435 | + if (check_wal_consistency_checking_deferred) |
| 4436 | + { |
| 4437 | + struct config_generic *guc; |
| 4438 | + |
| 4439 | + guc = find_option("wal_consistency_checking", false, false, ERROR); |
| 4440 | + |
| 4441 | + check_wal_consistency_checking_deferred = false; |
| 4442 | + |
| 4443 | + set_config_option_ext("wal_consistency_checking", |
| 4444 | + wal_consistency_checking_string, |
| 4445 | + guc->scontext, guc->source, guc->srole, |
| 4446 | + GUC_ACTION_SET, true, ERROR, false); |
| 4447 | + |
| 4448 | + /* checking should not be deferred again */ |
| 4449 | + Assert(!check_wal_consistency_checking_deferred); |
| 4450 | + } |
| 4451 | +} |
| 4452 | + |
| 4453 | +/* |
| 4454 | + * GUC show_hook for archive_command |
| 4455 | + */ |
| 4456 | +const char * |
| 4457 | +show_archive_command(void) |
| 4458 | +{ |
| 4459 | + if (XLogArchivingActive()) |
| 4460 | + return XLogArchiveCommand; |
| 4461 | + else |
| 4462 | + return "(disabled)"; |
| 4463 | +} |
| 4464 | + |
| 4465 | +/* |
| 4466 | + * GUC show_hook for in_hot_standby |
| 4467 | + */ |
| 4468 | +const char * |
| 4469 | +show_in_hot_standby(void) |
| 4470 | +{ |
| 4471 | + /* |
| 4472 | + * We display the actual state based on shared memory, so that this GUC |
| 4473 | + * reports up-to-date state if examined intra-query. The underlying |
| 4474 | + * variable (in_hot_standby_guc) changes only when we transmit a new value |
| 4475 | + * to the client. |
| 4476 | + */ |
| 4477 | + return RecoveryInProgress() ? "on" : "off"; |
| 4478 | +} |
| 4479 | + |
| 4480 | + |
4307 | 4481 | /*
|
4308 | 4482 | * Read the control file, set respective GUCs.
|
4309 | 4483 | *
|
|
0 commit comments