いますぐ実践! Linuxシステム管理

いますぐ実践! Linux システム管理 / Vol.281 / 読者数:2721名

ごぶさたいたしております、うすだです。

前回発行したのが、2018年の10月でした。1年9ヶ月ぶりでございます。

現在、コロナ禍さんのために世界が大きく変わっておりますが、そんな中でも、 当メルマガを続ける意義はまだまだあるのではないかと思い、 久々に書いてみようと思った次第です。

…すみません。というのは建前です。

ほそぼそと続けてきた当メルマガが自然消滅してしまうのもなあ…という未練と、 何かしら発信してちょびっとでも世の中の役に立たないと、 己の存在意義がなくなってしまうのでは、という焦りが、主なきっかけです。

…すみません、これも、やや建前でした。
ほんとうの理由は、

GWに某原稿を書き終え余裕ができた & メルマガのことをやっと思い出した

からでした…。(基本的に、あまり考えないヒトです。)

今後は、月1回発行に戻せるよう努力したいと思います。(歯切悪っ。)
というわけですので、読むに値する内容と思われるなら、 引き続きお付き合いいただけますと、誠に幸いです。

…解除せずにいてほしいなと思いつつ、今回もはりきってまいります。

今回のお題 - 複数がファイルアクセスするとどうなる? (レベル:初級)

昔からずっと気になっていたことがあります。

それは、複数のプロセスが同じファイルを同時に読み書きするとどうなるのか、 という疑問です。

…いえ、学生の頃、本で読んだ記憶がかすかにあるのですが、 どうだったか覚えておらず、実際に確認しないまま、時が過ぎてしまいました。

というわけで今回は、複数のプロセスが同じファイルにアクセスしたときの動作を、 ある程度はっきりさせたいと思います。(歯切れが悪いな…。)

…はい、これのどこがシステム管理なんだ? と疑問に思われた貴兄が大半ではないかと思います。が、なにかのトラブルの際に、 ほんのちょびっとたしになるかもしれない、などと思って読んでいただけますと幸いです。

最初に、確認した内容とその結果を

今回は、2つのプロセスを半ば同時に動かし、

  • 一方のプロセスがファイルを読んでいる最中に、もう一方のプロセスが同じファイルを上書き・追記・削除するとどうなるか?
  • 一方のプロセスがファイルを書いている最中に、もう一方のプロセスが同じファイルを上書き・追記・削除するとどうなるか?

について、簡単に調べました。

当メルマガは、簡単に試せることをモットーとしていますので、 試すためのスクリプトをPythonでちゃちゃっと書きました。
つまり、必要最低限かつチェックなし(ノーチェックで引数を使ったり、 エラーチェックを端折っています)という代物ですので、 その前提でみていただければと思います。

まずは、ファイル読み込みのスクリプトです。
以降では、これを「read_test.py」というファイル名で扱います。

#!/usr/bin/env python3
with open("./test.txt", buffering=1) as f:
    print(f.readline().rstrip())
    print('# Please enter')
    input()
    for l in f: 
        print(l.rstrip())

2行目で、カレントディレクトリにある「test.txt」をオープンし、
3行目で、まずファイルから1行読んで出力します。
4〜5行目では、「# Please enter」と出力してキー入力を待ちます。
6〜7行目では、残りをファイルから読んで出力します。

つまり、4〜5行目で待っている間に、他のプロセスに横槍を入れさせようという寸法です。

次に、ファイル書き込みのスクリプトですが、こんな感じです。
こちらは、「write_test.py」という名前にしておきます。

#!/usr/bin/env python3
import sys
import os

print("# PID=%d" % os.getpid())
with open("./test.txt", sys.argv[1]) as f:
    f.write('%d test1\n' % os.getpid())
    f.flush()
    print('# Please enter')
    input()
    f.write('%d test2\n' % os.getpid())
    f.write('%d test3\n' % os.getpid())

5行目では、自分のプロセスIDを出力します。(他と区別するためです。)
6行目で、カレントディレクトリにある「test.txt」をオープンし、
7〜8行目で、「PID test1」という1行をファイルに書きます。
9〜10行目では、「# Please enter」と出力してキー入力を待ちます。
11〜12行目では、「PID test2」と「PID test3」をファイルに書きます。
(「PID」の部分は実際のプロセスIDの値が入ります。)

こちらも、9〜10行目で待っている間に、他のプロセスに処理させようという寸法です。

で、得られた結果は以下の通りです。

  • ファイルの読み込みに関しては、元データが読み出せる。
    ただし、元データ以上に書き込まれると、それが追加で読み出せる。
  • ファイルの書き込みに関しては、ファイルの先頭から順に上書きする。
  • ファイルの追記に関しては、常にファイルの末尾に追記する。
  • ファイルを削除しても、削除前にオープンしていればアクセス可能。
    ただし、クローズするとファイルは失われる。

まあ、わりと予想通りの結果が得られたように思います。

では、よろしければ詳細をどうぞ〜。

読み込んでいる最中の場合

