1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00

MDEV-11111: mtr --embedded-launcher checks the error log; launcher sweeps leftovers

* mtr: the per-test check of the error log (include/check-warnings.inc)
  runs in --embedded-launcher mode too. There is no running mysqld, so the
  check starts another private server on the datadir the test has left, as
  mysqltest does for the test, and applies the suppressions that the test
  stored there with mtr.add_suppression. This replaces the temporary
  --nowarnings behaviour of this mode.
* launcher: an application that is killed cannot remove the private
  directory (Unix) or the server log (Windows) of its server. Name them
  with the pid of the application, and remove those of dead applications
  at the next start. Only the current user's, and not while the pid exists.

Linux (WSL, RelWithDebInfo): 286 tests of main and embedded pass, no
warnings, no leftover servers or directories. Windows (Debug): 299 tests
pass; the only warning is a plugin that is not built there.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Vladislav Vaintroub
2026-10-01 17:54:19 +02:00
parent 939cccf791
commit fc6640d782
2 changed files with 93 additions and 12 deletions

View File

@@ -38,6 +38,7 @@
#include <windows.h>
#else
#include <dlfcn.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
@@ -221,6 +222,42 @@ static void append_quoted(char *dst, size_t size, const char *s)
dst[len]= 0;
}
/*
Logs of servers whose application was killed stay in the temp directory.
The name has the pid of the application: delete the ones whose application
is no longer there.
*/
static void sweep_stale(void)
{
char tmp[MAX_PATH], pattern[MAX_PATH + 32], path[MAX_PATH + 300];
WIN32_FIND_DATAA fd;
HANDLE h;
if (!GetTempPathA(sizeof(tmp), tmp))
return;
snprintf(pattern, sizeof(pattern), "%sMariaDB-embedded-*.log", tmp);
if ((h= FindFirstFileA(pattern, &fd)) == INVALID_HANDLE_VALUE)
return;
do
{
unsigned long pid;
HANDLE p;
if (sscanf(fd.cFileName, "MariaDB-embedded-%lu-", &pid) != 1)
continue;
p= OpenProcess(SYNCHRONIZE, FALSE, (DWORD) pid);
if (p)
{
CloseHandle(p); /* still running */
continue;
}
if (GetLastError() != ERROR_INVALID_PARAMETER)
continue; /* exists, but not for us */
snprintf(path, sizeof(path), "%s%s", tmp, fd.cFileName);
DeleteFileA(path);
} while (FindNextFileA(h, &fd));
FindClose(h);
}
int mariadb_embedded_start(int argc, char **argv, char **groups)
{
HANDLE rd= NULL, wr= NULL, logh= INVALID_HANDLE_VALUE;
@@ -241,6 +278,7 @@ int mariadb_embedded_start(int argc, char **argv, char **groups)
if (running)
return fail("embedded server is already started");
sweep_stale();
snprintf(socket_name, sizeof(socket_name), "MariaDB-embedded-%lu-%lu",
(unsigned long) GetCurrentProcessId(),
(unsigned long) GetTickCount());
@@ -431,6 +469,50 @@ static int socket_ready(void)
return ok;
}
/*
An application that was killed cannot clean up after itself. Its server
shuts down, but the private directory (with the server's log) stays.
The directory name has the pid of the application: remove the ones of
our own user whose application is no longer there.
*/
static void sweep_stale(const char *tmpdir)
{
DIR *d= opendir(tmpdir);
struct dirent *e;
if (!d)
return;
while ((e= readdir(d)))
{
long pid;
char path[600], file[900];
struct stat st;
DIR *sub;
struct dirent *se;
if (sscanf(e->d_name, "mariadb-embedded-%ld-", &pid) != 1 || pid <= 0)
continue;
if (kill((pid_t) pid, 0) == 0 || errno != ESRCH)
continue; /* still running, or not ours */
snprintf(path, sizeof(path), "%s/%s", tmpdir, e->d_name);
if (lstat(path, &st) || !S_ISDIR(st.st_mode) || st.st_uid != getuid())
continue;
if ((sub= opendir(path)))
{
while ((se= readdir(sub)))
{
if (strcmp(se->d_name, ".") && strcmp(se->d_name, ".."))
{
snprintf(file, sizeof(file), "%s/%s", path, se->d_name);
unlink(file);
}
}
closedir(sub);
}
rmdir(path);
}
closedir(d);
}
int mariadb_embedded_start(int argc, char **argv, char **groups)
{
int fds[2], nargs, timeout, rc= 1, waited_ms= 0;
@@ -444,8 +526,11 @@ int mariadb_embedded_start(int argc, char **argv, char **groups)
/* Private directory: only the current user can reach the socket */
tmp= getenv("TMPDIR");
snprintf(socket_dir, sizeof(socket_dir), "%s/mariadb-embedded-XXXXXX",
tmp && *tmp ? tmp : "/tmp");
if (!tmp || !*tmp)
tmp= "/tmp";
sweep_stale(tmp);
snprintf(socket_dir, sizeof(socket_dir), "%s/mariadb-embedded-%ld-XXXXXX",
tmp, (long) getpid());
if (!mkdtemp(socket_dir))
return fail("cannot create temporary directory: %s", strerror(errno));
snprintf(socket_name, sizeof(socket_name), "%s/mysqld.sock", socket_dir);

View File

@@ -1611,15 +1611,6 @@ sub command_line_setup {
# Embedded server flag
# --------------------------------------------------------------------------
$opt_embedded_server= 1 if $opt_embedded_launcher;
if ($opt_embedded_launcher)
{
# The server lives only as long as one mysqltest, so the per-test check
# of the error log (which applies suppressions added by the tests with
# mtr.add_suppression) never runs, and the final scan would flag
# warnings that tests provoke on purpose.
# ToDo: run include/check-warnings.inc from mysqltest before it exits.
$opt_warnings= 0;
}
if ( $opt_embedded_server )
{
$opt_skip_ssl= 1; # Turn off use of SSL
@@ -4749,7 +4740,12 @@ sub check_warnings ($) {
my %started;
foreach my $mysqld ( mysqlds() )
{
if ( defined $mysqld->{'proc'} )
# With --embedded-launcher there is no running mysqld: the server of the
# test has exited, and the check starts another private one on its
# datadir (as mysqltest does for the test), to apply the suppressions
# that the test has stored in it with mtr.add_suppression.
my $launcher_check= $opt_embedded_launcher && $mysqld->name() eq 'mysqld.1';
if ( defined $mysqld->{'proc'} or $launcher_check )
{
my $proc= start_check_warnings($tinfo, $mysqld);
$started{$proc->pid()}= $proc;