以下のスクリプトを使用して、排他ロックのストレス テストを行っていますflock
。
私のノートパソコンでは、常に正常に動作します。
しかし、デスクトップ PC で実行すると、ランダムに失敗し、2 つのインスタンスが同時に実行されることがあります (同じロックを取得します)。
どちらも Ubuntu 20.04 を実行しています。
それで、デスクトップのハードウェアに問題があるのではないかと疑っています。RAM の問題でしょうか?
そこで質問なのですが、Flock Missbehavior が提供しているヒントに基づいて、どのハードウェア部分に欠陥があるのかを追跡/特定するにはどうすればよいでしょうか?
つまり、どのハードウェアに欠陥があるか (または品質が低い可能性があるか) を指摘できる Flock は何でしょうか?
問題の確認方法:
フルパス スクリプト名に一致する子コマンドを持つすべての flock プロセスを取得します (これは flock が子コマンドとして実行する必要があるものです)。
また、各スクリプトによって実行された作業をログに記録し、そのログに 2 つ以上のインスタンスの同時作業が記録されます。作業は、ロックが取得された場合にのみログに記録されます。
排他的/一意のロックを提供するように flock を正しく構成していない可能性がありますか?
現在、別の端末でもこれを使用しています:
while true;do date;lslocks |grep flock;sleep 1;done
スクリプト:
cat >flock.tst.sh;chmod +x flock.tst.sh
#!/bin/bash
LC_NUMERIC=en_US.UTF-8
# HELPERS:
#trash /tmp/flock.tst.log;for((i=0;i<20;i++));do flock.tst.sh&:;done #run this on shell
#pkill -fe flock.tst.sh #end all concurrent children trying to acquire the lock
#while true;do date;lslocks |grep flock;sleep 1;done #use this to check if there is more than one lock acquired, check also the log file to confirm it, and if there is two subsequent WORK on the terminal log, it means a problem happened too
: ${bDaemonizing:=false}
: ${bReport:=false} #help use this to show more log, but will be harder to read it.
: ${bCheck:=false} #help this will let the script check if there is more than one instance working, but it may be slow and make it more difficult to let the problem happen
if ! $bDaemonizing;then
echo "this IS a daemon script, only one instace runnable"
flSelf="`realpath $0`"
#set -x
while ! bDaemonizing=true flock --timeout=$(bc <<< "0.2+0.0$RANDOM") "$flSelf" "$flSelf" "$@";do
if $bCheck;then
strParents="$(nice -n 19 pgrep -f "^flock --timeout=.* $flSelf $flSelf" |tr '\n' ',' |sed -r 's"(.*),"\1"')"
if [[ -n "$strParents" ]];then
anDaemonPid=( $(nice -n 19 pgrep --parent "$strParents" -f "$flSelf") )
if((${#anDaemonPid[*]}>1));then echo "ERROR: more than one daemon, flock failed!? :(";ps --no-headers -o ppid,pid,cmd -p "${anDaemonPid[@]}";fi
if $bReport && ((${#anDaemonPid[*]}==1));then echo "$$:Wait daemon stop running or 'kill ${anDaemonPid[0]}'";fi #could be: "already running, exiting.", but the new instance may have updated parameters that work as intended now.
fi
fi
done
exit #returns w/e flock does
fi
echo "$$:Work:`date`"
for((i=0;i<60;i++));do
echo "`\
echo $i;\
date;\
ps --no-headers -o ppid,pid,stat,state,pcpu,rss,cmd -p "$PPID";\
ps --no-headers -o ppid,pid,stat,state,pcpu,rss,cmd -p "$$";\
`" >>/tmp/flock.tst.log
sleep 1
done
echo "$$:Done:`date`"
いくつかの結果:
ご覧のとおり、排他ロックはプロセス 1458428 (flock:1458427) と 1438949 (flock:1438941) によって同時に取得されました :(
ログ ファイル (スクリプトによって作成) には、この問題が表示されます (50 秒目に、ロックを取得するべきではない他のインスタンスの 2 秒目のログが発生しました)。
2
Fri 22 Jan 17:03:16 -03 2021
1438953 1458427 S S 0.0 784 flock --timeout=.22377 /home/myUser/bin/flock.tst.sh /home/myUser/bin/flock.tst.sh
1458427 1458428 S S 0.0 3852 /bin/bash /home/myUser/bin/flock.tst.sh
50
Fri 22 Jan 17:03:16 -03 2021
1438925 1438941 S S 0.0 788 flock --timeout=.229687 /home/myUser/bin/flock.tst.sh /home/myUser/bin/flock.tst.sh
1438941 1438949 S S 0.0 3900 /bin/bash /home/myUser/bin/flock.tst.sh
lslock
これを示します (while with はdate
スクリプトのヒントとして表示されます)。
Fri 22 Jan 17:03:16 -03 2021
flock 1459088 FLOCK 1.8K WRITE* 0 0 0 /home/myUser/bin/flock.tst.sh
flock 1458427 FLOCK 1.8K WRITE 0 0 0 /home/myUser/bin/flock.tst.sh
flock 1438941 FLOCK 1.8K WRITE 0 0 0 /home/myUser/bin/flock.tst.sh (deleted)
Fri 22 Jan 17:03:17 -03 2021
flock 1459616 FLOCK 1.8K WRITE* 0 0 0 /home/myUser/bin/flock.tst.sh
flock 1458427 FLOCK 1.8K WRITE 0 0 0 /home/myUser/bin/flock.tst.sh
flock 1438941 FLOCK 1.8K WRITE 0 0 0 /home/myUser/bin/flock.tst.sh (deleted)
ターミナル ログ (多数の同時インスタンスを生成したもの) には次のように表示されます。
1438949:Work:Fri 22 Jan 17:02:23 -03 2021
1458428:Work:Fri 22 Jan 17:03:14 -03 2021
1438949:Done:Fri 22 Jan 17:03:26 -03 2021
1476209:Work:Fri 22 Jan 17:04:02 -03 2021
1458428:Done:Fri 22 Jan 17:04:17 -03 2021
答え1
仮説: この問題が発生する直前にスクリプトを保存しました。エディターがコピーを保存し、そのコピーを元のパスに移動しました。Vimがどのようにこれを実現するかそしてなぜ。
実際には、古いロックは古いファイル (inode) に対してまだ保持されていました。これは、…/flock.tst.sh (deleted)
の出力でのように表示されました。lslocks
しかし、flock
スクリプト (その別のインスタンス?) は、パスを使用して生成し続けました。パスが別の inode を指し始めると、新しい inode がflock
新しいロックを取得できるようになりました。これは、…/flock.tst.sh
の出力でのように表示されましたlslocks
。
2つのロックは独立しており、お互いをブロックすることはできませんでした。違うファイル。Flock は設計どおりに動作しました。
vim
実際に、スクリプトのインスタンスを 2 つ実行し (1 つはロックを取得し、もう 1 つはロックの取得を試行し続ける)、それを で開いてすぐに( ) と書き込むことで、結果を再現でき:w
ます。または、次の操作を実行します。
cp flock.tst.sh foo
mv foo flock.tst.sh