diff --git a/maker/golang/cmd/bench.go b/maker/golang/cmd/bench.go index 9bf763f..8500a9f 100644 --- a/maker/golang/cmd/bench.go +++ b/maker/golang/cmd/bench.go @@ -109,7 +109,7 @@ func Bench(sCmd string) { // check the region info count++ - if r != seg.Region { + if r != seg.Region.Str { errCount++ slog.Error(" --[Failed] region not match", "src", r, "dst", seg.Region) if !ignoreError { diff --git a/maker/golang/xdb/editor.go b/maker/golang/xdb/editor.go index c179048..7b15ee3 100644 --- a/maker/golang/xdb/editor.go +++ b/maker/golang/xdb/editor.go @@ -108,7 +108,7 @@ func (e *Editor) loadSegments() error { e.segments.PushBack(&Segment{ StartIP: e.verison.Min, EndIP: IPSubOne(seg.StartIP), - Region: "", + Region: REmpty(), }) } } else if err := seg.RightBehind(last); err == nil { @@ -121,7 +121,7 @@ func (e *Editor) loadSegments() error { e.segments.PushBack(&Segment{ StartIP: IPAddOne(last.EndIP), EndIP: IPSubOne(seg.StartIP), - Region: "", + Region: REmpty(), }) } @@ -138,7 +138,7 @@ func (e *Editor) loadSegments() error { e.segments.PushBack(&Segment{ StartIP: IPAddOne(back.Value.(*Segment).EndIP), EndIP: e.verison.Max, - Region: "", + Region: REmpty(), }) } } @@ -395,7 +395,7 @@ func (e *Editor) SaveToFile(dstFile string) error { } // ignore the padded or empty segment - if s.Region == "" { + if s.Region.IsEmpty() { continue } diff --git a/maker/golang/xdb/maker.go b/maker/golang/xdb/maker.go index bd4f56c..3aee6a3 100644 --- a/maker/golang/xdb/maker.go +++ b/maker/golang/xdb/maker.go @@ -276,13 +276,13 @@ func (m *Maker) Start() error { slog.Info("try to write the data block ... ") for _, seg := range m.segments { slog.Debug("try to write", "region", seg.Region) - ptr, has := m.regionPool[seg.Region] + ptr, has := m.regionPool[seg.Region.Str] if has { slog.Debug(" --[Cached]", "ptr=", ptr) continue } - var region = []byte(seg.Region) + var region = []byte(seg.Region.Str) if len(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) } - m.regionPool[seg.Region] = uint32(pos) + m.regionPool[seg.Region.Str] = uint32(pos) slog.Debug(" --[Added] with", "ptr", pos) } @@ -312,14 +312,14 @@ func (m *Maker) Start() error { var indexBuff = make([]byte, m.version.SegmentIndexSize) var counter, startIndexPtr, endIndexPtr = 0, int64(-1), int64(-1) for _, seg := range m.segments { - dataPtr, has := m.regionPool[seg.Region] + dataPtr, has := m.regionPool[seg.Region.Str] if !has { return fmt.Errorf("missing ptr cache for region `%s`", seg.Region) } // @Note: data length should be the length of bytes. // 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 { // @TODO: could this even be a case ? // return fmt.Errorf("empty region info for segment '%s'", seg) diff --git a/maker/golang/xdb/region.go b/maker/golang/xdb/region.go new file mode 100644 index 0000000..874a26f --- /dev/null +++ b/maker/golang/xdb/region.go @@ -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 +} diff --git a/maker/golang/xdb/segment.go b/maker/golang/xdb/segment.go index 6a5a995..e123035 100644 --- a/maker/golang/xdb/segment.go +++ b/maker/golang/xdb/segment.go @@ -12,7 +12,7 @@ import ( type Segment struct { StartIP []byte EndIP []byte - Region string + Region *Region } func SegmentFrom(seg string) (*Segment, error) { @@ -38,7 +38,7 @@ func SegmentFrom(seg string) (*Segment, error) { return &Segment{ StartIP: sip, EndIP: eip, - Region: ps[2], + Region: RNew(ps[2]), }, nil } diff --git a/maker/golang/xdb/util.go b/maker/golang/xdb/util.go index c28359a..9c3eaf4 100644 --- a/maker/golang/xdb/util.go +++ b/maker/golang/xdb/util.go @@ -200,7 +200,7 @@ func IterateSegments(handle *os.File, autoMerge bool, before func(l string), fil var seg = &Segment{ StartIP: sip, EndIP: eip, - Region: region, + Region: RNew(region), } // 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 { last = seg continue - } else if autoMerge && last.Region == seg.Region { + } else if autoMerge && last.Region.Equal(seg.Region) { if err = seg.RightBehind(last); err == nil { mergeCount++ last.EndIP = seg.EndIP @@ -266,7 +266,7 @@ func MergeSegments(segList []*Segment) []*Segment { if last == nil { last = seg continue - } else if last.Region == seg.Region { + } else if last.Region.Equal(seg.Region) { if err = seg.RightBehind(last); err == nil { last.EndIP = seg.EndIP continue diff --git a/maker/golang/xdb/util_test.go b/maker/golang/xdb/util_test.go index f428974..e7a151a 100644 --- a/maker/golang/xdb/util_test.go +++ b/maker/golang/xdb/util_test.go @@ -225,7 +225,7 @@ func TestRegionFiltering(t *testing.T) { 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 { t.Fatalf("failed to filter region '%s': %s", seg.Region, err) }