Description:
This has been detected during analyze of Bug#38133 (Myisamlog test fails on Windows). The third patch (http://lists.mysql.com/commits/58606) contains a possible fix for the problem, but it was rejected for Bug#38133. For more information, you may study the review thread attached at that link.
IMHO the problem is that my_lock() behaves differently on Windows than on UNIX-like platforms. On Windows, a lock on a file does not necessarily replace a former lock by the same process. Namely it is possible to hold an exclusive lock (write lock) in parallel to a shared lock (read lock). On UNIX-like platforms a new lock on the same portion of a file replaces a former lock on the same portion of the file.
MyISAM code, in mi_lock_database(), clearly expects the behavior of UNIX-like platforms. When it changes the lock type on the file, say from write lock to read lock, it just requests a read lock on the file, expecting that the write lock is replaced and goes away.
How to repeat:
You need a -master.opt file with --external-locking.
CREATE TABLE t1 (c1 INT) ENGINE=MyISAM;
INSERT INTO t1 VALUES (1);
# This takes a write lock through the first instance of the table and a
# read lock through the second instance. The write lock is propagated
# to my_lock(), but the read lock is skipped, because a stonger lock
# exists. On unlock, the write lock is removed first. On file level, the
# write lock is converted to a read lock, as the second instance is not
# unlocked yet. On Windows, this conversion turns into an additional
# lock, because a write lock and a read lock can co-exist on a file.
# Unlocking the second instance leads to the latest lock to be removed
# from the file. But the former lock, the write lock, still exists on
# Windows.
INSERT INTO t1 SELECT * FROM t1;
# This blocks on Windows, because it tries a write lock on the file,
# that is write locked already. It blocks, even though it's the same
# process taking the lock.
INSERT INTO t1 VALUES (2);
Suggested fix:
I suggest to stick with the valuable tradition of mysys to compensate differences of platforms. This could be done in my_lock() by removing an old lock with (void) UnlockFileEx() before taking a new one with LockFileEx(). See the link to my proposed patch for Bug#38133.
Perhaps Windows has a flag or a different set of functions to accomplish the same. After all, unlocking before (re-)locking could leave a short time frame with an unlocked file when the lock type changes, which could be a problem for co-working processes. But if there is no other way to solve it with Windows features, it is better to live with the race condition than to block after INSERT...SELECT.
Please note: If you fix the bug in my_lock(), or otherwise in mi_lock_database(), you may remove the code from mi_examine_log(), which tries to accomplish the same on the client side only. See later patches for Bug#38133.