|
| 1 | +# ProxySQL: On‑Demand Core Dump Generation (coredump_filters) |
| 2 | + |
| 3 | +## Introduction |
| 4 | + |
| 5 | +ProxySQL includes a debugging feature that allows on‑demand generation of core dump files when specific code locations are reached. This is useful for diagnosing rare or hard‑to‑reproduce bugs without requiring a full debug build or restarting the proxy. |
| 6 | + |
| 7 | +The feature works by: |
| 8 | + |
| 9 | +1. **Defining filters**: Inserting file‑name and line‑number pairs into the `coredump_filters` table. |
| 10 | +2. **Enabling filters**: Loading the filters to runtime with `LOAD COREDUMP TO RUNTIME`. |
| 11 | +3. **Triggering core dumps**: When the macro `generate_coredump()` is executed at a filtered location, a core file is written to disk (subject to rate‑limiting and platform constraints). |
| 12 | + |
| 13 | +Core dump generation is **rate‑limited** and **platform‑specific** (currently Linux on x86‑32, x86‑64, ARM, and MIPS architectures). |
| 14 | + |
| 15 | +--- |
| 16 | + |
| 17 | +## Table Definitions |
| 18 | + |
| 19 | +### `coredump_filters` (persistent configuration) |
| 20 | + |
| 21 | +| Column | Type | Nullable | Primary Key | Description | |
| 22 | +|----------|--------------|----------|-------------|-------------| |
| 23 | +| filename | VARCHAR | NOT NULL | Yes | Source file name (as seen by the compiler) | |
| 24 | +| line | INT | NOT NULL | Yes | Line number within that file | |
| 25 | + |
| 26 | +**Primary key**: (`filename`, `line`) |
| 27 | + |
| 28 | +**SQL definition**: |
| 29 | +```sql |
| 30 | +CREATE TABLE coredump_filters ( |
| 31 | + filename VARCHAR NOT NULL, |
| 32 | + line INT NOT NULL, |
| 33 | + PRIMARY KEY (filename, line) |
| 34 | +); |
| 35 | +``` |
| 36 | + |
| 37 | +### `runtime_coredump_filters` (runtime state) |
| 38 | + |
| 39 | +This table mirrors the active filters currently loaded into memory. It is updated automatically when `LOAD COREDUMP TO RUNTIME` is executed. |
| 40 | + |
| 41 | +**SQL definition**: |
| 42 | +```sql |
| 43 | +CREATE TABLE runtime_coredump_filters ( |
| 44 | + filename VARCHAR NOT NULL, |
| 45 | + line INT NOT NULL, |
| 46 | + PRIMARY KEY (filename, line) |
| 47 | +); |
| 48 | +``` |
| 49 | + |
| 50 | +--- |
| 51 | + |
| 52 | +## Configuration Variables |
| 53 | + |
| 54 | +Two global variables control the rate‑limiting behavior: |
| 55 | + |
| 56 | +| Variable | Default | Range | Description | |
| 57 | +|----------|---------|-------|-------------| |
| 58 | +| `admin‑coredump_generation_threshold` | 10 | 1–500 | Maximum number of core files that can be generated during the lifetime of the ProxySQL process. | |
| 59 | +| `admin‑coredump_generation_interval_ms` | 30000 (30 seconds) | 0–INT_MAX | Minimum time between two consecutive core dump generations. A value of `0` disables the interval check. | |
| 60 | + |
| 61 | +**Notes**: |
| 62 | +- Both variables are stored in the `global_variables` table (admin database). |
| 63 | +- Changes take effect immediately when the variable is set (no need to `LOAD … TO RUNTIME`). |
| 64 | +- The threshold is a **global counter**; once reached, no further core dumps will be generated until the process restarts. |
| 65 | +- The interval is measured in **milliseconds**. |
| 66 | + |
| 67 | +--- |
| 68 | + |
| 69 | +## Admin Commands |
| 70 | + |
| 71 | +### `LOAD COREDUMP TO RUNTIME` |
| 72 | + |
| 73 | +Reads the `coredump_filters` table and loads the filters into memory. After this command, any location matching a filter becomes active for core dump generation. |
| 74 | + |
| 75 | +**Aliases**: |
| 76 | +- `LOAD COREDUMP FROM MEMORY` |
| 77 | +- `LOAD COREDUMP FROM MEM` |
| 78 | +- `LOAD COREDUMP TO RUN` |
| 79 | + |
| 80 | +**Example**: |
| 81 | +```sql |
| 82 | +LOAD COREDUMP TO RUNTIME; |
| 83 | +``` |
| 84 | + |
| 85 | +**Effect**: |
| 86 | +1. Clears the previous runtime filter set. |
| 87 | +2. Reads all rows from `coredump_filters`. |
| 88 | +3. Converts each row into a string `"filename:line"` and stores it in an internal hash set. |
| 89 | +4. If at least one filter exists, the global flag `coredump_enabled` is set to `true`. |
| 90 | + |
| 91 | +### `SAVE COREDUMP` (not implemented) |
| 92 | + |
| 93 | +As of this writing, there is **no `SAVE COREDUMP` command**. The runtime state (`runtime_coredump_filters`) is automatically updated when filters are loaded, but there is no built‑in command to persist runtime filters back to the `coredump_filters` table. |
| 94 | + |
| 95 | +If you need to copy the active filters back to the configuration table, you can do so manually: |
| 96 | + |
| 97 | +```sql |
| 98 | +INSERT INTO coredump_filters SELECT * FROM runtime_coredump_filters; |
| 99 | +``` |
| 100 | + |
| 101 | +--- |
| 102 | + |
| 103 | +## Important Notes |
| 104 | + |
| 105 | +- **Case‑sensitive filenames**: The `filename` column must match exactly the string returned by `__FILE__` (including relative path from the source root). The comparison is case‑sensitive. |
| 106 | +- **Runtime‑only behavior**: Filters loaded via `LOAD COREDUMP TO RUNTIME` are stored in memory only. They are lost when ProxySQL restarts. To make filters persistent, keep them in the `coredump_filters` table and reload after each restart. |
| 107 | +- **Instance‑specific**: Filters are local to the ProxySQL instance; there is no automatic synchronization across a cluster. |
| 108 | +- **Rate limiting**: The feature includes two safety limits (`admin‑coredump_generation_threshold` and `admin‑coredump_generation_interval_ms`) to prevent disk filling and performance degradation. |
| 109 | +- **Platform‑specific**: Core dump generation works only on Linux x86‑32, x86‑64, ARM, and MIPS architectures. On other platforms the macro logs a warning and does nothing. |
| 110 | + |
| 111 | +--- |
| 112 | + |
| 113 | +## Usage Example |
| 114 | + |
| 115 | +### 1. Insert a filter |
| 116 | + |
| 117 | +Suppose you want to generate a core dump when the function `MySQL_Data_Stream::check_data_flow()` reaches line 485 (where `generate_coredump()` is called). |
| 118 | + |
| 119 | +First, find the exact file name as used in the source code. The macro `LOCATION()` expands to `__FILE__ ":" __LINE__`. For the file `lib/mysql_data_stream.cpp` line 485: |
| 120 | + |
| 121 | +```sql |
| 122 | +INSERT INTO coredump_filters (filename, line) VALUES ('lib/mysql_data_stream.cpp', 485); |
| 123 | +``` |
| 124 | + |
| 125 | +### 2. (Optional) Adjust rate‑limiting variables |
| 126 | + |
| 127 | +Increase the threshold and shorten the interval if you expect to trigger the dump multiple times quickly: |
| 128 | + |
| 129 | +```sql |
| 130 | +SET admin-coredump_generation_threshold = 50; |
| 131 | +SET admin-coredump_generation_interval_ms = 1000; -- 1 second |
| 132 | +``` |
| 133 | + |
| 134 | +These changes take effect immediately. |
| 135 | + |
| 136 | +### 3. Load filters to runtime |
| 137 | + |
| 138 | +```sql |
| 139 | +LOAD COREDUMP TO RUNTIME; |
| 140 | +``` |
| 141 | + |
| 142 | +### 4. Trigger the condition |
| 143 | + |
| 144 | +Cause the code path to reach the filtered location. In this example, you would need to create a MySQL data‑stream condition where data exists at both ends of the stream (a fatal error). When that happens, ProxySQL will log: |
| 145 | + |
| 146 | +``` |
| 147 | +[INFO] Coredump filter location 'lib/mysql_data_stream.cpp:485' was hit. |
| 148 | +[INFO] Generating coredump file 'core.<pid>.<counter>'... |
| 149 | +[INFO] Coredump file 'core.<pid>.<counter>' was generated ... |
| 150 | +``` |
| 151 | + |
| 152 | +### 5. Inspect the core file |
| 153 | + |
| 154 | +The core file is written in the current working directory of the ProxySQL process, with the name pattern `core.<pid>.<counter>` (e.g., `core.12345.0`). It is compressed using the **coredumper** library. |
| 155 | + |
| 156 | +Analyze it with `gdb`: |
| 157 | + |
| 158 | +```bash |
| 159 | +gdb /usr/bin/proxysql core.12345.0 |
| 160 | +``` |
| 161 | + |
| 162 | +--- |
| 163 | + |
| 164 | +## Rate Limiting and Safety Features |
| 165 | + |
| 166 | +To prevent disk filling and performance impact, core dump generation is protected by two mechanisms: |
| 167 | + |
| 168 | +1. **Threshold limit**: The total number of core dumps generated during the process lifetime cannot exceed `admin‑coredump_generation_threshold` (default 10). Once the threshold is reached, `generate_coredump()` will still log the hit but will not write a new core file. |
| 169 | + |
| 170 | +2. **Interval limit**: After a core dump is written, at least `admin‑coredump_generation_interval_ms` milliseconds must pass before another core dump can be generated (unless the interval is set to 0). This prevents burst generation when a hot code path is repeatedly executed. |
| 171 | + |
| 172 | +Both counters are reset when `LOAD COREDUMP TO RUNTIME` is executed (or when `proxy_coredump_reset_stats()` is called internally). |
| 173 | + |
| 174 | +--- |
| 175 | + |
| 176 | +## Platform Support |
| 177 | + |
| 178 | +Core dump generation is **only available** on the following platforms: |
| 179 | + |
| 180 | +- **Operating system**: Linux |
| 181 | +- **Architectures**: x86‑32 (`__i386__`), x86‑64 (`__x86_64__`), ARM (`__ARM_ARCH_3__`), MIPS (`__mips__`) |
| 182 | + |
| 183 | +On other platforms (e.g., FreeBSD, macOS, Windows) the `generate_coredump()` macro will log a warning and do nothing. |
| 184 | + |
| 185 | +The feature relies on the **coredumper** library (https://github.com/elastic/coredumper), which is bundled as a dependency. |
| 186 | + |
| 187 | +--- |
| 188 | + |
| 189 | +## Internal Implementation Details |
| 190 | + |
| 191 | +### Macros and Functions |
| 192 | + |
| 193 | +- `generate_coredump()`: The macro used in the source code to conditionally generate a core dump. It checks `coredump_enabled` and looks up the current `__FILE__:__LINE__` in the filter set. |
| 194 | +- `proxy_coredump_load_filters()`: Loads a set of `"filename:line"` strings into the internal hash table. |
| 195 | +- `proxy_coredump_generate()`: Performs the actual core dump writing, subject to rate‑limiting checks. |
| 196 | +- `proxy_coredump_reset_stats()`: Resets the generation counter and last‑creation timestamp. |
| 197 | + |
| 198 | +### Database‑to‑Runtime Flow |
| 199 | + |
| 200 | +1. `LOAD COREDUMP TO RUNTIME` calls `ProxySQL_Admin::load_coredump_to_runtime()`. |
| 201 | +2. Which calls `flush_coredump_filters_database_to_runtime()`. |
| 202 | +3. Reads `coredump_filters` table, builds the string set, and passes it to `proxy_coredump_load_filters()`. |
| 203 | +4. The runtime state is mirrored to `runtime_coredump_filters` via `dump_coredump_filter_values_table()`. |
| 204 | + |
| 205 | +### Where `generate_coredump()` is Used |
| 206 | + |
| 207 | +Currently, the macro is placed in a few strategic “fatal error” locations: |
| 208 | + |
| 209 | +- `MySQL_Data_Stream::check_data_flow()` – when data exists at both ends of a MySQL data stream. |
| 210 | +- `PgSQL_Data_Stream::check_data_flow()` – analogous condition for PostgreSQL. |
| 211 | + |
| 212 | +Developers can add more `generate_coredump()` calls in other debug‑sensitive code sections. |
| 213 | + |
| 214 | +--- |
| 215 | + |
| 216 | +## Troubleshooting |
| 217 | + |
| 218 | +### No core file is generated even though the filter was hit |
| 219 | + |
| 220 | +1. **Check platform support**: Verify ProxySQL is running on a supported Linux architecture. |
| 221 | +2. **Check rate‑limiting counters**: The global threshold may have been reached. Execute `LOAD COREDUMP TO RUNTIME` to reset the counters (or restart ProxySQL). |
| 222 | +3. **Check directory permissions**: The process must have write permission in the current working directory. |
| 223 | +4. **Check disk space**: Ensure there is sufficient free disk space. |
| 224 | + |
| 225 | +### Error “Coredump generation is not supported on this platform.” |
| 226 | + |
| 227 | +The platform is not among the supported architectures. Use a different machine or consider using a debugger instead. |
| 228 | + |
| 229 | +### Filters are not being activated after `LOAD COREDUMP TO RUNTIME` |
| 230 | + |
| 231 | +- Verify that the `filename` matches exactly the string that `__FILE__` expands to (relative path from the source root). |
| 232 | +- Ensure the line number is correct (check the source code for the exact line where `generate_coredump()` appears). |
| 233 | +- Inspect the `runtime_coredump_filters` table to confirm the filters were loaded. |
| 234 | + |
| 235 | +### High frequency of core dumps is affecting performance |
| 236 | + |
| 237 | +Increase `admin‑coredump_generation_interval_ms` to space out the generation, or reduce `admin‑coredump_generation_threshold` to limit the total number. |
| 238 | + |
| 239 | +--- |
| 240 | + |
| 241 | +## Best Practices |
| 242 | + |
| 243 | +1. **Use for debugging only**: Enable coredump filters only during debugging sessions. Remove filters afterward to avoid unnecessary overhead. |
| 244 | +2. **Limit the threshold**: Keep `admin‑coredump_generation_threshold` low (e.g., 1‑5) unless you are investigating a recurring issue. |
| 245 | +3. **Set a reasonable interval**: A minimum interval of several seconds (e.g., 30000 ms) prevents storm generation. |
| 246 | +4. **Document filter locations**: Keep a record of why each filter was inserted and under what condition it triggers. |
| 247 | +5. **Monitor disk usage**: Core files can be large; ensure the working directory has enough space and consider a dedicated partition. |
| 248 | + |
| 249 | +--- |
| 250 | + |
| 251 | +## Related Features |
| 252 | + |
| 253 | +- **Debug filters**: ProxySQL also supports `debug_filters` for enabling debug logs at specific file‑line locations. |
| 254 | +- **Core dump on crash**: For crash‑induced core dumps, use system‑level configuration (e.g., `ulimit -c unlimited`, `sysctl kernel.core_pattern`). |
| 255 | + |
| 256 | +--- |
| 257 | + |
| 258 | +## Summary |
| 259 | + |
| 260 | +The `coredump_filters` feature provides a targeted, rate‑limited way to obtain core dumps from specific code locations without restarting ProxySQL or building a debug binary. It is a valuable tool for diagnosing elusive bugs in production‑like environments. |
| 261 | + |
| 262 | +Remember that core dump generation is **platform‑dependent** and **rate‑limited**; always verify support and adjust the configuration variables according to your debugging needs. |
0 commit comments