1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-11-16 01:17:30 -05:00

Refinement: geodata decoder removes unnecessary GC & exports methods for 3rd party (#965)

This commit is contained in:
Loyalsoldier 2021-05-04 01:39:47 +08:00 committed by GitHub
parent 238b87d26a
commit de71e63893
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 20 additions and 29 deletions

View File

@ -2,7 +2,6 @@ package geodata
import ( import (
"io/ioutil" "io/ioutil"
"runtime"
"strings" "strings"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
@ -33,7 +32,7 @@ func (g GeoIPCache) Set(key string, value *router.GeoIP) {
func (g GeoIPCache) Unmarshal(filename, code string) (*router.GeoIP, error) { func (g GeoIPCache) Unmarshal(filename, code string) (*router.GeoIP, error) {
asset := platform.GetAssetLocation(filename) asset := platform.GetAssetLocation(filename)
idx := strings.ToUpper(asset + "|" + code) idx := strings.ToUpper(asset + "_" + code)
if g.Has(idx) { if g.Has(idx) {
return g.Get(idx), nil return g.Get(idx), nil
} }
@ -48,11 +47,11 @@ func (g GeoIPCache) Unmarshal(filename, code string) (*router.GeoIP, error) {
g.Set(idx, &geoip) g.Set(idx, &geoip)
return &geoip, nil return &geoip, nil
case errCodeNotFound: case ErrCodeNotFound:
return nil, newError(code, " not found in ", filename) return nil, newError(code, " not found in ", filename)
case errFailedToReadBytes, errFailedToReadExpectedLenBytes, case ErrFailedToReadBytes, ErrFailedToReadExpectedLenBytes,
errInvalidGeodataFile, errInvalidGeodataVarintLength: ErrInvalidGeodataFile, ErrInvalidGeodataVarintLength:
newError("failed to decode geodata file: ", filename, ". Fallback to the original ReadFile method.").AtWarning().WriteToLog() newError("failed to decode geodata file: ", filename, ". Fallback to the original ReadFile method.").AtWarning().WriteToLog()
geoipBytes, err = ioutil.ReadFile(asset) geoipBytes, err = ioutil.ReadFile(asset)
if err != nil { if err != nil {
@ -62,13 +61,11 @@ func (g GeoIPCache) Unmarshal(filename, code string) (*router.GeoIP, error) {
if err := proto.Unmarshal(geoipBytes, &geoipList); err != nil { if err := proto.Unmarshal(geoipBytes, &geoipList); err != nil {
return nil, err return nil, err
} }
runtime.GC()
for _, geoip := range geoipList.GetEntry() { for _, geoip := range geoipList.GetEntry() {
if strings.EqualFold(code, geoip.GetCountryCode()) { if strings.EqualFold(code, geoip.GetCountryCode()) {
g.Set(idx, geoip) g.Set(idx, geoip)
return geoip, nil return geoip, nil
} }
runtime.GC()
} }
default: default:
@ -100,7 +97,7 @@ func (g GeoSiteCache) Set(key string, value *router.GeoSite) {
func (g GeoSiteCache) Unmarshal(filename, code string) (*router.GeoSite, error) { func (g GeoSiteCache) Unmarshal(filename, code string) (*router.GeoSite, error) {
asset := platform.GetAssetLocation(filename) asset := platform.GetAssetLocation(filename)
idx := strings.ToUpper(asset + "|" + code) idx := strings.ToUpper(asset + "_" + code)
if g.Has(idx) { if g.Has(idx) {
return g.Get(idx), nil return g.Get(idx), nil
} }
@ -115,11 +112,11 @@ func (g GeoSiteCache) Unmarshal(filename, code string) (*router.GeoSite, error)
g.Set(idx, &geosite) g.Set(idx, &geosite)
return &geosite, nil return &geosite, nil
case errCodeNotFound: case ErrCodeNotFound:
return nil, newError(code, " not found in ", filename) return nil, newError(code, " not found in ", filename)
case errFailedToReadBytes, errFailedToReadExpectedLenBytes, case ErrFailedToReadBytes, ErrFailedToReadExpectedLenBytes,
errInvalidGeodataFile, errInvalidGeodataVarintLength: ErrInvalidGeodataFile, ErrInvalidGeodataVarintLength:
newError("failed to decode geodata file: ", filename, ". Fallback to the original ReadFile method.").AtWarning().WriteToLog() newError("failed to decode geodata file: ", filename, ". Fallback to the original ReadFile method.").AtWarning().WriteToLog()
geositeBytes, err = ioutil.ReadFile(asset) geositeBytes, err = ioutil.ReadFile(asset)
if err != nil { if err != nil {
@ -129,13 +126,11 @@ func (g GeoSiteCache) Unmarshal(filename, code string) (*router.GeoSite, error)
if err := proto.Unmarshal(geositeBytes, &geositeList); err != nil { if err := proto.Unmarshal(geositeBytes, &geositeList); err != nil {
return nil, err return nil, err
} }
runtime.GC()
for _, geosite := range geositeList.GetEntry() { for _, geosite := range geositeList.GetEntry() {
if strings.EqualFold(code, geosite.GetCountryCode()) { if strings.EqualFold(code, geosite.GetCountryCode()) {
g.Set(idx, geosite) g.Set(idx, geosite)
return geosite, nil return geosite, nil
} }
runtime.GC()
} }
default: default:

View File

@ -11,7 +11,6 @@ package geodata
import ( import (
"io" "io"
"runtime"
"strings" "strings"
"google.golang.org/protobuf/encoding/protowire" "google.golang.org/protobuf/encoding/protowire"
@ -23,14 +22,14 @@ import (
//go:generate go run github.com/v2fly/v2ray-core/v4/common/errors/errorgen //go:generate go run github.com/v2fly/v2ray-core/v4/common/errors/errorgen
var ( var (
errFailedToReadBytes = errors.New("failed to read bytes") ErrFailedToReadBytes = errors.New("failed to read bytes")
errFailedToReadExpectedLenBytes = errors.New("failed to read expected length of bytes") ErrFailedToReadExpectedLenBytes = errors.New("failed to read expected length of bytes")
errInvalidGeodataFile = errors.New("invalid geodata file") ErrInvalidGeodataFile = errors.New("invalid geodata file")
errInvalidGeodataVarintLength = errors.New("invalid geodata varint length") ErrInvalidGeodataVarintLength = errors.New("invalid geodata varint length")
errCodeNotFound = errors.New("code not found") ErrCodeNotFound = errors.New("code not found")
) )
func emitBytes(f io.ReadSeeker, code string) ([]byte, error) { func EmitBytes(f io.ReadSeeker, code string) ([]byte, error) {
count := 1 count := 1
isInner := false isInner := false
tempContainer := make([]byte, 0, 5) tempContainer := make([]byte, 0, 5)
@ -44,19 +43,19 @@ Loop:
container := make([]byte, advancedN) container := make([]byte, advancedN)
bytesRead, err := f.Read(container) bytesRead, err := f.Read(container)
if err == io.EOF { if err == io.EOF {
return nil, errCodeNotFound return nil, ErrCodeNotFound
} }
if err != nil { if err != nil {
return nil, errFailedToReadBytes return nil, ErrFailedToReadBytes
} }
if bytesRead != len(container) { if bytesRead != len(container) {
return nil, errFailedToReadExpectedLenBytes return nil, ErrFailedToReadExpectedLenBytes
} }
switch count { switch count {
case 1, 3: // data type ((field_number << 3) | wire_type) case 1, 3: // data type ((field_number << 3) | wire_type)
if container[0] != 10 { // byte `0A` equals to `10` in decimal if container[0] != 10 { // byte `0A` equals to `10` in decimal
return nil, errInvalidGeodataFile return nil, ErrInvalidGeodataFile
} }
advancedN = 1 advancedN = 1
count++ count++
@ -68,7 +67,7 @@ Loop:
} }
lenVarint, n := protowire.ConsumeVarint(tempContainer) lenVarint, n := protowire.ConsumeVarint(tempContainer)
if n < 0 { if n < 0 {
return nil, errInvalidGeodataVarintLength return nil, ErrInvalidGeodataVarintLength
} }
tempContainer = nil tempContainer = nil
if !isInner { if !isInner {
@ -98,11 +97,8 @@ Loop:
result = container result = container
break Loop break Loop
} }
runtime.GC() // run GC every round to save memory
} }
runtime.GC() // run GC at the end to save memory
return result, nil return result, nil
} }
@ -113,7 +109,7 @@ func Decode(filename, code string) ([]byte, error) {
} }
defer f.Close() defer f.Close()
geoBytes, err := emitBytes(f, code) geoBytes, err := EmitBytes(f, code)
if err != nil { if err != nil {
return nil, err return nil, err
} }