|
@@ -3,6 +3,8 @@ package importer
|
|
|
import (
|
|
|
"encoding/json"
|
|
|
"fmt"
|
|
|
+ "regexp"
|
|
|
+ "strings"
|
|
|
"sync"
|
|
|
"sync/atomic"
|
|
|
"time"
|
|
@@ -151,7 +153,7 @@ func (odbci *ODBCImporter) masterlevel1data(classaliasname string, suid string,
|
|
|
level1data = entiredata
|
|
|
}
|
|
|
// 重新插入完整的 level1
|
|
|
- retrycount, e := odbci.insertData("level1", "", "", level1data)
|
|
|
+ retrycount, _, e := odbci.insertData("level1", "", "", level1data)
|
|
|
if e != nil {
|
|
|
return retrycount, e
|
|
|
}
|
|
@@ -175,7 +177,7 @@ func (odbci *ODBCImporter) masterlevel1data(classaliasname string, suid string,
|
|
|
data = entiredata
|
|
|
}
|
|
|
// 插入 level1 数据
|
|
|
- retrycount, e := odbci.insertData("level1", "", "", data)
|
|
|
+ retrycount, _, e := odbci.insertData("level1", "", "", data)
|
|
|
if e != nil {
|
|
|
return retrycount, e
|
|
|
}
|
|
@@ -320,7 +322,7 @@ func (odbci *ODBCImporter) InsertData(classaliasname string, data map[string]any
|
|
|
} else {
|
|
|
data["depend"] = referencedata(classaliasname, data)
|
|
|
}
|
|
|
- rc, e := odbci.insertData(classaliasname, oid, suid, data)
|
|
|
+ rc, _, e := odbci.insertData(classaliasname, oid, suid, data)
|
|
|
retrycount += rc
|
|
|
if e != nil {
|
|
|
return retrycount, e
|
|
@@ -382,13 +384,13 @@ func referencedata(classaliasname string, data map[string]any) (depend map[strin
|
|
|
return
|
|
|
}
|
|
|
|
|
|
-func (odbci *ODBCImporter) insertData(classaliasname string, oid, suid string, data map[string]any) (retrycount int, err error) {
|
|
|
+func (odbci *ODBCImporter) insertData(classaliasname string, oid, suid string, data map[string]any) (retrycount int, responsetime time.Duration, err error) {
|
|
|
cdi := classdatainfos.GetIFPresent(classaliasname)
|
|
|
if cdi == nil {
|
|
|
- return retrycount, merrs.NewError("class not defined " + classaliasname)
|
|
|
+ return retrycount, 0, merrs.NewError("class not defined " + classaliasname)
|
|
|
}
|
|
|
if cdi.Insertmql == "" {
|
|
|
- return retrycount, merrs.NewError("class no fields to insert " + classaliasname)
|
|
|
+ return retrycount, 0, merrs.NewError("class no fields to insert " + classaliasname)
|
|
|
}
|
|
|
values := []any{}
|
|
|
for _, fn := range cdi.Fieldslist {
|
|
@@ -400,7 +402,7 @@ func (odbci *ODBCImporter) insertData(classaliasname string, oid, suid string, d
|
|
|
// 合并扩展字段
|
|
|
if strset.New(fi.Datakey...).Has("*") {
|
|
|
if fi.Fieldtype != "map<varchar,varchar>" {
|
|
|
- return retrycount, merrs.NewError("fi.Fieldtype=" + fi.Fieldtype + " != map<varchar,varchar>")
|
|
|
+ return retrycount, 0, merrs.NewError("fi.Fieldtype=" + fi.Fieldtype + " != map<varchar,varchar>")
|
|
|
}
|
|
|
td := map[string]any{}
|
|
|
for k, v := range data {
|
|
@@ -422,7 +424,7 @@ func (odbci *ODBCImporter) insertData(classaliasname string, oid, suid string, d
|
|
|
case "timestamp":
|
|
|
tv, e := cast.ToDateTimeE(v, "2006-01-02-15.04.05.000000")
|
|
|
if e != nil {
|
|
|
- return retrycount, merrs.NewError(fmt.Sprint("can't parse datetime value '", v, "'"))
|
|
|
+ return retrycount, 0, merrs.NewError(fmt.Sprint("can't parse datetime value '", v, "'"))
|
|
|
}
|
|
|
v = tv.Format("2006-01-02 15:04:05.000000")
|
|
|
}
|
|
@@ -439,14 +441,14 @@ func (odbci *ODBCImporter) insertData(classaliasname string, oid, suid string, d
|
|
|
mql := "select id,uniqueid from " + classaliasname + " where id=?"
|
|
|
r, e := odbci.client.Query(mql, oid).Do()
|
|
|
if e != nil {
|
|
|
- return retrycount, e
|
|
|
+ return retrycount, 0, e
|
|
|
}
|
|
|
if r != nil && len(r.Data) != 0 {
|
|
|
logger.Debug(classaliasname, "exists id:", oid, ", uniqueid:", r.Data[0]["uniqueid"], ", new uniqueid:", suid)
|
|
|
}
|
|
|
}
|
|
|
// logger.Info(values...)
|
|
|
- retrycount, err = odbci.insertDo(cdi.Insertmql, values...)
|
|
|
+ retrycount, responsetime, err = odbci.insertDo(cdi.Insertmql, values...)
|
|
|
if err != nil {
|
|
|
databs, _ := json.MarshalIndent(data, "", " ")
|
|
|
err = merrs.NewError(err, merrs.SSMaps{{"mql": cdi.Insertmql}, {"values": fmt.Sprint(values)}, {"data": string(databs)}})
|
|
@@ -465,28 +467,78 @@ func (odbci *ODBCImporter) insertData(classaliasname string, oid, suid string, d
|
|
|
return
|
|
|
}
|
|
|
|
|
|
-var insertretrylimitcount = 0
|
|
|
+type ODBCRetryConfig struct {
|
|
|
+ retry int
|
|
|
+ contains string
|
|
|
+}
|
|
|
+
|
|
|
+var reodbcretry = regexp.MustCompile(`(?s)^\s*(-?[0-9]+)\s*(?:,\s*(.*)\s*)?$`)
|
|
|
+var odbcretry = ""
|
|
|
+var odbcretryconfig []*ODBCRetryConfig
|
|
|
|
|
|
func init() {
|
|
|
mcfg.OnChange(func() {
|
|
|
- insertretrylimitcount = mcfg.GetInt("odbc.insert.retry", 3)
|
|
|
+ _odbcretry := mcfg.GetStrings("odbc.retry", "-1, timed out")
|
|
|
+ if strings.Join(_odbcretry, "|") != odbcretry {
|
|
|
+ odbcretryconfig = RetryConfig(_odbcretry...)
|
|
|
+ odbcretry = strings.Join(_odbcretry, "|")
|
|
|
+ }
|
|
|
})
|
|
|
}
|
|
|
|
|
|
-func (odbci *ODBCImporter) insertDo(insertmql string, values ...any) (trycount int, err error) {
|
|
|
+func RetryConfig(retryconfig ...string) (orcs []*ODBCRetryConfig) {
|
|
|
+ defaultorc := &ODBCRetryConfig{
|
|
|
+ retry: 0,
|
|
|
+ contains: "",
|
|
|
+ }
|
|
|
+ for _, retrycfg := range retryconfig {
|
|
|
+ ss := reodbcretry.FindStringSubmatch(retrycfg)
|
|
|
+ if len(ss) > 1 {
|
|
|
+ orc := &ODBCRetryConfig{
|
|
|
+ retry: cast.ToInt(ss[0]),
|
|
|
+ contains: ss[1],
|
|
|
+ }
|
|
|
+ if orc.contains == "" {
|
|
|
+ defaultorc = orc
|
|
|
+ } else {
|
|
|
+ orcs = append(orcs, orc)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ panic("odbc.retry config format error")
|
|
|
+ }
|
|
|
+ }
|
|
|
+ orcs = append(orcs, defaultorc)
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+func (odbci *ODBCImporter) insertDo(insertmql string, values ...any) (trycount int, responsetime time.Duration, err error) {
|
|
|
for {
|
|
|
+ st := time.Now()
|
|
|
_, e := odbci.client.Query(insertmql, values...).Do()
|
|
|
if e != nil {
|
|
|
+ maxtrycount := 0
|
|
|
+ for _, orc := range odbcretryconfig {
|
|
|
+ if orc.contains != "" {
|
|
|
+ if strings.Contains(e.Error(), orc.contains) {
|
|
|
+ maxtrycount = orc.retry
|
|
|
+ break
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ maxtrycount = orc.retry
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
trycount++
|
|
|
e = merrs.New(e, merrs.Map{"trycount": trycount})
|
|
|
- if trycount <= insertretrylimitcount {
|
|
|
- logger.Debug(e)
|
|
|
+ if maxtrycount < 0 || trycount <= maxtrycount {
|
|
|
+ logger.Debug(merrs.New(e, merrs.Map{"retrycount": trycount}))
|
|
|
time.Sleep(time.Duration(trycount) * time.Second)
|
|
|
continue
|
|
|
}
|
|
|
- return trycount, e
|
|
|
+ return trycount, 0, e
|
|
|
}
|
|
|
- return trycount, nil
|
|
|
+ responsetime = time.Since(st)
|
|
|
+ return trycount, responsetime, nil
|
|
|
}
|
|
|
}
|
|
|
|