package importer import ( "os" "path/filepath" "regexp" "strings" "sync" "time" "git.wecise.com/wecise/cgimport/schema" ci "git.wecise.com/wecise/odb-go/schema" "github.com/wecisecode/util/cmap" "github.com/wecisecode/util/merrs" "github.com/wecisecode/util/mio" "github.com/wecisecode/util/spliter" ) type classdatainfo struct { *ci.ClassInfoHelper insertcount int64 lastlogtime time.Time lastlogicount int64 mutex sync.Mutex } var classdatainfos = cmap.NewSingle[string, *classdatainfo]() var recreatestatement = regexp.MustCompile(`(?is)create\s+(class|edge\s+type)\s+(?:if\s+not\s+exists\s+)?([\/@\.\w]+)`) var respace = regexp.MustCompile(`\s*`) // 根据数据修正类定义 func (odbci *ODBCImporter) ReviseClassStruct() (err error) { if odbci.client == nil { return } mqlfile := filepath.Join(filepath.Dir(os.Args[0]), "cgimport.mql") bs, e := mio.ReadFile(mqlfile) if e != nil { return e } schema_mqls := schema.MQLs if len(bs) > 0 { logger.Info("read schema mql from file", mqlfile) schema_mqls = string(bs) } mqls := spliter.MQLSplit(schema_mqls) for _, mql := range mqls { sstn := recreatestatement.FindStringSubmatch(mql) if len(sstn) > 2 { switch strings.ToLower(respace.ReplaceAllString(sstn[1], "")) { case "class": e := odbci.createclass(sstn[2], mql) if e != nil { return e } case "edgetype": e := odbci.createedgetype(sstn[2], mql) if e != nil { return e } } } } return } func (odbci *ODBCImporter) createclass(classname, mql string) (err error) { logger.Debug("create class " + classname) _, e := odbci.client.Query(mql).Do() if e != nil { return e } cis, e := odbci.client.ClassInfo(classname, false) if e != nil { return e } if len(cis) != 1 { return merrs.New("len(cis) != 1") } oci := cis[0] aci := ci.Schema.NewClassinfo(oci) // add graph tags _, e = odbci.client.Query(aci.Addtagmql, aci.Classaliasname, aci.Classaliasname, []string{aci.Classaliasname}).Do() if e != nil { return e } cdi := &classdatainfo{ClassInfoHelper: aci} classdatainfos.Set(aci.Classaliasname, cdi) classdatainfos.Set(aci.Classfullname, cdi) logger.Info("created class", aci.Classfullname) return } func (odbci *ODBCImporter) createedgetype(edgetypename, mql string) (err error) { _, e := odbci.client.Query(mql).Do() if e != nil { if strings.Contains(e.Error(), "already exist") { return nil } return e } logger.Info("created edge type", edgetypename) return nil } func (odbci *ODBCImporter) getClassinfos() (err error) { ci.Schema.Clear() classinfos, e := odbci.client.ClassInfo("/m3cnet", true) if e != nil { return e } for _, oci := range classinfos { aci := ci.Schema.NewClassinfo(oci) cdi := &classdatainfo{ClassInfoHelper: aci} classdatainfos.Set(aci.Classaliasname, cdi) classdatainfos.Set(aci.Classfullname, cdi) } return nil } func (odbci *ODBCImporter) init(rebuild bool) (err error) { err = odbci.getClassinfos() if err != nil { return } // bs, _ := json.MarshalIndent(schema.ClassInfos, "", " ") // fmt.Println(string(bs)) if rebuild { // 清除已有类 err = odbci.rebuild() if err != nil { return } ci.Schema.Clear() } if ci.Schema.ClassCount() == 0 { // 建类 err = odbci.ReviseClassStruct() if err != nil { return } } return nil } func (odbci *ODBCImporter) rebuild() error { if odbci.client != nil { classaliasnames := ci.Schema.ClassAliasNames() for i := len(classaliasnames) - 1; i >= 0; i-- { classaliasname := classaliasnames[i] ci := ci.Schema.GetClassInfo(classaliasname) if ci == nil { continue } e := odbci.dropclass(ci.Classfullname) if e != nil { return e } } } return nil } func (odbci *ODBCImporter) dropclass(classnames ...string) error { for _, classname := range classnames { for retry := 2; retry >= 0; retry-- { // 强制多次删除,避免drop失败导致后续错误 _, e := odbci.client.Query(`delete from /matrix/tagdir where tags='` + classname + `'`).Do() _ = e _, e = odbci.client.Query(`delete from "` + classname + `" with version`).Do() _ = e _, e = odbci.client.Query(`drop class if exists "` + classname + `"`).Do() if e != nil { matchstr := regexp.MustCompile(`refer by ([^,]+)`).FindStringSubmatch(e.Error()) if len(matchstr) >= 2 { e = odbci.dropclass(matchstr[1]) if e != nil { return e } } else { matchstr := regexp.MustCompile(`has children \[([^\]]+)\]`).FindStringSubmatch(e.Error()) if len(matchstr) >= 2 { e = odbci.dropclass(strings.Split(matchstr[1], " ")...) if e != nil { return e } } } if retry > 0 { continue } return e } } logger.Info("drop class " + classname) ci.Schema.RemoveClassInfo(classname) } return nil }