まずは、読み込んでいる最中に、上書き・追記・削除をしてみます。

読み込むファイルは、こんな内容のものを用意しました。

  $ cat test.txt
  AAAA
  BBBB
  CCCC

まず、1つ目のプロセスに読み込みをさせてみます。

  $ ./read_test.py
  AAAA
  # Please enter

1行目の「AAAA」を読んだ後、待ち状態になっています。
この状態で置いておいて、2つ目のプロセスに書き込みをさせます。
(引数の「w」はそのままopenの第2引数(上書き)に渡されます。)

  $ ./write_test.py w
  # PID=1240
  # Please enter

これで、1行書き込んで待ち状態になっているはずです。
実際、test.txt を見ると、2つ目のプロセスが1行書いた状態です。

  $ cat test.txt
  1240 test1

ここで、2つ目のプロセスでリターンキーを押して、 3行とも書き込みしてしまいます。
そして、1つ目のプロセスでリターンキーを押すと、以下のように、 元のファイルの中身を読み込めていますが、何か余計に読み込んでいます。

  (read_test.pyの続き)
  BBBB
  CCCC
   test2
  1240 test3

2つ目のプロセスが、元のファイルの長さ以上に書き込んでおり、 その分を読み出しているようです。

なお、test.txtの中身は、最終的には、2つ目のプロセスが書いた状態のものになりました。

  $ cat test.txt
  1240 test1
  1240 test2
  1240 test3

読み込んでいる最中に追記すると、どうなるでしょうか。
上記と同じ手順で、 引数を「a」に変更して(つまり追記のモードにして)write_test.pyを実行すると、 元の3行に加えて、追記した3行もそのまま読み出せました。

また、write_test.pyの代わりにrm test.txtを実行した場合(つまり削除の場合)、 元と同じ内容を読み出せました。
rmコマンドでファイルシステムからは参照できなくなるものの、 1つ目のプロセスがオープンしたままなので、その間、ファイルは存在したままになる、 ということだと思います。
(クローズすると、ファイルを参照するヒトがいなくなり、消えます。)

書き込んでいる最中の場合

次に、書き込んでいる最中に、上書き・追記・削除をしてみます。
1つ目のプロセスも、書き込む方のスクリプトを実行します。

  $ ./write_test.py w
  # PID=2345
  # Please enter

この状態で、2つ目のプロセスも同様に実行します。

  $ ./write_test.py w
  # PID=2350
  # Please enter

今度は、1つ目のプロセスからリターンキーを押してみます。
すると、test.txt は以下のように変化していきました。

(1)1つ目実行(2)2つ目実行(3)1つ目終了(4)2つ目終了
2345 test12350 test12350 test12350 test1
2345 test22350 test2
2345 test32350 test3

つまり、上書きのときは、ファイルの先頭から順に書き込みますが、 書き込んだ直後の位置を覚えていて、その後はその位置から書き込んでいく、 ということのようです。
お互いが協調することなく上書きしていくので、上記のように、 書き込み合戦みたいな動作になります。

書き込み最中に追記をすると、こうなりました。

(1)1つ目実行(2)2つ目実行(3)1つ目終了(4)2つ目終了
2345 test12345 test12345 test12345 test1
2350 test12345 test22345 test2
2345 test32345 test3
2350 test2
2350 test3

1つ目のプロセスは、先ほどと同様、先頭から順に書いていきます。
2つ目のプロセスは、そのときのファイルの最後に追記をしています。

削除の場合は、特にエラーなど置きませんが、test.txtが失われました。
こちらも、rmされた時点でファイルシステムからは参照できなくなりますが、 1つ目のプロセスがオープンしている間はファイルが存在していて、 書き込みができていたと思われます。

おわりに

以上、2つのプロセスが同じファイルにアクセスした際の動作を確認する方法とその結果を、 淡々とご紹介しました。

…説明がわかりにくかったら申し訳ございません。
自分で実行してみて、なぜそうなるのかひとつずつ追っていけば、わかると思います。

あと、追記中に上書きとか、読み書きでオープンしたときにどうかというのも、 追加で調べてみるとよいかもしれません。

宿題の答え

前回の宿題は、

  「df -h | ssh myserver Mail -s 'df\ result' dana」のように空白の
  手前に「\」を入れているのはなぜか調べてみましょう。

でした。

1年9ヶ月前に出した宿題なので、出した本人ですら、 宿題の意図を完全に失念していました。

それはさておき、Mailコマンドだと変な人にメールしてしまうと困りますので、 ここは当たり障りのなさそうなcatコマンドで試してみましょう。

  $ ssh myserver cat 'df\ result'
  cat: df result: そのようなファイルやディレクトリはありません

  $ ssh myserver cat 'df result'
  cat: df: そのようなファイルやディレクトリはありません
  cat: result: そのようなファイルやディレクトリはありません

「\」を入れた場合はひとつの引数として処理されますが、 「\」がないと別の引数と解釈されてしまいました。
つまり、「df result」をひとつの引数として処理してもらうために「\」が必要、 ということでした。

