diff options
Diffstat (limited to 'src/backend/utils/misc/injection_point.c')
-rw-r--r-- | src/backend/utils/misc/injection_point.c | 55 |
1 files changed, 44 insertions, 11 deletions
diff --git a/src/backend/utils/misc/injection_point.c b/src/backend/utils/misc/injection_point.c index 0cf4d51cac4..5c2a0d2297e 100644 --- a/src/backend/utils/misc/injection_point.c +++ b/src/backend/utils/misc/injection_point.c @@ -42,6 +42,7 @@ static HTAB *InjectionPointHash; /* find points from names */ #define INJ_NAME_MAXLEN 64 #define INJ_LIB_MAXLEN 128 #define INJ_FUNC_MAXLEN 128 +#define INJ_PRIVATE_MAXLEN 1024 /* Single injection point stored in InjectionPointHash */ typedef struct InjectionPointEntry @@ -49,6 +50,12 @@ typedef struct InjectionPointEntry char name[INJ_NAME_MAXLEN]; /* hash key */ char library[INJ_LIB_MAXLEN]; /* library */ char function[INJ_FUNC_MAXLEN]; /* function */ + + /* + * Opaque data area that modules can use to pass some custom data to + * callbacks, registered when attached. + */ + char private_data[INJ_PRIVATE_MAXLEN]; } InjectionPointEntry; #define INJECTION_POINT_HASH_INIT_SIZE 16 @@ -61,6 +68,7 @@ typedef struct InjectionPointEntry typedef struct InjectionPointCacheEntry { char name[INJ_NAME_MAXLEN]; + char private_data[INJ_PRIVATE_MAXLEN]; InjectionPointCallback callback; } InjectionPointCacheEntry; @@ -73,7 +81,8 @@ static HTAB *InjectionPointCache = NULL; */ static void injection_point_cache_add(const char *name, - InjectionPointCallback callback) + InjectionPointCallback callback, + const void *private_data) { InjectionPointCacheEntry *entry; bool found; @@ -99,6 +108,8 @@ injection_point_cache_add(const char *name, Assert(!found); strlcpy(entry->name, name, sizeof(entry->name)); entry->callback = callback; + if (private_data != NULL) + memcpy(entry->private_data, private_data, INJ_PRIVATE_MAXLEN); } /* @@ -124,11 +135,14 @@ injection_point_cache_remove(const char *name) * Retrieve an injection point from the local cache, if any. */ static InjectionPointCallback -injection_point_cache_get(const char *name) +injection_point_cache_get(const char *name, const void **private_data) { bool found; InjectionPointCacheEntry *entry; + if (private_data) + *private_data = NULL; + /* no callback if no cache yet */ if (InjectionPointCache == NULL) return NULL; @@ -137,7 +151,11 @@ injection_point_cache_get(const char *name) hash_search(InjectionPointCache, name, HASH_FIND, &found); if (found) + { + if (private_data) + *private_data = entry->private_data; return entry->callback; + } return NULL; } @@ -186,7 +204,9 @@ InjectionPointShmemInit(void) void InjectionPointAttach(const char *name, const char *library, - const char *function) + const char *function, + const void *private_data, + int private_data_size) { #ifdef USE_INJECTION_POINTS InjectionPointEntry *entry_by_name; @@ -201,6 +221,9 @@ InjectionPointAttach(const char *name, if (strlen(function) >= INJ_FUNC_MAXLEN) elog(ERROR, "injection point function %s too long (maximum of %u)", function, INJ_FUNC_MAXLEN); + if (private_data_size >= INJ_PRIVATE_MAXLEN) + elog(ERROR, "injection point data too long (maximum of %u)", + INJ_PRIVATE_MAXLEN); /* * Allocate and register a new injection point. A new point should not @@ -223,6 +246,8 @@ InjectionPointAttach(const char *name, entry_by_name->library[INJ_LIB_MAXLEN - 1] = '\0'; strlcpy(entry_by_name->function, function, sizeof(entry_by_name->function)); entry_by_name->function[INJ_FUNC_MAXLEN - 1] = '\0'; + if (private_data != NULL) + memcpy(entry_by_name->private_data, private_data, private_data_size); LWLockRelease(InjectionPointLock); @@ -233,8 +258,10 @@ InjectionPointAttach(const char *name, /* * Detach an existing injection point. + * + * Returns true if the injection point was detached, false otherwise. */ -void +bool InjectionPointDetach(const char *name) { #ifdef USE_INJECTION_POINTS @@ -245,10 +272,12 @@ InjectionPointDetach(const char *name) LWLockRelease(InjectionPointLock); if (!found) - elog(ERROR, "injection point \"%s\" not found", name); + return false; + return true; #else elog(ERROR, "Injection points are not supported by this build"); + return true; /* silence compiler */ #endif } @@ -265,6 +294,7 @@ InjectionPointRun(const char *name) InjectionPointEntry *entry_by_name; bool found; InjectionPointCallback injection_callback; + const void *private_data; LWLockAcquire(InjectionPointLock, LW_SHARED); entry_by_name = (InjectionPointEntry *) @@ -286,10 +316,10 @@ InjectionPointRun(const char *name) * Check if the callback exists in the local cache, to avoid unnecessary * external loads. */ - injection_callback = injection_point_cache_get(name); - if (injection_callback == NULL) + if (injection_point_cache_get(name, NULL) == NULL) { char path[MAXPGPATH]; + InjectionPointCallback injection_callback_local; /* not found in local cache, so load and register */ snprintf(path, MAXPGPATH, "%s/%s%s", pkglib_path, @@ -299,18 +329,21 @@ InjectionPointRun(const char *name) elog(ERROR, "could not find library \"%s\" for injection point \"%s\"", path, name); - injection_callback = (InjectionPointCallback) + injection_callback_local = (InjectionPointCallback) load_external_function(path, entry_by_name->function, false, NULL); - if (injection_callback == NULL) + if (injection_callback_local == NULL) elog(ERROR, "could not find function \"%s\" in library \"%s\" for injection point \"%s\"", entry_by_name->function, path, name); /* add it to the local cache when found */ - injection_point_cache_add(name, injection_callback); + injection_point_cache_add(name, injection_callback_local, + entry_by_name->private_data); } - injection_callback(name); + /* Now loaded, so get it. */ + injection_callback = injection_point_cache_get(name, &private_data); + injection_callback(name, private_data); #else elog(ERROR, "Injection points are not supported by this build"); #endif |