Ble.sh: [履歴]巨大な履歴ファイルがあると動作が極端に遅くなる。

Created on 30 Jun 2019  ·  13Comments  ·  Source: akinomyoga/ble.sh

ble version: 0.4.0-devel1+7be255c
Bash version: 5.0.3(1)-release

題名の通り,巨大な履歴ファイルに対してble.shが正常に動作しません。
正確な閾値は不明ですが,1.4 GiB程の大きさの履歴ファイルがあると,(単に沢山の履歴を処理しているのに時間が掛かっているとは思えない程)動作が遅くなります。

この一つ前のバージョン ( コミットID: 518e2ee) まででは起きなかった挙動です。

また,上述の状態でコマンドを実行すると実行(実行の結果それ自体は尋常です)の後に

awk: write failure (No space left on device)
awk: close failed on file /run/user/1000/blesh/〈数字〉.history.new (No space left on device)

というエラー文が表示され,履歴に実行したコマンドが書き込まれません。“No space left on device”とありますが,実際にはまだかなり空き容量には余裕があります(残り82 GiB程)し,iノードも殆ど使っていません(割合として1%強くらい)。またファイルシステムはext4で構築しているので,ファイルサイズそのものも(テキストファイルとしては些か巨大ですが)影響しているとは思えません。

なお,私のGNU Bashの履歴に関する設定は以下の通りです。

HISTSIZE=''
HISTFILESIZE=''

というか,そんな馬鹿デカい履歴を保持し続けるのが間違っているのかもしれませんが……。

compatibility

All 13 comments

ご報告ありがとうございます。すみません。1.4G (1.4M ではなくて 1.4G なのですよね) もの履歴ファイルを持っているとは想定していませんでした。

/run/user/1000 は tmpfs でマウントされている筈なので、/ のファイルシステムの容量と関係なく、自分の積んでいるRAMの容量に応じて容量が設定される筈です。

確認なのですが、1.4G の履歴ファイルがある時に 518e2ee 以前の ble.sh はどのように動いていましたか。特に、

  • 大量の処理時間とメモリを消費しそうな気がするのですが、気にならない速さで動いていましたか。
  • 起動した直後に で履歴を遡ろうとした時の処理時間は如何ですか。
  • (518e2ee では未だ問題の挙動は見られなかったということでよろしいですか)

申し訳ありません。念の為にと確認したところ,コミット 518e2ee どころかその一つ前のコミット f204bc7 でも,巨大な履歴ファイルに対して同様の問題が発生しました。容量を(1000分の1程に)減らしてみたところ,最新版でも今までと同様に動作しました(つまり 7be255c での変更は全く原因ではない)。どうもble.shの更新を行なった前後で,(偶然)時を同じくして履歴ファイルの容量が上限に達したようです。確認不足でした……すいません。

ファイル容量の確認

はい,1.4 GiBです。また,/run/user/1000には800 MiB程しか容量が割り当てられていないようでした。

ble.shの動作速度

起動時は,素のBashなどと比べると時間が掛かってはいましたが,一旦コマンドを入力し初めるときびきびとした反応が返ってきました。

起動直後での履歴遡及に要する処理時間

起動直後の履歴遡及速度は非常に遅いです。「loading history...」という表示が十分に目視できる程度(1秒前後?)には時間が掛かります。

どうもble.shの更新を行なった前後で,(偶然)時を同じくして履歴ファイルの容量が上限に達したようです。確認不足でした……すいません。

もしかすると ble.sh の異常が原因で履歴ファイルに過剰のコマンド履歴が書き込まれるようになってしまったという可能性はあると思われますか (例えば Bash を起動する度に履歴ファイルが二倍になってしまうなど)。1.4GiB というのはやはりありえない様な気がしてしまって…。1.4GiB の行数は幾つでしょうか。また、1.4GiB の内の重複する行数というのは分かりますか。

ファイル容量の確認

また,/run/user/1000には800 MiB程しか容量が割り当てられていないようでした。

tmpfs はファイルの内容に応じて容量が拡大します。拡大の最大値は実際のメモリの大きさに応じて (ディスクに退避する量も含めて) 設定されるということだったように思います。それが 1.4GiB 付近という事になるのではないかと推察いたします。

