Use the Region struct to manager the region info instead of old string

This commit is contained in:
lionsoul2014 2026-04-29 12:23:51 +08:00
parent 4dd0a1e006
commit 90e827633a
7 changed files with 116 additions and 16 deletions

View File

@ -109,7 +109,7 @@ func Bench(sCmd string) {
// check the region info // check the region info
count++ count++
if r != seg.Region { if r != seg.Region.Str {
errCount++ errCount++
slog.Error(" --[Failed] region not match", "src", r, "dst", seg.Region) slog.Error(" --[Failed] region not match", "src", r, "dst", seg.Region)
if !ignoreError { if !ignoreError {

View File

@ -108,7 +108,7 @@ func (e *Editor) loadSegments() error {
e.segments.PushBack(&Segment{ e.segments.PushBack(&Segment{
StartIP: e.verison.Min, StartIP: e.verison.Min,
EndIP: IPSubOne(seg.StartIP), EndIP: IPSubOne(seg.StartIP),
Region: "", Region: REmpty(),
}) })
} }
} else if err := seg.RightBehind(last); err == nil { } else if err := seg.RightBehind(last); err == nil {
@ -121,7 +121,7 @@ func (e *Editor) loadSegments() error {
e.segments.PushBack(&Segment{ e.segments.PushBack(&Segment{
StartIP: IPAddOne(last.EndIP), StartIP: IPAddOne(last.EndIP),
EndIP: IPSubOne(seg.StartIP), EndIP: IPSubOne(seg.StartIP),
Region: "", Region: REmpty(),
}) })
} }
@ -138,7 +138,7 @@ func (e *Editor) loadSegments() error {
e.segments.PushBack(&Segment{ e.segments.PushBack(&Segment{
StartIP: IPAddOne(back.Value.(*Segment).EndIP), StartIP: IPAddOne(back.Value.(*Segment).EndIP),
EndIP: e.verison.Max, EndIP: e.verison.Max,
Region: "", Region: REmpty(),
}) })
} }
} }
@ -395,7 +395,7 @@ func (e *Editor) SaveToFile(dstFile string) error {
} }
// ignore the padded or empty segment // ignore the padded or empty segment
if s.Region == "" { if s.Region.IsEmpty() {
continue continue
} }

View File

