mirror of https://github.com/sysown/proxysql
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
271 lines
11 KiB
271 lines
11 KiB
/**
|
|
* @file genai_plugin.h
|
|
* @brief GenAI plugin shared context + plugin-wide entry points.
|
|
*
|
|
* Holds the singletons the plugin owns at runtime (services pointer
|
|
* received during init, optional Anomaly_Detector instance, Prometheus
|
|
* counter handles), plus declarations for helper functions defined in
|
|
* sibling translation units (e.g. plugin_hooks.cpp).
|
|
*
|
|
* Lifecycle is documented per-field below. Plugins MUST NOT touch any
|
|
* field that depends on Admin DBs (none today; Step 4 will add some)
|
|
* before `start()` runs — see ProxySQL_Plugin.h for the full contract.
|
|
*
|
|
* @see plugins/genai/src/plugin_main.cpp for descriptor + lifecycle.
|
|
* @see plugins/genai/src/plugin_hooks.cpp for the query-hook adapter.
|
|
*/
|
|
|
|
#ifndef PROXYSQL_GENAI_PLUGIN_H
|
|
#define PROXYSQL_GENAI_PLUGIN_H
|
|
|
|
#include "ProxySQL_Plugin.h"
|
|
|
|
#include <atomic>
|
|
|
|
namespace prometheus { class Counter; }
|
|
class Anomaly_Detector;
|
|
class MCP_Threads_Handler;
|
|
class GenAI_Threads_Handler;
|
|
|
|
/**
|
|
* @brief Process-wide state shared across the plugin's translation units.
|
|
*
|
|
* Singleton accessed via genai_context(). Populated by `genai_init()`
|
|
* and `genai_start()` in plugin_main.cpp; torn down by `genai_stop()`.
|
|
*/
|
|
struct GenAIPluginContext {
|
|
/// Services callbacks vended by core during init(). Borrowed; do
|
|
/// not free. Valid for the plugin's entire lifetime.
|
|
ProxySQL_PluginServices* services { nullptr };
|
|
|
|
/// True between successful start() and stop(). Hot-path readers
|
|
/// outside the plugin lifecycle (e.g. the query-hook adapter) read
|
|
/// it relaxed; it is only mutated on the lifecycle thread.
|
|
std::atomic<bool> started { false };
|
|
|
|
/// Anomaly detector instance. Created during init(), deleted
|
|
/// during stop(). nullptr before init() and after stop().
|
|
Anomaly_Detector* anomaly_detector { nullptr };
|
|
|
|
/// Prometheus counter for anomalies *detected* (any risk threshold).
|
|
/// Registered against the shared registry during init(); pointer
|
|
/// remains valid for the registry's lifetime (the plugin does not
|
|
/// own the underlying storage). nullptr if registration failed.
|
|
prometheus::Counter* metric_detected_anomalies { nullptr };
|
|
|
|
/// Prometheus counter for anomalies that were *blocked* (DENY
|
|
/// returned to the client). Same lifetime rules as above.
|
|
prometheus::Counter* metric_blocked_queries { nullptr };
|
|
|
|
/// MCP listener handler. Replaces the former core global
|
|
/// `GloMCPH` as of Step 4.C. Constructed in `genai_init()`,
|
|
/// started by `genai_start()`, torn down by `genai_stop()`.
|
|
/// See plugins/genai/src/MCP_Thread.cpp for the listener
|
|
/// implementation.
|
|
MCP_Threads_Handler* mcp { nullptr };
|
|
};
|
|
|
|
/**
|
|
* @brief Reload the GenAI runtime components after genai-* variables change.
|
|
*
|
|
* Defined in plugin_main.cpp. Tears down and reinitialises the
|
|
* `GloGATH` (GenAI_Threads_Handler) and `GloAI` (AI_Features_Manager)
|
|
* singletons in place — the only way to pick up changes to bootstrap-
|
|
* time values like worker count, embedding endpoint, or LLM-bridge
|
|
* provider configuration.
|
|
*
|
|
* @par Concurrency contract
|
|
* Caller MUST guarantee no other thread is dereferencing `GloGATH` or
|
|
* `GloAI` while this runs. The teardown calls `delete`-equivalent
|
|
* `shutdown()` methods on both globals; concurrent reads from MCP
|
|
* listener threads, tool-handler workers, or the anomaly-detector hot
|
|
* path would observe a half-destroyed handler. Today the function is
|
|
* called from:
|
|
*
|
|
* 1. `genai_start()` — single-threaded plugin lifecycle, no traffic
|
|
* yet, always safe.
|
|
* 2. `LOAD GENAI VARIABLES TO RUNTIME` admin command — runs on the
|
|
* admin SQL thread while MCP listener / tool handlers may be
|
|
* actively serving requests. Currently this is racy; the
|
|
* practical mitigation is operator-side: quiesce traffic before
|
|
* issuing the LOAD command, or accept the brief reload window.
|
|
* 3. `LOAD GENAI VARIABLES FROM CONFIG` — same constraint as (2).
|
|
*
|
|
* Adding a proper rwlock-around-GloGATH/GloAI is a follow-up tracked
|
|
* separately; it touches every consumer of those globals (not just
|
|
* the reload path) and is too large for this carve-out PR.
|
|
*/
|
|
bool genai_refresh_runtime_components(GenAIPluginContext& ctx);
|
|
|
|
/**
|
|
* @brief Accessor for the plugin's shared context singleton.
|
|
*
|
|
* Meyers-singleton; thread-safe construction since C++11. Callers
|
|
* may treat the returned reference as having static storage duration.
|
|
*/
|
|
GenAIPluginContext& genai_context();
|
|
|
|
/**
|
|
* @brief Format-style log helper that routes through the chassis
|
|
* services->log_message callback (so messages land in
|
|
* proxysql.log) and falls back to stderr if the chassis isn't
|
|
* wired up yet (e.g. very early init or unit-test harness).
|
|
*
|
|
* Severity follows syslog levels: 3=ERROR, 4=WARN, 6=INFO, 7=DEBUG.
|
|
* Messages over ~4 KiB after formatting are silently truncated;
|
|
* they're admin/operator log lines, not data.
|
|
*
|
|
* Defined in plugin_main.cpp.
|
|
*/
|
|
void genai_log(int level, const char* fmt, ...) __attribute__((format(printf, 2, 3)));
|
|
|
|
/**
|
|
* @brief Push admin DB's `mcp-*` global_variables values into the
|
|
* running MCP_Threads_Handler.
|
|
*
|
|
* Defined in plugin_main.cpp. Called from `genai_start()` (initial
|
|
* read at plugin start) and from the `LOAD MCP VARIABLES TO RUNTIME`
|
|
* admin command (in plugin_commands.cpp) — both go through this one
|
|
* helper to keep behavior consistent.
|
|
*
|
|
* @return true on success; false if admindb is unavailable or the
|
|
* lookup query errored out.
|
|
*/
|
|
bool mcp_load_variables_from_admindb(GenAIPluginContext& ctx);
|
|
|
|
/**
|
|
* @brief Push admin DB's `genai-*` global_variables values into the
|
|
* running GenAI_Threads_Handler.
|
|
*
|
|
* Defined in plugin_main.cpp. Called from the
|
|
* `LOAD GENAI VARIABLES TO RUNTIME` admin command. Mirrors the
|
|
* pre-Step-5 `flush_genai_variables___database_to_runtime` in core.
|
|
*/
|
|
bool genai_load_variables_from_admindb(GenAIPluginContext& ctx);
|
|
|
|
/**
|
|
* @brief Pull runtime `genai-*` values from the running
|
|
* GenAI_Threads_Handler back into main.global_variables.
|
|
*
|
|
* Defined in plugin_main.cpp. Called from the
|
|
* `SAVE GENAI VARIABLES TO MEMORY` admin command. Mirrors the
|
|
* pre-Step-5 `flush_genai_variables___runtime_to_database` in core.
|
|
*/
|
|
bool genai_save_variables_to_admindb(GenAIPluginContext& ctx);
|
|
|
|
/**
|
|
* @brief Pull runtime mcp-* values from the running
|
|
* MCP_Threads_Handler back into main.global_variables.
|
|
*
|
|
* Defined in plugin_main.cpp. Called from the
|
|
* `SAVE MCP VARIABLES TO MEMORY` / `... FROM RUNTIME` admin command.
|
|
* Mirrors the pre-4.C `flush_mcp_variables___runtime_to_database`
|
|
* with `runtime=false` (write-back to main, not runtime).
|
|
*
|
|
* @return true on success; false on SQL error or if admindb /
|
|
* ctx.mcp are unavailable.
|
|
*/
|
|
bool mcp_save_variables_to_admindb(GenAIPluginContext& ctx);
|
|
|
|
/**
|
|
* @brief Install main.mcp_auth_profiles + main.mcp_target_profiles into
|
|
* the MCP_Threads_Handler in-memory snapshot, then rebuild the
|
|
* joined target_auth_map consumed by the listener.
|
|
*
|
|
* Defined in plugin_main.cpp. Called from `genai_start()` and the
|
|
* `LOAD MCP PROFILES TO RUNTIME` admin command. Per the ABI-3
|
|
* separation-of-duties contract this MUST NOT touch runtime_mcp_*
|
|
* (those are admin-side projections owned by the chassis).
|
|
*/
|
|
bool mcp_load_target_auth_map_from_admindb(GenAIPluginContext& ctx);
|
|
|
|
/**
|
|
* @brief Dump the MCP_Threads_Handler in-memory profile snapshots back
|
|
* to main.mcp_auth_profiles + main.mcp_target_profiles.
|
|
*
|
|
* Defined in plugin_main.cpp. Called by the
|
|
* `SAVE MCP PROFILES TO MEMORY` admin command (ABI-3 SAVE side of the
|
|
* triplet). Never reads runtime_mcp_*.
|
|
*/
|
|
bool mcp_save_target_auth_map_to_admindb(GenAIPluginContext& ctx);
|
|
|
|
/**
|
|
* @brief Install main.mcp_query_rules into the MCP_Threads_Handler
|
|
* in-memory snapshot. When the MCP listener is running, the
|
|
* rows are also pushed into Discovery_Schema for the request
|
|
* hot-path; otherwise the snapshot stays for SAVE / projection.
|
|
*
|
|
* Defined in plugin_main.cpp. Called by the
|
|
* `LOAD MCP QUERY RULES TO RUNTIME` admin command.
|
|
*/
|
|
bool mcp_load_query_rules_to_runtime(GenAIPluginContext& ctx);
|
|
|
|
/**
|
|
* @brief Dump the MCP_Threads_Handler in-memory query-rule snapshot
|
|
* back to main.mcp_query_rules.
|
|
*
|
|
* Defined in plugin_main.cpp. Called by the
|
|
* `SAVE MCP QUERY RULES TO MEMORY` admin command. The legacy second
|
|
* parameter is unused (kept only because callers haven't been
|
|
* regenerated); pass false.
|
|
*/
|
|
bool mcp_save_query_rules_from_runtime(GenAIPluginContext& ctx, bool runtime);
|
|
|
|
/**
|
|
* @brief Bring the MCP listener (`ProxySQL_MCP_Server`) up if
|
|
* `ctx.mcp->variables.mcp_enabled` is true and no listener is
|
|
* currently running.
|
|
*
|
|
* Defined in plugin_main.cpp. Called from `genai_start()` and from
|
|
* the `LOAD MCP VARIABLES TO RUNTIME` admin command (after a
|
|
* variable change might have flipped mcp_enabled to true).
|
|
*/
|
|
void mcp_start_listener_if_enabled(GenAIPluginContext& ctx);
|
|
|
|
/**
|
|
* @brief Register the plugin's admin SQL verbs (LOAD/SAVE MCP …)
|
|
* with the chassis command registry.
|
|
*
|
|
* Defined in plugin_commands.cpp. Called from `genai_init()`.
|
|
*
|
|
* @param services The same pointer `genai_init` received. Must
|
|
* expose `register_command` (and ideally
|
|
* `register_command_alias`) — both are valid during
|
|
* init() per the chassis ABI.
|
|
*/
|
|
void genai_register_admin_commands(ProxySQL_PluginServices* services);
|
|
|
|
/**
|
|
* @brief Register all MCP-related admin / config / stats tables
|
|
* with the chassis `register_table` registry.
|
|
*
|
|
* Defined in plugin_tables.cpp. Called from `genai_init()`.
|
|
*
|
|
* @param services The same pointer `genai_init` received. Must
|
|
* expose `register_table` — valid during init()
|
|
* per the chassis ABI.
|
|
*/
|
|
void genai_register_admin_tables(ProxySQL_PluginServices* services);
|
|
|
|
/**
|
|
* @brief Query-hook adapter: ABI callback that runs the anomaly detector.
|
|
*
|
|
* Defined in plugin_hooks.cpp. Registered with the plugin manager
|
|
* during init() via services->register_query_hook for both MySQL and
|
|
* PgSQL protocols.
|
|
*
|
|
* Behaviour:
|
|
* - If `genai_context().anomaly_detector` is null (carve-out
|
|
* transition window, or init failed) → return ALLOW.
|
|
* - Otherwise run `Anomaly_Detector::analyze` on the payload.
|
|
* - On `is_anomaly`, increment `metric_detected_anomalies`.
|
|
* - On `should_block`, increment `metric_blocked_queries` and return
|
|
* DENY with the detector's explanation as message.
|
|
*
|
|
* @param payload Borrowed; pointers valid only during this call.
|
|
* @return ALLOW or DENY (with message) per the plugin ABI.
|
|
*/
|
|
ProxySQL_PluginQueryHookResult genai_query_hook(const ProxySQL_PluginQueryHookPayload& payload);
|
|
|
|
#endif /* PROXYSQL_GENAI_PLUGIN_H */
|