mirror of https://github.com/sysown/proxysql
GH-Actions
feature/ci-codecov-tap-legacy-g2
docs/passthrough-auth-spec
v3.0_fix-stale-pause-until
v3.0
feature/perf-improvements-test2
v3.0_fix_pgsql-set_statement_test_5788
v3.0_pgsql_options_5801
feature/ci-codecov-unit-tests
fix/kill-proxysqlgenai-build-flag-v2
fix/kill-proxysqlgenai-build-flag
v3.0-260523
feat/passthrough-auth
ci-trigger-tolerate-cleanup-401
fix/5790-mariadb-collation-255
fix/parsersql-1.0.3-pg-set-fixes
issue_5639
pgsql_dns_cache
fix/5755-followup-typecast-digest-fixtures
fix/5708-followup-multiline-for
fix/ci-asan-zombie-checks
v3.0_merge-5776-5784
genai_5534
aws-rds-bg
v3.0_partition-gate
feature/perf-improvements-rene
v3.0_latency_consistency_improvement
fix/5796-ci-mysqlx-build-cache
fix/remove-skip-all
test/cluster-simulator
fix/galera-g5-cluster-start
integration/v3.0-batch-2026-05-13
fix/ghcr-pull-retry
fix/issue-5620-fast-routing-qr-leak
fix/issue-5684-tsdb-dashboard-same-origin
fix/5770-gcc16-jemalloc
fix/issue-5766-libconfig-escape-passthrough
v3.0_cap_violation_5767
fix/issue-5755-pgsql-digest-truncation
fix/issue-5580-deb-xz-compression
ci-mariadb10-galera-v3.0
ci-mariadb10-galera-GH-Actions
ci/fix-gr-g1-hostgroups
ci/fix-gr-g5-cluster-start
issue-5686-galera-vars
ci-mysql84-gr-g1-g9-GH-Actions
ci-mysql84-gr-g1-g9-v3.0
perf/pull-ci-base-from-ghcr
fix/rename-set-parser-group-and-bench-complexity
fix/split-test-groups
fix/rename-set-parser-workflow
perf/scram-cached-hmac
feature/parsersql-integration
gh-actions/add-set-parser-algorithm-3-g1
issue-5729-stats-projection-abi
fix/4760-lenenc-auth-v3.0
fix/tsan-unit-tests-build-failure
fix/4530-mysql-server-selection-prng
fix/4760-advertise-lenenc-auth-capability
fix/unit-test-asan-double-link
fix-auth-lock-order
v3.0-genai-plugin
feature/mysqlx-stack-consolidated
feature/mysqlx-asan-coverage-docker-isolation
fix/ci-unit-tests-tsan-project-name
feature/mysqlx-tsan-v3-companion
feature/ci-builds-add-tsan-matrix
ci-reduce-polling-interval
feature/mysqlx-tsan-workflow-only
feature/mysqlx-ci-validation-workflows
feature/mysqlx-test-leak-cleanup
feature/mysqlx-behavioural-tap
feature/mysqlx-parity-cleanup
ci-g5-enable-cluster
ci-g5-debug-clean
feature/mysqlx-tls-passthrough
feature/mysqlx-asymmetric-tls
feature/mysqlx-state-machines
feature/build-tsan-plumbing
feature/mysqlx-observability-p0
plugin-chassis
fix/mysqlx-review-findings
fix/test-mysqlx-plugin-load-phase-b
docs/plugin-chassis-abi3-update
fix/mysqlx-runtime-views-separation
v3.0-ci-asan-libprotobuf-dev
ProtocolX
ProtocolX-rebased
v3.0-fix-macos-release-upload
v3.0-test-ci
v3.0-fix-init-release-race
v3.0-cleanup-stale-plans
v3.0-ci-pkg-workflows
fix/macos-build-deps
feat/arm64-on-demand-package-builds
fix/3.0.8-review-items
fix/pgsql-active-tx-on-broken-conn
feat/pgsql-tx-poisoned-recovery
pull-5659
session-track-system-variable
feat/cla-assistant-setup
v3.0-slim-dbdeployer-images
ci/fix-mysql-apt-key-expired-v2
ci/fix-mysql-apt-key-expired
fix/mysqlx-check-connect-poll
fix/mysqlx-stale-row-sync
feature/mysqlx-route-identity
fix/mysqlx-listener-lifecycle
fix/mysqlx-backend-tls-post-auth
chore/retire-dead-mysqlx-worker
v3.0-issue5621
v3.0_new_zstd
fix/lint-groups-json-format
v3.0-dbdeployer-mysql84-gr
lint-tap-tests-static-analysis
fix/groups-json-orphaned-entries
mariadb-rpl-helper
feature/gtid-range-update
fix-fc-parsing
v3.0-pgsql-monitor-reschedule-on-interval-change
v3.0-remove-sqlite-rembed
v3.0-fix-read-only-actions-hostgroup
v3.0-fix-pgsql-ssl-keylog-path
v3.0-fix-flake-test-flush-logs
v3.0-doc-test-readme
v3.0-doc-gh-actions-vocabulary
ci/fix-upload-artifact-eacces
v3.0_pgsql-copy-matcher-5568
ci/fix-cache-prune-permissions
ci/disable-unittests-caller
ci/shrink-test-cache
ci/proxysql-tester-zero-test-safety-net
ci/fix-tap-build-target
ci/gh-actions-readme-pointer
ci/rewire-group-callers-and-docs
ci/fix-mysql84-infradb-label
ci/add-missing-group-reusables
v3.0-lint
fix/ci-workflow-run-chain-pr-sha
fix/postgresql-cluster-sync_2
v3.0_ci_min_proxysql_version_5561
mysqlx-plugin-impl
infra-mysql57-binlog
v3.0-ci0405
feature/pgbouncer-compat
v3.0_pgsql_sslkeylog_5281
v3.0-issue5556
fix/5554-resolution-family-limitation
v3.0-CodeCov0325
v3.0-ci260323
fix/3p-ci-error-handling
feat/ffto-error-recording
v3.0-5493
v3.0-ci260322
v3.0-ci260322_cluster
v3.0-5516
v3.0-5517
copilot/feature-load-restapi-routes-config
copilot/add-ssl-tls-certificate-stats-table
unit-tests-skip-proxysql
private/multi-group-runner
v3.0-5473
v3.0-5499
copilot/extract-server-selection-algorithm
copilot/extract-health-state-logic
copilot/extract-query-rule-matching-logic
copilot/extract-connection-pool-logic
v3.0-set_parser_v3
feature/arm-builds
release-notes-3.0.6-4.0.6-draft
v3.0.6-add-tap-test_stats_table_check
v2.7.3-test260221
v4.0-mcp-stats
copilot/uninstall-amazon-linux-2023
fix-prometheus-labels-test
tap-mcp-client
agent-skill-tap-test
v4.0-tsdb1
v3.0-fix_5256
gh-pages
feature/modern-docs
v4.0
v4.0-fix-vec-search
v4.0_rag_sys_prompt
v4.0-mcp_rules_test
v4.0_rag_mcp
v4.0-tsdb
feature/v4-docs-init
otel_system_libs
otel_clean
v3.0-5288
otel
otel_2
fix/postgresql-cluster-sync
v3.0-releate_notes_scripts_fixes
test_gh-actions_triggers
postgresql-digest-testing-improvement
v3.0_select_auto_commit
v3.0-5218
fix-5221
fix/5186-proxysql-stop-admin-crash
v3.0-4951
add-claude-github-actions-1763877527835
fix-rpm
v3.0-DS_crash
add-claude-github-actions-1763663272333
add-claude-github-actions-1763663091346
add-claude-github-actions-1763663091411
add-claude-github-actions-1763476725261
add-claude-github-actions-1763476725489
v3.0_optimizations_and_stability
v2.7.3.1
v3.0.3-upgrade_json
v3.0.sonar-cli
v3.0.sonar-config
otel-tracepoint
v3.0.2-merge-upgrade_deps-add_new_distros
v3.0.2-upgrade_deps
v3.0.2-add_new_distros
v3.0-add_more_testing_groups
v3.0-upgrade_prometheus-cpp
v3.0-upgrade_json
v3.0-upgrade_sqlite3
v3.0-upgrade_libmicrohttpd
v3.0-upgrade_curl
v3.0-add_centos10_builds
v3.0-add_fedora42_builds
v3.0_PG_PrepStmt
v3.0-sliced_groups
v3.0_auth_negotiation
v2.7
v2.7-fix_run_name
v3.0_4799_4827
v3.0-3687
v2.7-pmm_runtime_servers_metrics
v2.7-4839
v2.7-4841
v2.7-bump_version_to_2.7.3
2.6.6-4841
v2.x_pg_PrepStmtBase_240714
v3.0-4803-4817
v3.0-4803
v2.7-minorBugs
v3.0-privates
v2.x-logging_mem_2
v2.7_fix
v2.7_amd64_build_fix
v2.7-fix_aux_threads_ssl_leaks
v2.7-fix_ssl_params_leak
v2.7-rm_malloc_conf_on_version
v2.7_compression
v2.7-actions-add-3p-tests-parameter
none
v2.7-fix_hang_on_resume
v2.x-logging_mem
v2.7_servers_defaults
v2.7-mariadb_column_metadata_integrity_check
ssl_optimization
v2.7_reg_test_4716_single_semicolon
v2.7_issue_4707_threshold_resultset_size
v2.7_reg_test_4723_query_cache_stores_empty_result
2.7_randomized_cache_ttl
v3.0_fix_multiple_builds
v3.0_servers_defaults
v2.7-update_actions_triggers_v2
v2.7-update_actions_triggers
v2.6
v2.6.x-update_triggers
v2.6-4646
v2.7.1-update_actions
v2.x
v2.6.x-testing-global-multiplexing-disabled
use-wrlock-in-dns-cache-empty
v2.6.x-fix-darwin
v2.x-admin_list_ciphers
v2.x-sqlite3_pass_exts
v2.x-tap_tests_opt_ssl
v2.6.0-update_to_libhttpserver_v0.19
v2.x_router_2ports
v2.6.0-update_to_openssl_v3.1.5
v2.x-2411025
v2.x-profiling_poc1
v2.x_sha2pass_draft2
v2.x-webui_fixes
v2.6.0-more-makefile-fixes
v2.x-20230914_test
v2.x-20230913_test
v2.5.5-branch
v2.5.5-branch_255_patches
v2.x-aurora_autodiscovery-refactor_cluster_mysql_servers-gr_bootstrap_mode_2
v2.x_mysql_connector_j_fixes
v2.6-deprecate_old_clickhouse
v2.x_refactor_cluster_mysql_servers
v2.x-aurora_autodiscovery
v2.x-zd70545
v2.x-aurora_autodiscovery_shunned_promotion
v2.x-tap20230609
v2.x-test20230530
v2.x_sha2pass_draft2-TEST
v2.x-session_track_system_variables_v2
v2.x-status-variables-for-set-stmts
v2.x-enable_session_state_trackers
v2.x-increase-logging-eof_fast_forward-t
v2.x-3863-special-query
v2.x-session_track_system_variables
v2.x_refactor_read_only_action
v2.x_sha2pass_draft1
v2.2.0-sqliteserver_read_only
v2.x-digest_umap_aux-comparison
v2.4.8
v2.x-4105_4114
v2.x-3583-server_closed_conn
v2.x-group_replication_rework-SHUNNED_promotion
v2.1.0-var-global-multiplex
v2.x-CI-hostname-tap-test-fixes
v2.x-limit-version-check
v2.x-fix_deprecate_eof_warning
v2.x-3698
v2.x_tidb_replica_read
v2.x-HostGroups_attributes
v2.0.18.221009
v2.x-ci_reg_test_3273_ssl_con
TAP_test_restapi
v2.x-tap_tests_groups
v2.x-tap_test_sqlite3_server-t
PRS_3888_3903_2
PRS_3888_3903
v2.x_code_refactor_2206
v2.x-multipacket_poc_1
v2.x-impr_hg_latency_obsv
v2.x-gcc-warnings
v2.x-hg_lock_session_id
v2.x-3768
v2.x-3371
v2.x-ci_verifications
v2.x-thread_local_qps_limit
v2.x-parser_table
v2.1.1-3207
v2.x-qps_limits
v2.x-3711
v2.x-3642
v2.x-3674
v2.x-ssl3_warnings
V2
v2.3.2
v2.3.2_3646_3647
v2.x-client_err_limit_conn_timeout
v2.x-keep_multiplexing_regression_fix
v2.3.2-3628
v2.2.2-to-v2.3.0-7
v2.2.2-to-v2.3.0-7_merge
v2.2.2-to-v2.3.0-6
v2.2.2-to-v2.3.0-6_merge
v2.2.2-to-v2.3.0-5
v2.2.2-to-v2.3.0-4
v2.2.2-to-v2.3.0-3
v2.2.2-to-v2.3.0-2
v2.2.2-to-v2.3.0-1
v2.3.1
v2.0.14-70226
v2.3.0
v2.x-client_err_limit-gr_replication_lag_action
v2.2.2
v2.2.1-3603
v2.2.1-centos7-ASAN
v2.2.1
v2.2.1-3601
v2.2.1-3599
v2.2.1-3597
v2.2.1-3595
v2.2.0-restapi_server_exc_log
v2.x-3574
v2.x-3558
v2.2.0-3546-centos-7-gcc-8
v2.x-3549
v2.x-cluster_large_mysql_users
v2.x-cov_ci_verification
v2.0.14-tb1
v2.0.14-tb1-3494
v2.0.14-tb1-3488
v2.0.14-tb1-3117
v2.0.14-tb1-2762
v2.0.14-2762
v1.4.13-arm
v2.1.1-3296
v2.2.0
v2.0.18
v2.1.1
v2.0.18-3342
v2.0.18-3182
v2.1.1-3184
v2.1.0-revert-da7fdfe14
v2.0.18-revert-da7fdfe14
v1.4.13-70160
v2.0.18-3354
v2.0.18-3350
v2.0.14-3339
1.4.13-70160
v2.0.18-3339
v2.1.1-3317
v2.1.1-3319
v2.0.18-3317
v2.1.2-LBalgo
v2.0.18-1574
v2.1.2-hgman
v2.0.17
v2.1.0
v2.0.17-3288
v2.0.17-3276
v2.0.17-3273
v2.0.16
v2.0.16-3267
v2.0.16-3265
v2.0.16-3262
v2.0.16-3261
v2.1.1-3252
v2.1.1-collation
v2.0.16-3252
v2.0.16-collation
v2.1.0-parser
v2.0.16-3219
v2.0.16-3216
v2.0.16-3201
v2.0.16-2330
revert-3191-v2.0.16-3190
v2.0.16-3204
v2.0.16-3177
v2.0.16-2619
v2.0.16-3190
v2.0.16-3187
v2.1.0-70118
v2.0.16-3133
v2.0.16-3133_ci_verification
v2.0.16-3150
v2.0.16-change_user
v2.0.15
v2.0.15_amd64_fix
v2.0.15_arm64_packages
v1.4.14-ssl
v2.0.15_arm64
v2.1.0-2820
v2.0.15-sslbug
v2.0.15-KillTrx
v2.0.14
v2.0.14-ch_build_fix
v2.0.14-focal
v2.0.14-valgrind20200904
v2.1.0-3042
v2.0.14-3035
v2.0.14-3036
v2.0.14-2955
v2.0.14-vars
v2.0.14-3005
v2.0.14-3003
v2.0.14_2970_2979
v2.0.14-NOTSOCK
v2.1.0'
v2.0.14-2958
v1.4.10-zd
v2.0.13
v2.0.13-autocommit_fix
v2.1.0-2892
v2.0.13-2711
v2.0.13-duplicated_variables
v2.0.13-duplicated_variables_for_2.1.0
v2.0.12-deprecate_eof
v2.1.0-1377
v2.1.0-admin_queries
v2.0.12-var-global-multiplex
v2.1.0-var-foreign-key
v2.0.12
v2.0.12-tab-small-log
v2.0.12-var-foreign-key
v2.0.12-var-long-query-time
v2.0.12-galera-shunned
v2.1.0-admin_queries_2
v2.1.0-tap-rm-config
v2.0.12-tap-rm-config-test
v2.1.0-QP_stmt_3
v2.0.11-fix-multi-2-ci
v2.0.11-fix-multi
v2.0.11-266_0-3
2.1.0
v2.0.11
v2.1.0-track-vars
v2.1.0-track-variables
v2.0.11-track-variables
v2.0.11-2526
v2.0.11-tap-tests
v2.0.13-2698-commit1
v2.0.10-galera-pxc-maint-mode
v2.0.11-track-vars
v2.0.10-2647
v2.0.11-track
v2.0.11-track-session-vars
v2.0.9-var-array-review
v2.0.11-stats
v2.0.10
v2.0.10-centos67
v1.4.14.2
1.4.14.2
v1.4.14-show-warnings
v2.0.9
v2.0.9-var-array_2
v2.0.9-var-array
v1.4.16
v2.0.8
val214-changing_charset
v2.0.6
v1.4.16-1922_2
v1.4.13.2
v2.0.4-charset248
v2.0.5
v1.4.10-67841
v2.0.4
v2.0.4-sqlite327
v2.0.3
v2.0.2
v1.4.15
v2.0.1
v1.4.14
v2.0.0
v1.4.14-ping_shun
v1.4.14-1828
v1.4.14-latency_awareness
v1.4.12
v1.4.13-admin_deadlock
v2.0.0-improve_speed
v1.4.13
v1.4.13-autocommit_revert
v1.4.11.2
v1.4.13-ps
v2.0.0_bionic_deb_fix
v2_962
v1.4.12-1640
v1.4.11-names_tz
v1.4.12-1693
master
v1.4.11
v1.4.10
v1.4.6
v1.3.10
jenkins_test
v2.0.0-cachegrind
v1.4.9
v2.0-lab
v149_1511
v149_1382
v1.4.7-f2
v1.4.7-f1
v149_1491
v1.4.5-kub
v1.4.8
v2.0-web2
v1.4.3
v1.4.7
bsd_install_update
v1.4.2
v1.4.1-ch2
v1.4.1
v1.3.9
v1.4.1-ch
v1.3.8
v1.3.8-dev
v1.3.7
v1.3.7-dev
v1.3.6-dev
v1.4.0-clickhouse
v1.4.0
v1.3.6
v1.3.5
v1.3.5-dev
v1.4.0-955
v1.3.4
v1.3.4-dev
v1.3.3
v1.3.3-dev
v1.3.2
v1.3.2-dev
v1.3.2-766
v1.3.0h
v1.3.1-utf8mb4
1.4.0-840
v1.3.1
v1.2.6
v1.3.0
v1.4.0-797
v1.2.5-715
v1.2.5
v1.2.4-lowmem
v1.3.1-dev-mem
v1.2.0
connleak
lab-1.2.0
v1.1.2
T107_add_proxysql_consul_requirements
T89_write_consul_integration_doc
T98_consul_multi_table_config
mongoose
evhttp
SQLiteServer
1.0
3.0.8
3.0.7
3.0.6
3.0.5
3.0.4
3.0.3
3.0.2
2.7.3
2.6.6.1
3.0.1
2.7.2
3.0.0
2.6.6
2.7.1
2.7.0
2.6.5
2.6.4
2.6.3
2.6.2
2.6.1
2.5.5
2.6.0
2.5.4
2.5.3
2.5.2
2.5.1
2.4.8
2.5.0
2.4.7
2.4.6
2.4.5
2.4.4
2.4.3
2.4.2
2.4.1
2.4.0
2.3.2
2.3.1
2.3.0
2.2.2
2.2.1
2.2.0
2.0.18
2.1.1
2.0.17
2.0.16
2.0.15
2.0.14
2.0.13
2.0.12
2.0.11
2.1.0
2.0.10
2.0.9
2.0.8
2.0.7
2.0.6
2.0.5
2.0.4
2.0.3
2.0.2
1.4.16
1.4.15
2.0.1
1.4.14
1.4.13
1.4.12
1.4.11
1.4.10
1.3.10
1.4.9
2.0.0
1.4.8
1.4.7
1.4.6
1.4.4
1.4.3
1.4.2
1.3.9
1.3.8
1.4.1
1.3.7
1.4.0
1.3.6
1.3.5
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0h
1.3.0g
1.3.0f
1.3.0e
1.3.0d
1.3.0c
v1.3.0b
1.4.5
v1.1.0
v1.1.0-rc
v1.1.1-beta
v1.1.1-beta.1
v1.1.1-beta.2
v1.1.1-beta.3
v1.1.1-beta.4
v1.1.1-beta.5
v1.1.1-beta.6
v1.1.2
v1.2.0a
v1.2.0b
v1.2.0c
v1.2.0d
v1.2.0e
v1.2.0f
v1.2.0g
v1.2.0h
v1.2.0i
v1.2.0j
v1.2.0k
v1.2.1
v1.2.2
v1.2.3
v1.2.4
v1.2.4.0923
v1.2.5
v1.2.6
v1.3.0
v1.3.0a
v1.3.0g
v1.3.0h
v1.3.1
v1.3.10
v1.3.2
v1.3.2-1
v1.3.3
v1.3.4
v1.3.5
v1.3.6
v1.3.7
v1.3.8
v1.3.9
v1.3.9-prev.1
v1.4.0
v1.4.1
v1.4.10
v1.4.11
v1.4.12
v1.4.13
v1.4.14
v1.4.15
v1.4.16
v1.4.2
v1.4.3
v1.4.4
v1.4.5
v1.4.6
v1.4.7
v1.4.8
v1.4.9
v2.0.0-beta.1
v2.0.0-rc1
v2.0.0-rc2
v2.0.1
v2.0.10
v2.0.11
v2.0.12
v2.0.13
v2.0.14
v2.0.15
v2.0.16
v2.0.17
v2.0.18
v2.0.2
v2.0.3
v2.0.4
v2.0.5
v2.0.6
v2.0.7
v2.0.8
v2.0.9
v2.1.0
v2.1.1
v2.2.0
v2.2.1
v2.2.2
v2.3.0
v2.3.1
v2.3.2
v2.4.0
v2.4.1
v2.4.2
v2.4.3
v2.4.4
v2.4.5
v2.4.6
v2.4.7
v2.4.8
v2.5.0
v2.5.1
v2.5.2
v2.5.3
v2.5.4
v2.5.5
v2.6.0
v2.6.1
v2.6.2
v2.6.3
v2.6.4
v2.6.5
v2.6.6
v2.7.0
v2.7.1
v2.7.2
v2.7.3
v3.0.0-alpha
v3.0.1
v3.0.2
v3.0.3
v3.0.4
v3.0.5
v3.0.6
v3.0.7
v3.0.8
v3.1.6
v3.1.7
v3.1.8
v4.0.6
v4.0.7
v4.0.8
${ noResults }
9820 Commits (31d7ae9ecbfcce4062dde20dfd67ff60dd0db29c)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
31d7ae9ecb |
docs(mysqlx): reconcile comprehensive-testing plan against ProtocolX-rebased
Audit the 14-task plan from 2026-04-09 against the actual test tree on
ProtocolX-rebased and record the result inline.
Findings:
- Tasks 1-8, 10-14: every Tier-1 / Tier-2 / Tier-3 target file exists
with a plan() at or above the assertion budget the plan called for.
Tasks 5, 6, 8, 12 went well beyond their targets through interim
expansion work; the others land exactly on plan.
- Task 9 is obsolete: test_mysqlx_listener_smoke-t.cpp was deleted in
|
4 weeks ago |
|
|
aef01ef0be |
feat(mysqlx): compress outbound server frames (Phase 3)
Phase 3 of three-phase X Protocol compression support: server→client
compression on outbound frames. Wraps up the MVP — CapabilitiesSet
negotiation (Phase 1), inbound decompression (Phase 2), and now
outbound compression all roundtrip.
What this commit does
=====================
forward_frame_to_client() — the chokepoint for backend→client frame
forwarding — now routes through send_to_client_compressed(), which:
1. Returns early to plain client_ds_.enqueue_frame() when compression
is not negotiated OR the body is below COMPRESSION_MIN_OUTPUT_BYTES
(50 bytes — same threshold the upstream MySQL X plugin uses; per-
message envelope + framing overhead would otherwise dwarf savings).
2. With combine_mixed_messages = false: emits one Compression frame
per body. The protobuf has server_messages set to the original
frame's msg_type and uncompressed_size set to the original body
length, so a spec-compliant client can decompress in place.
3. With combine_mixed_messages = true: appends a fully-framed copy
of the body to compress_batch_framed_ and bumps compress_batch_count_.
Once the count reaches max_combine_messages (defaulting to 64 if
the client didn't supply one), or flush_compression_batch() is
invoked at a natural boundary, all buffered frames are emitted as
one Compression message with NEITHER server_messages nor
client_messages set — payload is the concatenated stream of framed
X messages, matching the spec's third payload shape.
The flush points are:
- handler_waiting_server_msg() when it sees a terminal frame (end
of a result set / final OK / etc.) — the response is "done" so
anything still buffered must reach the wire before we go back to
WAITING_CLIENT_XMSG.
- handler_session_reset_waiting() on the ERROR path before
write_to_net(), same reasoning.
Mid-response we deliberately do NOT flush — that would defeat the
combine_mixed_messages benefit by emitting a Compression message per
batch hit, which is exactly what we're trying to avoid for streaming
result sets. The count cap bounds how long a single batch can grow.
Compressor selection mirrors Phase 2:
- zstd_stream uses ZSTD_compressCCtx() with a per-session ZSTD_CCtx
that's lazily allocated and freed in reset_compression_state().
- lz4_message uses LZ4_compress_default() one-shot.
On compressor failure (ZSTD_isError or lz4 returning <= 0) the helper
falls back to enqueueing the body uncompressed — losing compression
benefit beats dropping the message. The session itself stays healthy.
Tests
=====
mysqlx_compression_unit-t now plans 64 sub-tests, all passing:
- Phase 1: 22 sub-tests for capability negotiation
- Phase 2: 17 sub-tests for inbound decompression
- Phase 3 (new, 25 sub-tests):
- zstd round-trip: frame on the wire is COMPRESSION with
server_messages = NOTICE; payload decompresses back to the
exact original 200-byte body
- lz4 round-trip, same shape
- below-threshold passthrough: 20-byte body emitted as plain
NOTICE, not COMPRESSION (verifies the fast path)
- combine_mixed_messages with max_combine_messages=3: three
successive sends produce ONE Compression frame whose
decompressed payload contains all three NOTICE bodies in
order, with neither server_messages nor client_messages set
- compression-disabled passthrough: when no negotiation, the
helper acts as a plain enqueue_frame() (proves a client that
never opts in is unaffected)
A few new test-only accessors expose the batch state and
send_to_client_compressed() entry point so tests can exercise the
output path without wiring a fake backend (which would block on
connect() in the dispatcher anyway).
Verification
============
Top-level `PROXYSQLGENAI=1 make` builds cleanly. mysqlx_compression_unit-t
passes 64/64. plugin_lifecycle_unit-t (26/26) passes unchanged.
mysqlx_session_unit-t still has its two pre-existing failures at
sub-tests 33-34 (auth flow), unrelated to compression and present on
this branch before the Phase 1 commit.
|
4 weeks ago |
|
|
b1fd6b31fc |
feat(mysqlx): decompress incoming Compression messages (Phase 2)
Phase 2 of three-phase X Protocol compression support: client→server
decompression. Compression on the server→client path (Phase 3) still
goes out uncompressed; CapabilitiesSet stores the negotiation in
Phase 1 and this commit consumes it.
What this commit does
=====================
When the client sends a Mysqlx.Connection.Compression message AND
compression has been negotiated, we now:
1. Parse the Compression protobuf — payload bytes, optional
uncompressed_size hint, optional client_messages tag.
2. Decompress the payload using the negotiated algorithm:
- zstd_stream: streaming decompression via a ZSTD_DCtx that
persists across messages on the same session (per spec —
successive Compression frames may continue a single zstd
stream, so we cannot recreate the context per frame).
- lz4_message: one-shot LZ4_decompress_safe. The X spec defines
lz4_message as one independent frame per message, so no
persistent context is needed.
3. Feed the decompressed bytes back into client_ds_.feed_bytes() so
the existing frame parser picks them up. Two payload shapes per
spec are handled:
- client_messages set: payload is one decompressed body of that
type — we re-frame with a 5-byte X header in front.
- neither set: payload is already a sequence of fully-framed
X messages — fed verbatim.
4. The dispatch loop re-enters on the same handler tick (to_process
set), so a Compression-wrapped StmtExecute runs end-to-end without
an extra network roundtrip.
If client_messages is unset and server_messages IS set, the message
is rejected (5008): server_messages on the c→s path is always wrong.
Anti-bomb / bounds
==================
COMPRESSION_MAX_DECOMPRESSED_BYTES = 16 MiB caps how much output a
single Compression message can produce, mirroring MysqlxDataStream's
existing on-the-wire X_MAX_PAYLOAD_SIZE so a Compression frame never
expands beyond what the rest of the data plane can handle anyway. If
the client provides an uncompressed_size hint smaller than 16 MiB we
honor that as the tighter bound. Hint of 0 with non-empty payload is
treated as malformed.
For zstd, the decompression loop re-checks the cap before each
ZSTD_decompressStream call and bails (with 5008) the moment the
output buffer would exceed it. A no-progress condition (zout.pos == 0
with input remaining) also bails — that catches malformed streams
that would otherwise spin forever.
For lz4, LZ4_decompress_safe(dstCapacity = cap) naturally enforces
the limit: the decompressor refuses to write past dstCapacity and
returns an error code we map to 5008.
Linkage / build
===============
The plugin .so is dlopen'd with RTLD_LOCAL, so symbols from libzstd
/ liblz4 that the proxysql binary may already pull in are NOT
visible to the plugin. This commit links the static
deps/zstd/zstd/lib/libzstd.a + deps/lz4/lz4/lib/liblz4.a archives
directly into the .so so the plugin is self-contained.
The session header forward-declares ZSTD_DCtx / ZSTD_CCtx so the
zstd headers don't leak through include/mysqlx_session.h into other
translation units.
Tests
=====
mysqlx_compression_unit-t now covers Phase 2 end-to-end (39 sub-
tests total, all passing):
- Phase 1: capability negotiation (22 sub-tests, unchanged)
- decompress zstd_stream client_messages=SQL_STMT_EXECUTE,
inner StmtExecute reaches dispatch (no 5008, session moves
past WAITING_CLIENT_XMSG)
- same for lz4_message
- oversize bomb attempt: lie about uncompressed_size, send
a 1 MiB-of-zeros payload — rejected with 5008
- garbage compressed payload: rejected with 5008
- sanity: COMPRESSION before negotiation still 5008
Verification
============
Top-level `PROXYSQLGENAI=1 make` builds cleanly; the plugin .so
links against the static zstd + lz4 archives. plugin_lifecycle_unit-t
(26/26) passes unchanged. mysqlx_session_unit-t still has its two
pre-existing failures at sub-tests 33-34, identical to behavior
before this commit (verified by stashing only the Phase 2 edits to
plugins/mysqlx/{src,include}/* + Makefile and rebuilding). The
mysqlx_thread_unit-t / mysqlx_concurrent_unit-t hangs are also
pre-existing and reproduce on the unmodified branch.
|
4 weeks ago |
|
|
f19be5f3a0 |
feat(mysqlx): negotiate X Protocol compression capability (Phase 1)
Phase 1 of three-phase X Protocol compression support: capability
negotiation only. The COMPRESSION message itself is still rejected
with error 5008 in dispatch_client_message(); Phase 2 wires up
decompression on input and Phase 3 wires up compression on output.
What this commit does
=====================
- send_capabilities() now advertises a `compression` capability listing
the algorithms the plugin can support: zstd_stream and lz4_message.
Both libraries (libzstd, liblz4) are already statically linked into
libproxysql.a / pulled into the unit-test link line, so this does not
introduce any new runtime dependency.
- handler_capabilities_set() detects when a client sets the `compression`
capability and parses the OBJECT value's sub-keys:
- `algorithm` (required string) — must match an advertised value;
anything else is rejected with X-Protocol error 5052 (the
capability-prepare-failed code per the spec).
- `server_combine_mixed_messages` / `combine_mixed_messages` (bool)
- `server_max_combine_messages` / `max_combine_messages` (uint)
Both spelling variants are accepted because mysql-connector-python
emits the short form while libmysqlclient emits the spec form, and
the upstream MySQL server tolerates both.
- Negotiation outcome is stored on MysqlxSession via three new members
(compression_algo_, compression_combine_mixed_messages_,
compression_max_combine_messages_). Phase 2 / Phase 3 will read
these to drive (de)compression. They are reset by both init() and
reset() so a session reuse does not inherit stale negotiation.
- Unsupported algorithms (e.g. deflate_stream) and structurally
malformed values (wrong protobuf type, missing algorithm field) are
rejected with a non-fatal X-Protocol Error frame — the session
remains healthy so the client can either retry CapabilitiesSet or
proceed without compression.
Why 5052 (non-fatal) and not 5008
---------------------------------
5008 is the runtime "compression message arrived but compression is
disabled" error and stays in dispatch_client_message() for now. 5052
is the spec-defined "capability prepare failed" status used during the
CapabilitiesSet handshake; treating an unknown algorithm as a
capability error matches the upstream MySQL X plugin's behavior and
lets compliant clients downgrade to no-compression on the same
connection.
Tests
=====
New unit test: test/tap/tests/unit/mysqlx_compression_unit-t.cpp
(22 sub-tests, all passing). Covers:
- CapGet response advertises `compression` with both algorithms
- CapSet zstd_stream + combine hints accepted, stored on session
- CapSet lz4_message accepted, stored on session
- CapSet deflate_stream rejected with 5052 (non-fatal), session
remains healthy with no algorithm set
- CapSet with wrong-shape compression value (scalar instead of
object) rejected with 5052
Existing mysqlx_session_unit-t / plugin_lifecycle_unit-t still pass
(the two pre-existing failures in mysqlx_session_unit-t at sub-tests
33-34, "auth succeeded for correct password" and "session in
WAITING_CLIENT_XMSG after auth", are present on this branch before
this commit and unrelated to compression — verified by stashing only
the mysqlx_session.{cpp,h} edits and re-running).
Build infra fix piggy-backed on this commit
-------------------------------------------
test/tap/tests/unit/Makefile referenced
$(SQLITE3_LDIR)/../libsqlite_rembed.a in the GenAI-tier link line,
but that .a is no longer produced on this branch (it was the artifact
of the now-removed sqlite-rembed Rust extension). Without removing
this stale reference, no plugin/mysqlx unit test can link, which
blocks verifying the new compression test alongside the existing
mysqlx tests required by the task. Mirrors the upstream fix that
already landed on sibling branches as commit
|
4 weeks ago |
|
|
79cac4c976 |
chore(mysqlx): retire MysqlxFrontendSession, MysqlxBackendSession, X_FAST_FORWARD
Three pieces of dead code that survived the MysqlxWorker retirement
(commit
|
4 weeks ago |
|
|
c723ede0cf |
Merge remote-tracking branch 'origin/plugin-chassis' into ProtocolX-rebased
# Conflicts: # lib/ProxySQL_PluginManager.cpp # plugins/mysqlx/Makefile # plugins/mysqlx/include/mysqlx_plugin.h # plugins/mysqlx/include/mysqlx_session.h # test/tap/groups/groups.json # test/tap/tests/test_mysqlx_listener_smoke-t.cpp # test/tap/tests/unit/Makefile |
1 month ago |
|
|
b3d4de0bc8 |
Merge remote-tracking branch 'origin/v3.0' into plugin-chassis
# Conflicts: # test/tap/groups/groups.json |
1 month ago |
|
|
d2e03fae36 |
fix(test groups): resolve groups.json conflict + tag plugin tests for v4.0
The `test/tap/groups/groups.json` on `origin/v3.0` was reformatted and expanded (mysql95 targets added, legacy-g1..g5 merged into mysql84-g1..g5, etc.) in commits that landed after `plugin-chassis` branched. Merging `plugin-chassis -> v3.0` therefore produced a content conflict in this file. Resolve by taking `origin/v3.0`'s current `groups.json` as the base and re-adding every plugin-chassis and mysqlx-plugin test entry on top, each tagged with `@proxysql_min_version:4.0` per the existing tier convention (`test_mcp_static_harvest-t`, `anomaly_detection-t`, etc. already use this pattern). Tests tagged v4.0: * Plugin-chassis unit tests (7): plugin_config_unit-t, plugin_dispatch_unit-t, plugin_manager_unit-t, plugin_registry_unit-t, plugin_query_hook_unit-t, plugin_prometheus_unit-t, plugin_lifecycle_unit-t * Mysqlx-plugin unit tests (22): test_mysqlx_plugin_load-t, test_mysqlx_admin_tables-t, test_mysqlx_listener_smoke-t, mysqlx_config_store_unit-t, mysqlx_config_store_concurrent_unit-t, mysqlx_config_store_pure_unit-t, mysqlx_protocol_unit-t, mysqlx_protocol_socket_unit-t, mysqlx_route_store_unit-t, mysqlx_stats_unit-t, mysqlx_admin_schema_unit-t, mysqlx_admin_commands_unit-t, mysqlx_admin_disk_commands_unit-t, mysqlx_data_stream_unit-t, mysqlx_connection_unit-t, mysqlx_session_unit-t, mysqlx_thread_unit-t, mysqlx_message_dispatch_unit-t, mysqlx_concurrent_unit-t, mysqlx_backend_auth_unit-t, mysqlx_credential_verify_unit-t, mysqlx_robustness_unit-t, mysqlx_tls_unit-t * Mysqlx E2E tests (2, group `mysqlx-e2e-g1`): test_mysqlx_e2e_handshake-t, test_mysqlx_e2e_routing-t Formatting is preserved from v3.0 (one entry per line, alphabetically sorted, 2-space indent). Entries that existed only on plugin-chassis under the old per-line layout and were never in v3.0 are now inserted in the correct alphabetical position. |
1 month ago |
|
|
e462bb0cb4 |
fix: address PR review feedback
Resolves in-scope review items on PR #5651. Items deemed out of scope for this PR (O(N) admin dispatch lookup, per-plugin mutex, worker backpressure, runtime-reload DDL semantics, E2E tests going through ProxySQL rather than directly to MySQL) are tracked elsewhere; items that were already fixed in earlier commits on this branch (Admin_Handler MYSQLX alias vectors, Admin_Bootstrap PROXYSQL40 gating) are acknowledged as stale. Changes: * .github/workflows/CI-mysqlx.yml: add `include/` and `src/proxysql_global.cpp` to both `sparse-checkout` blocks. The plugin Makefile discovers the repo root via `src/proxysql_global.cpp` and includes headers from `include/`; without these, `make` inside `plugins/mysqlx` climbs up to `/` or fails on missing includes. (coderabbit: "Checkout the files required by the plugin Makefile.") * .github/workflows/CI-mysqlx.yml: `fail-on-cache-miss` now depends on `github.event_name == 'workflow_run'`. Strict behavior is retained for the cache-driven pipeline that CI-trigger populates; manual `workflow_dispatch` runs no longer fail when the SHA-specific cache doesn't exist yet. (coderabbit: "Don't make manual runs depend on a pre-existing build cache.") * plugins/mysqlx/Makefile: replace the unbounded `while [ ! -f ./src/proxysql_global.cpp ]; do cd ..; done` with a bounded upward walk (up to 12 levels) that fails fast with a clear error message when the marker file is missing — e.g. on a sparse checkout that omits `src/proxysql_global.cpp`. Build output no longer appears to hang indefinitely. (coderabbit: "Prevent root discovery from hanging on sparse or invalid checkouts.") * doc/PLUGIN_API.md: update startup sequence from the old three-phase (load → init → start) description to the four-phase chassis lifecycle (load → register_schemas → admin materialize → init → start). Document the `register_schemas` descriptor field and the `abi_version` / `PROXYSQL_PLUGIN_ABI_VERSION` contract. Clarify that `stop()` pairs with `init()` (not `start()`) for teardown symmetry. (coderabbit: "Update plugin lifecycle documentation to reflect four-phase model and ABI versioning.") * plugins/mysqlx/include/mysqlx_session.h: default-initialize every field in `MysqlxCredentials`. `bool x_enabled` was indeterminate for a default-constructed instance, which would let a lookup miss produce a value that silently authenticates. In-class initializers give every field a deterministic default. (coderabbit: "Default- initialize credential fields used by auth decisions.") * plugins/mysqlx/src/mysqlx_backend_session.cpp: close `backend_fd_` when `authenticate_backend()` returns false. Previously `connect()` stored the newly-opened fd in `backend_fd_` and returned the auth result; a retry on the same `MysqlxBackendSession` would then overwrite `backend_fd_` and leak the previous socket. (coderabbit: "Close/reset `backend_fd_` when authentication fails.") * lib/Admin_Bootstrap.cpp: `materialize_plugin_tables()` now runs DDL only for the subset of plugin-declared tables that were freshly inserted into `tables_defs_*` (the rest are already materialized). DDL failures are startup-fatal: on `execute()` returning false, log the plugin kind + table name + SQL and `exit(EXIT_FAILURE)`. A partially materialized schema produces opaque runtime errors from the plugin later on, so aborting startup is the right default. (gemini + coderabbit: "Execute DDL only for newly materialized plugin tables" / "add error checking".) Not changed in this commit (deferred / out of scope / stale): * CI-mysqlx E2E tests going through ProxySQL (requires plumbing listener + admin config in the CI workflow). * O(N) admin dispatch scan → hash map. * Descriptor build-id hash for libstdc++ compat detection. * Per-plugin mutex on mutable plugin context. * Worker client-fd enqueue backpressure. * Stale plan-doc feedback on docs/superpowers/plans/*.md. Verification (clean tree): * `unset PROXYSQL*; make cleanall && make debug -j$(nproc) && make build_tap_test_debug -j$(nproc)` -- 0 errors. * `PROXYSQLGENAI=1 make cleanall && PROXYSQLGENAI=1 make debug -j$(nproc) && PROXYSQLGENAI=1 make build_tap_test_debug -j$(nproc)` -- 0 errors. * Plugin unit tests (PROXYSQL40): 48 + 52 + 26 + 46 + 10 = 182 pass. |
1 month ago |
|
|
e20876a451 |
fix(tests): repair pre-existing mysqlx test build breakage
Under `export PROXYSQLGENAI=1 && export PROXYSQL40=1 && make debug -j &&
make build_tap_test_debug -j` the tap build failed with ~78 errors
spread across several mysqlx tests. None were caused by the chassis
work; they are drift between test code and current APIs that no plain
build had ever exercised (unit builds tried PROXYSQL40 without DEBUG;
the debug path uncovers them).
Changes:
* test/tap/tests/unit/mysqlx_route_store_unit-t.cpp (19 sites),
test/tap/tests/unit/mysqlx_stats_unit-t.cpp (7 sites),
test/tap/tests/unit/mysqlx_admin_commands_unit-t.cpp (1 site),
test/tap/tests/unit/mysqlx_admin_disk_commands_unit-t.cpp (2 sites):
the `// NOSONAR:` comment was placed BEFORE the closing `)` of
`SQLite3DB::open(..., FLAGS);`, commenting out both the flags and the
closing paren. Move the NOSONAR comment to end of line and restore
the flags argument.
* test/tap/tests/unit/mysqlx_stats_unit-t.cpp (28 sites):
`record_conn_ok/err/used` added a second argument (destination
hostgroup) in
|
1 month ago |
|
|
6edde821c7 |
fix(glovars): forward-declare debug_level for direct header consumers
proxysql_glovars.hpp uses `debug_level *gdbg_lvl` under #ifdef DEBUG
but does not include the proxysql_structs.h header where the type is
defined. Core code paths work because proxysql_structs.h #include's
proxysql_glovars.hpp AFTER defining debug_level -- so any TU that
includes proxysql_structs.h gets both, in the right order.
Plugin unit tests include proxysql_glovars.hpp directly (they only need
the GloVars struct layout, not the full core-side definitions). Under
`make debug` (which propagates -DDEBUG through autodetection in the
unit Makefile), proxysql_glovars.hpp:110 references debug_level without
the forward declaration it needs, producing:
error: ‘debug_level’ does not name a type
Reported when building `PROXYSQLGENAI=1 make debug &&
PROXYSQLGENAI=1 make build_tap_test_debug` from a clean tree.
Fix: add a forward declaration of `struct _debug_level` and typedef
inside proxysql_glovars.hpp under #ifdef DEBUG. C++ allows identical
typedefs across headers, so this doesn't conflict with the full
definition in proxysql_structs.h when both are seen by the same TU.
|
1 month ago |
|
|
f34dc4573a |
fix(tap tests): gate test_mysqlx_*-t under PROXYSQL40
test/tap/tests/Makefile's tests-cpp target uses `$(wildcard *-t.cpp)`
to pick up all test sources. test_mysqlx_e2e_handshake-t.cpp,
test_mysqlx_e2e_routing-t.cpp, test_mysqlx_listener_smoke-t.cpp,
test_mysqlx_admin_tables-t.cpp and test_mysqlx_plugin_load-t.cpp all
reference chassis types (ProxySQL_PluginServices, mysqlx_config_store.h)
that only exist in the public headers under -DPROXYSQL40.
Under a plain v3.0 build (`unset PROXYSQLGENAI && unset PROXYSQL40 &&
make debug -j && make build_tap_test_debug -j`), the wildcard still
matched them, and the generic `%-t: %-t.cpp` recipe tried to compile
them -- producing 130+ `error:` lines (mysqlx_config_store.h not
found, Mysqlx::Datatypes::* conversion failures, ProxySQL_PluginServices
undeclared, etc.). Reported by the user.
Fix: autodetect PROXYSQL40 via `nm libproxysql.a | grep -c
invoke_register_schemas_phase` (same probe the unit Makefile uses) and
filter out `test_mysqlx_*` from the wildcard when the chassis symbol is
absent. Under PROXYSQL40 the wildcard is unmodified and all mysqlx
tests are built as before.
Verification:
* `unset PROXYSQLGENAI && unset PROXYSQL40 && make debug -j &&
make build_tap_test_debug -j` -> 0 errors, builds complete.
- proxysql binary built (122 MB)
- ProxySQL_MySQLX_Plugin.so NOT built (skipped by top-level Makefile)
- 51 unit tests built, 0 plugin/mysqlx unit tests, 0 mysqlx tests/
tests -> chassis is completely invisible to v3.0.
|
1 month ago |
|
|
b65ba99118 |
fix(unit tests): gate plugin + mysqlx tests behind PROXYSQL40
After the previous commit made the plugin chassis invisible in v3.x
builds (no ProxySQL_PluginManager, no ProxySQL_PluginServices types
available from public headers), the unit-test Makefile still listed
all plugin/mysqlx tests in the unconditional UNIT_TESTS base list.
`make build_tap_test_debug` (no PROXYSQL40) then attempted to compile:
* test/tap/test_helpers/fake_plugin.cpp — uses ProxySQL_PluginServices,
ProxySQL_PluginCommandResult, ProxySQL_PluginDescriptor at file
scope; none of these exist under !PROXYSQL40.
* test/tap/tests/unit/plugin_{config,dispatch,manager,registry}_unit-t —
reference ProxySQL_PluginManager's public API.
* test/tap/tests/unit/mysqlx_*_unit-t + test_mysqlx_*-t — include
plugins/mysqlx/include/mysqlx_*.h which transitively include
ProxySQL_Plugin.h and use chassis types.
Reported by user with a `make debug && make build_tap_test_debug`
invocation that produced 121 `error:` lines and failed to link.
Move every plugin-chassis and mysqlx-plugin unit test out of the base
UNIT_TESTS list and into the existing `ifeq ($(PROXYSQL40),1)` block.
v3.x builds now build 23 core unit tests (smoke, query_cache, query
processor, protocol, auth, hostgroups, FFTO, etc.) and zero chassis
artifacts; PROXYSQL40 builds add the 31 plugin/mysqlx tests on top.
Verification:
* `unset PROXYSQLGENAI && unset PROXYSQL40 && make debug -j &&
make build_tap_test_debug -j` — 0 errors, 23 unit tests built,
fake_plugin.so not even attempted.
* `PROXYSQLGENAI=1 make debug -j && PROXYSQLGENAI=1 make
build_tap_test_debug -j` — 0 errors, full chassis + mysqlx test
suite builds (54 unit tests).
|
1 month ago |
|
|
3ba92815f8 |
fix(plugin-chassis): make chassis fully invisible in v3.x builds
Review feedback identified that the chassis was leaking into the v3.0
stable build via unfenced references in core code:
* Admin_Bootstrap.cpp had `if (auto* m = proxysql_get_plugin_manager())`
and a full materialize_plugin_tables() implementation outside any
PROXYSQL40 fence
* proxysql_admin.h declared materialize_plugin_tables()
* proxysql_glovars.hpp held GloVars.plugin_modules and
proxysql_load_plugin_modules_from_config()
* ProxySQL_GloVars.cpp had three unfenced .clear()/use sites
* ProxySQL_Admin.cpp::dispatch_plugin_admin_command (template + two
instantiations) was unfenced
* src/main.cpp's GloPluginManager, LoadConfiguredPlugins,
InitConfiguredPlugins, StartConfiguredPlugins, StopConfiguredPlugins,
UnloadPlugins teardown, the four-phase orchestration block, and the
proxysql_load_plugin_modules_from_config call were all unfenced
Separately, Admin_Handler.cpp held 16 hardcoded MYSQLX alias vectors
(LOAD_MYSQLX_USERS_FROM_MEMORY, etc.) and a 16-deep if-ladder that
called resolve_admin_alias_to_canonical(). This embedded plugin-specific
knowledge in core code -- core should know nothing about any specific
plugin's commands.
The agreed architecture: v3.0/v3.1 builds have NO plugin loader at all;
the entire plugin chassis (including its public manager surface, its
loader, and its dispatch helpers) only exists under PROXYSQL40. v3.0
core code therefore holds zero plugin-related code paths.
Changes:
* include/ProxySQL_Plugin.h, include/ProxySQL_PluginManager.h,
lib/ProxySQL_PluginManager.cpp: wrap entire file body in
`#ifdef PROXYSQL40 ... #endif`. Including the header from a v3.x
translation unit yields nothing; the .cpp compiles to an empty object
file. Removed redundant inner PROXYSQL40 fences inside the now-empty
v3.x body of Plugin.h (kept the few that are inside the file-wide
outer for clarity). PROXYSQL_PLUGIN_ABI_VERSION is now unconditionally
2 (the macro is no longer reachable from a v3.x compile, so the
PROXYSQL40-vs-1 split is moot).
* include/proxysql_glovars.hpp, lib/ProxySQL_GloVars.cpp: gate
GloVars.plugin_modules field, all .clear() sites, the
proxysql_load_plugin_modules_from_config declaration + definition.
* include/proxysql_admin.h: gate materialize_plugin_tables and
dispatch_plugin_admin_command<S> declarations.
* lib/Admin_Bootstrap.cpp: gate `#include "ProxySQL_PluginManager.h"`,
the `if (auto* m = proxysql_get_plugin_manager())` merge block, and
the materialize_plugin_tables definition.
* lib/Admin_Handler.cpp: delete the 16 LOAD_/SAVE_MYSQLX_* const
std::vector<std::string> declarations entirely. Delete the helper
resolve_admin_alias_to_canonical(). Delete the 16-deep if-ladder
+ the !PROXYSQL40 fallback dispatch branch. The remaining plugin
dispatch is one generic call to
proxysql_resolve_configured_plugin_admin_alias() inside an
#ifdef PROXYSQL40 block; v3.x compiles it out entirely. Core now
holds no plugin-specific knowledge of any kind.
* lib/ProxySQL_Admin.cpp: gate dispatch_plugin_admin_command template
body + both explicit instantiations.
* src/main.cpp: gate `#include "ProxySQL_PluginManager.h"`,
GloPluginManager declaration, all four wrapper functions
(LoadConfiguredPlugins / InitConfiguredPlugins /
StartConfiguredPlugins / StopConfiguredPlugins), the
StopConfiguredPlugins call inside UnloadPlugins, the four-phase
orchestration in ProxySQL_Main_init_phase2___not_started, the
GloVars.plugin_modules.clear() and the
proxysql_load_plugin_modules_from_config call in
ProxySQL_Main_process_global_variables. v3.x builds reduce that
whole block to a single ProxySQL_Main_init_Admin_module call.
* plugins/mysqlx/src/mysqlx_plugin.cpp,
plugins/mysqlx/src/mysqlx_admin_schema.cpp: drop the !PROXYSQL40
fallback paths. The plugin only loads under PROXYSQL40 now (no
loader exists in v3.x), so the legacy combined-init code path and
the 16 fallback register_command() calls were dead code. The
descriptor unconditionally wires register_schemas; mysqlx_init holds
only context setup.
* Makefile (top-level): the four build_src_* recipes that recurse into
plugins/mysqlx are wrapped in `$(if $(filter 1,$(PROXYSQL40)),...)`.
v3.x builds emit "[skip] mysqlx plugin (PROXYSQL40 not set)" instead
of building the .so. Clean targets stay unconditional.
* test/tap/tests/unit/mysqlx_admin_alias_resolution_unit-t.cpp:
delete the test (it covered resolve_admin_alias_to_canonical, which
is itself deleted). Remove from unit Makefile UNIT_TESTS list.
Verification:
* v3.0 stable build (`make`, no flags):
- Produces 147 MB src/proxysql binary
- `nm src/proxysql | grep -cE 'invoke_register_schemas_phase|GloPluginManager|materialize_plugin_tables'` -> 0
- mysqlx plugin .so is correctly skipped: "[skip] mysqlx plugin (PROXYSQL40 not set)"
* PROXYSQLGENAI=1 build (cascades PROXYSQL40/31/FFTO/TSDB):
- Produces 200 MB src/proxysql binary with chassis symbols
- mysqlx plugin .so built (9.2 MB), contains mysqlx_register_schemas
* All 5 plugin unit tests pass under PROXYSQL40:
plugin_config_unit-t 48/48
plugin_dispatch_unit-t 52/52
plugin_lifecycle_unit-t 26/26
plugin_query_hook_unit-t 46/46
plugin_prometheus_unit-t 10/10
|
1 month ago |
|
|
946c71fe2d |
build: set default goal to build_src, not the first target
The Makefile had `.DEFAULT: default` intending to make the `default` target
(which builds the project) the fallback when `make` is invoked with no
arguments. `.DEFAULT` is a different special target — it provides a
fallback *recipe* for targets with no rule, and has no effect on default
goal selection.
With the `lint-generate-cdb` target now defined above `default` in the
Makefile, plain `make` resolved to `lint-generate-cdb`, which invokes
`./scripts/lint/generate-compile-commands.sh`, which re-runs `bear -- make`
— with no arguments, triggering the same lint-generate-cdb path under Bear,
in an infinite fork loop. Each recursion spawned additional Bear
compile-intercept wrappers and the process tree grew without bound.
Replace `.DEFAULT: default` with `.DEFAULT_GOAL := default` so `make` with
no arguments correctly runs `default: build_src` as originally intended.
Equivalent to commit
|
1 month ago |
|
|
ab9d5a1036 |
fix(plugin-chassis): address deep-review findings
Follow-up to
|
1 month ago |
|
|
cd48c5613e |
feat(plugin-chassis): gate chassis ABI additions behind PROXYSQL40
The four-phase plugin lifecycle (Step 2.2), pre-execution query-hook ABI
(Step 2.1), shared Prometheus registry access (Step 2.3), and generic
admin-command alias dispatch (Step 2.5) introduce new plugin ABI surface
area — a new descriptor field (register_schemas), new services-struct
entries (register_query_hook, get_prometheus_registry,
register_command_alias), new public manager methods
(invoke_register_schemas_phase, dispatch_query_hook, etc.), and a new
startup ordering in main().
These changes should not appear in the v3.x stable/innovative tiers.
Wrap every chassis-only declaration, definition, and dispatch path in
`#ifdef PROXYSQL40` so the v3.0/v3.1 builds retain the pre-chassis
behavior: a single init()-only descriptor layout, two-phase load+init
lifecycle, and the hardcoded MYSQLX alias ladder in Admin_Handler.cpp.
Changes:
* Top-level Makefile: introduce PROXYSQL40 as a distinct tier above
PROXYSQL31. Cascade rule: PROXYSQLGENAI=1 implies PROXYSQL40=1
implies PROXYSQL31=1. Bump major version number on PROXYSQL40=1
(previously tied to PROXYSQLGENAI). Export PROXYSQL40 for recursive
submakes.
* lib/Makefile, src/Makefile: add -DPROXYSQL40 via $(PSQL40) so the
compile commands match the top-level tier selection.
* include/ProxySQL_Plugin.h: gate the register_schemas descriptor
field, query-hook types/enums/typedefs, the alias-registration
callback, and the trailing services-struct fields
(register_query_hook, get_prometheus_registry,
register_command_alias). The pre-chassis descriptor remains six
fields (name, abi_version, init, start, stop, status_json) so
plugins built against v3.x headers still link and load.
* include/ProxySQL_PluginManager.h: gate the chassis-exclusive public
methods and private members (schemas_registered, aliases,
services_phase_b_, query hook pointers). Provide two declarations
of proxysql_load_configured_plugins — the four-phase variant (paired
with proxysql_init_configured_plugins) under PROXYSQL40, the legacy
single-call variant otherwise.
* lib/ProxySQL_PluginManager.cpp: gate every method that belongs to
the chassis (invoke_register_schemas_phase, register_command_alias,
resolve_alias_to_canonical, register_query_hook, has_query_hook,
dispatch_query_hook), plus the services_phase_b_ initialization
(nullptr DB handle stubs), the proxysql_dispatch_configured_plugin_
query_hook entry point, and the alternate four-phase body of
proxysql_load_configured_plugins / proxysql_init_configured_plugins.
The legacy two-phase loader is restored under !PROXYSQL40.
get_admindb_service / get_configdb_service / get_statsdb_service
stay ungated because they back the unconditional services_ member.
* lib/Admin_Handler.cpp: gate the `#include \"ProxySQL_PluginManager.h\"`
and restore under !PROXYSQL40 the 16 hardcoded MYSQLX alias vectors
plus the 16-deep if-ladder in admin_handler_command_*(). Under
PROXYSQL40 the ladder is replaced by a single call to
proxysql_resolve_configured_plugin_admin_alias(), which is
plugin-agnostic.
* src/main.cpp: gate InitConfiguredPlugins and branch the startup
sequence in ProxySQL_Main_init_phase2___not_started:
- PROXYSQL40: LoadConfiguredPlugins (Phase A+B) -> admin init (C) ->
materialize_plugin_tables -> InitConfiguredPlugins (D) ->
StartConfiguredPlugins (E).
- !PROXYSQL40: admin init -> LoadConfiguredPlugins (combined
load+init) -> materialize_plugin_tables -> StartConfiguredPlugins,
matching the pre-chassis ordering.
* plugins/mysqlx/src/mysqlx_plugin.cpp: split init under PROXYSQL40
into mysqlx_register_schemas (schema + commands) and a minimal
mysqlx_init (context only). Under !PROXYSQL40 the original single
mysqlx_init remains. Descriptor conditionally wires
register_schemas.
* plugins/mysqlx/src/mysqlx_admin_schema.cpp: under PROXYSQL40 use
the reg() helper to register canonical+aliases via the new ABI;
under !PROXYSQL40 fall back to 16 direct register_command() calls
(aliases handled by Admin_Handler's hardcoded ladder).
* test/tap/test_helpers/fake_plugin.cpp: gate fake_query_hook,
fake_register_schemas, fake_descriptor_with_phase_b, the
REGISTER_QUERY_HOOK block in fake_init, and the ENABLE_PHASE_B
descriptor selection. The pre-chassis descriptor-returning stub is
the sole return path under !PROXYSQL40.
* test/tap/tests/unit/Makefile: autodetect PROXYSQL40 via
invoke_register_schemas_phase (the chassis-exclusive symbol) in the
library archive; add -DPROXYSQL40 to fake_plugin .so compilation so
the descriptor layout matches the loader's expectations; append the
three chassis-only tests (plugin_lifecycle, plugin_prometheus,
plugin_query_hook) to UNIT_TESTS only when PROXYSQL40=1.
* test/tap/tests/unit/plugin_config_unit-t.cpp,
test/tap/tests/unit/plugin_dispatch_unit-t.cpp: compile-time-gate
the chassis-only subtests, adjust plan() counts per mode
(48/50 with PROXYSQL40, 47/32 without), and provide a
proxysql_init_configured_plugins_compat() helper that is a no-op
returning true under !PROXYSQL40 so shared test helpers work in
both modes.
Verification — all plugin unit tests pass in both modes:
PROXYSQL40=1 build (chassis enabled):
plugin_config_unit-t: 48/48
plugin_dispatch_unit-t: 50/50
plugin_lifecycle_unit-t: 14/14
plugin_query_hook_unit-t: 41/41
PROXYSQL40=0 build (v3.x behavior):
plugin_config_unit-t: 47/47
plugin_dispatch_unit-t: 32/32
(plugin_lifecycle, plugin_query_hook not built)
|
1 month ago |
|
|
41918a42df |
docs(plugin-abi): Step 2.6 — ABI guidance on empty-source sync
Codifies the "stale rows" rule that PR #5643 fixed in the mysqlx plugin, so future plugins inheriting the three-tier disk/memory/ runtime pattern don't repeat the bug. The original mysqlx_plugin.cpp had: if (disk_cnt == 0) continue; if (cnt == 0) continue; as early exits inside sync_disk_to_memory / copy_to_runtime. On a plugin reload where the user had DELETEd all rows from the source tier, those early exits skipped the destination-side DELETE, leaving stale rows from a previous session surviving the reload — the exact observable "I removed every mysqlx_user yet they still work after reload" regression reported before #5643. The correct invariant (captured as an ABI contract comment next to ProxySQL_PluginDescriptor): after a sync transaction, dest == source row-for-row, including the empty case. Run the DELETE + INSERT unconditionally, inside a single BEGIN/COMMIT, with each execute() return checked and a ROLLBACK on any failure. Documentation-only; no code change. |
1 month ago |
|
|
51535aaeca |
feat(plugin-abi): Step 2.5 — generic admin-command alias dispatch
Replaces the hardcoded 16-deep MYSQLX alias ladder in
lib/Admin_Handler.cpp with a table-driven lookup against
ProxySQL_PluginManager::registered_commands. New plugins register their
own canonical + alias spellings and admin dispatches them without any
core change.
ABI (include/ProxySQL_Plugin.h):
* New callback typedef proxysql_plugin_register_command_alias_cb.
* Appended register_command_alias field to ProxySQL_PluginServices.
Additive, backward-compatible; plugins built against the previous
layout don't read past the older tail (same tail-extension rule
used in Step 2.2 for register_schemas).
Manager (lib/ProxySQL_PluginManager.cpp):
* registered_command_t grows an `aliases` vector of normalized
alternate spellings.
* ProxySQL_PluginManager::register_command_alias(canonical, alias)
— rejects collision with any other command's canonical or alias;
idempotent for duplicate (canonical, alias) pairs.
* ProxySQL_PluginManager::resolve_alias_to_canonical(sql) — returns
the canonical c_str() if the normalized `sql` matches a registered
command's canonical or any of its aliases; nullptr otherwise.
* dispatch_admin_command extended to match aliases too, and now
passes the canonical form (not the incoming spelling) to the
plugin callback — plugins match their own canonical strings only.
* register_command_alias_service trampoline wires the callback into
the active manager during init. Phase-B services expose this as
well, consistent with register_command availability.
Core dispatch (lib/Admin_Handler.cpp):
* Deleted the 16 hardcoded MYSQLX alias vectors (LOAD/SAVE MYSQLX
{USERS,ROUTES,BACKEND ENDPOINTS,VARIABLES} {FROM MEMORY,TO DISK},
...) — ~65 lines.
* Replaced the 16-deep if-ladder of resolve_admin_alias_to_canonical
calls with a single proxysql_resolve_configured_plugin_admin_alias
call. No MYSQLX-specific code left in Admin_Handler; the
dispatcher is now plugin-agnostic.
mysqlx plugin (plugins/mysqlx/src/mysqlx_admin_schema.cpp):
* mysqlx_register_admin_schema now calls register_command_alias for
every user-friendly alternate spelling that previously lived in
Admin_Handler's hardcoded vectors:
LOAD MYSQLX * TO RUNTIME: "FROM MEMORY", "FROM MEM", "TO RUN"
SAVE MYSQLX * TO MEMORY: "TO MEM", "FROM RUNTIME", "FROM RUN"
(disk commands: no aliases, as before)
Tests:
* plugin_dispatch_unit-t gets one new case covering the spec's
requirement — two plugins registering non-conflicting commands,
each with its own alias set. Asserts: canonical dispatch routes
correctly; alias dispatch routes to the owning plugin's callback;
resolve_alias_to_canonical returns the canonical regardless of
which spelling was used to probe it; whitespace/case normalization;
cross-plugin alias shadowing is rejected; duplicate (canonical,
alias) registration is idempotent. plan(32) -> plan(50).
No behavior change for users: the exact same set of LOAD/SAVE MYSQLX
spellings continues to work; the routing now goes through the plugin
manager rather than through Admin_Handler-embedded tables. A future
plugin that wants to add admin commands can do so entirely from its
own source — no core touch required.
|
1 month ago |
|
|
f13463d334 |
feat(plugin-abi): Step 2.2 — four-phase plugin lifecycle
Adds the register_schemas() callback to the plugin descriptor and
wires the loader + main.cpp so that a plugin's schema is declared
BEFORE the admin module bootstraps, and the plugin's init() runs
AFTER the schema has been materialized.
Phase sequence (previously two-phase: load+init):
A. load() — dlopen each .so, read the descriptor.
B. register_schemas() — NEW, optional; plugin calls services->register_table
with its admin/config/stats table defs. Services
hand has register_table live but all DB-handle
getters stubbed to nullptr.
C. ProxySQL_Main_init_Admin_module + GloAdmin->materialize_plugin_tables
— admin bootstrap drains the pending-tables list
via merge_plugin_tables (first-boot == reload).
D. init() — plugin's startup logic with full services
(live DB handles pointing at a schema that
already contains its own tables).
E. start() — plugin launches threads / accept loops.
ABI (include/ProxySQL_Plugin.h):
* New callback typedef proxysql_plugin_register_schemas_cb.
* New descriptor field register_schemas — appended at the end of
ProxySQL_PluginDescriptor so existing 6-field initializers leave
it null (aggregate init value-initializes the trailing slot).
Plugins that left register_schemas null keep the pre-existing
two-phase behavior: Phase B is skipped and their init() is
responsible for both schema registration and startup work.
* Phase-by-phase services availability matrix documented next to
ProxySQL_PluginServices.
Manager (lib/ProxySQL_PluginManager.cpp):
* invoke_register_schemas_phase(err) — public method that runs
Phase B for every plugin whose descriptor sets the callback.
Uses a "services_phase_b_" variant where DB-handle getters are
nullptr stubs; register_query_hook returns false with a warning
(hooks cannot register this early).
* proxysql_load_configured_plugins() — now stops at Phase B. On
success, installs the built manager as the active one so that
ProxySQL_Admin::materialize_plugin_tables (which reads from the
active manager's pending-tables list) sees the registered
tables.
* proxysql_init_configured_plugins() — new entry point, calls
init_all() for Phase D. Separated from load so admin bootstrap
can run between the two.
Main (src/main.cpp):
* Reorder in ProxySQL_Main_init_phase2___not_started:
LoadConfiguredPlugins(); // Phase A + B
ProxySQL_Main_init_Admin_module(...); // Phase C
GloAdmin->materialize_plugin_tables(); // Phase C (materialize)
InitConfiguredPlugins(); // Phase D — NEW
StartConfiguredPlugins(); // Phase E
* Error messages updated to name the phase that failed.
mysqlx plugin:
* mysqlx_init split into:
- mysqlx_register_schemas() — calls mysqlx_register_admin_schema
(pure services->register_table use, no DB access);
- mysqlx_init() — wires the plugin context (services, config
store, started flag) and returns true.
* Descriptor wires the new callback, exercising the full four-
phase path end-to-end.
Tests:
* plugin_lifecycle_unit-t (new) — four cases: both callbacks fire in
order; register_schemas-null skips Phase B; Phase-B DB handles
return nullptr; Phase-B failure aborts init.
* plugin_config_unit-t, plugin_dispatch_unit-t, plugin_query_hook_unit-t
— existing tests updated to also call proxysql_init_configured_plugins
after proxysql_load_configured_plugins where init side-effects are
asserted. test_init_registration_failure_aborts_load reworked: the
fake plugin's invalid-table registration happens in init (not
register_schemas), so load now succeeds and the failure surfaces at
init time.
* test_mysqlx_admin_tables / test_mysqlx_listener_smoke — add an
explicit invoke_register_schemas_phase() call before init_all()
so the mysqlx plugin's schema gets registered under its new
split.
No behavior change for plugins that didn't opt into Phase B: they
still see the same services_ layout and the same {load, init, start,
stop} ordering. Opt-in plugins gain DB access from init() against a
schema that already contains their tables, eliminating the chicken-
and-egg that required ProtocolX's
|
1 month ago |
|
|
872479aeba
|
Merge pull request #5650 from sysown/feat/cla-assistant-setup
Add Contributor License Agreement (ICLA + CCLA) |
1 month ago |
|
|
615a620ee6 |
Add Contributor License Agreement (ICLA + CCLA) for CLA assistant
Introduces .github/CLA.md with both Individual and Corporate variants,
adapted from the Apache ICLA v2.2 and Software Grant / Corporate CLA
(r190612) with the following changes:
- "The Apache Software Foundation" replaced with "ProxySQL LLC"
throughout; downstream references to "the Foundation" become "the
Company".
- Nonprofit-specific language ("not use Your Contributions in a way
that is contrary to the public benefit or inconsistent with its
nonprofit status and bylaws") removed — ProxySQL LLC is a commercial
entity, so the reservation reduces to the simpler "Except for the
license granted herein to the Company and recipients of software
distributed by the Company, You reserve all right, title, and
interest in and to Your Contributions."
- Email-submission instructions and PDF form fields removed; signing
is handled by the CLA assistant (https://cla-assistant.io) flow and
identity is captured from the contributor's GitHub account.
- Apache-specific references removed (Apache IDs, Apache mailing
lists, Apache privacy policy).
Substance of the license grants, definitions, and representations is
preserved verbatim from the Apache templates.
CONTRIBUTING.md gains a 'Contributor License Agreement' section linking
to .github/CLA.md and describing the CLA assistant signing flow.
Two browser steps still required to activate:
1. Sign in to cla-assistant.io as a sysown/proxysql admin
2. Point it at https://github.com/sysown/proxysql/blob/v3.0/.github/CLA.md
(after this PR is merged so the raw URL resolves). No workflow file
or webhook is needed; the bot operates via the installed GitHub App.
Recommend legal review before enforcing on PRs.
|
1 month ago |
|
|
6fe50376d5 |
Merge remote-tracking branch 'origin/feature/mysqlx-route-identity' into HEAD
# Conflicts: # plugins/mysqlx/src/mysqlx_session.cpp # test/tap/tests/unit/Makefile # test/tap/tests/unit/mysqlx_robustness_unit-t.cpp |
1 month ago |
|
|
017496bc45 |
test(mysqlx): add runtime_mysqlx_variables to config-store test fixture
MysqlxConfigStore::load_from_runtime issues five fetch_result queries in sequence and returns false (leaving the store empty) if any one fails. One of those queries — SELECT FROM runtime_mysqlx_variables — hit a table that create_test_db() never created, so every scenario that depended on data actually being loaded silently short-circuited before the swap. Effect: eight assertions in mysqlx_config_store_pure_unit-t.cpp were quietly failing under the pre-existing plan(25) — none of the tests that exercised a loaded identity, route, or endpoint were actually verifying the production code, because identities_/routes_/ hostgroup_endpoints_ were never populated. Adding the DDL fixes all eight. No production changes; test harness only. |
1 month ago |
|
|
c32c2fed35 |
scripts/lint: pass explicit target to bear-wrapped make
generate-compile-commands.sh wrapped the top-level build with
bear -- make -j\$(nproc)
with no explicit target, so the inner make resolved its default goal
dynamically. Combined with the previous Makefile bug that left
lint-generate-cdb as the default goal, invoking `make` with no arguments
produced an exponential fork bomb: lint-generate-cdb → this script →
bear -- make -jN → lint-generate-cdb → this script → …, with each level
forking up to \$(nproc) concurrent sub-makes under Bear's LD_PRELOAD
exec intercept. Spawned hundreds of `bear -- make -jN` processes before
grinding the system to a halt.
The Makefile default-goal fix in
|
1 month ago |
|
|
4f8764ee73 |
build: set default goal to build_src, not the first target
The Makefile had `.DEFAULT: default` intending to make the `default` target (which builds the project) the fallback when `make` is invoked with no arguments. `.DEFAULT` is a different special target — it provides a fallback *recipe* for targets with no rule, and has no effect on default goal selection. GNU make picks the first real target as the default goal unless `.DEFAULT_GOAL` is set. The first real target in this Makefile is `lint-generate-cdb` (line 19), so `make` with no arguments ran `scripts/lint/generate-compile-commands.sh`, which does `bear -- make -j\$(nproc)` — a full rebuild of the project under Bear's compile-intercept wrappers. Each C++ compile under Bear spawned a wrapper process, producing hundreds of bear processes per plain `make` invocation and burying the intended default behaviour. Replace `.DEFAULT: default` with `.DEFAULT_GOAL := default` so `make` with no arguments runs `default: build_src` as originally intended. |
1 month ago |
|
|
6435524416 |
ci(mysqlx): run all mysqlx tests and fail fast when X Protocol missing
CI-mysqlx.yml previously only ran the test_mysqlx_e2e_* binaries and hard-coded the MYSQLX_E2E_* variables inline. That missed the integration smoke tests (test_mysqlx_admin_tables, test_mysqlx_listener_smoke, test_mysqlx_plugin_load) and meant the group's env.sh was never consulted, so MYSQLX_E2E_PROXYSQL_PORT was unset and test_mysqlx_e2e_routing-t silently skipped. Now the step sources test/tap/groups/mysqlx-e2e/env.sh and iterates every test_mysqlx_*-t binary. Errors out if the glob matches nothing, so a future rename that quietly elides every mysqlx test doesn't pass a green CI. env.sh: use the mysqlx_test / mysqlx_test credentials provisioned by setup-infras.bash, not root with empty password. setup-infras.bash: return exit 1 when X Protocol isn't reachable on 33060 rather than exit 0, so CI actually fails instead of running every test against a missing backend. pre-cleanup.bash: derive the sandbox version from the msb_*/ directory name rather than hardcoding 8.4.8. setup-infras.bash uses --newest so the patch level drifts with upstream MySQL releases. |
1 month ago |
|
|
a2e99eed50 |
perf(mysqlx): only invoke handler() for sessions with real work
process_all_sessions previously forced sess->to_process=true on every tick and unconditionally called sess->handler(), burning CPU at large idle session counts (one full state-machine traversal per session per loop iteration, regardless of whether anything had changed). Now only call handler() when at least one of these is true: - a poll event landed on the client or server data stream - the session self-flagged to_process (handler wants to re-run) - a complete frame is already buffered on either stream Also make Mysqlx_Thread::sessions_mutex_ mutable and take it in get_session_count() const. Previously const accessors that needed to lock the mutex couldn't — and the session count was read without the lock at all, racing the writer that appends/removes sessions. |
1 month ago |
|
|
bbe8122511 |
fix(mysqlx): reject auth without credential_lookup and release pooled fd
Session auth previously accepted any client when credential_lookup_ was unset — an open-proxy fallback that turned a wiring bug into a silent security hole. Both PLAIN (handle_auth_plain) and MYSQL41 (handler_auth_challenge_response) now hard-reject with 1045 when no lookup is installed. A credential_lookup is always wired from mysqlx_thread.cpp via the config store, so there is no legitimate code path that reaches auth without one. Also tightened the credential check: password_hash must be exactly 20 bytes (MYSQL41 hash length) rather than simply non-empty, which could previously let a short or garbage hash pass CRYPTO_memcmp's min()-clamped comparison. In return_backend_to_pool(), replace the fresh-construct move-assign over server_ds_ with server_ds_.close_and_reset(). The old code constructed a new MysqlxDataStream (fd=-1, no SSL) and moved it in, whose destructor then close()d the fd that had just been returned to the pooled MysqlxConnection — silently corrupting the pool entry. close_and_reset() releases SSL/buffers without touching the fd. Unit test mysqlx_robustness_unit-t.cpp: setup_authenticated_session now installs a real credential_lookup with a known password, drives the server's AuthenticateContinue frame to extract the challenge, and computes the MYSQL41 scramble reply. This matches the new reality that auth requires a valid lookup. The previously-misnamed test_mysql41_no_credential_lookup_ accepts_any is renamed _rejects and asserts that without a lookup the session goes unhealthy and does not reach WAITING_CLIENT_XMSG. |
1 month ago |
|
|
6a921514cc |
fix(mysqlx): protocol, data-stream and stats robustness fixes
mysqlx_connection.cpp:
Drain leading NOTICE frames in read_auth_frame() instead of returning
nullopt on the first NOTICE. MySQL backends commonly emit a
session-state-change notice before AuthenticateContinue or Ok, and
returning nullopt caused the auth state machine to spin on try-read
for the full 10s handshake timeout before completing. The two callers
(step_auth_capabilities_get_sent and step_auth_capabilities_set_sent)
now use the shared helper and drop their duplicated NOTICE checks.
Also added a frame-size guard before reading the message-type byte.
mysqlx_data_stream.{h,cpp}:
Add close_and_reset() which tears down SSL/BIO state and clears every
read/write buffer and parse flag without close()ing the fd. Required
by mysqlx_session.cpp's return_backend_to_pool(), where the fd is
owned by the pooled MysqlxConnection and must stay open after the
data stream is wiped. Fix SSL_read return handling: a 0-return is a
clean TLS shutdown (close_notify) and must surface as a connection
close, not as a WANT_IO/retry. The previous code treated 0 and <0
identically and would loop forever on a cleanly-closed TLS peer.
mysqlx_protocol.cpp:
mysqlx_build_frame now rejects serialized payloads at the uint32
boundary so the +1 for the message-type byte cannot wrap to 0. This
mirrors the X_MAX_PAYLOAD_SIZE clamp already applied by the inbound
parser in MysqlxDataStream.
mysqlx_stats.cpp:
Rewrite the stats_mysqlx_routes INSERT builder to use std::string
concatenation instead of a fixed 1024-byte snprintf buffer. Long
route names plus escaping could overflow the buffer and the row was
silently dropped without reaching the statsdb.
|
1 month ago |
|
|
84e90e5e3c |
build(mysqlx): pin protobuf ABI and harden plugin .so flags
Detect the installed libprotobuf via pkg-config at configure time and fail fast unless it is 3.x. The vendored .pb.cc/.pb.h were generated with protoc 3.21.12, and the plugin links dynamically against the system libprotobuf — which is ABI-compatible only within the 3.x major version (4.x released with an incompatible ABI and a changed SONAME). Without this check, a .so that linked cleanly would crash the first time a virtual dispatched into the proto runtime. Add -fvisibility=hidden and -fvisibility-inlines-hidden so only the explicitly extern "C"-declared proxysql_plugin_descriptor_v1 entry point is exported. Prevents ODR collisions with the proxysql core when the .so is dlopen'd, and stops template instantiations from leaking across the boundary. Add -fstack-protector-strong unconditionally, and -D_FORTIFY_SOURCE=2 when not building under ASAN and when OPTZ is not -O0 (both conditions are incompatible with FORTIFY_SOURCE). Install the built ProxySQL_MySQLX_Plugin.so to /usr/lib/proxysql/plugins/ from the top-level Makefile install target, with matching cleanup in uninstall. Previously the plugin was built but never staged into a system location, so `make install` produced a proxysql binary that couldn't find it. |
1 month ago |
|
|
f104116926 |
fix(plugin-mgr): serialize lifecycle and always reset manager on stop
Add g_plugin_lifecycle_mutex to serialize load/start/stop transitions so two reload paths cannot race on g_registry_target and the registration-failure globals. g_active_plugin_manager_mutex remains the pointer-read guard for the dispatch path; the new mutex is held only for the duration of a lifecycle transition. In proxysql_stop_configured_plugins, always call manager.reset() so the .so is unmapped and no stale function pointers remain reachable, even when stop_all() reports a failure. stop_all() is idempotent across failure (each plugin is marked stopped after one attempt) so the destructor's stop_all() will be a no-op. Also fix the log-level table in PLUGIN_API.md: numeric levels are 3 (Error), 4 (Warning), and any-other (Info), matching the internal proxy_* severity scheme — not 1/2/3 as previously documented. |
1 month ago |
|
|
d0f6d8e4a8 |
Merge remote-tracking branch 'origin/fix/mysqlx-listener-lifecycle' into HEAD
# Conflicts: # plugins/mysqlx/Makefile # plugins/mysqlx/src/mysqlx_plugin.cpp # test/tap/tests/unit/Makefile # test/tap/tests/unit/mysqlx_robustness_unit-t.cpp |
1 month ago |
|
|
fb1a0cd706 |
Merge remote-tracking branch 'origin/fix/mysqlx-backend-tls-post-auth' into HEAD
# Conflicts: # test/tap/tests/unit/mysqlx_robustness_unit-t.cpp |
1 month ago |
|
|
5ed92a7594
|
Merge pull request #5646 from sysown/fix/mysqlx-check-connect-poll
fix(mysqlx): harden check_connect() poll and getsockopt handling |
1 month ago |
|
|
9bbc0d71a4
|
Merge pull request #5643 from sysown/fix/mysqlx-stale-row-sync
fix(mysqlx): sync empty source tables to overwrite stale rows |
1 month ago |
|
|
541dc0aaec
|
Merge pull request #5642 from sysown/chore/retire-dead-mysqlx-worker
chore(mysqlx): retire dormant MysqlxWorker path and its smoke test |
1 month ago |
|
|
dbb40a30ba
|
Merge pull request #5647 from sysown/v3.0-slim-dbdeployer-images
v3.0: slim dbdeployer images + test-harness and monitor fixes |
1 month ago |
|
|
0ce8693c29 |
ci: disable CI-taptests-groups auto-trigger (same 403 on jenkins-build-scripts)
All four matrices (tests, tests/unit, tests_with_deps/*) of CI-taptests-groups fail at the 'Checkout jenkins_build_scripts' step with: fatal: unable to access 'https://github.com/proxysql/jenkins-build-scripts/': The requested URL returned error: 403 Same root cause as the CI-repltests / CI-shuntest disabling in the previous commit: GH_TOKEN_PROXYSQL no longer has access to the proxysql/jenkins-build-scripts repo. Comment out the workflow_run trigger so the workflow stops firing automatically on every push; workflow_dispatch is preserved for manual re-runs once the secret is refreshed. |
1 month ago |
|
|
feed404031 |
ci: disable repltests/shuntest auto-trigger and fix 'make unit_tests'
Two test-infrastructure fixes on this branch.
1) CI-repltests / CI-shuntest: every run since the upstream
proxysql/jenkins-build-scripts access broke has been failing at the
Checkout step with HTTP 403. Comment out the workflow_run trigger so
they no longer auto-fire on every push; keep workflow_dispatch so
they can still be manually re-run once the token/repo-access is
fixed. Same root cause affects CI-taptests-groups as well — that
needs the GH_TOKEN_PROXYSQL secret refreshed, not a code change.
2) test/tap/tests/unit/Makefile: 'make unit_tests' (invoked from
test/tap/Makefile via $(MAKECMDGOALS)) failed with
make[1]: *** No rule to make target 'unit_tests'
because the unit Makefile only exposed 'all' and 'debug'. Commit
|
1 month ago |
|
|
04afb09886 |
ci: retrigger CI after MySQL APT keyring fix (#5649)
|
1 month ago |
|
|
deb1cbe93e |
test_cluster_sync: widen sync timeout, fix own-vs-remote query mix-up
Two test-only fixes for the cluster-sync flakes on legacy-g5 /
mysql84-g5 / mysql90-g5 when groups run concurrently.
1) get_checksum_sync_timeout() used
((cluster_check_interval_ms/1000) * cluster_check_status_frequency) + 1
which integer-truncated the ms→s conversion (1001ms → 1s) and left
only 1s of slack on top of a full status-collection cycle. A single
cycle slipping under CI load — exactly what
|
1 month ago |
|
|
ee6d4e506a |
ci: retrigger CI after MySQL APT key fix
|
1 month ago |
|
|
25c8fd1609 |
test/tap/tests: drain in-flight monitor cycle in pgsql-servers_ssl_params-t
The test samples PgSQL_Monitor_ssl_connections_OK immediately after LOAD PGSQL SERVERS TO RUNTIME, then sleeps 5s and checks the counter did not advance (TLSv1 pin should have broken SSL). A monitor connect cycle scheduled with the OLD params can land AFTER ok_before is taken but BEFORE the sleep, succeeding and falsely bumping the counter. Poll for two consecutive equal 1s samples so ok_before is recorded after the new config has taken effect and the counter has plateaued. |
1 month ago |
|
|
96c686dafa |
MySQL_Monitor: GR thread ignores cached ping state on first iteration
Why: mysql_server_ping_log can carry stale "unpingable" entries from before monitor_GR_thread_HG was (re)started (e.g. a previous test left those hostnames marked bad). With the cache filter applied on the very first cycle, find_resp_srvs() returns empty, the writer HG stays empty for a full healthcheck_interval, and GR-based tests flake on warm-up. Probe all configured hosts on the first iteration so subsequent cycles see a fresh ping_log. The filter resumes from iteration two onward. |
1 month ago |
|
|
9ed621edac |
test: substantially expand plugin unit test coverage
Plugin assertions: 63 → 230 (+167) across 4 binaries.
Per-binary deltas (assertions / plan):
plugin_registry_unit-t : 25 → 68 (+43)
plugin_manager_unit-t : 26 → 83 (+57)
plugin_config_unit-t : 12 → 47 (+35)
plugin_dispatch_unit-t : - → 32 (new file)
New coverage areas:
Registry edge cases:
- case-insensitive duplicate-table detection (lower vs upper vs mixed)
- case-insensitive duplicate-command detection across canonical forms
- tabs / newlines / multi-space canonicalisation
- leading + trailing spaces, multiple trailing semicolons (incl. interleaved)
- internal semicolons preserved (not collapsed)
- ";;;" / whitespace-only / "\\t\\n \\r ;" canonicalise to empty → reject
- register_table input validation (null name, empty name, null/empty def,
out-of-range db_kind)
- same-name tables across admin/config/stats kinds all accepted
- tables() returns empty for invalid db_kind
- insertion-order preservation for both tables and commands
- 64-table stress: all stored pointers remain valid after deque growth
- 2KB command roundtrip
- dispatch result fields (error_code / rows_affected / message) propagated
Manager state machine:
- load on a missing path: false, non-empty err mentions dlopen, size stays 0
- empty manager: init/start/stop all succeed
- idempotent init/start/stop (re-calls are no-ops)
- destructor stops started plugins (verified via log)
- destructor SKIPS plugins that were never started
- destructor doesn't re-run stop if explicit stop_all already happened
- register_command failure inside init_all aborts and names the operation
- register_table-with-invalid-kind inside init_all aborts and names op
Multi-plugin (new fake_plugin2.so):
- init/start happen in registration order; stop runs in reverse order
(verified via shared log)
- second plugin's init failure prevents both starts (no destructor stops)
- second plugin's start failure: first plugin (which started) IS stopped
by the destructor, second is NOT (never successfully started)
Config helpers:
- multiple plugins parsed
- empty plugins=() clears stale modules
- non-string entries (int, bool) silently skipped between strings
- missing path bubbles up with the path in err
- active manager visibility before/after load and stop
- reload replaces previous manager (full lifecycle for both old and new)
- reload to empty list: previous plugin stopped, manager nulled
- partial-load failure leaves no active manager behind
New plugin_dispatch_unit-t:
- global dispatcher returns false when no manager active
- dispatcher canonicalises input the same way registry does
- dispatcher tolerates context with all-null DB pointers
- dispatcher returns false after stop, even for a previously-routed command
- 8 threads x 250 dispatches concurrent: 2000/2000 succeed, 0 fail
- stop helper / start helper safe on null inputs
Infrastructure changes:
- test/tap/test_helpers/fake_plugin.cpp: parameterised via FAKE_PLUGIN_NAME
and FAKE_PLUGIN_ENV_PREFIX so the same source can be compiled into a
second .so (libproxysql_fake_plugin2.so) used by multi-plugin tests.
Log entries now prefixed with "<name>:" so a shared log file can
distinguish events from each plugin.
- test/tap/tests/unit/Makefile: builds the second .so, wires it into
plugin_manager_unit-t and plugin_config_unit-t, and adds the new
plugin_dispatch_unit-t target.
All 57 unit-test binaries pass.
|
1 month ago |
|
|
398b833aeb |
feat(plugin-abi): Step 2.3 — shared Prometheus registry access
Second half of Step 2 from the GenAI plugin carve-out design. Lets plugins register their counters / gauges / histograms against the same prometheus::Registry core uses; their metrics surface alongside core's at the same /metrics endpoint scrapers already poll. ABI extension (include/ProxySQL_Plugin.h): - Forward-declare prometheus::Registry to avoid pulling prometheus-cpp into the plugin ABI header. - proxysql_plugin_get_prometheus_registry_cb typedef. - New field on ProxySQL_PluginServices: get_prometheus_registry, added at the end of the struct (additive -- older plugins stop reading at the previous member). Manager (lib/ProxySQL_PluginManager.cpp): - get_prometheus_registry_service() returns GloVars.prometheus_registry.get(). - Wired into services_ at construction. Lifetime is simpler than initially documented: GloVars (and its prometheus_registry shared_ptr, allocated in its constructor) exists before any plugin is loaded, so the service returns non-null for every callback the plugin will see (init, start, admin command callback, query hook). ABI-header docs updated to reflect this -- plugins MAY register metrics in init() if they want them visible from first scrape. New unit test: plugin_prometheus_unit-t (10 assertions) - after test_init_minimal, GloVars.prometheus_registry is non-null. - A counter registered through prometheus-cpp directly (BuildCounter + Register(*reg)) is visible in the registry's text serialisation by name; the counter's Value() reflects increments through the same prometheus-cpp API plugins will use. - The registry pointer captured BEFORE plugin load equals the pointer observed during init/start AND after stop -- the loader does not swap, replace, or null out the registry; it only installs a service callback that points at it. All 60 unit-test binaries pass. Note: this finishes the Step 2 ABI surface (query hook + Prometheus registry). Step 3 starts moving real GenAI subsystems -- Anomaly_Detector first -- which will be the first consumer of the query hook from inside the plugin and the first plugin to register a metric against the shared Prometheus registry. |
1 month ago |
|
|
55556979e0 |
feat(plugin-abi): Step 2.1 — pre-execution query-hook ABI + dispatch
First half of Step 2 from the GenAI plugin carve-out design (see
docs/superpowers/specs/2026-04-16-genai-plugin-carveout-design.md).
Adds the query-hook ABI surface and the manager-level dispatch, but
NOT yet the hot-path call sites in MySQL_Session / PgSQL_Session --
those are intentionally split into the next commit so the hot-path
diff stays small and reviewable on its own.
ABI extension (include/ProxySQL_Plugin.h):
- ProxySQL_PluginProtocol enum {mysql, pgsql}
- ProxySQL_PluginQueryHookPayload {user, client_ip, schema, query_text, query_len}
- ProxySQL_PluginQueryHookAction enum {allow, deny}
- ProxySQL_PluginQueryHookResult {action, message}
- proxysql_plugin_query_hook_cb typedef
- proxysql_plugin_register_query_hook_cb typedef
- new field on ProxySQL_PluginServices: register_query_hook
(additive at the end of the struct -- older plugins that were built
against the previous layout don't read past it; new plugins must
check non-null before calling, same convention used elsewhere)
Manager (lib/ProxySQL_PluginManager.cpp + .h):
- One hook per protocol per manager (nullptr means "no hook").
- register_query_hook(proto, cb): rejects null cb; rejects duplicate
registration for a protocol that already has a hook; surfaces
registration errors through the same note_registration_failure /
init-aborts path that register_table and register_command use.
- dispatch_query_hook(proto, payload, result): synchronous,
returns true if a hook fired and stored its result, false otherwise.
- has_query_hook(proto): cheap predicate for the hot-path predicate.
Global helpers (for the hot path, next commit):
- proxysql_dispatch_configured_plugin_query_hook(proto, payload, result):
takes the active-manager mutex, dispatches if there is one.
- proxysql_has_configured_plugin_query_hook(proto): lock-free atomic
read of the manager pointer + a pointer-sized field read. Designed
to be the gate the hot path checks first; the dispatch call can be
elided entirely on the no-plugin path. Documented as
spurious-true-tolerant -- the dispatch helper re-checks under the
lock.
Test plugin extension (test/tap/test_helpers/fake_plugin.cpp):
- New env vars PROXYSQL_FAKE_PLUGIN[2]_REGISTER_QUERY_HOOK,
REGISTER_QUERY_HOOK_PROTO ("mysql"|"pgsql"), HOOK_DENY.
- fake_query_hook echoes the SQL through the result message so tests
can verify the payload reached the callback intact.
New unit test: plugin_query_hook_unit-t (41 assertions)
- empty manager: neither protocol has a hook, dispatch returns false,
result struct untouched
- register MySQL allow hook → dispatch returns ALLOW with empty msg
- register MySQL deny hook → dispatch returns DENY with the message
- null callback rejected; duplicate registration rejected;
original hook still in effect after rejected duplicate
- protocols are independent (mysql allow + pgsql deny coexist)
- payload threaded through (echo hook reads user/ip/schema/sql)
- global dispatcher: false when no active manager, untouched result
- global dispatcher with active manager: routes to the fake plugin's
hook, propagates ALLOW vs DENY (env-flipped between calls), and
goes back to false after stop_configured_plugins
All 59 unit-test binaries pass.
|
1 month ago |
|
|
3d107c3bed |
chore: commit pre-existing plugin manager improvements
Improvements left uncommitted at the end of Step 0: - atomic g_active_plugin_manager pointer - reject plugin descriptors with null/empty name - assert single-threaded init phase - debug-log dispatched plugin commands - propagate mysqlx_register_admin_schema failure into init - additional plugin manager unit tests (init/start/stop fail, double load) - updated ABI doc/comments for table copy semantics, command context lifetime, services availability, and status_json storage |
1 month ago |
|
|
7de6edf30a |
fix(test): drop flawed check_connect not-ready test
The removed test case assumed that calling poll(POLLOUT) on a fresh non-blocking socket (one that never had connect() called) would return 0 (no POLLOUT) and drive check_connect() through the "not ready yet" branch. On Linux, a fresh unconnected socket has an empty send buffer so POLLOUT fires immediately; getsockopt() then returns SO_ERROR=0 and check_connect() legitimately transitions to AUTHENTICATING. The production code is correct — the test premise was wrong. A deterministic "not ready" scenario would require an in-progress connect() to a blackhole or filtered endpoint, which is either flaky or slow to drive in a unit test. The "not ready" path (pr == 0 branch returning 1) is trivial by inspection and exercised in practice by real backend connects where the TCP handshake is pending. Kept the two genuine tests: bad-fd error path and happy-path connect. Plan count 42 -> 39. |
1 month ago |