Skip to content

Commit

Permalink
MDEV-16944 Fix file sharing issues on Windows in mysqltest
Browse files Browse the repository at this point in the history
On Windows systems, occurrences of ERROR_SHARING_VIOLATION due to
conflicting share modes between processes accessing the same file can
result in CreateFile failures.

mysys' my_open() already incorporates a workaround by implementing
wait/retry logic on Windows.

But this does not help if files are opened using shell redirection like
mysqltest traditionally did it, i.e via

--echo exec "some text" > output_file

In such cases, it is cmd.exe, that opens the output_file, and it
won't do any sharing-violation retries.

This commit addresses the issue by introducing a new built-in command,
'write_line', in mysqltest. This new command serves as a brief alternative
to 'write_file', with a single line output, that also resolves variables
like "exec" would.

Internally, this command will use my_open(), and therefore retry-on-error
logic.

Hopefully this will eliminate the very sporadic "can't open file because
it is used by another process" error on CI.
  • Loading branch information
vaintroub committed Apr 17, 2024
1 parent b48de97 commit 061adae
Show file tree
Hide file tree
Showing 66 changed files with 179 additions and 134 deletions.
49 changes: 47 additions & 2 deletions client/mysqltest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ enum enum_commands {
Q_IF,
Q_DISABLE_PARSING, Q_ENABLE_PARSING,
Q_REPLACE_REGEX, Q_REMOVE_FILE, Q_FILE_EXIST,
Q_WRITE_FILE, Q_COPY_FILE, Q_PERL, Q_DIE, Q_EXIT, Q_SKIP,
Q_WRITE_FILE, Q_WRITE_LINE, Q_COPY_FILE, Q_PERL, Q_DIE, Q_EXIT, Q_SKIP,
Q_CHMOD_FILE, Q_APPEND_FILE, Q_CAT_FILE, Q_DIFF_FILES,
Q_SEND_QUIT, Q_CHANGE_USER, Q_MKDIR, Q_RMDIR,
Q_LIST_FILES, Q_LIST_FILES_WRITE_FILE, Q_LIST_FILES_APPEND_FILE,
Expand Down Expand Up @@ -501,6 +501,7 @@ const char *command_names[]=
"remove_file",
"file_exists",
"write_file",
"write_line",
"copy_file",
"perl",
"die",
Expand Down Expand Up @@ -4302,6 +4303,49 @@ void do_write_file(struct st_command *command)
do_write_file_command(command, FALSE);
}

/**
Write a line to the start of the file.
Truncates existing file, creates new one if it doesn't exist.
Usage
write_line <line> <filename>;
Example
--write_line restart $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
@note Both the file and the line parameters are evaluated
(can be variables).
@note This is a better alternative to
exec echo > file, as it doesn't depend on shell,
and can better handle sporadic file access errors caused
by antivirus or backup software on Windows.
*/
void do_write_line(struct st_command *command)
{
DYNAMIC_STRING ds_line;
DYNAMIC_STRING ds_filename;

struct command_arg write_line_args[] = {
{ "line", ARG_STRING, FALSE, &ds_line, "line to add" },
{ "filename", ARG_STRING, TRUE, &ds_filename, "File to write to" },
};
DBUG_ENTER("do_write_line");

check_command_args(command,
command->first_argument,
write_line_args,
sizeof(write_line_args)/sizeof(struct command_arg),
' ');

if (bad_path(ds_filename.str))
DBUG_VOID_RETURN;
dynstr_append_mem(&ds_line, "\n", 1);
str_to_file2(ds_filename.str, ds_line.str, ds_line.length, FALSE);
dynstr_free(&ds_filename);
dynstr_free(&ds_line);
DBUG_VOID_RETURN;
}

