github.com/matrixorigin/matrixone@v0.7.0/pkg/frontend/util.go (about) 1 // Copyright 2021 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package frontend 16 17 import ( 18 "bytes" 19 "context" 20 "fmt" 21 "os" 22 "runtime" 23 "strconv" 24 "sync/atomic" 25 "time" 26 27 "go.uber.org/zap" 28 29 "path/filepath" 30 "strings" 31 32 "github.com/BurntSushi/toml" 33 "github.com/matrixorigin/matrixone/pkg/common/moerr" 34 "github.com/matrixorigin/matrixone/pkg/common/mpool" 35 "github.com/matrixorigin/matrixone/pkg/container/batch" 36 "github.com/matrixorigin/matrixone/pkg/container/nulls" 37 "github.com/matrixorigin/matrixone/pkg/container/types" 38 "github.com/matrixorigin/matrixone/pkg/container/vector" 39 "github.com/matrixorigin/matrixone/pkg/sql/colexec" 40 plan2 "github.com/matrixorigin/matrixone/pkg/sql/plan" 41 dumpUtils "github.com/matrixorigin/matrixone/pkg/vectorize/dump" 42 43 mo_config "github.com/matrixorigin/matrixone/pkg/config" 44 "github.com/matrixorigin/matrixone/pkg/logutil" 45 "github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect" 46 "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" 47 "github.com/matrixorigin/matrixone/pkg/util/trace" 48 "github.com/matrixorigin/matrixone/pkg/util/trace/impl/motrace" 49 "github.com/matrixorigin/matrixone/pkg/vm/engine" 50 ) 51 52 type CloseFlag struct { 53 //closed flag 54 closed uint32 55 } 56 57 // 1 for closed 58 // 0 for others 59 func (cf *CloseFlag) setClosed(value uint32) { 60 atomic.StoreUint32(&cf.closed, value) 61 } 62 63 func (cf *CloseFlag) Open() { 64 cf.setClosed(0) 65 } 66 67 func (cf *CloseFlag) Close() { 68 cf.setClosed(1) 69 } 70 71 func (cf *CloseFlag) IsClosed() bool { 72 return atomic.LoadUint32(&cf.closed) != 0 73 } 74 75 func (cf *CloseFlag) IsOpened() bool { 76 return atomic.LoadUint32(&cf.closed) == 0 77 } 78 79 func Min(a int, b int) int { 80 if a < b { 81 return a 82 } else { 83 return b 84 } 85 } 86 87 func MinInt64(a int64, b int64) int64 { 88 if a < b { 89 return a 90 } else { 91 return b 92 } 93 } 94 95 func MinUint64(a uint64, b uint64) uint64 { 96 if a < b { 97 return a 98 } else { 99 return b 100 } 101 } 102 103 func Max(a int, b int) int { 104 if a < b { 105 return b 106 } else { 107 return a 108 } 109 } 110 111 func MaxInt64(a int64, b int64) int64 { 112 if a < b { 113 return b 114 } else { 115 return a 116 } 117 } 118 119 func MaxUint64(a uint64, b uint64) uint64 { 120 if a < b { 121 return b 122 } else { 123 return a 124 } 125 } 126 127 type Uint64List []uint64 128 129 func (ul Uint64List) Len() int { 130 return len(ul) 131 } 132 133 func (ul Uint64List) Less(i, j int) bool { 134 return ul[i] < ul[j] 135 } 136 137 func (ul Uint64List) Swap(i, j int) { 138 ul[i], ul[j] = ul[j], ul[i] 139 } 140 141 // GetRoutineId gets the routine id 142 func GetRoutineId() uint64 { 143 data := make([]byte, 64) 144 data = data[:runtime.Stack(data, false)] 145 data = bytes.TrimPrefix(data, []byte("goroutine ")) 146 data = data[:bytes.IndexByte(data, ' ')] 147 id, _ := strconv.ParseUint(string(data), 10, 64) 148 return id 149 } 150 151 type DebugCounter struct { 152 length int 153 counter []uint64 154 Cf CloseFlag 155 } 156 157 func NewDebugCounter(l int) *DebugCounter { 158 return &DebugCounter{ 159 length: l, 160 counter: make([]uint64, l), 161 } 162 } 163 164 func (dc *DebugCounter) Add(i int, v uint64) { 165 atomic.AddUint64(&dc.counter[i], v) 166 } 167 168 func (dc *DebugCounter) Set(i int, v uint64) { 169 atomic.StoreUint64(&dc.counter[i], v) 170 } 171 172 func (dc *DebugCounter) Get(i int) uint64 { 173 return atomic.LoadUint64(&dc.counter[i]) 174 } 175 176 func (dc *DebugCounter) Len() int { 177 return dc.length 178 } 179 180 func (dc *DebugCounter) DCRoutine() { 181 dc.Cf.Open() 182 183 for dc.Cf.IsOpened() { 184 for i := 0; i < dc.length; i++ { 185 if i != 0 && i%8 == 0 { 186 logutil.Infof("") 187 } 188 v := dc.Get(i) 189 logutil.Infof("[%4d %4d]", i, v) 190 dc.Set(i, 0) 191 } 192 logutil.Infof("") 193 time.Sleep(5 * time.Second) 194 } 195 } 196 197 const ( 198 TIMEOUT_TYPE_SECOND int = iota 199 TIMEOUT_TYPE_MILLISECOND 200 ) 201 202 type Timeout struct { 203 //last record of the time 204 lastTime atomic.Value //time.Time 205 206 //period 207 timeGap time.Duration 208 209 //auto update 210 autoUpdate bool 211 } 212 213 func NewTimeout(tg time.Duration, autoUpdateWhenChecked bool) *Timeout { 214 ret := &Timeout{ 215 timeGap: tg, 216 autoUpdate: autoUpdateWhenChecked, 217 } 218 ret.lastTime.Store(time.Now()) 219 return ret 220 } 221 222 func (t *Timeout) UpdateTime(tn time.Time) { 223 t.lastTime.Store(tn) 224 } 225 226 /* 227 ----------+---------+------------------+-------- 228 229 lastTime Now lastTime + timeGap 230 231 return true : is timeout. the lastTime has been updated. 232 return false : is not timeout. the lastTime has not been updated. 233 */ 234 func (t *Timeout) isTimeout() bool { 235 if time.Since(t.lastTime.Load().(time.Time)) <= t.timeGap { 236 return false 237 } 238 239 if t.autoUpdate { 240 t.lastTime.Store(time.Now()) 241 } 242 return true 243 } 244 245 /* 246 length: 247 -1, complete string. 248 0, empty string 249 >0 , length of characters at the header of the string. 250 */ 251 func SubStringFromBegin(str string, length int) string { 252 if length == 0 || length < -1 { 253 return "" 254 } 255 256 if length == -1 { 257 return str 258 } 259 260 l := Min(len(str), length) 261 if l != len(str) { 262 return str[:l] + "..." 263 } 264 return str[:l] 265 } 266 267 /* 268 path exists in the system 269 return: 270 true/false - exists or not. 271 true/false - file or directory 272 error 273 */ 274 var PathExists = func(path string) (bool, bool, error) { 275 fi, err := os.Stat(path) 276 if err == nil { 277 return true, !fi.IsDir(), nil 278 } 279 if os.IsNotExist(err) { 280 return false, false, err 281 } 282 283 return false, false, err 284 } 285 286 /* 287 MakeDebugInfo prints bytes in multi-lines. 288 */ 289 func MakeDebugInfo(data []byte, bytesCount int, bytesPerLine int) string { 290 if len(data) == 0 || bytesCount == 0 || bytesPerLine == 0 { 291 return "" 292 } 293 pl := Min(bytesCount, len(data)) 294 ps := "" 295 for i := 0; i < pl; i++ { 296 if i > 0 && (i%bytesPerLine == 0) { 297 ps += "\n" 298 } 299 if i%bytesPerLine == 0 { 300 ps += fmt.Sprintf("%d", i/bytesPerLine) + " : " 301 } 302 ps += fmt.Sprintf("%02x ", data[i]) 303 } 304 return ps 305 } 306 307 func getSystemVariables(configFile string) (*mo_config.FrontendParameters, error) { 308 sv := &mo_config.FrontendParameters{} 309 var err error 310 _, err = toml.DecodeFile(configFile, sv) 311 if err != nil { 312 return nil, err 313 } 314 return sv, err 315 } 316 317 func getParameterUnit(configFile string, eng engine.Engine, txnClient TxnClient) (*mo_config.ParameterUnit, error) { 318 sv, err := getSystemVariables(configFile) 319 if err != nil { 320 return nil, err 321 } 322 logutil.Info("Using Dump Storage Engine and Cluster Nodes.") 323 pu := mo_config.NewParameterUnit(sv, eng, txnClient, engine.Nodes{}, nil) 324 325 return pu, nil 326 } 327 328 // WildcardMatch implements wildcard pattern match algorithm. 329 // pattern and target are ascii characters 330 // TODO: add \_ and \% 331 func WildcardMatch(pattern, target string) bool { 332 var p = 0 333 var t = 0 334 var positionOfPercentPlusOne int = -1 335 var positionOfTargetEncounterPercent int = -1 336 plen := len(pattern) 337 tlen := len(target) 338 for t < tlen { 339 //% 340 if p < plen && pattern[p] == '%' { 341 p++ 342 positionOfPercentPlusOne = p 343 if p >= plen { 344 //pattern end with % 345 return true 346 } 347 //means % matches empty 348 positionOfTargetEncounterPercent = t 349 } else if p < plen && (pattern[p] == '_' || pattern[p] == target[t]) { //match or _ 350 p++ 351 t++ 352 } else { 353 if positionOfPercentPlusOne == -1 { 354 //have not matched a % 355 return false 356 } 357 if positionOfTargetEncounterPercent == -1 { 358 return false 359 } 360 //backtrace to last % position + 1 361 p = positionOfPercentPlusOne 362 //means % matches multiple characters 363 positionOfTargetEncounterPercent++ 364 t = positionOfTargetEncounterPercent 365 } 366 } 367 //skip % 368 for p < plen && pattern[p] == '%' { 369 p++ 370 } 371 return p >= plen 372 } 373 374 // only support single value and unary minus 375 func GetSimpleExprValue(e tree.Expr, ses *Session) (interface{}, error) { 376 switch v := e.(type) { 377 case *tree.UnresolvedName: 378 // set @a = on, type of a is bool. 379 return v.Parts[0], nil 380 default: 381 binder := plan2.NewDefaultBinder(ses.GetRequestContext(), nil, nil, nil, nil) 382 planExpr, err := binder.BindExpr(e, 0, false) 383 if err != nil { 384 return nil, err 385 } 386 // set @a = 'on', type of a is bool. And mo cast rule does not fit set variable rule so delay to convert type. 387 bat := batch.NewWithSize(0) 388 bat.Zs = []int64{1} 389 vec, err := colexec.EvalExpr(bat, ses.txnCompileCtx.GetProcess(), planExpr) 390 if err != nil { 391 return nil, err 392 } 393 return getValueFromVector(vec, ses) 394 } 395 } 396 397 func getValueFromVector(vec *vector.Vector, ses *Session) (interface{}, error) { 398 if nulls.Any(vec.Nsp) { 399 return nil, nil 400 } 401 switch vec.Typ.Oid { 402 case types.T_bool: 403 return vector.GetValueAt[bool](vec, 0), nil 404 case types.T_int8: 405 return vector.GetValueAt[int8](vec, 0), nil 406 case types.T_int16: 407 return vector.GetValueAt[int16](vec, 0), nil 408 case types.T_int32: 409 return vector.GetValueAt[int32](vec, 0), nil 410 case types.T_int64: 411 return vector.GetValueAt[int64](vec, 0), nil 412 case types.T_uint8: 413 return vector.GetValueAt[uint8](vec, 0), nil 414 case types.T_uint16: 415 return vector.GetValueAt[uint16](vec, 0), nil 416 case types.T_uint32: 417 return vector.GetValueAt[uint32](vec, 0), nil 418 case types.T_uint64: 419 return vector.GetValueAt[uint64](vec, 0), nil 420 case types.T_float32: 421 return vector.GetValueAt[float32](vec, 0), nil 422 case types.T_float64: 423 return vector.GetValueAt[float64](vec, 0), nil 424 case types.T_char, types.T_varchar, types.T_text, types.T_blob: 425 return vec.GetString(0), nil 426 case types.T_decimal64: 427 val := vector.GetValueAt[types.Decimal64](vec, 0) 428 return val.String(), nil 429 case types.T_decimal128: 430 val := vector.GetValueAt[types.Decimal128](vec, 0) 431 return val.String(), nil 432 case types.T_json: 433 val := vec.GetBytes(0) 434 byteJson := types.DecodeJson(val) 435 return byteJson.String(), nil 436 case types.T_uuid: 437 val := vector.GetValueAt[types.Uuid](vec, 0) 438 return val.ToString(), nil 439 case types.T_date: 440 val := vector.GetValueAt[types.Date](vec, 0) 441 return val.String(), nil 442 case types.T_time: 443 val := vector.GetValueAt[types.Time](vec, 0) 444 return val.String(), nil 445 case types.T_datetime: 446 val := vector.GetValueAt[types.Datetime](vec, 0) 447 return val.String(), nil 448 case types.T_timestamp: 449 val := vector.GetValueAt[types.Timestamp](vec, 0) 450 return val.String2(ses.GetTimeZone(), vec.Typ.Precision), nil 451 default: 452 return nil, moerr.NewInvalidArg(ses.GetRequestContext(), "variable type", vec.Typ.Oid.String()) 453 } 454 } 455 456 type statementStatus int 457 458 const ( 459 success statementStatus = iota 460 fail 461 ) 462 463 func (s statementStatus) String() string { 464 switch s { 465 case success: 466 return "success" 467 case fail: 468 return "fail" 469 } 470 return "running" 471 } 472 473 // logStatementStatus prints the status of the statement into the log. 474 func logStatementStatus(ctx context.Context, ses *Session, stmt tree.Statement, status statementStatus, err error) { 475 var stmtStr string 476 stm := motrace.StatementFromContext(ctx) 477 if stm == nil { 478 fmtCtx := tree.NewFmtCtx(dialect.MYSQL) 479 stmt.Format(fmtCtx) 480 stmtStr = fmtCtx.String() 481 } else { 482 stmtStr = stm.Statement 483 } 484 logStatementStringStatus(ctx, ses, stmtStr, status, err) 485 } 486 487 func logStatementStringStatus(ctx context.Context, ses *Session, stmtStr string, status statementStatus, err error) { 488 str := SubStringFromBegin(stmtStr, int(ses.GetParameterUnit().SV.LengthOfQueryPrinted)) 489 if status == success { 490 motrace.EndStatement(ctx, nil) 491 logInfo(ses.GetConciseProfile(), "query trace status", logutil.ConnectionIdField(ses.GetConnectionID()), logutil.StatementField(str), logutil.StatusField(status.String()), trace.ContextField(ctx)) 492 } else { 493 motrace.EndStatement(ctx, err) 494 logError(ses.GetConciseProfile(), "query trace status", logutil.ConnectionIdField(ses.GetConnectionID()), logutil.StatementField(str), logutil.StatusField(status.String()), logutil.ErrorField(err), trace.ContextField(ctx)) 495 } 496 } 497 498 func logInfo(info string, msg string, fields ...zap.Field) { 499 fields = append(fields, zap.String("session_info", info)) 500 logutil.Info(msg, fields...) 501 } 502 503 //func logDebug(info string, msg string, fields ...zap.Field) { 504 // fields = append(fields, zap.String("session_info", info)) 505 // logutil.Debug(msg, fields...) 506 //} 507 508 func logError(info string, msg string, fields ...zap.Field) { 509 fields = append(fields, zap.String("session_info", info)) 510 logutil.Error(msg, fields...) 511 } 512 513 func logInfof(info string, msg string, fields ...interface{}) { 514 fields = append(fields, info) 515 logutil.Infof(msg+" %s", fields...) 516 } 517 518 func logDebugf(info string, msg string, fields ...interface{}) { 519 fields = append(fields, info) 520 logutil.Debugf(msg+" %s", fields...) 521 } 522 523 func logErrorf(info string, msg string, fields ...interface{}) { 524 fields = append(fields, info) 525 logutil.Errorf(msg+" %s", fields...) 526 } 527 528 func fileExists(path string) (bool, error) { 529 _, err := os.Stat(path) 530 if err == nil { 531 return true, nil 532 } 533 if os.IsNotExist(err) { 534 return false, nil 535 } 536 return false, err 537 } 538 539 func getAttrFromTableDef(defs []engine.TableDef) ([]string, bool, error) { 540 attrs := make([]string, 0, len(defs)) 541 isView := false 542 for _, tblDef := range defs { 543 switch def := tblDef.(type) { 544 case *engine.AttributeDef: 545 if def.Attr.IsHidden || def.Attr.IsRowId { 546 continue 547 } 548 attrs = append(attrs, def.Attr.Name) 549 case *engine.ViewDef: 550 isView = true 551 } 552 } 553 return attrs, isView, nil 554 } 555 556 func getDDL(bh BackgroundExec, ctx context.Context, sql string) (string, error) { 557 bh.ClearExecResultSet() 558 err := bh.Exec(ctx, sql) 559 if err != nil { 560 return "", err 561 } 562 ret := string(bh.GetExecResultSet()[0].(*MysqlResultSet).Data[0][1].([]byte)) 563 if !strings.HasSuffix(ret, ";") { 564 ret += ";" 565 } 566 return ret, nil 567 } 568 569 func convertValueBat2Str(ctx context.Context, bat *batch.Batch, mp *mpool.MPool, loc *time.Location) (*batch.Batch, error) { 570 var err error 571 rbat := batch.NewWithSize(bat.VectorCount()) 572 rbat.InitZsOne(bat.Length()) 573 for i := 0; i < rbat.VectorCount(); i++ { 574 rbat.Vecs[i] = vector.New(types.Type{Oid: types.T_varchar, Width: types.MaxVarcharLen}) //TODO: check size 575 rs := make([]string, bat.Length()) 576 switch bat.Vecs[i].Typ.Oid { 577 case types.T_bool: 578 xs := vector.MustTCols[bool](bat.Vecs[i]) 579 rs, err = dumpUtils.ParseBool(xs, bat.GetVector(int32(i)).GetNulls(), rs) 580 case types.T_int8: 581 xs := vector.MustTCols[int8](bat.Vecs[i]) 582 rs, err = dumpUtils.ParseSigned(xs, bat.GetVector(int32(i)).GetNulls(), rs) 583 case types.T_int16: 584 xs := vector.MustTCols[int16](bat.Vecs[i]) 585 rs, err = dumpUtils.ParseSigned(xs, bat.GetVector(int32(i)).GetNulls(), rs) 586 case types.T_int32: 587 xs := vector.MustTCols[int32](bat.Vecs[i]) 588 rs, err = dumpUtils.ParseSigned(xs, bat.GetVector(int32(i)).GetNulls(), rs) 589 case types.T_int64: 590 xs := vector.MustTCols[int64](bat.Vecs[i]) 591 rs, err = dumpUtils.ParseSigned(xs, bat.GetVector(int32(i)).GetNulls(), rs) 592 593 case types.T_uint8: 594 xs := vector.MustTCols[uint8](bat.Vecs[i]) 595 rs, err = dumpUtils.ParseUnsigned(xs, bat.GetVector(int32(i)).GetNulls(), rs) 596 case types.T_uint16: 597 xs := vector.MustTCols[uint16](bat.Vecs[i]) 598 rs, err = dumpUtils.ParseUnsigned(xs, bat.GetVector(int32(i)).GetNulls(), rs) 599 case types.T_uint32: 600 xs := vector.MustTCols[uint32](bat.Vecs[i]) 601 rs, err = dumpUtils.ParseUnsigned(xs, bat.GetVector(int32(i)).GetNulls(), rs) 602 603 case types.T_uint64: 604 xs := vector.MustTCols[uint64](bat.Vecs[i]) 605 rs, err = dumpUtils.ParseUnsigned(xs, bat.GetVector(int32(i)).GetNulls(), rs) 606 case types.T_float32: 607 xs := vector.MustTCols[float32](bat.Vecs[i]) 608 rs, err = dumpUtils.ParseFloats(xs, bat.GetVector(int32(i)).GetNulls(), rs, 32) 609 case types.T_float64: 610 xs := vector.MustTCols[float64](bat.Vecs[i]) 611 rs, err = dumpUtils.ParseFloats(xs, bat.GetVector(int32(i)).GetNulls(), rs, 64) 612 case types.T_decimal64: 613 xs := vector.MustTCols[types.Decimal64](bat.Vecs[i]) 614 rs, err = dumpUtils.ParseQuoted(xs, bat.GetVector(int32(i)).GetNulls(), rs, dumpUtils.DefaultParser[types.Decimal64]) 615 case types.T_decimal128: 616 xs := vector.MustTCols[types.Decimal128](bat.Vecs[i]) 617 rs, err = dumpUtils.ParseQuoted(xs, bat.GetVector(int32(i)).GetNulls(), rs, dumpUtils.DefaultParser[types.Decimal128]) 618 case types.T_char, types.T_varchar, types.T_blob, types.T_text: 619 xs := vector.MustStrCols(bat.Vecs[i]) 620 rs, err = dumpUtils.ParseQuoted(xs, bat.GetVector(int32(i)).GetNulls(), rs, dumpUtils.DefaultParser[string]) 621 case types.T_json: 622 xs := vector.MustBytesCols(bat.Vecs[i]) 623 rs, err = dumpUtils.ParseQuoted(xs, bat.GetVector(int32(i)).GetNulls(), rs, dumpUtils.JsonParser) 624 625 case types.T_timestamp: 626 xs := vector.MustTCols[types.Timestamp](bat.Vecs[i]) 627 rs, err = dumpUtils.ParseTimeStamp(xs, bat.GetVector(int32(i)).GetNulls(), rs, loc, bat.GetVector(int32(i)).Typ.Precision) 628 case types.T_datetime: 629 xs := vector.MustTCols[types.Datetime](bat.Vecs[i]) 630 rs, err = dumpUtils.ParseQuoted(xs, bat.GetVector(int32(i)).GetNulls(), rs, dumpUtils.DefaultParser[types.Datetime]) 631 case types.T_date: 632 xs := vector.MustTCols[types.Date](bat.Vecs[i]) 633 rs, err = dumpUtils.ParseQuoted(xs, bat.GetVector(int32(i)).GetNulls(), rs, dumpUtils.DefaultParser[types.Date]) 634 case types.T_uuid: 635 xs := vector.MustTCols[types.Uuid](bat.Vecs[i]) 636 rs, err = dumpUtils.ParseUuid(xs, bat.GetVector(int32(i)).GetNulls(), rs) 637 default: 638 err = moerr.NewNotSupported(ctx, "type %v", bat.Vecs[i].Typ.String()) 639 } 640 if err != nil { 641 return nil, err 642 } 643 for j := 0; j < len(rs); j++ { 644 err = rbat.Vecs[i].Append([]byte(rs[j]), false, mp) 645 if err != nil { 646 return nil, err 647 } 648 } 649 } 650 rbat.InitZsOne(bat.Length()) 651 return rbat, nil 652 } 653 654 func genDumpFileName(outfile string, idx int64) string { 655 path := filepath.Dir(outfile) 656 filename := strings.Split(filepath.Base(outfile), ".") 657 base, extend := strings.Join(filename[:len(filename)-1], ""), filename[len(filename)-1] 658 return filepath.Join(path, fmt.Sprintf("%s_%d.%s", base, idx, extend)) 659 } 660 661 func createDumpFile(ctx context.Context, filename string) (*os.File, error) { 662 exists, err := fileExists(filename) 663 if err != nil { 664 return nil, err 665 } 666 if exists { 667 return nil, moerr.NewFileAlreadyExists(ctx, filename) 668 } 669 670 ret, err := os.Create(filename) 671 if err != nil { 672 return nil, err 673 } 674 return ret, nil 675 } 676 677 func writeDump2File(ctx context.Context, buf *bytes.Buffer, dump *tree.MoDump, f *os.File, curFileIdx, curFileSize int64) (ret *os.File, newFileIdx, newFileSize int64, err error) { 678 if dump.MaxFileSize > 0 && int64(buf.Len()) > dump.MaxFileSize { 679 err = moerr.NewInternalError(ctx, "dump: data in db is too large,please set a larger max_file_size") 680 return 681 } 682 if dump.MaxFileSize > 0 && curFileSize+int64(buf.Len()) > dump.MaxFileSize { 683 f.Close() 684 if curFileIdx == 1 { 685 os.Rename(dump.OutFile, genDumpFileName(dump.OutFile, curFileIdx)) 686 } 687 newFileIdx = curFileIdx + 1 688 newFileSize = int64(buf.Len()) 689 ret, err = createDumpFile(ctx, genDumpFileName(dump.OutFile, newFileIdx)) 690 if err != nil { 691 return 692 } 693 _, err = buf.WriteTo(ret) 694 if err != nil { 695 return 696 } 697 buf.Reset() 698 return 699 } 700 newFileSize = curFileSize + int64(buf.Len()) 701 _, err = buf.WriteTo(f) 702 if err != nil { 703 return 704 } 705 buf.Reset() 706 return f, curFileIdx, newFileSize, nil 707 } 708 709 func maybeAppendExtension(s string) string { 710 path := filepath.Dir(s) 711 filename := strings.Split(filepath.Base(s), ".") 712 if len(filename) == 1 { 713 filename = append(filename, "sql") 714 } 715 base, extend := strings.Join(filename[:len(filename)-1], ""), filename[len(filename)-1] 716 return filepath.Join(path, base+"."+extend) 717 } 718 719 func removeFile(s string, idx int64) { 720 if idx == 1 { 721 os.RemoveAll(s) 722 return 723 } 724 path := filepath.Dir(s) 725 filename := strings.Split(filepath.Base(s), ".") 726 base, extend := strings.Join(filename[:len(filename)-1], ""), filename[len(filename)-1] 727 for i := int64(1); i <= idx; i++ { 728 os.RemoveAll(filepath.Join(path, fmt.Sprintf("%s_%d.%s", base, i, extend))) 729 } 730 } 731 732 func isInvalidConfigInput(config string) bool { 733 // first verify if the input string can parse as a josn type data 734 _, err := types.ParseStringToByteJson(config) 735 return err != nil 736 }