Skip to content

Pr/postgre sql in taf - #7

Open
lukas7811 wants to merge 18 commits into
MariaDB:mainfrom
lukas7811:pr/PostgreSQL-in-TAF
Open

Pr/postgre sql in taf#7
lukas7811 wants to merge 18 commits into
MariaDB:mainfrom
lukas7811:pr/PostgreSQL-in-TAF

Conversation

@lukas7811

Copy link
Copy Markdown

This is the first attempt to add support for PostgreSQL to the TAF test automation framework and slightly extend the MariaDB configuration options. While it was almost completely generated by Claude and while not all the intended design decisions were known to me, feel free to propose any modifications.

@JonathanBMiller

Copy link
Copy Markdown
Collaborator

Thank you! I will put full effort in going through, and getting merged. Seriously, thank you for this contribution.

@lukas7811

Copy link
Copy Markdown
Author

@JonathanBMiller Oh, you're welcome :-). See more info and background for these changes in a mail I sent you few minutes ago. Looking forward for cooperation.

@JonathanBMiller

JonathanBMiller commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Hi Lukas,

This branch looks good, but it’s not based on the latest TAF main.

Would you please rebase it with current main so the diff is clean and I can review it properly?

These are some of the changes that will impact PG plugin.

    # Runtime directory (pid, socket, logs)
    runtime_dir    => $args{db_runtime_dir} // $args{tmp_dir},
  
    # CPU Affinity (normalized list from Database.pm)
    db_cpu_affinity  => $args{db_cpu_affinity},

Best,
/Jeb