/*
SYNOPSIS
Expand Down Expand Up @@ -7423,7 +7467,7 @@ void str_to_file2(const char *fname, char *str, size_t size, my_bool append)
die("Could not open '%s' for writing, errno: %d", buff, errno);
if (append && my_seek(fd, 0, SEEK_END, MYF(0)) == MY_FILEPOS_ERROR)
die("Could not find end of file '%s', errno: %d", buff, errno);
if (my_write(fd, (uchar*)str, size, MYF(MY_WME|MY_FNABP)))
if (size > 0 && my_write(fd, (uchar*)str, size, MYF(MY_WME|MY_FNABP)))
die("write failed, errno: %d", errno);
my_close(fd, MYF(0));
}
Expand Down Expand Up @@ -10160,6 +10204,7 @@ int main(int argc, char **argv)
break;
case Q_FILE_EXIST: do_file_exist(command); break;
case Q_WRITE_FILE: do_write_file(command); break;
case Q_WRITE_LINE: do_write_line(command); break;
case Q_APPEND_FILE: do_append_file(command); break;
case Q_DIFF_FILES: do_diff_files(command); break;
case Q_SEND_QUIT: do_send_quit(command); break;
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/include/crash_mysqld.inc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
--source include/not_embedded.inc

# Write file to make mysql-test-run.pl expect crash and restart
--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--write_line restart $MYSQLTEST_VARDIR/tmp/mysqld.1.expect

# Setup the mysqld to crash at shutdown
SET debug_dbug="d,crash_shutdown";
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/include/expect_crash.inc
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/$_expect_file_name.expect

# There should be a debug crash after using this .inc file
--exec echo "wait" > $_expect_file_name
--write_line wait $_expect_file_name
2 changes: 1 addition & 1 deletion mysql-test/include/kill_and_restart_mysqld.inc
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ if (!$restart_parameters)
--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.$_server_id.expect

--echo # Kill and $restart_parameters
--exec echo "$restart_parameters" > $_expect_file_name
--write_line "$restart_parameters" $_expect_file_name
--shutdown_server 0
--source include/wait_until_disconnected.inc
--enable_reconnect
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/include/kill_galera.inc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Write file to make mysql-test-run.pl expect the crash, but don't start it
--let $_expect_file_name= `select regexp_replace(@@tmpdir, '^.*/','')`
--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/$_expect_file_name.expect
--exec echo "wait" > $_expect_file_name
--write_line wait $_expect_file_name

# Kill the connected server
--disable_reconnect
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/include/kill_mysqld.inc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/$_expect_file_name.expect

--echo # Kill the server
--exec echo "wait" > $_expect_file_name
--write_line wait $_expect_file_name
--shutdown_server 0
--source include/wait_until_disconnected.inc
2 changes: 1 addition & 1 deletion mysql-test/include/rpl_start_server.inc
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ if ($rpl_server_parameters)
--source include/rpl_connection.inc

# Write file to make mysql-test-run.pl start up the server again
--exec echo "$_rpl_start_server_command" > $MYSQLTEST_VARDIR/tmp/mysqld.$rpl_server_number.expect
--write_line "$_rpl_start_server_command" $MYSQLTEST_VARDIR/tmp/mysqld.$rpl_server_number.expect

