diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index ff42fb92d69..743557ac3eb 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -66,6 +66,7 @@ #include "utils/resowner.h" #include "utils/timestamp.h" +uint32 (*get_pin_limit_hook)(void); /* Note: these two macros only work on shared buffers, not local ones! */ #define BufHdrGetBlock(bufHdr) ((Block) (BufferBlocks + ((Size) (bufHdr)->buf_id) * BLCKSZ)) @@ -2131,7 +2132,7 @@ LimitAdditionalPins(uint32 *additional_pins) return; max_backends = MaxBackends + NUM_AUXILIARY_PROCS; - max_proportional_pins = NBuffers / max_backends; + max_proportional_pins = get_pin_limit_hook ? get_pin_limit_hook() : NBuffers / max_backends; /* * Subtract the approximate number of buffers already pinned by this diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 5ff0d0bd177..b3a44583eea 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -107,6 +107,10 @@ int client_connection_check_interval = 0; /* flags for non-system relation kinds to restrict use */ int restrict_nonsystem_relation_kind; +#ifdef USE_INJECTION_POINTS +/* Counter which can show us if we are in SMGR */ +int inside_smgr_api = 0; +#endif /* ---------------- * private typedefs etc * ---------------- @@ -3275,6 +3279,12 @@ ProcessInterrupts(void) /* OK to accept any interrupts now? */ if (InterruptHoldoffCount != 0 || CritSectionCount != 0) return; +#ifdef USE_INJECTION_POINTS + if (inside_smgr_api > 0) + { + INJECTION_POINT("SMGR_API"); + } +#endif InterruptPending = false; retry: diff --git a/src/include/postgres.h b/src/include/postgres.h index 5d5fd7813e8..7d22dc0c946 100644 --- a/src/include/postgres.h +++ b/src/include/postgres.h @@ -577,3 +577,8 @@ extern Datum Float8GetDatum(float8 X); #endif #endif /* POSTGRES_H */ + +/* Declare for neon use */ +#ifdef USE_INJECTION_POINTS +extern int inside_smgr_api; +#endif diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h index a6c2beb06d8..9f3a9a4e247 100644 --- a/src/include/storage/bufmgr.h +++ b/src/include/storage/bufmgr.h @@ -325,6 +325,7 @@ extern int GetAccessStrategyPinLimit(BufferAccessStrategy strategy); extern void FreeAccessStrategy(BufferAccessStrategy strategy); +extern uint32 (*get_pin_limit_hook)(void); /* inline functions */ diff --git a/src/test/modules/injection_points/injection_points.c b/src/test/modules/injection_points/injection_points.c index 1b695a18203..e7e386111d3 100644 --- a/src/test/modules/injection_points/injection_points.c +++ b/src/test/modules/injection_points/injection_points.c @@ -16,6 +16,7 @@ */ #include "postgres.h" +#include #include "fmgr.h" #include "miscadmin.h" @@ -59,6 +60,8 @@ typedef struct InjectionPointCondition /* ID of the process where the injection point is allowed to run */ int pid; + /* probability in [0,1], 1.0 = always */ + double prob; } InjectionPointCondition; /* @@ -88,6 +91,8 @@ static InjectionPointSharedState *inj_state = NULL; extern PGDLLEXPORT void injection_error(const char *name, const void *private_data); +extern PGDLLEXPORT void injection_error_prob(const char *name, + const void *private_data); extern PGDLLEXPORT void injection_notice(const char *name, const void *private_data); extern PGDLLEXPORT void injection_wait(const char *name, @@ -95,6 +100,7 @@ extern PGDLLEXPORT void injection_wait(const char *name, /* track if injection points attached in this process are linked to it */ static bool injection_point_local = false; +static double action2prob(const char *action, int pos); /* * Callback for shared memory area initialization. @@ -184,7 +190,20 @@ injection_error(const char *name, const void *private_data) elog(ERROR, "error triggered for injection point %s", name); } +void +injection_error_prob(const char *name, const void *private_data) +{ + InjectionPointCondition *condition = (InjectionPointCondition *) private_data; + if (!injection_point_allowed(condition)) + return; + + /* Use the probability stored in the condition. */ + if ((double) rand() / (double) RAND_MAX > condition->prob) + return; + + elog(ERROR, "error triggered for injection point %s", name); +} void injection_notice(const char *name, const void *private_data) { @@ -278,6 +297,11 @@ injection_points_attach(PG_FUNCTION_ARGS) function = "injection_notice"; else if (strcmp(action, "wait") == 0) function = "injection_wait"; + else if (strncmp(action, "error-prob-", 11) == 0) + { + condition.prob = action2prob(action, 11); + function = "injection_error_prob"; + } else elog(ERROR, "incorrect action \"%s\" for injection point creation", action); @@ -402,3 +426,29 @@ injection_points_detach(PG_FUNCTION_ARGS) PG_RETURN_VOID(); } + +/* + * Coverts the action name into probability + */ +static double action2prob(const char *action, const int pos) +{ + /* + * Simple parser: convert "0-01" -> "0.01" then strtod(). + */ + const char *p = action + pos; /* points to "0-01" */ + double prob; + char *endptr; + char buf[32]; + int i, j; + + for (i = 0, j = 0; p[i] != '\0' && j < (int) sizeof(buf) - 1; i++) + { + buf[j++] = (p[i] == '-') ? '.' : p[i]; + } + buf[j] = '\0'; + errno = 0; + prob = strtod(buf, &endptr); + if (errno != 0 || endptr == buf || prob < 0.0 || prob > 1.0) + elog(ERROR, "invalid probability in action \"%s\"", action); + return prob; +}