さて、こうなる原因ですが、「-v」オプション付きで実行すると、 なんとなく見えてきます。

  $ ssh -v myserver cat 'df\ result'
  ...中略...
  debug1: Sending command: cat df\\ result
  ...後略...

  $ ssh -v myserver cat 'df result'
  ...中略...
  debug1: Sending command: cat df result
  ...後略...

SSHサーバに実行してもらう際、引数も含めて一括で渡してしまうため、 別の引数として処理されてしまうようです。

ちなみに、catも含めて「'」で囲っても、同じ結果が得られました。
(気になる方は、ぜひご自身で実行して確認してみてください。)

というわけで、意図しない現象が起きたときは、いろいろ確かめてみるとよいですね、 という話でした。

今回の宿題

今回の宿題は、

  得られた結果が概ね正しいことを、他の手段でも確認してみましょう。

です。

具体的には、Cかなにかでプログラムを書いて確認するとか、 カーネルの(システムコールの)ソースコードを確認するとか、でしょうか。

できる範囲内でトライしていただければと思います。

あとがき

私事で恐縮ですが、3月末で退職し、4月から別の会社で働いております。

これまでは、無節操にプログラムを書いたり、 自動運転のオペレーションをやったりしていました。

これからは、主に、システムや装置のテストを行うことになります。

テストと言っても、プランニングから設計、実施、バグを含めた管理など、 様々なことを行う必要があり、思った以上に幅広い分野です。
今は、テストの入門書をバリバリと楽しく読んでいます。

ただ、問題があります。それは、Linuxを使う機会と、プログラムを書く機会が、 しばらくはないかもしれない、ということです。

自社で作っているソフトウェアがありますし、 テスト用のソフトウェアを都度用意することもあるため、 プログラムを書く機会はありそうです。

ですが、Linuxに関しては、しばらくどころか、未来永劫ずっとない可能性もあります。

現に、今やっている仕事の環境は、Windowsです。

それだけだと寂しい?ので、WindowsにWSLを入れてLinuxをごりごり使ってみたり、 VBScriptで手順を簡略化するスクリプトを書いたりしています。

できれば、そのうち、Linuxの良さをみんなに知ってもらい、 いい方向に変えていけたらいいなと思っています。
まだ入ったばかりなので、様子を見ながら機会を伺いたいと思います。

…逆に、空気を読みすぎて染まってしまわないよう、気をつけます…。

 

今回も、ここまで読んでいただき、誠にありがとうございました。
次回は、6月7日に発行したいと思っております。

 

「いますぐ実践! Linux システム管理」はこちらです。
メルマガの解除、バックナンバーなども、以下からどうぞ。
http://www.usupi.org/sysad/ (まぐまぐ ID:149633)

その他、作者に関するページは、概ね以下にございます。
http://www.usupi.org/kuri/ (まぐまぐ ID:126454)
http://usupi.seesaa.net/ (栗日記ブログ)
http://twitter.com/kuriking/ (twitter)
http://facebook.com/kuriking3 (facebook)
https://jp.pinterest.com/kuriking/ (pinterest) https://www.instagram.com/kuri_king_/ (instagram)


[バックナンバーのトップへ] [Linux システム管理のトップへ]

トップ

バックナンバー
    [日付順] [目的別]

プロフィール

▼ リンク

独学Linux
Linuxデスクトップ環境に関する情報が満載です。 メルマガもありますよ。
Server World
CentOS 6をサーバとしたときの設定例が、これでもかというくらいたくさん載っています。 CentOS以外のディストリビューション(Fedora, Ubuntu)も充実しています。
LINUXで自宅サーバーを構築・導入(Fedora9)
Fedora9のインストールの仕方から管理方法まで、詳しく載っています。 SearchManには情報がもりだくさんです。
マロンくん.NET
〜サーバ管理者への道〜
Linuxをサーバとして使用するための、いろいろな設定方法が載っています。 マロンくんもかわいいです。 なんといっても、マロンくんという名前がいいですね!!
日経Linux
今や数少なくなってしまったLinuxの雑誌。
Linux Square − @IT
@ITが提供する、Linux の情報が満載。 載っていない設定方法はないんじゃないでしょうか。
gihyo.jp…技術評論社
Linuxに限らず様々な技術情報が満載のサイト。 SoftwareDesign誌も、 ソフトウェア技術者は必見です。
SourceForge.JP Magazine
Linux に限らず、オープンソース関連の記事が網羅されています。
ITmediaエンタープライズ:Linux Tips 一覧
Tips というより FAQ 集でしょうか。わからないことがあれば覗きましょう。
IBM developerWorks : Linux
開発者向けですが、勉強になりますよ。
栗日記
システム管理とかと全然関係ありませんが、毎日栗の絵を描いています。
システム管理につかれちゃったとき、癒されたいときに、ご覧ください。:-)
WEB RANKING - PC関連
ランキングに参加してみました。押してやってください。

▼ 作ってみました

Add to Google

▼ せんでん




▼ 最近読んだ本

▼ 気に入ってる本