@ -276,13 +276,13 @@ func (m *Maker) Start() error {
slog.Info("try to write the data block ... ") slog.Info("try to write the data block ... ")
for _, seg := range m.segments { for _, seg := range m.segments {
slog.Debug("try to write", "region", seg.Region) slog.Debug("try to write", "region", seg.Region)
ptr, has := m.regionPool[seg.Region] ptr, has := m.regionPool[seg.Region.Str]
if has { if has {
slog.Debug(" --[Cached]", "ptr=", ptr) slog.Debug(" --[Cached]", "ptr=", ptr)
continue continue
} }
var region = []byte(seg.Region) var region = []byte(seg.Region.Str)
if len(region) > 0xFFFF { if len(region) > 0xFFFF {
return fmt.Errorf("too long region info `%s`: should be less than %d bytes", seg.Region, 0xFFFF) return fmt.Errorf("too long region info `%s`: should be less than %d bytes", seg.Region, 0xFFFF)
} }
@ -303,7 +303,7 @@ func (m *Maker) Start() error {
return fmt.Errorf("write region '%s': %w", seg.Region, err) return fmt.Errorf("write region '%s': %w", seg.Region, err)
} }
m.regionPool[seg.Region] = uint32(pos) m.regionPool[seg.Region.Str] = uint32(pos)
slog.Debug(" --[Added] with", "ptr", pos) slog.Debug(" --[Added] with", "ptr", pos)
} }
@ -312,14 +312,14 @@ func (m *Maker) Start() error {
var indexBuff = make([]byte, m.version.SegmentIndexSize) var indexBuff = make([]byte, m.version.SegmentIndexSize)
var counter, startIndexPtr, endIndexPtr = 0, int64(-1), int64(-1) var counter, startIndexPtr, endIndexPtr = 0, int64(-1), int64(-1)
for _, seg := range m.segments { for _, seg := range m.segments {
dataPtr, has := m.regionPool[seg.Region] dataPtr, has := m.regionPool[seg.Region.Str]
if !has { if !has {
return fmt.Errorf("missing ptr cache for region `%s`", seg.Region) return fmt.Errorf("missing ptr cache for region `%s`", seg.Region)
} }
// @Note: data length should be the length of bytes. // @Note: data length should be the length of bytes.
// this works fine because of the string feature (byte sequence) of golang. // this works fine because of the string feature (byte sequence) of golang.
var dataLen = len(seg.Region) var dataLen = len(seg.Region.Str)
if dataLen < 1 { if dataLen < 1 {
// @TODO: could this even be a case ? // @TODO: could this even be a case ?
// return fmt.Errorf("empty region info for segment '%s'", seg) // return fmt.Errorf("empty region info for segment '%s'", seg)

100
maker/golang/xdb/region.go Normal file
View File

@ -0,0 +1,100 @@
package xdb
import (
"fmt"
"strings"
)
// region manager with:
// 1, content cache.
// 2, util functions
type Region struct {
Str string // region string
fields []string // region fields
}
// global cache map
var regionCache = map[string]*Region{}
func RNew(str string) *Region {
return NewRegion(str)
}
func REmpty() *Region {
return NewRegion("")
}
func NewRegion(str string) *Region {
// check the cache and return it directly
// if there is a cache available
region, ok := regionCache[str]
if ok {
return region
}
// cache the new region
region = &Region{
Str: str,
fields: nil,
}
regionCache[str] = region
return region
}
func (r *Region) Fields() []string {
if r.fields == nil {
r.fields = strings.Split(r.Str, "|")
}
return r.fields
}
func (r *Region) JoinBy(sep string) string {
if sep == "|" {
return r.Str
}
return strings.Join(r.Fields(), sep)
}
func (r *Region) Filtering(fields []int) (*Region, error) {
if len(fields) == 0 {
return r, nil
}
fs := r.Fields()
var sb []string
for _, idx := range fields {
if idx < 0 {
return r, fmt.Errorf("negative filter index %d", idx)
}
if idx >= len(fs) {
return r, fmt.Errorf("field index %d exceeded the max length of %d", idx, len(fs))
}
sb = append(sb, fs[idx])
}
new := RNew(strings.Join(sb, "|"))
if new.fields == nil {
new.fields = sb
}
return new, nil
}
// Equal check ptr (share the same region cache) or the Str is the same.
func (r *Region) Equal(dst *Region) bool {
return (r == dst || r.Str == dst.Str)
}
func (r *Region) IsEmpty() bool {
return r.Str == ""
}
func (r *Region) String() string {
return r.Str
}

View File

@ -12,7 +12,7 @@ import (
type Segment struct { type Segment struct {
StartIP []byte StartIP []byte
EndIP []byte EndIP []byte
Region string Region *Region
} }
func SegmentFrom(seg string) (*Segment, error) { func SegmentFrom(seg string) (*Segment, error) {
@ -38,7 +38,7 @@ func SegmentFrom(seg string) (*Segment, error) {
return &Segment{ return &Segment{
StartIP: sip, StartIP: sip,
EndIP: eip, EndIP: eip,
Region: ps[2], Region: RNew(ps[2]),
}, nil }, nil
} }

View File

@ -200,7 +200,7 @@ func IterateSegments(handle *os.File, autoMerge bool, before func(l string), fil
var seg = &Segment{ var seg = &Segment{
StartIP: sip, StartIP: sip,
EndIP: eip, EndIP: eip,
Region: region, Region: RNew(region),
} }
// check and automatic merging the Consecutive Segments, which means: // check and automatic merging the Consecutive Segments, which means:
@ -209,7 +209,7 @@ func IterateSegments(handle *os.File, autoMerge bool, before func(l string), fil
if last == nil { if last == nil {
last = seg last = seg
continue continue
} else if autoMerge && last.Region == seg.Region { } else if autoMerge && last.Region.Equal(seg.Region) {
if err = seg.RightBehind(last); err == nil { if err = seg.RightBehind(last); err == nil {
mergeCount++ mergeCount++
last.EndIP = seg.EndIP last.EndIP = seg.EndIP
@ -266,7 +266,7 @@ func MergeSegments(segList []*Segment) []*Segment {
if last == nil { if last == nil {
last = seg last = seg
continue continue
} else if last.Region == seg.Region { } else if last.Region.Equal(seg.Region) {
if err = seg.RightBehind(last); err == nil { if err = seg.RightBehind(last); err == nil {
last.EndIP = seg.EndIP last.EndIP = seg.EndIP
continue continue

View File

@ -225,7 +225,7 @@ func TestRegionFiltering(t *testing.T) {
t.Fatalf("failed to parse segment '%s': %s", line, err) t.Fatalf("failed to parse segment '%s': %s", line, err)
} }
fReg, err := RegionFiltering(seg.Region, []int{1, 2, 4, 6}) fReg, err := seg.Region.Filtering([]int{1, 2, 4, 6})
if err != nil { if err != nil {
t.Fatalf("failed to filter region '%s': %s", seg.Region, err) t.Fatalf("failed to filter region '%s': %s", seg.Region, err)
} }