lukas7811 and others added 17 commits July 28, 2026 13:49
- Added PostgreSQL database plugin (libs/db/postgresql.pm)
- Added PostgreSQL-specific benchmark configs and test suite entries
- Fixed schema public permission issue in PostgreSQL benchmarks
- Fixed remaining Czech comments; all comments now in English

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Run.pm: fix Executor->import(':all') to sql_libs::Executor->import(':all')
  (bare Executor wasn't a resolvable package name).
- setup_almalinux10.sh (appstream method): install postgresql-server +
  libpq-devel with --allowerasing instead of postgresql-server-devel, which
  conflicts with libpq-devel via postgresql-private-devel on EL10. Fall back
  to hardcoded AppStream include/lib paths when pg_config (shipped by
  postgresql-server-devel) isn't available.
- sysbench build: force a fresh --recurse-submodules clone whenever the
  LuaJIT submodule Makefile is missing (a zip-extracted source tree has no
  .git, so submodules are silently empty); invoke autogen.sh/configure via
  `bash` explicitly since files from a zip may lack the executable bit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…s OS user

Root cause of a campaign-wide failure: --method=percona (tarball) never
created the "postgres" OS user, unlike the appstream/pgdg RPM packages
(their %pre scriptlet does it automatically). postgres.pm's constructor
requires an OS user literally named "postgres" to drop root privileges
before running initdb -- PostgreSQL refuses to run as root -- so every
initdb failed with "cannot be run as root". Now creates the group+user
(system account, home /var/lib/pgsql) unconditionally before any install
method runs; a no-op if the RPM path already created it.

Also:
- EXPECTED_PG_VERSION="18.4" pinned at the top; new step 3b hard-fails
  setup if the installed `postgres --version` doesn't match exactly, across
  all three --method installers, instead of silently running benchmarks
  against an unintended version.
- install_percona_tarball(): VERSION 16.14 -> 18.4; corrected OpenSSL-tag
  detection for PG18's 3-way tarball split (ssl1.1/ssl3/ssl3.5 by major.minor,
  not PG16's 2-way ssl1/ssl3 by major only) -- these guests run OpenSSL
  3.5.x, which needs ssl3.5 specifically.
- install_pgdg_rpm()/install_appstream(): postgresql16-* -> postgresql18-*
  package names and PG_INSTALL_DIR paths.
- PERCONA_LOCAL_ARCHIVE: skip the downloads.percona.com fetch when
  taf_manage.py has already SCP'd a tarball here (--PERCONA_ARCHIVE_LOCAL),
  avoiding N guests hitting Percona's download server at once.

Verified live: postgres (PostgreSQL) 18.4 - Percona Server for PostgreSQL
18.4.1, full sysbench build + benchmark run succeeded end-to-end.
…uning

postgresql_default.conf: new stock-defaults reference profile for
PostgreSQL 18.4 (TAF/tests/setup_almalinux10.sh's EXPECTED_PG_VERSION).
Every setting is commented out with its PG18 default value and a doc link,
so diffing against it shows exactly what postgresql_oltp.conf/_analytics.conf
override and by how much. Documents the "mandatory parameters" question
directly: no postgresql.conf setting actually lacks a built-in default (initdb
generates a fully valid one); the only non-stock values a run gets are the
ones TAF forces regardless of db_config_file (port, listen_addresses, ssl).
Now the active taf.db_config_file in both .properties files (previously
postgresql_oltp.conf), so a plain run_me.sh invocation benchmarks against
stock PG18 settings unless a tuned profile is selected explicitly.

postgresql_oltp.conf / postgresql_analytics.conf: add an I/O Workers section
(io_method=worker, io_workers=16, up from the PG18 stock default of 3) --
PG18's new async-I/O worker pool is the direct answer to "how many IO
threads does a run use" now that we're off PG16 (which had no such pool;
effective_io_concurrency there was just an advisory prefetch depth).

All four .conf files: updated header comments to note the PG18.4 target
version and reference postgresql_default.conf for the stock-default diff.
…against fleet-scale flakiness

- oltp_skip_trx=on, number_of_tables=8 to match MariaDB's effective values
  (see mariadb-vs-postgresql-taf-test-implementaion-differences.md)
- Retry sysbench git clone (3x with backoff) instead of failing the whole
  host on a single transient network error at 200+-host fan-out
- Clear config.cache before configure: a stale cache from a killed/retried
  build was poisoning checks (observed: bogus "thread-local storage not
  supported" from a cached "checking for stdlib.h... (cached) no")

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Interpreting a TAF run's actual behavior requires reconstructing what
default properties, user properties, and CLI overrides resolved to --
none of that merged state was ever visible anywhere. This dumps
%options/%dirs/%files plus %ENV to STDERR as a YAML-comment block (4
spaces per level, "# key: value") so it can be pasted straight into a
result.yaml as documentation, redacting password-shaped keys
(case-insensitive match on AUTH/COOKIE/CREDENTIAL/PASS/PWD/PRIVATE/
SECRET/TOKEN, not just an exact-key list, so PGPASSWORD/MYSQL_PWD-style
env vars are caught too).
sysbench_lua.db_driver=mariadb normalizes to "mysql", but was compared
against the properties-file value verbatim (only lowercased, never
normalized), so a correctly configured MariaDB run always failed with
"Mismatch: sysbench_lua.db_driver = mariadb, db install shows mariadb
(normalized: mysql)" -- discovered running the MariaDB pipeline against
a freshly built local TAF.zip for the first time.
…p with pgsql

taf.threads was 4,8,16,32,64,128 here vs 8,16,32,64,128 in
properties/postgresql/sysbench_lua_pgsql.properties -- the extra
low-end data point was the last remaining mismatch in the thread
sweep between the two engines' example configs. Also strips trailing
whitespace from the license header.
…r too

SetConnectionArgs() always hardcoded --pgsql-host='127.0.0.1' for
PostgreSQL, ignoring taf.db_clients_use_unix_socket (which defaults to
true and already takes effect for MySQL/MariaDB via --mysql-socket) --
so PostgreSQL runs always went over TCP loopback while MariaDB runs
went over a unix socket, a client-connection asymmetry irrelevant to
the workload itself but not to measured latency/throughput.

drv_pgsql.c passes --pgsql-host straight into PQsetdbLogin(), and libpq
treats a value starting with '/' as a unix-socket directory rather
than a hostname (unlike libmysqlclient, where "localhost" already
implies socket use) -- so this has to be requested with an explicit
path, not by omitting the flag. pg_hba.conf already allows it ("local
all all md5", postgres.pm::_db_write_pg_hba_conf), and
taf_run_pgsql.sh already assumes /var/run/postgresql is writable for
the server's socket, so that path is reused as the default here
(overridable via taf.db_socket). The port is still passed alongside
the socket path since libpq derives the socket filename
(.s.PGSQL.<port>) from host dir + port.
…stgresql_default.conf

Every line commented out, documenting MariaDB 12.2.2's upstream default
for each setting also tuned by mariadb_cache.cnf / mariadb_simple_2gbp.cnf /
mariadb_tidesdb*.cnf, plus a KB doc link per setting -- gives the two
engines a directly comparable "everything stock" baseline for workload
equivalence testing, the same role postgresql_default.conf already
plays for PostgreSQL.
mariadbd unconditionally refuses to start as root (no --allow-run-as-root
override), so taf_run.sh hard-refused root outright rather than actually
handling it -- this broke MariaDB density campaigns on infrastructure
where the SSH/provisioning user is root throughout (e.g. the Plovdiv
vSAN pool, where PostgreSQL campaigns already work fine because
postgres.pm handles root by dropping to the 'postgres' OS user via
runuser). Add the same handling here: detect EUID 0 in the constructor,
resolve (or create, since this targets a tarball install with no
package postinstall script to have created one already) a 'mysql'
system user, and run mariadb-install-db/mariadbd via
runuser -u mysql -- through a new _os_prefix() helper. Also chowns
data_dir and tmpdir to that user in _db_prepare_data_dir(), since
mariadbd itself opens the socket/pidfile/log-error paths under tmpdir.

taf_run.sh's hard root guard removed in a companion mt-qa-tools.vhistrg
commit now that the plugin handles it.
_db_prepare_data_dir()'s root-handling chowned only the tmpdir entry
itself, not its contents. data_dir is wiped and recreated from scratch
every run, so it's never an issue there, but tmpdir persists across
attempts -- a bootstrap/runtime pidfile or log left behind by an
earlier failed attempt (e.g. one that predates this root-handling, or
one that failed before reaching this chown) stays owned by root, and
mariadbd (now running as 'mysql' via runuser) fails outright when it
can't create/write its own --pid-file over an existing root-owned one.
Confirmed via a real failure on the Plovdiv density-curve verification:
InnoDB started fine as 'mysql', then died on
"Can't create/write to file '.../mariadb_bootstrap.pid' (Errcode: 13)".
…t/mysql ownership race

_spawn_background()'s parent (always root, never drops privileges)
writes the same --pid-file= path that mariadbd itself (running as
'mysql' via runuser/_os_prefix() after this session's earlier fix)
also writes internally. Whichever of the two creates the file first
owns it; root's write happens first in practice (~1s after fork, right
around when mariadbd finishes InnoDB init and attempts its own
pid-file write), so mariadbd's later write failed with "Can't
create/write to file ... Permission denied" and the server died --
confirmed via a real failure on the Plovdiv density-curve verification,
past the point the previous two fixes (root detection, recursive
tmpdir chown) got it to.

Pre-creating and chowning the pidfile to the target OS user before
forking means both writers just open an *existing* file (which doesn't
change ownership) instead of racing to create it, regardless of order.
MariaDB's config parser rejects a file with no section headers at all
("Config file contains no section headers"), even when every setting
under that section is commented out -- unlike postgresql_default.conf,
which needs no section header since postgresql.conf has no sections.
Confirmed via a real failure (TAF Exit Code: 1) using this file as
taf.db_config_file on the Plovdiv verification.
…on, and $_me:: log interpolation

PostgreSQL sysbench connections were failing with "connection to server
on socket ".../db.sock/.s.PGSQL.<port>" failed: No such file or
directory": sysbench-lua.pm passed the raw db_socket file path (e.g.
"<tmp_dir>db.sock") as --pgsql-host, but libpq treats that value as a
unix-socket *directory* and appends ".s.PGSQL.<port>" itself. postgres.pm
never configured unix_socket_directories either, so PostgreSQL was left
listening at its own stock default (/tmp), which never matched anyway.

Fix: postgres.pm now sets unix_socket_directories to the same tmpdir
TAF already manages; sysbench-lua.pm passes dirname($options{db_socket})
as --pgsql-host instead of the raw file-shaped path, so the two agree.

Separately, both engines' "is sysbench already built" checks (taf_run.sh
for MariaDB, setup_almalinux10.sh for PostgreSQL) only checked that a
sysbench binary/symlink existed, not which database driver it was built
with. Running one engine after the other against the same guest (shared
client_source/sysbench-lua/ tree) left a binary built for the wrong
driver in place, and the second engine's sysbench prepare/run failed
immediately with "invalid option: --mysql-socket=..." or the pgsql
equivalent. setup_almalinux10.sh now verifies the driver via
`sysbench <script> --help` before trusting an existing binary.

Also fixed a latent bug in postgres.pm/mariadb.pm's own log tags: strings
written as "$_me::something" are parsed by Perl as the fully-qualified
variable ${_me::something} (undefined), not $_me followed by literal
"::something" -- silently dropping the log prefix and tripping "Use of
uninitialized value" warnings on every DB lifecycle call. Changed to
"${_me}::something" throughout both files (11 + 4 occurrences).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@lukas7811
lukas7811 force-pushed the pr/PostgreSQL-in-TAF branch from 769a6ca to 8cd7add Compare July 28, 2026 14:05
@lukas7811

lukas7811 commented Jul 28, 2026 via email

Copy link
Copy Markdown
Author

@JonathanBMiller

Copy link
Copy Markdown
Collaborator

Thank you! Time for me to get to work :-)