if (!$rpl_server_error)
{
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/include/rpl_stop_server.inc
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ if ($rpl_debug)

# Write file to make mysql-test-run.pl expect the "crash", but don't start
# it until it's told to
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.$rpl_server_number.expect
--write_line wait $MYSQLTEST_VARDIR/tmp/mysqld.$rpl_server_number.expect

# Send shutdown to the connected server and give
# it 60 seconds (of mysqltest's default) to die before zapping it
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/include/search_pattern_in_file.inc
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
# let SEARCH_FILE= $error_log;
# # Stop the server
# let $restart_file= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect;
# --exec echo "wait" > $restart_file
# --write_line wait $restart_file
# --shutdown_server
# --source include/wait_until_disconnected.inc
#
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/include/shutdown_mysqld.inc
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ if ($rpl_inited)
# Write file to make mysql-test-run.pl expect the "crash", but don't start it
--let $_expect_file_name= `select regexp_replace(@@tmpdir, '^.*/','')`
--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/$_expect_file_name.expect
--exec echo "wait" > $_expect_file_name
--write_line wait $_expect_file_name

# Avoid warnings from connection threads that does not have time to exit
--disable_query_log
Expand Down
4 changes: 2 additions & 2 deletions mysql-test/include/start_mysqld.inc
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ if ($restart_bindir)

if ($restart_parameters)
{
--exec echo "$restart_cmd: $restart_parameters" > $_expect_file_name
--write_line "$restart_cmd: $restart_parameters" $_expect_file_name
if (!$restart_noprint)
{
--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
Expand All @@ -34,7 +34,7 @@ if ($restart_parameters)
}
if (!$restart_parameters)
{
--exec echo "$restart_cmd" > $_expect_file_name
--write_line "$restart_cmd" $_expect_file_name
if ($restart_noprint < 2)
{
--exec echo "# $restart_cmd"
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/main/crash_commit_before.test
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ insert into t1 values(9);
SET GLOBAL debug_dbug="d,crash_commit_before";

# Write file to make mysql-test-run.pl expect crash and restart
--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--write_line restart $MYSQLTEST_VARDIR/tmp/mysqld.1.expect

# Run the crashing query
--error 2013
Expand Down
4 changes: 2 additions & 2 deletions mysql-test/main/empty_server_name-8224.test
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
#
--source include/not_embedded.inc
create server '' foreign data wrapper w2 options (host '127.0.0.1');
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--write_line wait $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--shutdown_server
--source include/wait_until_disconnected.inc
--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--write_line restart $MYSQLTEST_VARDIR/tmp/mysqld.1.expect

-- enable_reconnect
-- source include/wait_until_connected_again.inc
Expand Down
8 changes: 4 additions & 4 deletions mysql-test/main/host_cache_size_functionality.test
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ select @@global.Host_Cache_Size > 0;
--echo # Restart server with Host_Cache_Size 1

let $restart_file= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect;
--exec echo "wait" > $restart_file
--write_line wait $restart_file
--shutdown_server
--source include/wait_until_disconnected.inc
-- exec echo "restart:--host_cache_size=1 " > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--write_line "restart:--host_cache_size=1 " $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
-- enable_reconnect
-- source include/wait_until_connected_again.inc

Expand Down Expand Up @@ -142,10 +142,10 @@ SELECT Host_Cache_Size = @@SESSION.Host_Cache_Size;
#--remove_file $MYSQL_TMP_DIR/bind_ip

#let $restart_file= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect;
#--exec echo "wait" > $restart_file
#--write_line wait $restart_file
#--shutdown_server
#--source include/wait_until_disconnected.inc
#-- exec echo "restart:--bind-address=$bind_ip " > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
#-- write_line "restart:--bind-address=$bind_ip " $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
#-- enable_reconnect
#-- source include/wait_until_connected_again.inc

Expand Down
4 changes: 2 additions & 2 deletions mysql-test/main/init_file_set_password-7656.test
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ EOF

--enable_reconnect

--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--write_line wait $MYSQLTEST_VARDIR/tmp/mysqld.1.expect

--shutdown_server
--source include/wait_until_disconnected.inc

--exec echo "restart:--init-file=$MYSQLTEST_VARDIR/init.file " > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--write_line "restart:--init-file=$MYSQLTEST_VARDIR/init.file " $MYSQLTEST_VARDIR/tmp/mysqld.1.expect

--source include/wait_until_connected_again.inc
select user,host,password,plugin,authentication_string from mysql.user where user='foo';
Expand Down
4 changes: 2 additions & 2 deletions mysql-test/main/log_errchk.test
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@
--echo # Case 2: Starting server with fifo file as general log file
--echo # and slow query log file.
# Restart server with fifo file as general log file.
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--write_line wait $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--shutdown_server
--source include/wait_until_disconnected.inc
--enable_reconnect
# Write file to make mysql-test-run.pl start up the server again
--exec echo "restart: --general-log-file=$gen_log_file --slow-query-log-file=$slow_query_log_file" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--write_line "restart: --general-log-file=$gen_log_file --slow-query-log-file=$slow_query_log_file" $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--source include/wait_until_connected_again.inc

# Error 6 is reported, because the other end is closed
Expand Down
4 changes: 2 additions & 2 deletions mysql-test/main/lowercase_fs_on.test
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ let SEARCH_FILE= $MYSQLTEST_VARDIR/log/my_restart.err;
--remove_file $SEARCH_FILE

#Shutdown the server
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--write_line wait $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--shutdown_server
--source include/wait_until_disconnected.inc

Expand All @@ -30,7 +30,7 @@ let SEARCH_PATTERN= \[ERROR\] The server option \'lower_case_table_names\' is co
--source include/search_pattern_in_file.inc

#Restart the server
--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--write_line restart $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--source include/wait_until_connected_again.inc

#Cleanup
Expand Down
4 changes: 2 additions & 2 deletions mysql-test/main/myisam_crash_before_flush_keys.test
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ INSERT INTO t1 VALUES (1,2),(2,3),(3,4),(4,5),(5,6);
SET SESSION debug_dbug="d,crash_before_flush_keys";

--echo # Write file to make mysql-test-run.pl expect crash
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--write_line wait $MYSQLTEST_VARDIR/tmp/mysqld.1.expect

--echo # Run the crashing query
--error 2013
FLUSH TABLE t1;

--echo # Write file to make mysql-test-run.pl start the server
--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--write_line restart $MYSQLTEST_VARDIR/tmp/mysqld.1.expect

--echo # Turn on reconnect
--enable_reconnect
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/main/mysql_client_test.test
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ call mtr.add_suppression(" IP address .* could not be resolved");
# server or run mysql-test-run --debug mysql_client_test and check
# var/log/mysql_client_test.trace

--exec echo "$MYSQL_CLIENT_TEST" > $MYSQLTEST_VARDIR/log/mysql_client_test.out.log 2>&1
--write_line "$MYSQL_CLIENT_TEST" $MYSQLTEST_VARDIR/log/mysql_client_test.out.log
--exec $MYSQL_CLIENT_TEST --getopt-ll-test=25600M >> $MYSQLTEST_VARDIR/log/mysql_client_test.out.log 2>&1

# End of 4.1 tests
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/main/mysql_client_test_comp.test
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ SET @old_slow_query_log= @@global.slow_query_log;

call mtr.add_suppression(" Error reading file './client_test_db/test_frm_bug.frm'");
call mtr.add_suppression(" IP address .* could not be resolved");
--exec echo "$MYSQL_CLIENT_TEST" > $MYSQLTEST_VARDIR/log/mysql_client_test_comp.out.log 2>&1
--write_line "$MYSQL_CLIENT_TEST" $MYSQLTEST_VARDIR/log/mysql_client_test_comp.out.log
--exec $MYSQL_CLIENT_TEST --getopt-ll-test=25600M >> $MYSQLTEST_VARDIR/log/mysql_client_test_comp.out.log 2>&1

# End of test
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/main/mysql_client_test_nonblock.test
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ call mtr.add_suppression(" IP address .* could not be resolved");
# server or run mysql-test-run --debug mysql_client_test and check
# var/log/mysql_client_test.trace

--exec echo "$MYSQL_CLIENT_TEST --non-blocking-api" > $MYSQLTEST_VARDIR/log/mysql_client_test.out.log 2>&1
---write_line "$MYSQL_CLIENT_TEST --non-blocking-api" $MYSQLTEST_VARDIR/log/mysql_client_test.out.log
--exec $MYSQL_CLIENT_TEST --non-blocking-api --getopt-ll-test=25600M >> $MYSQLTEST_VARDIR/log/mysql_client_test.out.log 2>&1

# End of 4.1 tests
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/main/openssl_1.test
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ drop table t1;
# Test that we can't open connection to server if we are using
# a different cacert
#
--exec echo "this query should not execute;" > $MYSQLTEST_VARDIR/tmp/test.sql
--write_line "this query should not execute;" $MYSQLTEST_VARDIR/tmp/test.sql
# Handle that openssl gives different error messages from YaSSL.
--replace_regex /2026 TLS\/SSL error.*/2026 TLS\/SSL error: xxxx/
--error 1
Expand Down
4 changes: 2 additions & 2 deletions mysql-test/main/plugin_loaderr.test
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ FROM INFORMATION_SCHEMA.PLUGINS WHERE plugin_name = 'innodb';
--echo #
--echo # MDEV-6351 --plugin=force has no effect for built-in plugins
--echo #
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--write_line wait $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--shutdown_server
--source include/wait_until_disconnected.inc

--error 1
--exec $MYSQLD_CMD --innodb=force --innodb-page-size=6000 --disable-log-error

--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--write_line restart $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--enable_reconnect
--source include/wait_until_connected_again.inc
--disable_reconnect
4 changes: 2 additions & 2 deletions mysql-test/main/shutdown.test
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ drop procedure try_shutdown;

--let $_expect_file_name= `select regexp_replace(@@tmpdir, '^.*/','')`
--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/$_expect_file_name.expect
--exec echo "wait" > $_expect_file_name
--write_line wait $_expect_file_name

--send shutdown
--connection default
--source include/wait_until_disconnected.inc

--exec echo "restart" > $_expect_file_name
--write_line restart $_expect_file_name
--enable_reconnect
--source include/wait_until_connected_again.inc

Expand Down

0 comments on commit 061adae

Please sign in to comment.