|
19 | 19 | package fs
|
20 | 20 |
|
21 | 21 | import (
|
22 |
| - "bufio" |
| 22 | + "bytes" |
23 | 23 | "fmt"
|
| 24 | + "io" |
24 | 25 | "os"
|
25 | 26 | "os/exec"
|
26 | 27 | "path"
|
@@ -57,6 +58,9 @@ const (
|
57 | 58 | // A pool for restricting the number of consecutive `du` and `find` tasks running.
|
58 | 59 | var pool = make(chan struct{}, maxConcurrentOps)
|
59 | 60 |
|
| 61 | +// bufSize control size of read buffer in getDiskStatsMap() |
| 62 | +var bufSize = 5000 |
| 63 | + |
60 | 64 | func init() {
|
61 | 65 | for i := 0; i < maxConcurrentOps; i++ {
|
62 | 66 | releaseToken()
|
@@ -459,67 +463,100 @@ func getDiskStatsMap(diskStatsFile string) (map[string]DiskStats, error) {
|
459 | 463 | }
|
460 | 464 |
|
461 | 465 | defer file.Close()
|
462 |
| - scanner := bufio.NewScanner(file) |
463 | 466 |
|
464 |
| - for scanner.Scan() { |
465 |
| - line := scanner.Text() |
466 |
| - words := strings.Fields(line) |
467 |
| - if !partitionRegex.MatchString(words[2]) { |
468 |
| - continue |
| 467 | + leftover := []byte{} |
| 468 | + const newline = 10 |
| 469 | + for { |
| 470 | + buf := make([]byte, bufSize) |
| 471 | + count, err := file.Read(buf) |
| 472 | + buf = append(leftover, buf...) |
| 473 | + klog.V(10).Infof("read %d bytes in getDiskStatsMap()", count) |
| 474 | + if err == io.EOF { |
| 475 | + break |
| 476 | + } |
| 477 | + lines := bytes.Split(buf, []byte{newline}) |
| 478 | + var skipLastLine bool |
| 479 | + if buf[len(buf)-1] != newline { |
| 480 | + skipLastLine = true |
469 | 481 | }
|
470 |
| - // 8 50 sdd2 40 0 280 223 7 0 22 108 0 330 330 |
471 |
| - deviceName := path.Join("/dev", words[2]) |
472 | 482 |
|
473 |
| - var err error |
474 |
| - devInfo := make([]uint64, 2) |
475 |
| - for i := 0; i < len(devInfo); i++ { |
476 |
| - devInfo[i], err = strconv.ParseUint(words[i], 10, 64) |
| 483 | + for i, bLine := range lines { |
| 484 | + if len(bLine) == 0 { |
| 485 | + klog.V(10).Infof("skipping empty line in getDiskStatsMap() iteration %d", i) |
| 486 | + continue |
| 487 | + } |
| 488 | + if skipLastLine && i == len(lines)-1 { |
| 489 | + klog.V(10).Infof("skipping leftover line in getDiskStatsMap() iteration %d", i) |
| 490 | + continue |
| 491 | + } |
| 492 | + line := string(bLine) |
| 493 | + words := strings.Fields(line) |
| 494 | + |
| 495 | + if !partitionRegex.MatchString(words[2]) { |
| 496 | + continue |
| 497 | + } |
| 498 | + // 8 50 sdd2 40 0 280 223 7 0 22 108 0 330 330 |
| 499 | + deviceName := path.Join("/dev", words[2]) |
| 500 | + |
| 501 | + var err error |
| 502 | + devInfo := make([]uint64, 2) |
| 503 | + for i := 0; i < len(devInfo); i++ { |
| 504 | + devInfo[i], err = strconv.ParseUint(words[i], 10, 64) |
| 505 | + if err != nil { |
| 506 | + return nil, err |
| 507 | + } |
| 508 | + } |
| 509 | + |
| 510 | + wordLength := len(words) |
| 511 | + offset := 3 |
| 512 | + var stats = make([]uint64, wordLength-offset) |
| 513 | + if len(stats) < 11 { |
| 514 | + return nil, fmt.Errorf("could not parse all 11 columns of /proc/diskstats") |
| 515 | + } |
| 516 | + for i := offset; i < wordLength; i++ { |
| 517 | + stats[i-offset], err = strconv.ParseUint(words[i], 10, 64) |
| 518 | + if err != nil { |
| 519 | + return nil, err |
| 520 | + } |
| 521 | + } |
| 522 | + |
| 523 | + major64, err := strconv.ParseUint(words[0], 10, 64) |
477 | 524 | if err != nil {
|
478 | 525 | return nil, err
|
479 | 526 | }
|
480 |
| - } |
481 | 527 |
|
482 |
| - wordLength := len(words) |
483 |
| - offset := 3 |
484 |
| - var stats = make([]uint64, wordLength-offset) |
485 |
| - if len(stats) < 11 { |
486 |
| - return nil, fmt.Errorf("could not parse all 11 columns of /proc/diskstats") |
487 |
| - } |
488 |
| - for i := offset; i < wordLength; i++ { |
489 |
| - stats[i-offset], err = strconv.ParseUint(words[i], 10, 64) |
| 528 | + minor64, err := strconv.ParseUint(words[1], 10, 64) |
490 | 529 | if err != nil {
|
491 | 530 | return nil, err
|
492 | 531 | }
|
| 532 | + |
| 533 | + diskStats := DiskStats{ |
| 534 | + MajorNum: devInfo[0], |
| 535 | + MinorNum: devInfo[1], |
| 536 | + ReadsCompleted: stats[0], |
| 537 | + ReadsMerged: stats[1], |
| 538 | + SectorsRead: stats[2], |
| 539 | + ReadTime: stats[3], |
| 540 | + WritesCompleted: stats[4], |
| 541 | + WritesMerged: stats[5], |
| 542 | + SectorsWritten: stats[6], |
| 543 | + WriteTime: stats[7], |
| 544 | + IoInProgress: stats[8], |
| 545 | + IoTime: stats[9], |
| 546 | + WeightedIoTime: stats[10], |
| 547 | + Major: major64, |
| 548 | + Minor: minor64, |
| 549 | + } |
| 550 | + diskStatsMap[deviceName] = diskStats |
493 | 551 | }
|
494 | 552 |
|
495 |
| - major64, err := strconv.ParseUint(words[0], 10, 64) |
496 |
| - if err != nil { |
497 |
| - return nil, err |
| 553 | + if buf[len(buf)-1] != newline { |
| 554 | + leftover = lines[len(lines)-1] |
| 555 | + klog.V(10).Info("saving leftover line %q", leftover) |
| 556 | + } else { |
| 557 | + leftover = []byte{} |
498 | 558 | }
|
499 | 559 |
|
500 |
| - minor64, err := strconv.ParseUint(words[1], 10, 64) |
501 |
| - if err != nil { |
502 |
| - return nil, err |
503 |
| - } |
504 |
| - |
505 |
| - diskStats := DiskStats{ |
506 |
| - MajorNum: devInfo[0], |
507 |
| - MinorNum: devInfo[1], |
508 |
| - ReadsCompleted: stats[0], |
509 |
| - ReadsMerged: stats[1], |
510 |
| - SectorsRead: stats[2], |
511 |
| - ReadTime: stats[3], |
512 |
| - WritesCompleted: stats[4], |
513 |
| - WritesMerged: stats[5], |
514 |
| - SectorsWritten: stats[6], |
515 |
| - WriteTime: stats[7], |
516 |
| - IoInProgress: stats[8], |
517 |
| - IoTime: stats[9], |
518 |
| - WeightedIoTime: stats[10], |
519 |
| - Major: major64, |
520 |
| - Minor: minor64, |
521 |
| - } |
522 |
| - diskStatsMap[deviceName] = diskStats |
523 | 560 | }
|
524 | 561 | return diskStatsMap, nil
|
525 | 562 | }
|
|
0 commit comments