@JonathanBMiller

Copy link
Copy Markdown
Collaborator

pr7_changed_files.zip

Lukas,

Thank you — and thank you to Virtuozzo for supporting the work.

Below is the initial review. I have not tested any of it yet; I’m starting that now.
Wanted to get the review to you early so you can make the adjustments on your side and run your own tests.

I will update the PR with findings from my testing.

If you have questions, or think I missed something, please let me know.

Review is below, updated files attached.

Best,
/Jeb

  1. Update to taf.pl

Added support for dumping the fully resolved TAF configuration to a file.
This is controlled by new options and properties and is now part of the ctx
structure.

Changes:

  • Updated last modified date and version.
  • Removed old _PrintDebugConfig implementation.
  • Added new Logging function: PrintTafConfigToFile($ctx).
  • Added new options/properties:
    • debug_print_config (default: false)
    • debug_print_config_path (default: $working/logs/)
  • Filename is fixed and generated internally:
    taf_configuration_dump_YYYYMMDD_HHMMSS.txt
  • User controls only the directory path; framework controls filename and content.

Usage additions:

O = --debug-print-config
P = taf.debug_print_config={false|true}
: Enable dumping of the fully resolved TAF configuration.
: Output is written to a text file.
: Filename: taf_configuration_dump_YYYYMMDD_HHMMSS.txt
: See: debug_print_config_path below
: Default(false)

