classstruct.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. package importer
  2. import (
  3. "os"
  4. "path/filepath"
  5. "regexp"
  6. "strings"
  7. "sync"
  8. "time"
  9. "git.wecise.com/wecise/cgimport/schema"
  10. "github.com/wecisecode/util/cmap"
  11. "github.com/wecisecode/util/merrs"
  12. "github.com/wecisecode/util/mio"
  13. "github.com/wecisecode/util/spliter"
  14. )
  15. type classdatainfo struct {
  16. *schema.ClassInfo
  17. insertcount int64
  18. lastlogtime time.Time
  19. lastlogicount int64
  20. mutex sync.Mutex
  21. }
  22. var classdatainfos = cmap.NewSingle[string, *classdatainfo]()
  23. var recreatestatement = regexp.MustCompile(`(?is)create\s+(class|edge\s+type)\s+(?:if\s+not\s+exists\s+)?([\/@\.\w]+)`)
  24. var respace = regexp.MustCompile(`\s*`)
  25. // 根据数据修正类定义
  26. func (odbci *ODBCImporter) ReviseClassStruct() (err error) {
  27. if odbci.client == nil {
  28. return
  29. }
  30. mqlfile := filepath.Join(filepath.Dir(os.Args[0]), "cgimport.mql")
  31. bs, e := mio.ReadFile(mqlfile)
  32. if e != nil {
  33. return e
  34. }
  35. schema_mqls := schema.MQLs
  36. if len(bs) > 0 {
  37. logger.Info("read schema mql from file", mqlfile)
  38. schema_mqls = string(bs)
  39. }
  40. mqls := spliter.MQLSplit(schema_mqls)
  41. for _, mql := range mqls {
  42. sstn := recreatestatement.FindStringSubmatch(mql)
  43. if len(sstn) > 2 {
  44. switch strings.ToLower(respace.ReplaceAllString(sstn[1], "")) {
  45. case "class":
  46. e := odbci.createclass(sstn[2], mql)
  47. if e != nil {
  48. return e
  49. }
  50. case "edgetype":
  51. e := odbci.createedgetype(sstn[2], mql)
  52. if e != nil {
  53. return e
  54. }
  55. }
  56. }
  57. }
  58. return
  59. }
  60. func (odbci *ODBCImporter) createclass(classname, mql string) (err error) {
  61. logger.Debug("create class " + classname)
  62. _, e := odbci.client.Query(mql).Do()
  63. if e != nil {
  64. return e
  65. }
  66. cis, e := odbci.client.ClassInfo(classname, false)
  67. if e != nil {
  68. return e
  69. }
  70. if len(cis) != 1 {
  71. return merrs.New("len(cis) != 1")
  72. }
  73. oci := cis[0]
  74. ci := schema.ClassInfoHelper(oci)
  75. // add graph tags
  76. _, e = odbci.client.Query(ci.Addtagmql, ci.Classaliasname, ci.Classaliasname, []string{ci.Classaliasname}).Do()
  77. if e != nil {
  78. return e
  79. }
  80. cdi := &classdatainfo{ClassInfo: ci}
  81. classdatainfos.Set(ci.Classaliasname, cdi)
  82. classdatainfos.Set(ci.Classfullname, cdi)
  83. logger.Info("created class", ci.Classfullname)
  84. return
  85. }
  86. func (odbci *ODBCImporter) createedgetype(edgetypename, mql string) (err error) {
  87. _, e := odbci.client.Query(mql).Do()
  88. if e != nil {
  89. if strings.Contains(e.Error(), "already exist") {
  90. return nil
  91. }
  92. return e
  93. }
  94. logger.Info("created edge type", edgetypename)
  95. return nil
  96. }
  97. func (odbci *ODBCImporter) getClassinfos() (err error) {
  98. schema.ClassInfos.Clear()
  99. schema.ClassAliasNames = schema.ClassAliasNames[:0]
  100. classinfos, e := odbci.client.ClassInfo("/m3cnet", true)
  101. if e != nil {
  102. return e
  103. }
  104. for _, oci := range classinfos {
  105. ci := schema.ClassInfoHelper(oci)
  106. cdi := &classdatainfo{ClassInfo: ci}
  107. classdatainfos.Set(ci.Classaliasname, cdi)
  108. classdatainfos.Set(ci.Classfullname, cdi)
  109. }
  110. return nil
  111. }
  112. func (odbci *ODBCImporter) init(rebuild bool) (err error) {
  113. err = odbci.getClassinfos()
  114. if err != nil {
  115. return
  116. }
  117. // bs, _ := json.MarshalIndent(schema.ClassInfos, "", " ")
  118. // fmt.Println(string(bs))
  119. if rebuild {
  120. // 清除已有类
  121. err = odbci.rebuild()
  122. if err != nil {
  123. return
  124. }
  125. schema.ClassInfos.Clear()
  126. schema.ClassAliasNames = schema.ClassAliasNames[:0]
  127. }
  128. if schema.ClassInfos.Count() == 0 {
  129. // 建类
  130. err = odbci.ReviseClassStruct()
  131. if err != nil {
  132. return
  133. }
  134. }
  135. return nil
  136. }
  137. func (odbci *ODBCImporter) rebuild() error {
  138. if odbci.client != nil {
  139. for i := len(schema.ClassAliasNames) - 1; i >= 0; i-- {
  140. classaliasname := schema.ClassAliasNames[i]
  141. ci := schema.ClassInfos.GetIFPresent(classaliasname)
  142. if ci == nil {
  143. continue
  144. }
  145. e := odbci.dropclass(ci.Classfullname)
  146. if e != nil {
  147. return e
  148. }
  149. }
  150. }
  151. return nil
  152. }
  153. func (odbci *ODBCImporter) dropclass(classnames ...string) error {
  154. for _, classname := range classnames {
  155. for retry := 2; retry >= 0; retry-- {
  156. // 强制多次删除,避免drop失败导致后续错误
  157. _, e := odbci.client.Query(`delete from /matrix/tagdir where tags='` + classname + `'`).Do()
  158. _ = e
  159. _, e = odbci.client.Query(`delete from "` + classname + `" with version`).Do()
  160. _ = e
  161. _, e = odbci.client.Query(`drop class if exists "` + classname + `"`).Do()
  162. if e != nil {
  163. matchstr := regexp.MustCompile(`refer by ([^,]+)`).FindStringSubmatch(e.Error())
  164. if len(matchstr) >= 2 {
  165. e = odbci.dropclass(matchstr[1])
  166. if e != nil {
  167. return e
  168. }
  169. } else {
  170. matchstr := regexp.MustCompile(`has children \[([^\]]+)\]`).FindStringSubmatch(e.Error())
  171. if len(matchstr) >= 2 {
  172. e = odbci.dropclass(strings.Split(matchstr[1], " ")...)
  173. if e != nil {
  174. return e
  175. }
  176. }
  177. }
  178. if retry > 0 {
  179. continue
  180. }
  181. return e
  182. }
  183. }
  184. logger.Info("drop class " + classname)
  185. ci := schema.ClassInfos.GetIFPresent(classname)
  186. if ci == nil {
  187. continue
  188. }
  189. schema.ClassInfos.Remove(ci.Classaliasname)
  190. schema.ClassInfos.Remove(ci.Classfullname)
  191. }
  192. return nil
  193. }