ble.shの動作速度

素のBashは1.4GiBを一瞬で読み取れるという事になりますね…。

起動直後での履歴遡及に要する処理時間

それでも1秒で済むのですね。意外です。

例えば Bash を起動する度に履歴ファイルが二倍になってしまう

ああ,まさにこの現象が起こっていました(akinomyoga様の洞察力に感服しました)。Bashを起動する度に,履歴が丸々複製されているような状態です。しかし,この現象は 518e2ee でも生じました。確かにこのバージョンまでは問題なく動作していた記憶があるのですが……。

問題の履歴ファイルは約5000 0000行ありましたが,重複した行を削除すると,約1 4000行に激減しました(ファイルの容量は567 KiBになりました)。

蛇足かも知れませんが,私のBashの設定で,履歴に少しでも関係すると思われる設定を以下に書き出します(コメントが思い切り私事ですが……)。

# 履歴
shopt -s cmdhist
shopt -s lithist
# ↓複数シェルでおかしくなるので無効に
shopt -u histappend
shopt -s histreedit
shopt -s histverify
# ↓なんか履歴補完がおかしくなるのでCO
#HISTTIMEFORMAT=''
HISTCONTROL=ignoreboth
HISTFILE="${XDG_CACHE_HOME:-~/.cache}/bash/history.bash"
#HISTSIZE=100000
#HISTFILESIZE=10000000
#↑こういうことしなくても↓これで実質無制限っぽい?
HISTSIZE=''
HISTFILESIZE=''

すみません。今の所こちらでは二倍になってしまう現象を再現できていません。引き続き時間がある時に調べてみます。もしよろしければどの commit 以降で履歴が二倍になってしまうのかというのを確認していただければ幸いです。

コミット 305b89f までは起動時に履歴件数が倍増する現象は起きませんでした。コミット 655d73e よりその当該現象が生じるようになります。

ありがとうございます

  • bashrc などの中で直接 history コマンドを呼び出している箇所はありますか。
  • source ble.sh の直後で unset -f history を実行した場合にはどうなりますか。
  • $PROMPT_COMMAND変数に次のようなコマンドを登録しています。
function _usrcmd.synchist
{
    history -a && history -c && history -r
}
  • 相変らず履歴件数が倍増します。

ありがとうございます。いろいろ試行錯誤していたら今再現しました。また後で修正します

原因

直接の原因は以下の (素の) Bash の振る舞いでした。bashrc の中で history -r または history -n 等を実行して履歴項目を読み込んでおくと、対話セッションに入るときにも Bash 自体によって history -r が実行されて、履歴項目の数が2倍になってしまうという物です。例:

$ bash --norc
$ history 1
 5345  history 1
$ exit
$ bash --rcfile <(echo history -r)
$ history 1
10690  history 1   # ← 履歴項目の数が2倍になっている
$ exit

ble.sh による history -a の模倣では前回から増えた分をファイルに書き出します。bashrc で history が呼び出された後に Bash が新しく履歴を読み出すと、その読み出された項目が全て前回から増えた分と認識されて、履歴ファイルが倍加するという問題でした。

解決 e64edb7

ble.sh による history 模倣実装の外で履歴項目数が変化した場合は、history -a の前回から増えた分の記録をリセットする事にしました。

但し、素の Bash で元からあった「bashrchistory -r を使うとメモリ上にある履歴項目の数が2倍になってしまう問題」に関してはそのまま放置していますこと御了承ください。

動作についてご確認いただければ幸いです。

因みに以下の設定に関しては、 305b89f において対応した bleopt history_share=1 という設定で同様の機能を (より効率的な方法で) 実装しておりますので、代わりにそちらをご利用いただければ幸いです。

function _usrcmd.synchist
{
    history -a && history -c && history -r
}
PROMPT_COMMAND=_usrcmd.synchist

bleopt history_share=1 に関してまた何かお気づきの点があればお知らせいただけると幸いです。

ありがとうございます。 e64edb7 にて,履歴件数が倍増しなくなったことを確認いたしました。

(複数セッションでの履歴の共有について,自作函数ではなくble.shの機能を利用することにしました)

確認ありがとうございます! 閉じますね

Was this page helpful?
0 / 5 - 0 ratings