Use the Region struct to manager the region info instead of old string
This commit is contained in:
parent
4dd0a1e006
commit
90e827633a
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue