Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions ble.pp
Original file line number Diff line number Diff line change
Expand Up @@ -2000,11 +2000,17 @@ function ble/base/clean-up-runtime-directory {
[[ :$opts: == *:finalize:* ]] && alive[$$]=0

local file pid iremoved=0 ibgpid=0
for file in "$_ble_base_run"/[1-9]*.*; do
for file in "$_ble_base_run"/[1-9]*.* "$_ble_base_cache"/*.[1-9]*.part; do
[[ -e $file || -h $file ]] || continue

# extract pid (skip if it is not a number)
pid=${file##*/}; pid=${pid%%.*}
pid=${file##*/}
if [[ $file == "$_ble_base_cache"/*.part ]]; then
pid=${pid%.part}
pid=${pid##*.}
else
pid=${pid%%.*}
fi
[[ $pid && ! ${pid//[0-9]} ]] || continue

if [[ ! ${alive[pid]+set} ]]; then
Expand Down
1 change: 1 addition & 0 deletions docs/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@
- import (`ble/util/import/is-loaded`): skip the file existence check for an absolute path `#D2423` d8ad40e7
- util (`ble/path#canonicalize`): fix infinite loops (fixup d8ad40e7) (reported by chill-nemesis) `#D2426` 63c23e99
- nsearch: fix the search position after a forward mismatch (reported by NitramO-YT, fixed by dfherr) `#D2430` 5fe06d62
- global: generate cache atomically (reported by RakibFiha, fixed by vnz) `#D2432` xxxxxxxx

## Compatibility

Expand Down
12 changes: 9 additions & 3 deletions lib/init-bind.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#!/bin/bash

## @var[in] ble_decode_bind_cache
## @var[in] ble_decode_unbind_cache
## The filenames to write the caches for bind/unbind the ble.sh keybindings.

# 現在の bash の version に従って以下の二つのファイルを生成します:
#
# $_ble_base_cache/decode.bind.$_ble_bash.$bleopt_input_encoding.bind
Expand Down Expand Up @@ -205,12 +209,14 @@ function ble/init:bind/.generate {
}

function ble/init:bind/generate-binder {
local fbind1=$_ble_base_cache/decode.bind.$_ble_bash.$bleopt_input_encoding.bind
local fbind2=$_ble_base_cache/decode.bind.$_ble_bash.$bleopt_input_encoding.unbind
local fbind1=$ble_decode_bind_cache
local fbind2=$ble_decode_unbind_cache

ble/edit/info/show text "ble.sh: updating binders..."

ble/init:bind/.generate 3>| "$fbind1" 4>| "$fbind2"
ble/init:bind/.generate 3>| "$fbind1.$$.part" 4>| "$fbind2.$$.part" &&
ble/bin/mv -f "$fbind1"{".$$.part",} &&
ble/bin/mv -f "$fbind2"{".$$.part",}

ble/edit/info/immediate-show text "ble.sh: updating binders... done"
}
Expand Down
10 changes: 6 additions & 4 deletions lib/init-cmap.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#!/bin/bash

## @var[in] ble_decode_cmap_cache
## The filename to write the cache

#
# 以下は ble-decode.sh にて既定で定義される特殊キー
#
Expand Down Expand Up @@ -494,10 +497,8 @@ function ble/init:cmap/initialize-keys {
}

## @fn ble/init:cmap/initialize
## @var[in] dump
## The filename to write the cache
function ble/init:cmap/initialize {
ble/edit/info/immediate-show text 'ble.sh: generating "'"$dump"'"...'
ble/edit/info/immediate-show text 'ble.sh: generating "'"$ble_decode_cmap_cache"'"...'
ble/init:cmap/initialize-kbd
ble/init:cmap/initialize-keys
#%$ hash=$(bash ./make_command.sh hash lib/init-cmap.sh) && [ -n "$hash" ] && echo " local hash='$hash'"
Expand All @@ -514,7 +515,8 @@ function ble/init:cmap/initialize {
END {
print "_ble_decode_cmap_cache_hash='\''" hash "'\''";
}
' >| "$dump"
' >| "$ble_decode_cmap_cache.$$.part" &&
ble/bin/mv -f "$ble_decode_cmap_cache"{".$$.part",}

# If ble.sh has not yet attached, we want to clear the processing message.
[[ $_ble_attached ]] || ble/edit/info/immediate-clear
Expand Down
6 changes: 5 additions & 1 deletion lib/init-term.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#!/bin/bash

## @var[in] ble_term_cache
## The filename to write the cache for the present TERM.

# 2020-02-07 #D12MSYS2 の CR 対策のため更新の必要あり

_ble_term_tput=
Expand Down Expand Up @@ -339,7 +342,8 @@ function ble/init:term/initialize {
ble/init:term/register-varname "_ble_term_sgr_ab"

# save
ble/util/declare-print-definitions "${varnames[@]}" >| "$_ble_base_cache/term.$TERM"
ble/util/declare-print-definitions "${varnames[@]}" >| "$ble_term_cache.$$.part" &&
ble/bin/mv -f "$ble_term_cache"{".$$.part",}
}

ble/util/put "ble/term.sh: updating tput cache for TERM=$TERM... " >&2
Expand Down
3 changes: 2 additions & 1 deletion lib/keymap.emacs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,8 @@ function ble-decode/keymap:emacs/initialize {
ble/decode/keymap#load isearch dump
ble/decode/keymap#load nsearch dump
ble/decode/keymap#load emacs dump
} 3>| "$fname_keymap_cache"
} 3>| "$fname_keymap_cache.$$.part" &&
ble/bin/mv -f "$fname_keymap_cache"{".$$.part",}

ble/edit/info/immediate-show text "ble.sh: updating cache/keymap.emacs... done"
}
Expand Down
3 changes: 2 additions & 1 deletion lib/keymap.vi.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8662,7 +8662,8 @@ function ble-decode/keymap:vi/initialize {
ble/decode/keymap#load vi_omap dump
ble/decode/keymap#load vi_xmap dump
ble/decode/keymap#load vi_cmap dump
} 3>| "$fname_keymap_cache"
} 3>| "$fname_keymap_cache.$$.part" &&
ble/bin/mv -f "$fname_keymap_cache"{".$$.part",}

ble/edit/info/immediate-show text "ble.sh: updating cache/keymap.vi... done"
}
Expand Down
4 changes: 2 additions & 2 deletions lib/keymap.vi_digraph.sh
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ function ble-decode/keymap:vi_digraph/initialize {

ble/edit/info/immediate-show text "ble.sh: updating cache/keymap.vi_digraph..."

>| "$fname_keymap_cache"
ble/decode/keymap#load vi_digraph dump 3>> "$fname_keymap_cache"
ble/decode/keymap#load vi_digraph dump 3>| "$fname_keymap_cache.$$.part" &&
ble/bin/mv -f "$fname_keymap_cache"{".$$.part",}

ble/edit/info/immediate-show text "ble.sh: updating cache/keymap.vi_digraph... done"
}
Expand Down
56 changes: 56 additions & 0 deletions note.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8231,6 +8231,62 @@ bash_tips

2026-09-07

* global: generate cache atomically (reported by RakibFiha, fixed by vnz) [#D2432]
https://github.com/akinomyoga/ble.sh/issues/109
https://github.com/akinomyoga/ble.sh/pull/727

> The cache files under $_ble_base_cache were written in place with ">|".
> When many shells start at the same time with a stale cache (e.g. a
> terminal session restore right after "ble-update" or a bash upgrade), one
> shell truncates and rewrites a cache file while others already pass the
> "-s"/"-nt" checks and source it. A shell that sources a half-written
> "keymap.emacs" fails with "ble.sh: The keymap 'emacs' is empty." and
> ble-attach aborts; a half-written "decode.bind.*" fails with a Bash
> syntax error.
>
> Write every attach-time cache to "<file>.$$.part" first and rename it
> into place with "ble/bin/mv -f", so readers only ever see complete files.
> "decode.readline.*" already used a temporary file but with a name shared
> by all shells; use the per-process name there as well.

同時にシェルを複数人の手で立ち上げる様な事はないと想定していたが、
tmux-concurrent の様な物は同時に複数のシェルを立ち上げるという事の様だ。確
かに、それで全ての説明が付く。

init-*.sh に関しては全部呼び出し元からキャッシュファイルの書き込み先のファ
イル名を指定することにした。変数名は一様に ble_*_cache という事にする。

元々現在の様な設計になっていた一つの理由には外部プロセスの立ち上げを抑制し
て起動速度を可能な限り短くするという物だった。然し、結局 mv を呼び出さなけ
ればならないのだとしたらもっと別の方法はあるだろうか。取り敢えず何れの実行
パスもキャッシュが存在しない時にのみ実行されるところだという所は確認した。
なので、少なくとも毎回実行されるという訳でもない。

* reject: 例えば何らかの方法で mutex か何かを取得して同期をするなど。しかし、
その様な事をする方がやはり時間がかかるだろう。mkdir による方法を用いると
しても、少なくとも mkdir のコストは存在する事になるし例えば NFS 上でうま
くその様な処理が動くのかも分からない。

* done: 毎回 ble/bin/mv || ble/bin/rm を実行しているのは汚い。

a 毎回 ble/bin/rm を呼び出しているのはコストがかかるし、これは
$_ble_base_run/$$.* と同様に終了時に一発 rm で cleanup すれば良い。
cache は少なくとも in-memory filesystem に置くつもりはないので、中身の
消去も即座にしなくても大丈夫だろう。

b ble/bin/mv || ble/bin/rm もしくは ble/bin/mv "$file"{".$$.part",} || >|
"$file.$$.part"を行う様な関数を作ってもいいのかもしれないが今のところは
其処までして即座に削除しなくても良い様な気がする。

* done: 孤立リダイレクション >| "$cache" によって中身を空にする操作は
atomic ではないか? と思ったが、どうだろうか。例えば他の人がそのファイルに
書き込みをしている間に >| をすると、>| する事自体は atomic であったとして
も、他の人が続きを書き込むに従ってファイルの前半が NUL 埋めされてしまうの
ではないか? と思ったが、そもそも有限の大きさの内容を書き込む場合には
in-place ではなく .$$.part で行っているのでその様な事は起こらないはずであ
る。mv と >| が前後したり重なったりしても別に変な内容のファイルにはならな
い筈である。

* keymap.vi: support vi_nmap/accept-and-next (requested by sharpchen) [#D2431]
https://github.com/akinomyoga/ble.sh/discussions/726

Expand Down
29 changes: 17 additions & 12 deletions src/decode.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2844,11 +2844,11 @@ function ble/decode/cmap/initialize {
function ble/decode/cmap/initialize { return 0; }

local init=$_ble_base/lib/init-cmap.sh
local dump=$_ble_base_cache/decode.cmap.$_ble_decode_kbd_ver.$TERM.dump
local ble_decode_cmap_cache=$_ble_base_cache/decode.cmap.$_ble_decode_kbd_ver.$TERM.dump
#%$ hash=$(bash ./make_command.sh hash lib/init-cmap.sh) && [ -n "$hash" ] && echo " local hash='$hash'"
if [[ -s $dump && $dump -nt $init ]]; then
if [[ -s $ble_decode_cmap_cache && $ble_decode_cmap_cache -nt $init ]]; then
local _ble_decode_cmap_cache_hash=__uninitialized__
source -- "$dump"
source -- "$ble_decode_cmap_cache"
[[ $_ble_decode_cmap_cache_hash == "$hash" ]] && return 0
fi

Expand Down Expand Up @@ -3091,7 +3091,6 @@ _ble_decode_bind_encoding=

function ble/decode/readline/bind {
_ble_decode_bind_encoding=$bleopt_input_encoding
local file=$_ble_base_cache/decode.bind.$_ble_bash.$_ble_decode_bind_encoding.bind

# * 一時的に 'set convert-meta off' にする。
#
Expand All @@ -3105,21 +3104,25 @@ function ble/decode/readline/bind {
#
ble/term/rl-convert-meta/enter

local ble_decode_bind_cache=$_ble_base_cache/decode.bind.$_ble_bash.$_ble_decode_bind_encoding.bind
local ble_decode_unbind_cache=$_ble_base_cache/decode.bind.$_ble_bash.$_ble_decode_bind_encoding.unbind
#%$ hash=$(bash ./make_command.sh hash lib/init-bind.sh) && [ -n "$hash" ] && echo " local hash='$hash'"
local _ble_decode_bind_cache_hash=__uninitialized__
[[ -s $file && $file -nt $_ble_base/lib/init-bind.sh ]] && source -- "$file"
[[ -s $ble_decode_bind_cache && $ble_decode_bind_cache -nt $_ble_base/lib/init-bind.sh ]] &&
source -- "$ble_decode_bind_cache"

if [[ $_ble_decode_bind_cache_hash != "$hash" ]]; then
source -- "$_ble_base/lib/init-bind.sh"
source -- "$file"
source -- "$ble_decode_bind_cache"
fi

_ble_decode_bind__uvwflag=
ble/util/assign _ble_decode_bind_bindp 'builtin bind -p' # TERM 変更検出用
}
function ble/decode/readline/unbind {
local ble_decode_unbind_cache=$_ble_base_cache/decode.bind.$_ble_bash.$_ble_decode_bind_encoding.unbind
ble/function#try ble/encoding:"$bleopt_input_encoding"/clear
source -- "$_ble_base_cache/decode.bind.$_ble_bash.$_ble_decode_bind_encoding.unbind"
source -- "$ble_decode_unbind_cache"
}
function ble/decode/readline/rebind {
[[ $_ble_decode_bind_state == none ]] && return 0
Expand Down Expand Up @@ -4235,8 +4238,8 @@ function ble/builtin/bind/read-user-settings/.collect {
local cache=$_ble_base_cache/decode.readline.$_ble_bash.$map.txt
if ! [[ -s $cache && $cache -nt $_ble_base/ble.sh ]]; then
INPUTRC=/dev/null "$BASH" --noprofile --norc -i -c "builtin bind -m $map -p" 2>/dev/null |
LC_ALL= LC_CTYPE=C ble/bin/sed '/^#/d;s/"\\M-/"\\e/' >| "$cache.part" &&
ble/bin/mv "$cache.part" "$cache" || continue
LC_ALL= LC_CTYPE=C ble/bin/sed '/^#/d;s/"\\M-/"\\e/' >| "$cache.$$.part" &&
ble/bin/mv -f "$cache"{".$$.part",} || continue
fi
local cache_content
ble/util/readfile cache_content "$cache"
Expand Down Expand Up @@ -4385,16 +4388,18 @@ function ble/builtin/bind/read-user-settings/.cache-alive {
## @var[in] delay_prefix
## @var[in] cache_prefix
function ble/builtin/bind/read-user-settings/.cache-save {
local keymap content fail=
local keymap fail=
for keymap in emacs vi_imap vi_nmap; do
if [[ -s $delay_prefix.$keymap ]]; then
ble/util/copyfile "$delay_prefix.$keymap" "$cache_prefix.$keymap"
ble/util/copyfile "$delay_prefix.$keymap" "$cache_prefix.$keymap.$$.part" &&
ble/bin/mv -f "$cache_prefix.$keymap"{".$$.part",}
else
>| "$cache_prefix.$keymap"
fi || fail=1
done
[[ $fail ]] && return 1
ble/util/print "$settings" >| "$cache_prefix.settings"
ble/util/print "$settings" >| "$cache_prefix.settings.$$.part" &&
ble/bin/mv -f "$cache_prefix.settings"{".$$.part",}
}
## @fn ble/builtin/bind/read-user-settings/.cache-load
## @var[in] delay_prefix
Expand Down
5 changes: 3 additions & 2 deletions src/util.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6934,8 +6934,9 @@ function ble/term/DA2R.hook {
esac
}
function ble/term/.initialize {
if [[ -s $_ble_base_cache/term.$TERM && $_ble_base_cache/term.$TERM -nt $_ble_base/lib/init-term.sh ]]; then
source -- "$_ble_base_cache/term.$TERM"
local ble_term_cache=$_ble_base_cache/term.$TERM
if [[ -s $ble_term_cache && $ble_term_cache -nt $_ble_base/lib/init-term.sh ]]; then
source -- "$ble_term_cache"
else
source -- "$_ble_base/lib/init-term.sh"
fi
Expand Down