add field-list support self-define region fields
This commit is contained in:
parent
c1808255e7
commit
78c2fab10a
|
|
@ -12,6 +12,8 @@ import (
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
@ -74,6 +76,78 @@ func applyLogLevel(logLevel string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var pattern = regexp.MustCompile("^(\\d+(-\\d+)?)$")
|
||||||
|
|
||||||
|
func getFilterFields(fieldList string) ([]int, error) {
|
||||||
|
if len(fieldList) == 0 {
|
||||||
|
return []int{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var fields []int
|
||||||
|
var mapping = make(map[string]string)
|
||||||
|
fList := strings.Split(fieldList, ",")
|
||||||
|
for _, f := range fList {
|
||||||
|
f = strings.TrimSpace(f)
|
||||||
|
if len(f) == 0 {
|
||||||
|
return nil, fmt.Errorf("empty field index value `%s`", f)
|
||||||
|
}
|
||||||
|
|
||||||
|
ms := pattern.FindString(f)
|
||||||
|
if len(ms) == 0 {
|
||||||
|
return nil, fmt.Errorf("field `%s` is not a number or number range", f)
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Index(ms, "-") == -1 {
|
||||||
|
if _, ok := mapping[ms]; ok {
|
||||||
|
return nil, fmt.Errorf("duplicate option `%s`", f)
|
||||||
|
}
|
||||||
|
|
||||||
|
idx, err := strconv.Atoi(ms)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("field index `%s` not an integer", f)
|
||||||
|
}
|
||||||
|
|
||||||
|
mapping[ms] = ms
|
||||||
|
fields = append(fields, idx)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ra := strings.Split(ms, "-")
|
||||||
|
if len(ra) != 2 {
|
||||||
|
return nil, fmt.Errorf("invalid field index range `%s`", ms)
|
||||||
|
}
|
||||||
|
|
||||||
|
start, err := strconv.Atoi(ra[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("range start `%s` not an integer", ra[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
end, err := strconv.Atoi(ra[1])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("range end `%s` not an integer", ra[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
if start > end {
|
||||||
|
return nil, fmt.Errorf("index range start(%d) should <= end(%d)", start, end)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := start; i <= end; i++ {
|
||||||
|
s := strconv.Itoa(i)
|
||||||
|
if _, ok := mapping[s]; ok {
|
||||||
|
return nil, fmt.Errorf("duplicate option `%s`", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
mapping[s] = s
|
||||||
|
fields = append(fields, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort the fields
|
||||||
|
sort.Ints(fields)
|
||||||
|
// fmt.Printf("%+v\n", fields)
|
||||||
|
return fields, nil
|
||||||
|
}
|
||||||
|
|
||||||
func genDb() {
|
func genDb() {
|
||||||
var err error
|
var err error
|
||||||
var srcFile, dstFile = "", ""
|
var srcFile, dstFile = "", ""
|
||||||
|
|
@ -122,11 +196,15 @@ func genDb() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
slog.Info("field-list", "value", fieldList)
|
fields, err := getFilterFields(fieldList)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("failed to get filter fields", "error", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// make the binary file
|
// make the binary file
|
||||||
tStart := time.Now()
|
tStart := time.Now()
|
||||||
maker, err := xdb.NewMaker(indexPolicy, srcFile, dstFile)
|
maker, err := xdb.NewMaker(indexPolicy, srcFile, dstFile, fields)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("failed to create %s\n", err)
|
fmt.Printf("failed to create %s\n", err)
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,9 @@
|
||||||
// -- 4bytes: index block end ptr
|
// -- 4bytes: index block end ptr
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// 2. data block : region or whatever data info.
|
// 2. data block: region or whatever data info.
|
||||||
// 3. segment index block : binary index block.
|
// 3. segment index block: binary index block.
|
||||||
// 4. vector index block : fixed index info for block index search speed up.
|
// 4. vector index block: fixed index info for block index search speedup.
|
||||||
// space structure table:
|
// space structure table:
|
||||||
// -- 0 -> | 1rt super block | 2nd super block | 3rd super block | ... | 255th super block
|
// -- 0 -> | 1rt super block | 2nd super block | 3rd super block | ... | 255th super block
|
||||||
// -- 1 -> | 1rt super block | 2nd super block | 3rd super block | ... | 255th super block
|
// -- 1 -> | 1rt super block | 2nd super block | 3rd super block | ... | 255th super block
|
||||||
|
|
@ -54,6 +54,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -69,13 +70,16 @@ type Maker struct {
|
||||||
srcHandle *os.File
|
srcHandle *os.File
|
||||||
dstHandle *os.File
|
dstHandle *os.File
|
||||||
|
|
||||||
|
// self-define field index
|
||||||
|
fields []int
|
||||||
|
|
||||||
indexPolicy IndexPolicy
|
indexPolicy IndexPolicy
|
||||||
segments []*Segment
|
segments []*Segment
|
||||||
regionPool map[string]uint32
|
regionPool map[string]uint32
|
||||||
vectorIndex []byte
|
vectorIndex []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMaker(policy IndexPolicy, srcFile string, dstFile string) (*Maker, error) {
|
func NewMaker(policy IndexPolicy, srcFile string, dstFile string, fields []int) (*Maker, error) {
|
||||||
// open the source file with READONLY mode
|
// open the source file with READONLY mode
|
||||||
srcHandle, err := os.OpenFile(srcFile, os.O_RDONLY, 0600)
|
srcHandle, err := os.OpenFile(srcFile, os.O_RDONLY, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -92,6 +96,9 @@ func NewMaker(policy IndexPolicy, srcFile string, dstFile string) (*Maker, error
|
||||||
srcHandle: srcHandle,
|
srcHandle: srcHandle,
|
||||||
dstHandle: dstHandle,
|
dstHandle: dstHandle,
|
||||||
|
|
||||||
|
// fields filter index
|
||||||
|
fields: fields,
|
||||||
|
|
||||||
indexPolicy: policy,
|
indexPolicy: policy,
|
||||||
segments: []*Segment{},
|
segments: []*Segment{},
|
||||||
regionPool: map[string]uint32{},
|
regionPool: map[string]uint32{},
|
||||||
|
|
@ -133,6 +140,28 @@ func (m *Maker) initDbHeader() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Maker) getFilteredRegion(region string) (string, error) {
|
||||||
|
if len(m.fields) == 0 {
|
||||||
|
return region, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fs := strings.Split(region, "|")
|
||||||
|
var sb []string
|
||||||
|
for _, idx := range m.fields {
|
||||||
|
if idx < 0 {
|
||||||
|
return "", fmt.Errorf("negative filter index %d", idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
if idx >= len(fs) {
|
||||||
|
return "", fmt.Errorf("field index %d exceeded the max length of %d", idx, len(fs))
|
||||||
|
}
|
||||||
|
|
||||||
|
sb = append(sb, fs[idx])
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(sb, "|"), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Maker) loadSegments() error {
|
func (m *Maker) loadSegments() error {
|
||||||
slog.Info("try to load the segments ... ")
|
slog.Info("try to load the segments ... ")
|
||||||
var last *Segment = nil
|
var last *Segment = nil
|
||||||
|
|
@ -146,6 +175,14 @@ func (m *Maker) loadSegments() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// apply the field filter
|
||||||
|
region, err := m.getFilteredRegion(seg.Region)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// slog.Info("filtered", "region", region)
|
||||||
|
seg.Region = region
|
||||||
m.segments = append(m.segments, seg)
|
m.segments = append(m.segments, seg)
|
||||||
last = seg
|
last = seg
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -241,7 +278,7 @@ func (m *Maker) Start() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Note: data length should be the length of bytes.
|
// @Note: data length should be the length of bytes.
|
||||||
// this works find cuz 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)
|
||||||
if dataLen < 1 {
|
if dataLen < 1 {
|
||||||
// @TODO: could this even be a case ?
|
// @TODO: could this even be a case ?
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ func IterateSegments(handle *os.File, before func(l string), cb func(seg *Segmen
|
||||||
Region: ps[2],
|
Region: ps[2],
|
||||||
}
|
}
|
||||||
|
|
||||||
// check and automatic merging the Consecutive Segments which means:
|
// check and automatic merging the Consecutive Segments, which means:
|
||||||
// 1, region info is the same
|
// 1, region info is the same
|
||||||
// 2, last.eip+1 = cur.sip
|
// 2, last.eip+1 = cur.sip
|
||||||
if last == nil {
|
if last == nil {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue