Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parse recovery line to be synced blocks #637

Merged
merged 1 commit into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 26 additions & 16 deletions mdstat.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (

var (
statusLineRE = regexp.MustCompile(`(\d+) blocks .*\[(\d+)/(\d+)\] \[([U_]+)\]`)
recoveryLineBlocksRE = regexp.MustCompile(`\((\d+)/\d+\)`)
recoveryLineBlocksRE = regexp.MustCompile(`\((\d+/\d+)\)`)
recoveryLinePctRE = regexp.MustCompile(`= (.+)%`)
recoveryLineFinishRE = regexp.MustCompile(`finish=(.+)min`)
recoveryLineSpeedRE = regexp.MustCompile(`speed=(.+)[A-Z]`)
Expand All @@ -50,6 +50,8 @@ type MDStat struct {
BlocksTotal int64
// Number of blocks on the device that are in sync.
BlocksSynced int64
// Number of blocks on the device that need to be synced.
BlocksToBeSynced int64
// progress percentage of current sync
BlocksSyncedPct float64
// estimated finishing time for current sync (in minutes)
Expand Down Expand Up @@ -115,7 +117,8 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) {

// If device is syncing at the moment, get the number of currently
// synced bytes, otherwise that number equals the size of the device.
syncedBlocks := size
blocksSynced := size
blocksToBeSynced := size
speed := float64(0)
finish := float64(0)
pct := float64(0)
Expand All @@ -136,9 +139,9 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) {
// Handle case when resync=PENDING or resync=DELAYED.
if strings.Contains(lines[syncLineIdx], "PENDING") ||
strings.Contains(lines[syncLineIdx], "DELAYED") {
syncedBlocks = 0
blocksSynced = 0
} else {
syncedBlocks, pct, finish, speed, err = evalRecoveryLine(lines[syncLineIdx])
blocksSynced, blocksToBeSynced, pct, finish, speed, err = evalRecoveryLine(lines[syncLineIdx])
if err != nil {
return nil, fmt.Errorf("%w: Cannot parse sync line in md device: %q: %w", ErrFileParse, mdName, err)
}
Expand All @@ -154,7 +157,8 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) {
DisksSpare: spare,
DisksTotal: total,
BlocksTotal: size,
BlocksSynced: syncedBlocks,
BlocksSynced: blocksSynced,
BlocksToBeSynced: blocksToBeSynced,
BlocksSyncedPct: pct,
BlocksSyncedFinishTime: finish,
BlocksSyncedSpeed: speed,
Expand Down Expand Up @@ -206,48 +210,54 @@ func evalStatusLine(deviceLine, statusLine string) (active, total, down, size in
return active, total, down, size, nil
}

func evalRecoveryLine(recoveryLine string) (syncedBlocks int64, pct float64, finish float64, speed float64, err error) {
func evalRecoveryLine(recoveryLine string) (blocksSynced int64, blocksToBeSynced int64, pct float64, finish float64, speed float64, err error) {
matches := recoveryLineBlocksRE.FindStringSubmatch(recoveryLine)
if len(matches) != 2 {
return 0, 0, 0, 0, fmt.Errorf("%w: Unexpected recoveryLine %s: %w", ErrFileParse, recoveryLine, err)
return 0, 0, 0, 0, 0, fmt.Errorf("%w: Unexpected recoveryLine blocks %s: %w", ErrFileParse, recoveryLine, err)
}

syncedBlocks, err = strconv.ParseInt(matches[1], 10, 64)
blocks := strings.Split(matches[1], "/")
blocksSynced, err = strconv.ParseInt(blocks[0], 10, 64)
if err != nil {
return 0, 0, 0, 0, fmt.Errorf("%w: Unexpected parsing of recoveryLine %q: %w", ErrFileParse, recoveryLine, err)
return 0, 0, 0, 0, 0, fmt.Errorf("%w: Unable to parse recovery blocks synced %q: %w", ErrFileParse, matches[1], err)
}

blocksToBeSynced, err = strconv.ParseInt(blocks[1], 10, 64)
if err != nil {
return blocksSynced, 0, 0, 0, 0, fmt.Errorf("%w: Unable to parse recovery to be synced blocks %q: %w", ErrFileParse, matches[2], err)
}

// Get percentage complete
matches = recoveryLinePctRE.FindStringSubmatch(recoveryLine)
if len(matches) != 2 {
return syncedBlocks, 0, 0, 0, fmt.Errorf("%w: Unexpected recoveryLine matching percentage %s", ErrFileParse, recoveryLine)
return blocksSynced, blocksToBeSynced, 0, 0, 0, fmt.Errorf("%w: Unexpected recoveryLine matching percentage %s", ErrFileParse, recoveryLine)
}
pct, err = strconv.ParseFloat(strings.TrimSpace(matches[1]), 64)
if err != nil {
return syncedBlocks, 0, 0, 0, fmt.Errorf("%w: Error parsing float from recoveryLine %q", ErrFileParse, recoveryLine)
return blocksSynced, blocksToBeSynced, 0, 0, 0, fmt.Errorf("%w: Error parsing float from recoveryLine %q", ErrFileParse, recoveryLine)
}

// Get time expected left to complete
matches = recoveryLineFinishRE.FindStringSubmatch(recoveryLine)
if len(matches) != 2 {
return syncedBlocks, pct, 0, 0, fmt.Errorf("%w: Unexpected recoveryLine matching est. finish time: %s", ErrFileParse, recoveryLine)
return blocksSynced, blocksToBeSynced, pct, 0, 0, fmt.Errorf("%w: Unexpected recoveryLine matching est. finish time: %s", ErrFileParse, recoveryLine)
}
finish, err = strconv.ParseFloat(matches[1], 64)
if err != nil {
return syncedBlocks, pct, 0, 0, fmt.Errorf("%w: Unable to parse float from recoveryLine: %q", ErrFileParse, recoveryLine)
return blocksSynced, blocksToBeSynced, pct, 0, 0, fmt.Errorf("%w: Unable to parse float from recoveryLine: %q", ErrFileParse, recoveryLine)
}

// Get recovery speed
matches = recoveryLineSpeedRE.FindStringSubmatch(recoveryLine)
if len(matches) != 2 {
return syncedBlocks, pct, finish, 0, fmt.Errorf("%w: Unexpected recoveryLine value: %s", ErrFileParse, recoveryLine)
return blocksSynced, blocksToBeSynced, pct, finish, 0, fmt.Errorf("%w: Unexpected recoveryLine value: %s", ErrFileParse, recoveryLine)
}
speed, err = strconv.ParseFloat(matches[1], 64)
if err != nil {
return syncedBlocks, pct, finish, 0, fmt.Errorf("%w: Error parsing float from recoveryLine: %q: %w", ErrFileParse, recoveryLine, err)
return blocksSynced, blocksToBeSynced, pct, finish, 0, fmt.Errorf("%w: Error parsing float from recoveryLine: %q: %w", ErrFileParse, recoveryLine, err)
}

return syncedBlocks, pct, finish, speed, nil
return blocksSynced, blocksToBeSynced, pct, finish, speed, nil
}

func evalComponentDevices(deviceFields []string) []string {
Expand Down
272 changes: 255 additions & 17 deletions mdstat_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,261 @@ func TestFS_MDStat(t *testing.T) {
}

refs := map[string]MDStat{
"md127": {Name: "md127", ActivityState: "active", DisksActive: 2, DisksTotal: 2, DisksFailed: 0, DisksDown: 0, DisksSpare: 0, BlocksTotal: 312319552, BlocksSynced: 312319552, BlocksSyncedPct: 0, BlocksSyncedFinishTime: 0, BlocksSyncedSpeed: 0, Devices: []string{"sdi2", "sdj2"}},
"md0": {Name: "md0", ActivityState: "active", DisksActive: 2, DisksTotal: 2, DisksFailed: 0, DisksDown: 0, DisksSpare: 0, BlocksTotal: 248896, BlocksSynced: 248896, BlocksSyncedPct: 0, BlocksSyncedFinishTime: 0, BlocksSyncedSpeed: 0, Devices: []string{"sdi1", "sdj1"}},
"md4": {Name: "md4", ActivityState: "inactive", DisksActive: 0, DisksTotal: 0, DisksFailed: 1, DisksDown: 0, DisksSpare: 1, BlocksTotal: 4883648, BlocksSynced: 4883648, BlocksSyncedPct: 0, BlocksSyncedFinishTime: 0, BlocksSyncedSpeed: 0, Devices: []string{"sda3", "sdb3"}},
"md6": {Name: "md6", ActivityState: "recovering", DisksActive: 1, DisksTotal: 2, DisksFailed: 1, DisksDown: 1, DisksSpare: 1, BlocksTotal: 195310144, BlocksSynced: 16775552, BlocksSyncedPct: 8.5, BlocksSyncedFinishTime: 17, BlocksSyncedSpeed: 259783, Devices: []string{"sdb2", "sdc", "sda2"}},
"md3": {Name: "md3", ActivityState: "active", DisksActive: 8, DisksTotal: 8, DisksFailed: 0, DisksDown: 0, DisksSpare: 2, BlocksTotal: 5853468288, BlocksSynced: 5853468288, BlocksSyncedPct: 0, BlocksSyncedFinishTime: 0, BlocksSyncedSpeed: 0, Devices: []string{"sda1", "sdh1", "sdg1", "sdf1", "sde1", "sdd1", "sdc1", "sdb1", "sdd1", "sdd2"}},
"md8": {Name: "md8", ActivityState: "resyncing", DisksActive: 2, DisksTotal: 2, DisksFailed: 0, DisksDown: 0, DisksSpare: 2, BlocksTotal: 195310144, BlocksSynced: 16775552, BlocksSyncedPct: 8.5, BlocksSyncedFinishTime: 17, BlocksSyncedSpeed: 259783, Devices: []string{"sdb1", "sda1", "sdc", "sde"}},
"md7": {Name: "md7", ActivityState: "active", DisksActive: 3, DisksTotal: 4, DisksFailed: 1, DisksDown: 1, DisksSpare: 0, BlocksTotal: 7813735424, BlocksSynced: 7813735424, BlocksSyncedPct: 0, BlocksSyncedFinishTime: 0, BlocksSyncedSpeed: 0, Devices: []string{"sdb1", "sde1", "sdd1", "sdc1"}},
"md9": {Name: "md9", ActivityState: "resyncing", DisksActive: 4, DisksTotal: 4, DisksSpare: 1, DisksDown: 0, DisksFailed: 2, BlocksTotal: 523968, BlocksSynced: 0, BlocksSyncedPct: 0, BlocksSyncedFinishTime: 0, BlocksSyncedSpeed: 0, Devices: []string{"sdc2", "sdd2", "sdb2", "sda2", "sde", "sdf", "sdg"}},
"md10": {Name: "md10", ActivityState: "active", DisksActive: 2, DisksTotal: 2, DisksFailed: 0, DisksDown: 0, DisksSpare: 0, BlocksTotal: 314159265, BlocksSynced: 314159265, BlocksSyncedPct: 0, BlocksSyncedFinishTime: 0, BlocksSyncedSpeed: 0, Devices: []string{"sda1", "sdb1"}},
"md11": {Name: "md11", ActivityState: "resyncing", DisksActive: 2, DisksTotal: 2, DisksFailed: 1, DisksDown: 0, DisksSpare: 2, BlocksTotal: 4190208, BlocksSynced: 0, BlocksSyncedPct: 0, BlocksSyncedFinishTime: 0, BlocksSyncedSpeed: 0, Devices: []string{"sdb2", "sdc2", "sdc3", "hda", "ssdc2"}},
"md12": {Name: "md12", ActivityState: "active", DisksActive: 2, DisksTotal: 2, DisksSpare: 0, DisksDown: 0, DisksFailed: 0, BlocksTotal: 3886394368, BlocksSynced: 3886394368, BlocksSyncedPct: 0, BlocksSyncedFinishTime: 0, BlocksSyncedSpeed: 0, Devices: []string{"sdc2", "sdd2"}},
"md120": {Name: "md120", ActivityState: "active", DisksActive: 2, DisksTotal: 2, DisksFailed: 0, DisksDown: 0, DisksSpare: 0, BlocksTotal: 2095104, BlocksSynced: 2095104, BlocksSyncedPct: 0, BlocksSyncedFinishTime: 0, BlocksSyncedSpeed: 0, Devices: []string{"sda1", "sdb1"}},
"md126": {Name: "md126", ActivityState: "active", DisksActive: 2, DisksTotal: 2, DisksFailed: 0, DisksDown: 0, DisksSpare: 0, BlocksTotal: 1855870976, BlocksSynced: 1855870976, BlocksSyncedPct: 0, BlocksSyncedFinishTime: 0, BlocksSyncedSpeed: 0, Devices: []string{"sdb", "sdc"}},
"md219": {Name: "md219", ActivityState: "inactive", DisksTotal: 0, DisksFailed: 0, DisksActive: 0, DisksDown: 0, DisksSpare: 3, BlocksTotal: 7932, BlocksSynced: 7932, BlocksSyncedPct: 0, BlocksSyncedFinishTime: 0, BlocksSyncedSpeed: 0, Devices: []string{"sdc", "sda"}},
"md00": {Name: "md00", ActivityState: "active", DisksActive: 1, DisksTotal: 1, DisksFailed: 0, DisksDown: 0, DisksSpare: 0, BlocksTotal: 4186624, BlocksSynced: 4186624, BlocksSyncedPct: 0, BlocksSyncedFinishTime: 0, BlocksSyncedSpeed: 0, Devices: []string{"xvdb"}},
"md101": {Name: "md101", ActivityState: "active", DisksActive: 3, DisksTotal: 3, DisksFailed: 0, DisksDown: 0, DisksSpare: 0, BlocksTotal: 322560, BlocksSynced: 322560, BlocksSyncedPct: 0, BlocksSyncedFinishTime: 0, BlocksSyncedSpeed: 0, Devices: []string{"sdb", "sdd", "sdc"}},
"md201": {Name: "md201", ActivityState: "checking", DisksActive: 2, DisksTotal: 2, DisksFailed: 0, DisksDown: 0, DisksSpare: 0, BlocksTotal: 1993728, BlocksSynced: 114176, BlocksSyncedPct: 5.7, BlocksSyncedFinishTime: 0.2, BlocksSyncedSpeed: 114176, Devices: []string{"sda3", "sdb3"}},
"md127": {
Name: "md127",
ActivityState: "active",
DisksActive: 2,
DisksTotal: 2,
DisksFailed: 0,
DisksDown: 0,
DisksSpare: 0,
BlocksTotal: 312319552,
BlocksSynced: 312319552,
BlocksToBeSynced: 312319552,
BlocksSyncedPct: 0,
BlocksSyncedFinishTime: 0,
BlocksSyncedSpeed: 0,
Devices: []string{"sdi2", "sdj2"}},
"md0": {
Name: "md0",
ActivityState: "active",
DisksActive: 2,
DisksTotal: 2,
DisksFailed: 0,
DisksDown: 0,
DisksSpare: 0,
BlocksTotal: 248896,
BlocksSynced: 248896,
BlocksToBeSynced: 248896,
BlocksSyncedPct: 0,
BlocksSyncedFinishTime: 0,
BlocksSyncedSpeed: 0,
Devices: []string{"sdi1", "sdj1"}},
"md4": {
Name: "md4",
ActivityState: "inactive",
DisksActive: 0,
DisksTotal: 0,
DisksFailed: 1,
DisksDown: 0,
DisksSpare: 1,
BlocksTotal: 4883648,
BlocksSynced: 4883648,
BlocksToBeSynced: 4883648,
BlocksSyncedPct: 0,
BlocksSyncedFinishTime: 0,
BlocksSyncedSpeed: 0,
Devices: []string{"sda3", "sdb3"}},
"md6": {
Name: "md6",
ActivityState: "recovering",
DisksActive: 1,
DisksTotal: 2,
DisksFailed: 1,
DisksDown: 1,
DisksSpare: 1,
BlocksTotal: 195310144,
BlocksSynced: 16775552,
BlocksToBeSynced: 195310144,
BlocksSyncedPct: 8.5,
BlocksSyncedFinishTime: 17,
BlocksSyncedSpeed: 259783,
Devices: []string{"sdb2", "sdc", "sda2"}},
"md3": {
Name: "md3",
ActivityState: "active",
DisksActive: 8,
DisksTotal: 8,
DisksFailed: 0,
DisksDown: 0,
DisksSpare: 2,
BlocksTotal: 5853468288,
BlocksSynced: 5853468288,
BlocksToBeSynced: 5853468288,
BlocksSyncedPct: 0,
BlocksSyncedFinishTime: 0,
BlocksSyncedSpeed: 0,
Devices: []string{"sda1", "sdh1", "sdg1", "sdf1", "sde1", "sdd1", "sdc1", "sdb1", "sdd1", "sdd2"}},
"md8": {
Name: "md8",
ActivityState: "resyncing",
DisksActive: 2,
DisksTotal: 2,
DisksFailed: 0,
DisksDown: 0,
DisksSpare: 2,
BlocksTotal: 195310144,
BlocksSynced: 16775552,
BlocksToBeSynced: 195310144,
BlocksSyncedPct: 8.5,
BlocksSyncedFinishTime: 17,
BlocksSyncedSpeed: 259783,
Devices: []string{"sdb1", "sda1", "sdc", "sde"}},
"md7": {
Name: "md7",
ActivityState: "active",
DisksActive: 3,
DisksTotal: 4,
DisksFailed: 1,
DisksDown: 1,
DisksSpare: 0,
BlocksTotal: 7813735424,
BlocksSynced: 7813735424,
BlocksToBeSynced: 7813735424,
BlocksSyncedPct: 0,
BlocksSyncedFinishTime: 0,
BlocksSyncedSpeed: 0,
Devices: []string{"sdb1", "sde1", "sdd1", "sdc1"}},
"md9": {
Name: "md9",
ActivityState: "resyncing",
DisksActive: 4,
DisksTotal: 4,
DisksSpare: 1,
DisksDown: 0,
DisksFailed: 2,
BlocksTotal: 523968,
BlocksSynced: 0,
BlocksToBeSynced: 523968,
BlocksSyncedPct: 0,
BlocksSyncedFinishTime: 0,
BlocksSyncedSpeed: 0,
Devices: []string{"sdc2", "sdd2", "sdb2", "sda2", "sde", "sdf", "sdg"}},
"md10": {
Name: "md10",
ActivityState: "active",
DisksActive: 2,
DisksTotal: 2,
DisksFailed: 0,
DisksDown: 0,
DisksSpare: 0,
BlocksTotal: 314159265,
BlocksSynced: 314159265,
BlocksToBeSynced: 314159265,
BlocksSyncedPct: 0,
BlocksSyncedFinishTime: 0,
BlocksSyncedSpeed: 0,
Devices: []string{"sda1", "sdb1"}},
"md11": {
Name: "md11",
ActivityState: "resyncing",
DisksActive: 2,
DisksTotal: 2,
DisksFailed: 1,
DisksDown: 0,
DisksSpare: 2,
BlocksTotal: 4190208,
BlocksSynced: 0,
BlocksToBeSynced: 4190208,
BlocksSyncedPct: 0,
BlocksSyncedFinishTime: 0,
BlocksSyncedSpeed: 0,
Devices: []string{"sdb2", "sdc2", "sdc3", "hda", "ssdc2"}},
"md12": {
Name: "md12",
ActivityState: "active",
DisksActive: 2,
DisksTotal: 2,
DisksSpare: 0,
DisksDown: 0,
DisksFailed: 0,
BlocksTotal: 3886394368,
BlocksSynced: 3886394368,
BlocksToBeSynced: 3886394368,
BlocksSyncedPct: 0,
BlocksSyncedFinishTime: 0,
BlocksSyncedSpeed: 0,
Devices: []string{"sdc2", "sdd2"}},
"md120": {
Name: "md120",
ActivityState: "active",
DisksActive: 2,
DisksTotal: 2,
DisksFailed: 0,
DisksDown: 0,
DisksSpare: 0,
BlocksTotal: 2095104,
BlocksSynced: 2095104,
BlocksToBeSynced: 2095104,
BlocksSyncedPct: 0,
BlocksSyncedFinishTime: 0,
BlocksSyncedSpeed: 0,
Devices: []string{"sda1", "sdb1"}},
"md126": {
Name: "md126",
ActivityState: "active",
DisksActive: 2,
DisksTotal: 2,
DisksFailed: 0,
DisksDown: 0,
DisksSpare: 0,
BlocksTotal: 1855870976,
BlocksSynced: 1855870976,
BlocksToBeSynced: 1855870976,
BlocksSyncedPct: 0,
BlocksSyncedFinishTime: 0,
BlocksSyncedSpeed: 0,
Devices: []string{"sdb", "sdc"}},
"md219": {
Name: "md219",
ActivityState: "inactive",
DisksTotal: 0,
DisksFailed: 0,
DisksActive: 0,
DisksDown: 0,
DisksSpare: 3,
BlocksTotal: 7932,
BlocksSynced: 7932,
BlocksToBeSynced: 7932,
BlocksSyncedPct: 0,
BlocksSyncedFinishTime: 0,
BlocksSyncedSpeed: 0,
Devices: []string{"sdc", "sda"}},
"md00": {
Name: "md00",
ActivityState: "active",
DisksActive: 1,
DisksTotal: 1,
DisksFailed: 0,
DisksDown: 0,
DisksSpare: 0,
BlocksTotal: 4186624,
BlocksSynced: 4186624,
BlocksToBeSynced: 4186624,
BlocksSyncedPct: 0,
BlocksSyncedFinishTime: 0,
BlocksSyncedSpeed: 0,
Devices: []string{"xvdb"}},
"md101": {
Name: "md101",
ActivityState: "active",
DisksActive: 3,
DisksTotal: 3,
DisksFailed: 0,
DisksDown: 0,
DisksSpare: 0,
BlocksTotal: 322560,
BlocksSynced: 322560,
BlocksToBeSynced: 322560,
BlocksSyncedPct: 0,
BlocksSyncedFinishTime: 0,
BlocksSyncedSpeed: 0,
Devices: []string{"sdb", "sdd", "sdc"}},
"md201": {
Name: "md201",
ActivityState: "checking",
DisksActive: 2,
DisksTotal: 2,
DisksFailed: 0,
DisksDown: 0,
DisksSpare: 0,
BlocksTotal: 1993728,
BlocksSynced: 114176,
BlocksToBeSynced: 1993728,
BlocksSyncedPct: 5.7,
BlocksSyncedFinishTime: 0.2,
BlocksSyncedSpeed: 114176,
Devices: []string{"sda3", "sdb3"}},
}

if want, have := len(refs), len(mdStats); want != have {
Expand Down