From: Tianling Shen Date: Mon, 28 Nov 2022 18:32:01 +0000 (+0800) Subject: v2raya: backports upstream fixes and add 3 new options X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=e057ed8827072760bc0fb06399d1cd211eb19fb9;p=feed%2Fpackages.git v2raya: backports upstream fixes and add 3 new options It may take a long time waiting for a new tag, so backport these important bug fixes for now. While at it, added 3 new options provided by upstream, and deprecated the usage of `$(AUTORELEASE)`. Signed-off-by: Tianling Shen (cherry picked from commit 17362ce57c88da583c039d81b800b3edad5a6053) --- diff --git a/net/v2raya/Makefile b/net/v2raya/Makefile index 7f643501a6..17ab5e01c6 100644 --- a/net/v2raya/Makefile +++ b/net/v2raya/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=v2rayA PKG_VERSION:=1.5.9.1698.1 -PKG_RELEASE:=$(AUTORELEASE) +PKG_RELEASE:=2 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/v2rayA/v2rayA/tar.gz/v$(PKG_VERSION)? diff --git a/net/v2raya/files/v2raya.config b/net/v2raya/files/v2raya.config index fbda47431a..d9ff36581a 100644 --- a/net/v2raya/files/v2raya.config +++ b/net/v2raya/files/v2raya.config @@ -31,6 +31,19 @@ config v2raya 'config' # Additional v2ray config directory, files in it will be combined with config generated by v2rayA option v2ray_confdir '' + # The executable file to run in the transparent proxy life-cycle. + # v2rayA will pass in the --transparent-type (tproxy, redirect) + # and --stage (pre-start, post-start, pre-stop, post-stop) arguments. + option transparent_hook '' + + # The executable file to run in the v2ray-core life-cycle. + # v2rayA will pass in the --stage (pre-start, post-start, pre-stop, post-stop) argument. + option core_hook '' + + # The executable file to run in the v2ray-core life-cycle. + # v2rayA will pass in the --stage (pre-start, post-start, pre-stop, post-stop) argument. + option plugin_manager '' + # Specify the certification path instead of automatically generating a self-signed certificate. # Example: /etc/v2raya/grpc_certificate.crt,/etc/v2raya/grpc_private.key option vless_grpc_inbound_cert_key '' diff --git a/net/v2raya/files/v2raya.init b/net/v2raya/files/v2raya.init index 9c207f7d94..4120e90ffd 100755 --- a/net/v2raya/files/v2raya.init +++ b/net/v2raya/files/v2raya.init @@ -48,6 +48,9 @@ start_service() { append_env_arg "config" "log_max_days" "3" append_env_arg "config" "v2ray_bin" append_env_arg "config" "v2ray_confdir" + append_env_arg "config" "transparent_hook" + append_env_arg "config" "core_hook" + append_env_arg "config" "plugin_manager" append_env_arg "config" "vless_grpc_inbound_cert_key" append_env_bool "config" "log_disable_color" append_env_bool "config" "log_disable_timestamp" diff --git a/net/v2raya/patches/010-fixed-for-Docker-Compose.patch b/net/v2raya/patches/010-fixed-for-Docker-Compose.patch new file mode 100644 index 0000000000..8461660f7b --- /dev/null +++ b/net/v2raya/patches/010-fixed-for-Docker-Compose.patch @@ -0,0 +1,46 @@ +From 78336e55a31db578c139a5bb472aa0fc219c169d Mon Sep 17 00:00:00 2001 +From: Xiaoxu Guo +Date: Thu, 4 Aug 2022 16:24:04 +0800 +Subject: [PATCH] fixed for Docker Compose + +--- + service/core/iptables/tproxy.go | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/core/iptables/tproxy.go ++++ b/core/iptables/tproxy.go +@@ -65,6 +65,7 @@ iptables -w 2 -t mangle -A TP_PRE -p udp + + iptables -w 2 -t mangle -A TP_RULE -j CONNMARK --restore-mark + iptables -w 2 -t mangle -A TP_RULE -m mark --mark 0x40/0xc0 -j RETURN ++iptables -w 2 -t mangle -A TP_RULE -i br+ -j RETURN + iptables -w 2 -t mangle -A TP_RULE -i docker+ -j RETURN + iptables -w 2 -t mangle -A TP_RULE -i veth+ -j RETURN + ` +@@ -123,6 +124,8 @@ ip6tables -w 2 -t mangle -A TP_PRE -p ud + + ip6tables -w 2 -t mangle -A TP_RULE -j CONNMARK --restore-mark + ip6tables -w 2 -t mangle -A TP_RULE -m mark --mark 0x40/0xc0 -j RETURN ++ip6tables -w 2 -t mangle -A TP_RULE -m mark --mark 0x40/0xc0 -j RETURN ++ip6tables -w 2 -t mangle -A TP_RULE -i br+ -j RETURN + ip6tables -w 2 -t mangle -A TP_RULE -i docker+ -j RETURN + ip6tables -w 2 -t mangle -A TP_RULE -i veth+ -j RETURN + ` +@@ -156,7 +159,7 @@ ip6tables -w 2 -t mangle -A TP_MARK -j C + + func (t *tproxy) GetCleanCommands() Setter { + commands := ` +-ip rule del fwmark 0x40/0xc0 table 100 ++ip rule del fwmark 0x40/0xc0 table 100 + ip route del local 0.0.0.0/0 dev lo table 100 + + iptables -w 2 -t mangle -F TP_OUT +@@ -172,7 +175,7 @@ iptables -w 2 -t mangle -X TP_MARK + ` + if IsIPv6Supported() { + commands += ` +-ip -6 rule del fwmark 0x40/0xc0 table 100 ++ip -6 rule del fwmark 0x40/0xc0 table 100 + ip -6 route del local ::/0 dev lo table 100 + + ip6tables -w 2 -t mangle -F TP_OUT diff --git a/net/v2raya/patches/011-cleaned-up.patch b/net/v2raya/patches/011-cleaned-up.patch new file mode 100644 index 0000000000..74dc502ec4 --- /dev/null +++ b/net/v2raya/patches/011-cleaned-up.patch @@ -0,0 +1,37 @@ +From 0db405f50fd652d494f2066fc5e47c41666c96db Mon Sep 17 00:00:00 2001 +From: Xiaoxu Guo +Date: Thu, 4 Aug 2022 16:32:42 +0800 +Subject: [PATCH] cleaned up + +--- + service/core/iptables/tproxy.go | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +--- a/core/iptables/tproxy.go ++++ b/core/iptables/tproxy.go +@@ -124,7 +124,6 @@ ip6tables -w 2 -t mangle -A TP_PRE -p ud + + ip6tables -w 2 -t mangle -A TP_RULE -j CONNMARK --restore-mark + ip6tables -w 2 -t mangle -A TP_RULE -m mark --mark 0x40/0xc0 -j RETURN +-ip6tables -w 2 -t mangle -A TP_RULE -m mark --mark 0x40/0xc0 -j RETURN + ip6tables -w 2 -t mangle -A TP_RULE -i br+ -j RETURN + ip6tables -w 2 -t mangle -A TP_RULE -i docker+ -j RETURN + ip6tables -w 2 -t mangle -A TP_RULE -i veth+ -j RETURN +@@ -159,7 +158,7 @@ ip6tables -w 2 -t mangle -A TP_MARK -j C + + func (t *tproxy) GetCleanCommands() Setter { + commands := ` +-ip rule del fwmark 0x40/0xc0 table 100 ++ip rule del fwmark 0x40/0xc0 table 100 + ip route del local 0.0.0.0/0 dev lo table 100 + + iptables -w 2 -t mangle -F TP_OUT +@@ -175,7 +174,7 @@ iptables -w 2 -t mangle -X TP_MARK + ` + if IsIPv6Supported() { + commands += ` +-ip -6 rule del fwmark 0x40/0xc0 table 100 ++ip -6 rule del fwmark 0x40/0xc0 table 100 + ip -6 route del local ::/0 dev lo table 100 + + ip6tables -w 2 -t mangle -F TP_OUT diff --git a/net/v2raya/patches/012-improved.patch b/net/v2raya/patches/012-improved.patch new file mode 100644 index 0000000000..1c755d0153 --- /dev/null +++ b/net/v2raya/patches/012-improved.patch @@ -0,0 +1,38 @@ +From 4a87a6fc9a17939cc0fc54058b2128b1f688045a Mon Sep 17 00:00:00 2001 +From: Xiaoxu Guo +Date: Thu, 4 Aug 2022 22:56:46 +0800 +Subject: [PATCH] improved + +--- + service/core/iptables/tproxy.go | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/core/iptables/tproxy.go ++++ b/core/iptables/tproxy.go +@@ -16,7 +16,7 @@ var Tproxy tproxy + func (t *tproxy) AddIPWhitelist(cidr string) { + // avoid duplication + t.RemoveIPWhitelist(cidr) +- pos := 5 ++ pos := 6 + if configure.GetSettingNotNil().AntiPollution != configure.AntipollutionClosed { + pos += 3 + } +@@ -65,7 +65,7 @@ iptables -w 2 -t mangle -A TP_PRE -p udp + + iptables -w 2 -t mangle -A TP_RULE -j CONNMARK --restore-mark + iptables -w 2 -t mangle -A TP_RULE -m mark --mark 0x40/0xc0 -j RETURN +-iptables -w 2 -t mangle -A TP_RULE -i br+ -j RETURN ++iptables -w 2 -t mangle -A TP_RULE -i br-+ -j RETURN + iptables -w 2 -t mangle -A TP_RULE -i docker+ -j RETURN + iptables -w 2 -t mangle -A TP_RULE -i veth+ -j RETURN + ` +@@ -124,7 +124,7 @@ ip6tables -w 2 -t mangle -A TP_PRE -p ud + + ip6tables -w 2 -t mangle -A TP_RULE -j CONNMARK --restore-mark + ip6tables -w 2 -t mangle -A TP_RULE -m mark --mark 0x40/0xc0 -j RETURN +-ip6tables -w 2 -t mangle -A TP_RULE -i br+ -j RETURN ++ip6tables -w 2 -t mangle -A TP_RULE -i br-+ -j RETURN + ip6tables -w 2 -t mangle -A TP_RULE -i docker+ -j RETURN + ip6tables -w 2 -t mangle -A TP_RULE -i veth+ -j RETURN + ` diff --git a/net/v2raya/patches/013-fix-we-should-skip-interface-ppp-to-avoid-to-break-net.patch b/net/v2raya/patches/013-fix-we-should-skip-interface-ppp-to-avoid-to-break-net.patch new file mode 100644 index 0000000000..0ff5f6a541 --- /dev/null +++ b/net/v2raya/patches/013-fix-we-should-skip-interface-ppp-to-avoid-to-break-net.patch @@ -0,0 +1,38 @@ +From ca6a05273284daa04856a840e64f3936f700b7c3 Mon Sep 17 00:00:00 2001 +From: mzz2017 +Date: Fri, 16 Sep 2022 15:13:11 +0800 +Subject: [PATCH] fix: we should skip interface ppp+ to avoid to break net + +--- + service/core/iptables/tproxy.go | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/core/iptables/tproxy.go ++++ b/core/iptables/tproxy.go +@@ -16,7 +16,7 @@ var Tproxy tproxy + func (t *tproxy) AddIPWhitelist(cidr string) { + // avoid duplication + t.RemoveIPWhitelist(cidr) +- pos := 6 ++ pos := 8 + if configure.GetSettingNotNil().AntiPollution != configure.AntipollutionClosed { + pos += 3 + } +@@ -68,6 +68,8 @@ iptables -w 2 -t mangle -A TP_RULE -m ma + iptables -w 2 -t mangle -A TP_RULE -i br-+ -j RETURN + iptables -w 2 -t mangle -A TP_RULE -i docker+ -j RETURN + iptables -w 2 -t mangle -A TP_RULE -i veth+ -j RETURN ++iptables -w 2 -t mangle -A TP_RULE -i ppp+ -j RETURN ++iptables -w 2 -t mangle -A TP_RULE -i dn42-+ -j RETURN + ` + if configure.GetSettingNotNil().AntiPollution != configure.AntipollutionClosed { + commands += ` +@@ -127,6 +129,8 @@ ip6tables -w 2 -t mangle -A TP_RULE -m m + ip6tables -w 2 -t mangle -A TP_RULE -i br-+ -j RETURN + ip6tables -w 2 -t mangle -A TP_RULE -i docker+ -j RETURN + ip6tables -w 2 -t mangle -A TP_RULE -i veth+ -j RETURN ++ip6tables -w 2 -t mangle -A TP_RULE -i ppp+ -j RETURN ++ip6tables -w 2 -t mangle -A TP_RULE -i dn42-+ -j RETURN + ` + if configure.GetSettingNotNil().AntiPollution != configure.AntipollutionClosed { + commands += ` diff --git a/net/v2raya/patches/014-fix-seed-cannot-be-read-from-vless-sharing-link-and-add-m.patch b/net/v2raya/patches/014-fix-seed-cannot-be-read-from-vless-sharing-link-and-add-m.patch new file mode 100644 index 0000000000..ba50306244 --- /dev/null +++ b/net/v2raya/patches/014-fix-seed-cannot-be-read-from-vless-sharing-link-and-add-m.patch @@ -0,0 +1,105 @@ +From 5db722b22b39642280572a62b149d4e1efa21ce3 Mon Sep 17 00:00:00 2001 +From: mzz2017 +Date: Mon, 8 Aug 2022 22:30:36 +0800 +Subject: [PATCH] fix: seed cannot be read from vless sharing-link and add + missing sni field. #616 + +--- + service/core/serverObj/v2ray.go | 24 +++++++++++------------- + 1 file changed, 11 insertions(+), 13 deletions(-) + +--- a/core/serverObj/v2ray.go ++++ b/core/serverObj/v2ray.go +@@ -12,7 +12,6 @@ import ( + "time" + + jsoniter "github.com/json-iterator/go" +- "github.com/tidwall/gjson" + "github.com/v2rayA/v2rayA/common" + "github.com/v2rayA/v2rayA/core/coreObj" + "github.com/v2rayA/v2rayA/core/v2ray/service" +@@ -39,6 +38,7 @@ type V2Ray struct { + Net string `json:"net"` + Type string `json:"type"` + Host string `json:"host"` ++ SNI string `json:"sni"` + Path string `json:"path"` + TLS string `json:"tls"` + Flow string `json:"flow,omitempty"` +@@ -69,7 +69,8 @@ func ParseVlessURL(vless string) (data * + ID: u.User.String(), + Net: u.Query().Get("type"), + Type: u.Query().Get("headerType"), +- Host: u.Query().Get("sni"), ++ Host: u.Query().Get("host"), ++ SNI: u.Query().Get("sni"), + Path: u.Query().Get("path"), + TLS: u.Query().Get("security"), + Flow: u.Query().Get("flow"), +@@ -86,16 +87,13 @@ func ParseVlessURL(vless string) (data * + if data.Type == "" { + data.Type = "none" + } +- if data.Host == "" { +- data.Host = u.Query().Get("host") +- } + if data.TLS == "" { + data.TLS = "none" + } + if data.Flow == "" { + data.Flow = "xtls-rprx-direct" + } +- if data.Type == "mkcp" || data.Type == "kcp" { ++ if data.Net == "mkcp" || data.Net == "kcp" { + data.Path = u.Query().Get("seed") + } + return data, nil +@@ -145,6 +143,7 @@ func ParseVmessURL(vmess string) (data * + if aid == "" { + aid = q.Get("aid") + } ++ sni := q.Get("sni") + info = V2Ray{ + ID: subMatch[1], + Add: subMatch[2], +@@ -152,6 +151,7 @@ func ParseVmessURL(vmess string) (data * + Ps: ps, + Host: obfsParam, + Path: path, ++ SNI: sni, + Net: obfs, + Aid: aid, + TLS: map[string]string{"1": "tls"}[q.Get("tls")], +@@ -165,12 +165,6 @@ func ParseVmessURL(vmess string) (data * + if err != nil { + return + } +- if info.Host == "" { +- sni := gjson.Get(raw, "sni") +- if sni.Exists() { +- info.Host = sni.String() +- } +- } + } + // correct the wrong vmess as much as possible + if strings.HasPrefix(info.Host, "/") && info.Path == "" { +@@ -328,7 +322,9 @@ func (v *V2Ray) Configuration(info Prior + core.StreamSettings.TLSSettings.AllowInsecure = true + } + // SNI +- if v.Host != "" { ++ if v.SNI != "" { ++ core.StreamSettings.TLSSettings.ServerName = v.SNI ++ } else if v.Host != "" { + core.StreamSettings.TLSSettings.ServerName = v.Host + } + // Alpn +@@ -345,6 +341,8 @@ func (v *V2Ray) Configuration(info Prior + // SNI + if v.Host != "" { + core.StreamSettings.XTLSSettings.ServerName = v.Host ++ } else if v.Host != "" { ++ core.StreamSettings.TLSSettings.ServerName = v.Host + } + if v.AllowInsecure { + core.StreamSettings.XTLSSettings.AllowInsecure = true diff --git a/net/v2raya/patches/015-fix-a-problem-that-supervisor-cannot-exit-normally.patch b/net/v2raya/patches/015-fix-a-problem-that-supervisor-cannot-exit-normally.patch new file mode 100644 index 0000000000..5447dc0f9e --- /dev/null +++ b/net/v2raya/patches/015-fix-a-problem-that-supervisor-cannot-exit-normally.patch @@ -0,0 +1,100 @@ +From 3f78422f81f3abc2668fc3938b31d213bfe4dfff Mon Sep 17 00:00:00 2001 +From: mzz2017 +Date: Sun, 28 Aug 2022 17:54:36 +0800 +Subject: [PATCH] fix: a problem that supervisor cannot exit normally + +--- + service/core/specialMode/infra/handle.go | 11 ++++++---- + service/core/specialMode/infra/supervisor.go | 22 ++++++++------------ + 2 files changed, 16 insertions(+), 17 deletions(-) + +--- a/core/specialMode/infra/handle.go ++++ b/core/specialMode/infra/handle.go +@@ -127,10 +127,13 @@ func (interfaceHandle *handle) handleRec + return results, msg + } + +-func packetFilter(portCache *portCache, pPacket *gopacket.Packet, whitelistDnsServers *v2router.GeoIPMatcher) (m *dnsmessage.Message, pSAddr, pSPort, pDAddr, pDPort *gopacket.Endpoint) { +- packet := *pPacket +- trans := packet.TransportLayer() ++func packetFilter(portCache *portCache, packet gopacket.Packet, whitelistDnsServers *v2router.GeoIPMatcher) (m *dnsmessage.Message, pSAddr, pSPort, pDAddr, pDPort *gopacket.Endpoint) { ++ //跳过非网络层的包 ++ if packet.NetworkLayer() == nil { ++ return ++ } + //跳过非传输层的包 ++ trans := packet.TransportLayer() + if trans == nil { + return + } +@@ -180,7 +183,7 @@ func packetFilter(portCache *portCache, + } + + func (interfaceHandle *handle) handlePacket(packet gopacket.Packet, ifname string, whitelistDnsServers *v2router.GeoIPMatcher, whitelistDomains *strmatcher.MatcherGroup) { +- m, sAddr, sPort, dAddr, dPort := packetFilter(interfaceHandle.portCache, &packet, whitelistDnsServers) ++ m, sAddr, sPort, dAddr, dPort := packetFilter(interfaceHandle.portCache, packet, whitelistDnsServers) + if m == nil { + return + } +--- a/core/specialMode/infra/supervisor.go ++++ b/core/specialMode/infra/supervisor.go +@@ -9,7 +9,6 @@ import ( + v2router "github.com/v2rayA/v2ray-lib/router" + "github.com/v2rayA/v2rayA/pkg/util/log" + "sync" +- "time" + ) + + type DnsSupervisor struct { +@@ -70,7 +69,7 @@ func (d *DnsSupervisor) DeleteHandles(if + } + close(d.handles[ifname].done) + delete(d.handles, ifname) +- log.Trace("DnsSupervisor:%v closed", ifname) ++ log.Trace("DnsSupervisor:%v deleted", ifname) + return + } + +@@ -81,28 +80,24 @@ func (d *DnsSupervisor) Run(ifname strin + d.inner.Lock() + handle, ok := d.handles[ifname] + if !ok { ++ d.inner.Unlock() + return fmt.Errorf("Run: %v not exsits", ifname) + } + if handle.running { ++ d.inner.Unlock() + return fmt.Errorf("Run: %v is running", ifname) + } + handle.running = true + log.Trace("[DnsSupervisor] " + ifname + ": running") +- pkgsrc := gopacket.NewPacketSource(handle, layers.LayerTypeEthernet) ++ // we only decode UDP packets ++ pkgsrc := gopacket.NewPacketSource(handle, layers.LayerTypeDNS) + pkgsrc.NoCopy = true ++ //pkgsrc.Lazy = true + d.inner.Unlock() + packets := pkgsrc.Packets() + go func() { +- for { +- //心跳包,防止内存泄漏 +- packets <- gopacket.NewPacket(nil, layers.LinkTypeEthernet, gopacket.DecodeOptions{}) +- select { +- case <-handle.done: +- return +- default: +- time.Sleep(2 * time.Second) +- } +- } ++ <-handle.done ++ packets <- gopacket.NewPacket(nil, layers.LinkTypeEthernet, pkgsrc.DecodeOptions) + }() + out: + for packet := range packets { +@@ -113,5 +108,6 @@ out: + } + go handle.handlePacket(packet, ifname, whitelistDnsServers, whitelistDomains) + } ++ log.Trace("DnsSupervisor:%v closed", ifname) + return + } diff --git a/net/v2raya/patches/016-fix-unexpected-exit-does-not-apply-stop-steps.patch b/net/v2raya/patches/016-fix-unexpected-exit-does-not-apply-stop-steps.patch new file mode 100644 index 0000000000..a945dbdebe --- /dev/null +++ b/net/v2raya/patches/016-fix-unexpected-exit-does-not-apply-stop-steps.patch @@ -0,0 +1,52 @@ +From 153b72ed623876ad73b731c2ec2344e9057d3c35 Mon Sep 17 00:00:00 2001 +From: mzz2017 +Date: Wed, 21 Sep 2022 16:50:24 +0800 +Subject: [PATCH] fix: unexpected exit does not apply stop steps + +--- + service/core/v2ray/process.go | 4 ++-- + service/core/v2ray/processManager.go | 8 +++----- + 2 files changed, 5 insertions(+), 7 deletions(-) + +--- a/core/v2ray/process.go ++++ b/core/v2ray/process.go +@@ -35,7 +35,7 @@ type Process struct { + tag2WhichIndex map[string]int + } + +-func NewProcess(tmpl *Template, prestart func() error, poststart func() error) (process *Process, err error) { ++func NewProcess(tmpl *Template, prestart func() error, poststart func() error, stopfunc func(p *Process)) (process *Process, err error) { + process = &Process{ + template: tmpl, + } +@@ -111,7 +111,7 @@ func NewProcess(tmpl *Template, prestart + // canceled by v2rayA + return + } +- defer ProcessManager.Stop(false) ++ defer stopfunc(process) + var t []string + if p != nil { + if p.Success() { +--- a/core/v2ray/processManager.go ++++ b/core/v2ray/processManager.go +@@ -245,16 +245,14 @@ func (m *CoreProcessManager) Start(t *Te + return m.beforeStart(t) + }, func() error { + return m.afterStart(t) ++ }, func(p *Process) { ++ m.p = p ++ ProcessManager.Stop(false) + }) + if err != nil { + return err + } + m.p = process +- defer func() { +- if err != nil { +- m.stop(true) +- } +- }() + + configure.SetRunning(true) + return nil diff --git a/net/v2raya/patches/017-optimize-reduce-disk-writes.patch b/net/v2raya/patches/017-optimize-reduce-disk-writes.patch new file mode 100644 index 0000000000..5437570c93 --- /dev/null +++ b/net/v2raya/patches/017-optimize-reduce-disk-writes.patch @@ -0,0 +1,336 @@ +From 00366b224b2e28861b80f677e8aa604c5d08dae3 Mon Sep 17 00:00:00 2001 +From: Kelo +Date: Sat, 29 Oct 2022 16:27:26 +0800 +Subject: [PATCH] optimize: reduce disk writes + +--- + service/db/boltdb.go | 43 +++++++++++++++++++++++++++++++---- + service/db/listOp.go | 48 +++++++++++++++++++++------------------ + service/db/plainOp.go | 52 ++++++++++++++++++++++++------------------- + service/db/setOp.go | 20 +++++++++-------- + 4 files changed, 105 insertions(+), 58 deletions(-) + +--- a/db/boltdb.go ++++ b/db/boltdb.go +@@ -1,13 +1,14 @@ + package db + + import ( +- "go.etcd.io/bbolt" +- "github.com/v2rayA/v2rayA/conf" +- "github.com/v2rayA/v2rayA/pkg/util/copyfile" +- "github.com/v2rayA/v2rayA/pkg/util/log" + "os" + "path/filepath" + "sync" ++ ++ "github.com/v2rayA/v2rayA/conf" ++ "github.com/v2rayA/v2rayA/pkg/util/copyfile" ++ "github.com/v2rayA/v2rayA/pkg/util/log" ++ "go.etcd.io/bbolt" + ) + + var once sync.Once +@@ -46,3 +47,37 @@ func DB() *bbolt.DB { + once.Do(initDB) + return db + } ++ ++// The function should return a dirty flag. ++// If the dirty flag is true and there is no error then the transaction is commited. ++// Otherwise, the transaction is rolled back. ++func Transaction(db *bbolt.DB, fn func(*bbolt.Tx) (bool, error)) error { ++ tx, err := db.Begin(true) ++ if err != nil { ++ return err ++ } ++ defer tx.Rollback() ++ dirty, err := fn(tx) ++ if err != nil { ++ _ = tx.Rollback() ++ return err ++ } ++ if !dirty { ++ return nil ++ } ++ return tx.Commit() ++} ++ ++// If the bucket does not exist, the dirty flag is setted ++func CreateBucketIfNotExists(tx *bbolt.Tx, name []byte, dirty *bool) (*bbolt.Bucket, error) { ++ bkt := tx.Bucket(name) ++ if bkt != nil { ++ return bkt, nil ++ } ++ bkt, err := tx.CreateBucket(name) ++ if err != nil { ++ return nil, err ++ } ++ *dirty = true ++ return bkt, nil ++} +--- a/db/listOp.go ++++ b/db/listOp.go +@@ -2,13 +2,14 @@ package db + + import ( + "fmt" +- "go.etcd.io/bbolt" +- jsoniter "github.com/json-iterator/go" +- "github.com/tidwall/gjson" +- "github.com/tidwall/sjson" + "reflect" + "sort" + "strconv" ++ ++ jsoniter "github.com/json-iterator/go" ++ "github.com/tidwall/gjson" ++ "github.com/tidwall/sjson" ++ "go.etcd.io/bbolt" + ) + + func ListSet(bucket string, key string, index int, val interface{}) (err error) { +@@ -31,20 +32,21 @@ func ListSet(bucket string, key string, + } + + func ListGet(bucket string, key string, index int) (b []byte, err error) { +- err = DB().Update(func(tx *bbolt.Tx) error { +- if bkt, err := tx.CreateBucketIfNotExists([]byte(bucket)); err != nil { +- return err ++ err = Transaction(DB(), func(tx *bbolt.Tx) (bool, error) { ++ dirty := false ++ if bkt, err := CreateBucketIfNotExists(tx, []byte(bucket), &dirty); err != nil { ++ return dirty, err + } else { + v := bkt.Get([]byte(key)) + if v == nil { +- return fmt.Errorf("ListGet: can't get element from an empty list") ++ return dirty, fmt.Errorf("ListGet: can't get element from an empty list") + } + r := gjson.GetBytes(v, strconv.Itoa(index)) + if r.Exists() { + b = []byte(r.Raw) +- return nil ++ return dirty, nil + } else { +- return fmt.Errorf("ListGet: no such element") ++ return dirty, fmt.Errorf("ListGet: no such element") + } + } + }) +@@ -79,24 +81,25 @@ func ListAppend(bucket string, key strin + } + + func ListGetAll(bucket string, key string) (list [][]byte, err error) { +- err = DB().Update(func(tx *bbolt.Tx) error { +- if bkt, err := tx.CreateBucketIfNotExists([]byte(bucket)); err != nil { +- return err ++ err = Transaction(DB(), func(tx *bbolt.Tx) (bool, error) { ++ dirty := false ++ if bkt, err := CreateBucketIfNotExists(tx, []byte(bucket), &dirty); err != nil { ++ return dirty, err + } else { + b := bkt.Get([]byte(key)) + if b == nil { +- return nil ++ return dirty, nil + } + parsed := gjson.ParseBytes(b) + if !parsed.IsArray() { +- return fmt.Errorf("ListGetAll: is not array") ++ return dirty, fmt.Errorf("ListGetAll: is not array") + } + results := parsed.Array() + for _, r := range results { + list = append(list, []byte(r.Raw)) + } + } +- return nil ++ return dirty, nil + }) + return list, err + } +@@ -143,21 +146,22 @@ func ListRemove(bucket, key string, inde + } + + func ListLen(bucket string, key string) (length int, err error) { +- err = DB().Update(func(tx *bbolt.Tx) error { +- if bkt, err := tx.CreateBucketIfNotExists([]byte(bucket)); err != nil { +- return err ++ err = Transaction(DB(), func(tx *bbolt.Tx) (bool, error) { ++ dirty := false ++ if bkt, err := CreateBucketIfNotExists(tx, []byte(bucket), &dirty); err != nil { ++ return dirty, err + } else { + b := bkt.Get([]byte(key)) + if b == nil { +- return nil ++ return dirty, nil + } + parsed := gjson.ParseBytes(b) + if !parsed.IsArray() { +- return fmt.Errorf("ListLen: is not array") ++ return dirty, fmt.Errorf("ListLen: is not array") + } + length = len(parsed.Array()) + } +- return nil ++ return dirty, nil + }) + return length, err + } +--- a/db/plainOp.go ++++ b/db/plainOp.go +@@ -2,50 +2,54 @@ package db + + import ( + "fmt" +- "go.etcd.io/bbolt" ++ + jsoniter "github.com/json-iterator/go" + "github.com/v2rayA/v2rayA/common" + "github.com/v2rayA/v2rayA/pkg/util/log" ++ "go.etcd.io/bbolt" + ) + + func Get(bucket string, key string, val interface{}) (err error) { +- return DB().Update(func(tx *bbolt.Tx) error { +- if bkt, err := tx.CreateBucketIfNotExists([]byte(bucket)); err != nil { +- return err ++ return Transaction(DB(), func(tx *bbolt.Tx) (bool, error) { ++ dirty := false ++ if bkt, err := CreateBucketIfNotExists(tx, []byte(bucket), &dirty); err != nil { ++ return dirty, err + } else { + if v := bkt.Get([]byte(key)); v == nil { +- return fmt.Errorf("Get: key is not found") ++ return dirty, fmt.Errorf("Get: key is not found") + } else { +- return jsoniter.Unmarshal(v, val) ++ return dirty, jsoniter.Unmarshal(v, val) + } + } + }) + } + + func GetRaw(bucket string, key string) (b []byte, err error) { +- err = DB().Update(func(tx *bbolt.Tx) error { +- if bkt, err := tx.CreateBucketIfNotExists([]byte(bucket)); err != nil { +- return err ++ err = Transaction(DB(), func(tx *bbolt.Tx) (bool, error) { ++ dirty := false ++ if bkt, err := CreateBucketIfNotExists(tx, []byte(bucket), &dirty); err != nil { ++ return dirty, err + } else { + v := bkt.Get([]byte(key)) + if v == nil { +- return fmt.Errorf("GetRaw: key is not found") ++ return dirty, fmt.Errorf("GetRaw: key is not found") + } + b = common.BytesCopy(v) +- return nil ++ return dirty, nil + } + }) + return b, err + } + + func Exists(bucket string, key string) (exists bool) { +- if err := DB().Update(func(tx *bbolt.Tx) error { +- if bkt, err := tx.CreateBucketIfNotExists([]byte(bucket)); err != nil { +- return err ++ if err := Transaction(DB(), func(tx *bbolt.Tx) (bool, error) { ++ dirty := false ++ if bkt, err := CreateBucketIfNotExists(tx, []byte(bucket), &dirty); err != nil { ++ return dirty, err + } else { + v := bkt.Get([]byte(key)) + exists = v != nil +- return nil ++ return dirty, nil + } + }); err != nil { + log.Warn("%v", err) +@@ -55,23 +59,25 @@ func Exists(bucket string, key string) ( + } + + func GetBucketLen(bucket string) (length int, err error) { +- err = DB().Update(func(tx *bbolt.Tx) error { +- if bkt, err := tx.CreateBucketIfNotExists([]byte(bucket)); err != nil { +- return err ++ err = Transaction(DB(), func(tx *bbolt.Tx) (bool, error) { ++ dirty := false ++ if bkt, err := CreateBucketIfNotExists(tx, []byte(bucket), &dirty); err != nil { ++ return dirty, err + } else { + length = bkt.Stats().KeyN + } +- return nil ++ return dirty, nil + }) + return length, err + } + + func GetBucketKeys(bucket string) (keys []string, err error) { +- err = DB().Update(func(tx *bbolt.Tx) error { +- if bkt, err := tx.CreateBucketIfNotExists([]byte(bucket)); err != nil { +- return err ++ err = Transaction(DB(), func(tx *bbolt.Tx) (bool, error) { ++ dirty := false ++ if bkt, err := CreateBucketIfNotExists(tx, []byte(bucket), &dirty); err != nil { ++ return dirty, err + } else { +- return bkt.ForEach(func(k, v []byte) error { ++ return dirty, bkt.ForEach(func(k, v []byte) error { + keys = append(keys, string(k)) + return nil + }) +--- a/db/setOp.go ++++ b/db/setOp.go +@@ -4,8 +4,9 @@ import ( + "bytes" + "crypto/sha256" + "encoding/gob" +- "go.etcd.io/bbolt" ++ + "github.com/v2rayA/v2rayA/common" ++ "go.etcd.io/bbolt" + ) + + type set map[[32]byte]interface{} +@@ -28,26 +29,27 @@ func toSha256(val interface{}) (hash [32 + } + + func setOp(bucket string, key string, f func(m set) (readonly bool, err error)) (err error) { +- return DB().Update(func(tx *bbolt.Tx) error { +- if bkt, err := tx.CreateBucketIfNotExists([]byte(bucket)); err != nil { +- return err ++ return Transaction(DB(), func(tx *bbolt.Tx) (bool, error) { ++ dirty := false ++ if bkt, err := CreateBucketIfNotExists(tx, []byte(bucket), &dirty); err != nil { ++ return dirty, err + } else { + var m set + v := bkt.Get([]byte(key)) + if v == nil { + m = make(set) + } else if err := gob.NewDecoder(bytes.NewReader(v)).Decode(&m); err != nil { +- return err ++ return dirty, err + } + if readonly, err := f(m); err != nil { +- return err ++ return dirty, err + } else if readonly { +- return nil ++ return dirty, nil + } + if b, err := common.ToBytes(m); err != nil { +- return err ++ return dirty, err + } else { +- return bkt.Put([]byte(key), b) ++ return true, bkt.Put([]byte(key), b) + } + } + }) diff --git a/net/v2raya/patches/018-fix-do-not-rollback-closed-transaction.patch b/net/v2raya/patches/018-fix-do-not-rollback-closed-transaction.patch new file mode 100644 index 0000000000..b9815f4592 --- /dev/null +++ b/net/v2raya/patches/018-fix-do-not-rollback-closed-transaction.patch @@ -0,0 +1,27 @@ +From 451912074ba1ba4000c66874876bc0a6b64cb5da Mon Sep 17 00:00:00 2001 +From: Kelo +Date: Sun, 30 Oct 2022 16:49:22 +0800 +Subject: [PATCH] fix: do not rollback closed transaction + +--- + service/db/boltdb.go | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/db/boltdb.go ++++ b/db/boltdb.go +@@ -56,14 +56,13 @@ func Transaction(db *bbolt.DB, fn func(* + if err != nil { + return err + } +- defer tx.Rollback() + dirty, err := fn(tx) + if err != nil { + _ = tx.Rollback() + return err + } + if !dirty { +- return nil ++ return tx.Rollback() + } + return tx.Commit() + }