Serialize rule writes and add tests

This commit is contained in:
2026-04-17 10:21:37 +08:00
parent 66c25b06a7
commit eb8c76492c
7 changed files with 682 additions and 35 deletions

View File

@@ -172,7 +172,7 @@ cmd_list() {
fi
}
cmd_add_batch() {
_cmd_add_batch_locked() {
local proto=${1-}
local lport=${2-}
local tip=${3-}
@@ -191,14 +191,14 @@ cmd_add_batch() {
return 1
fi
if ! storage_add "${line}"; then
if ! storage_add_unlocked "${line}"; then
ipt_remove_rule "${uuid}" "${proto}" "${lport}" "${tip}" "${tport}" "${ipver}" >/dev/null 2>&1 || true
log_err '写入规则数据库失败。'
return 1
fi
if ! persist_save; then
storage_delete "${uuid}" >/dev/null 2>&1 || true
storage_delete_unlocked "${uuid}" >/dev/null 2>&1 || true
ipt_remove_rule "${uuid}" "${proto}" "${lport}" "${tip}" "${tport}" "${ipver}" >/dev/null 2>&1 || true
log_err '保存持久化规则失败,已回滚。'
return 1
@@ -208,6 +208,10 @@ cmd_add_batch() {
printf '%s\n' "${uuid}"
}
cmd_add_batch() {
storage_with_lock _cmd_add_batch_locked "$@"
}
cmd_add() {
local proto_choice ipver_choice proto ipver lport tip tport desc
@@ -264,7 +268,7 @@ cmd_add() {
cmd_add_batch "${proto}" "${lport}" "${tip}" "${tport}" "${ipver}" "${desc}" >/dev/null
}
cmd_delete_uuid() {
_cmd_delete_uuid_locked() {
local uuid=${1-}
local line proto lport tip tport ipver
line=$(storage_get "${uuid}") || {
@@ -283,13 +287,14 @@ cmd_delete_uuid() {
return 1
fi
if ! storage_delete "${uuid}"; then
log_err '删除规则数据库记录失败。'
if ! storage_delete_unlocked "${uuid}"; then
ipt_apply_rule "${uuid}" "${proto}" "${lport}" "${tip}" "${tport}" "${ipver}" >/dev/null 2>&1 || true
log_err '删除规则数据库记录失败,已尝试回滚。'
return 1
fi
if ! persist_save; then
storage_add "${line}" >/dev/null 2>&1 || true
storage_add_unlocked "${line}" >/dev/null 2>&1 || true
ipt_apply_rule "${uuid}" "${proto}" "${lport}" "${tip}" "${tport}" "${ipver}" >/dev/null 2>&1 || true
log_err '持久化保存失败,已尝试回滚。'
return 1
@@ -298,6 +303,10 @@ cmd_delete_uuid() {
log_ok "规则 ${uuid} 已删除。"
}
cmd_delete_uuid() {
storage_with_lock _cmd_delete_uuid_locked "$@"
}
cmd_delete() {
local index answer line uuid
rules_load_lines
@@ -348,7 +357,7 @@ cmd_show_env_status() {
pause_return
}
cmd_save_rules() {
_cmd_save_rules_locked() {
if persist_save; then
log_ok '规则已保存到磁盘。'
else
@@ -356,3 +365,7 @@ cmd_save_rules() {
return 1
fi
}
cmd_save_rules() {
storage_with_lock _cmd_save_rules_locked
}

View File

@@ -34,20 +34,30 @@ storage_init() {
chmod 600 "${lock}"
}
storage_add() {
local line=${1-}
local db lock
[[ -n ${line} ]] || return 1
storage_with_lock() {
local lock
storage_init
db=$(storage_db_path)
lock=$(storage_lock_path)
(
flock -x 9
printf '%s\n' "${line}" >>"${db}"
"$@"
) 9>>"${lock}"
}
storage_add_unlocked() {
local line=${1-}
local db
[[ -n ${line} ]] || return 1
storage_init
db=$(storage_db_path)
printf '%s\n' "${line}" >>"${db}"
}
storage_add() {
storage_with_lock storage_add_unlocked "$@"
}
storage_list() {
local db
db=$(storage_db_path)
@@ -83,34 +93,34 @@ storage_get() {
return 1
}
storage_delete() {
storage_delete_unlocked() {
local uuid=${1-}
local db lock tmp found=0 line current
local db tmp found=0 line current
[[ -n ${uuid} ]] || return 1
storage_init
db=$(storage_db_path)
lock=$(storage_lock_path)
tmp="${db}.tmp.$$"
(
flock -x 9
: >"${tmp}"
while IFS= read -r line || [[ -n ${line} ]]; do
current=$(storage_parse "${line}" uuid || true)
if [[ ${current} == "${uuid}" ]]; then
found=1
continue
fi
printf '%s\n' "${line}" >>"${tmp}"
done <"${db}"
if (( found == 0 )); then
rm -f "${tmp}"
exit 1
: >"${tmp}"
while IFS= read -r line || [[ -n ${line} ]]; do
current=$(storage_parse "${line}" uuid || true)
if [[ ${current} == "${uuid}" ]]; then
found=1
continue
fi
printf '%s\n' "${line}" >>"${tmp}"
done <"${db}"
mv "${tmp}" "${db}"
) 9>>"${lock}"
if (( found == 0 )); then
rm -f "${tmp}"
return 1
fi
mv "${tmp}" "${db}"
}
storage_delete() {
storage_with_lock storage_delete_unlocked "$@"
}
storage_count() {