O = --debug-print-config-path=/path/to/dump/
P = taf.debug_print_config_path=/path/to/dump/
: Directory where the configuration dump file is written.
: Default($working/logs/)

Files touched:

  • taf.pl
  • taf_usage.txt
  • package TAF::CommandLine
  • taf_default.properties
  • package TAF::Utilities (TrailingSlash only)
  • package TAF::Logging (new PrintTafConfigToFile)
  1. taf-perl/tests directory.

I think this directory would be confusing to other as "tests" actually are "properties"

Please create directory postgresql_related under taf-perl/scripts and move scripts/shells there.

eg. taf-perl/scripts/postgresql_related

  1. properties/postgresql

Both sysbench and tpcc properties look fine.

  1. sysbench_lua_default.properties

no issues...

  1. taf-perl/libs/taf_libs
  1. taf-perl/libs/sql_libs

Executor.pm:

  • Missing a version, please add in header "# Version: 4.0"
  • All other changes look good

sql_libs/dialects/postgres.sql

  • Nice!

taf-perl/libs/sql_libs/postgres.sql ??? Why is this there?

  1. taf-perl/libs/script_tools_lib
  • ClientCmakeBuild.pm : Nice!
  1. taf-perl/libs/databases
  • postgre.pm

There were serval changes needed..(attached updated pm)

1. new

What changed:  

Added runtime_dir support, runtime_dir pidfile, runtime_dir logs, and CPU‑affinity argument storage.

Why:  

To make PostgreSQL follow the same runtime contract as MariaDB/MySQL and ensure deterministic lifecycle behavior.

2. db_start

What changed:  

Added stale PID cleanup, switched to runtime_dir pidfile, added CPU affinity wrapper, fixed extra_args handling, and aligned readiness logic.

Why:  

To ensure correct startup, correct PID management, and full alignment with TAF’s lifecycle semantics.

3. db_stop

What changed:  

Switched to runtime_dir pidfile, added deterministic cleanup, and added pg_ctl status check.

Why:  

To ensure predictable shutdown and correct PID cleanup matching MariaDB’s behavior.

4. _db_apply_postgresql_conf

What changed:  

Added external_pid_file = '<runtime_dir>/postgresql_runtime.pid' and tightened core config enforcement.

Why:  

To force PostgreSQL to write its PID where TAF expects it and prevent user config from breaking core runtime settings.

5. _db_run_initdb

What changed:  

Adjusted pwfile location.

Why:  

Keep inline with other plugins.
  1. Removal of ability to run under root user account(s)

All PostgreSQL root-handling code has been removed. The framework will not allow execution under UID 0, and PostgreSQL now follows that policy with no
relocation logic, no runuser wrappers, and no root-mode accommodations.

Why root cannot be allowed for benchmarking:

 - CPU affinity: root can override sched_setaffinity and cpuset rules, causing benchmark threads to migrate off pinned cores.

 - ulimits: root bypasses RLIMITs (nofile, nproc, stack, memlock, etc.), giving different resource ceilings than non-root users.

 - scheduler behavior: root receives elevated scheduling privileges, bypasses fairness, and can preempt non-root tasks, altering latency.

 - NUMA locality: root can override numactl policies and allocate or migrate memory across nodes despite explicit binding.

 - threadpool behavior: MariaDB/MySQL threadpools behave differently under root due to starvation, wakeup, and fairness changes.

 - perf determinism: root bypasses perf_event restrictions and samples kernel space, changing profiling behavior compared to non-root.

 - sandboxing: root bypasses cgroups, namespaces, seccomp, and filesystem permissions, breaking benchmark isolation.

 - reproducibility: Running as root invalidates determinism and isolation guarantees required for consistent benchmark results.
  • mariadb.pm

With root user not being allowed, please restore mariadb.pm to the current main version, removing all root-user-specific code.

  1. taf-perl/database_config_files/

    1. postgresql
    • No issues with adding the configuration files.
    1. mariadb
    • No issue adding the default configuration file
    1. mysql
    • Adding a mysql default config file in this upload, please include in updated PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants