- PR -

ファイルの先頭から削除

投稿者投稿内容
カーニー
ぬし
会議室デビュー日: 2003/09/04
投稿数: 358
お住まい・勤務地: 東京
投稿日時: 2004-08-24 14:34
こんにちは、カーニーです。

あるプロセスが書き込み中のファイルを、「先頭から指定した長さだけ」削除したいのです。
もちろん、そのプロセスはその後も何事もなかったかのように追記し続けられる必要があるので、inode番号が変わらないような方法でないといけません。

まずはLinux上での実現方法を探していますが、UNIX全般に通用する方法があれば最高です。コマンドでもシステムコールでも構いません。

ちなみにファイルへの書き込みプロセスは商用プロダクトなので、一切手を入れることはできません。

「先頭から指定した長さだけ」というのがなければ/dev/nullをコピーすればよいだけなので楽なのですが。

何かアイディアがあればぜひ教えてください。
Gio
ぬし
会議室デビュー日: 2003/11/28
投稿数: 350
お住まい・勤務地: 都内から横浜の間に少量発生中
投稿日時: 2004-08-24 15:19
あるプロセスが書き込んでいる最中なのに /dev/null をコピーしてクリアするという方法が許されるのであれば、以下の方法でいけるかもしれません。

(1) そのファイルをモード r+ で fopen する。
(2) fseek ファンクションコールで削除する範囲の直後にカーソルを進め、その後をバッファに読み込む。
(3) rewind ファンクションコールでファイルの先頭に戻り、バッファの内容を書き戻す。
(低レベル API を使う場合は、fseek ではなく lseek システムコールを使います)

当然おわかりと思いますが、バッファに読み込んでいる最中、書き戻している最中に、別のプロセスで実行されている書き込み処理との間で排他制御を行う必要があります。
先頭を削除すると追記するカーソル位置も変わってしまうので、これを書き込みプロセスに通知する必要もあります。
商用プロダクトが何かはわかりませんが、おそらくこういった他プロセスとの排他制御やカーソル位置調整には対応していないでしょう。
他の方法を検討された方が良いかもしれません。

もし、書き込みプロセスがデーモンのような形で常駐して書き込みを続けるのではなく、一旦動作しては書き込んで終了という通常のアプリケーションであれば、前述の方法で inode を変えずにファイル内容を問題なく更新できると思います。
カーニー
ぬし
会議室デビュー日: 2003/09/04
投稿数: 358
お住まい・勤務地: 東京
投稿日時: 2004-08-24 16:51
Gioさん、コメントどうもありがとうございます。

引用:

Gioさんの書き込み (2004-08-24 15:19) より:
当然おわかりと思いますが、バッファに読み込んでいる最中、書き戻している最中に、別のプロセスで実行されている書き込み処理との間で排他制御を行う必要があります。
先頭を削除すると追記するカーソル位置も変わってしまうので、これを書き込みプロセスに通知する必要もあります。
商用プロダクトが何かはわかりませんが、おそらくこういった他プロセスとの排他制御やカーソル位置調整には対応していないでしょう。



試してみました。
flock(fd, LOCK_EX) してみましたが、書き込み側は全然ブロックされませんでした。

ちなみにそのプロダクトはOracleです。
Oracleのログファイルを別サーバに転送したいのです。
コネクションプーリングやTPモニターを使うとセッションが使い回しされて、ログファイルが巨大になってしまう恐れがあるため、転送の終わった分は都度削除したいと思っています。

引用:

もし、書き込みプロセスがデーモンのような形で常駐して書き込みを続けるのではなく、一旦動作しては書き込んで終了という通常のアプリケーションであれば、前述の方法で inode を変えずにファイル内容を問題なく更新できると思います。



ファイル開きっぱなしなので、これもだめでした。

取りこぼしが起きないように tail -f みたいのでキャプチャしながら、/dev/null をコピーしてやろうかしら・・・。

皆さん、他にもよいアイディアがあればぜひ聞かせて下さい。
ぽんす
ぬし
会議室デビュー日: 2003/05/21
投稿数: 1023
投稿日時: 2004-08-24 17:19
「ファイルの長さをゼロに切り詰める」であれば O_TRUNC をつけて
open(2) すればよいのですが、「先頭から指定された長さだけ」
ということだと、Gio さんが書かれていることが問題ですね。
アトミック操作を行うか、排他制御をすることが必要ですが、
どちらも困難でしょう。それ以上に、切り詰めた後の新しい
オフセット位置を伝えることが困難です、ていうか不可能でしょう。

> flock(fd, LOCK_EX) してみましたが、書き込み側は全然ブロックされませんでした。

flock が行うのは忠告ロックです。強制ロックではありません。
たとえ強制ロックを取得しても、今度は書き込んでいる側の
プロセスでエラーを吐きまくるか、下手をすると終了してしまう
のではないかと。

> 取りこぼしが起きないように tail -f みたいのでキャプチャしながら、/dev/null をコピーしてやろうかしら・・・。

それだと、取りこぼしが生じる可能性が大です。
t-wata
大ベテラン
会議室デビュー日: 2002/07/12
投稿数: 209
お住まい・勤務地: 東京
投稿日時: 2004-08-24 19:04
転送の終わった分を削除するより、未転送分を切り出して、それを転送するようにする方が簡単な気がしますが。
カーニー
ぬし
会議室デビュー日: 2003/09/04
投稿数: 358
お住まい・勤務地: 東京
投稿日時: 2004-08-24 19:48
色々と参考になるご意見をいただけて感謝しております。
どうもありがとうございます。

それにしても参りました。

例えばinodeの持つ「ファイル開始アドレス」みたいのを直接操作して、ずらしてしまうなんてのは非現実的ですかね?
やり方全然分かりませんが。

もしできたとしても、それで以ってファイルシステムにおける領域の解放になり、空き領域が増えるのかどうかという問題もありますが。

引用:

t-wataさんの書き込み (2004-08-24 19:04) より:
転送の終わった分を削除するより、未転送分を切り出して、それを転送するようにする方が簡単な気がしますが。



今回は削除そのもの(領域解放)が目的なわけでして。

定期的にコネクションを張りなおすとかして、1つのログファイルがあんま大きくならないような方法でも考えたほうが良さそうですね。
holic
ベテラン
会議室デビュー日: 2004/08/24
投稿数: 74
投稿日時: 2004-08-24 21:36
名前つきパイプにログは出せないんですか?
Linux なら mkfifo で作れますよね。

読む側のプログラムがこけると、ちょいとやな感じですが。
t-wata
大ベテラン
会議室デビュー日: 2002/07/12
投稿数: 209
お住まい・勤務地: 東京
投稿日時: 2004-08-24 22:57
> 今回は削除そのもの(領域解放)が目的なわけでして。

すみません。転送量を気にしてると勘違いしてました。

DBの処理が止まってもいいなら、SIG_STOPでログをopen中のプロセスを
一旦全部サスペンド(シグナルは非同期だから注意が必要だけど)して、
ファイルを別の場所にコピー&cp /dev/nullしてから、SIG_CONTでプロ
セスをレジュームすれば取りこぼしなくできそうですが。。。

スキルアップ/キャリアアップ(JOB@IT)