From 7575da794e14cd154b95baa948d2c4a37e498a90 Mon Sep 17 00:00:00 2001 From: yo Date: Sun, 25 Jun 2023 23:07:53 +0200 Subject: [PATCH] 0.33c : parallelize start/stop of jails up to gMaxThreads --- cmd/root.go | 2 +- cmd/start.go | 48 ++++++++++++++++++++++++++++++++++++-- cmd/stop.go | 66 ++++++++++++++++++++++++++++++++++++++++++++++++---- cmd/utils.go | 2 ++ 4 files changed, 110 insertions(+), 8 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 4b23445..8b9b772 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -14,7 +14,7 @@ import ( ) const ( - gVersion = "0.33b" + gVersion = "0.33c" // TODO : Get from $jail_zpool/defaults.json MIN_DYN_DEVFS_RULESET = 1000 diff --git a/cmd/start.go b/cmd/start.go index f9ceed5..02b2b88 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -4,6 +4,7 @@ import ( "os" "fmt" "net" + "sync" "time" "errors" "regexp" @@ -1055,6 +1056,9 @@ func cleanAfterStartCrash() { // Start all jails with boot=true, in priority order func StartJailsAtBoot() { var startList []Jail + var wg *sync.WaitGroup + var curThNb int + var curPri int // Get boot enabled jails for _, j := range gJails { @@ -1072,11 +1076,51 @@ func StartJailsAtBoot() { } JailsOrderedBy(fct.Interface().(jailLessFunc)).Sort(startList) - for _, j := range startList { + wg = new(sync.WaitGroup) + curThNb = 0 + for i, j := range startList { jFullName := fmt.Sprintf("%s/%s", j.Datastore, j.Name) log.Debugf("Starting %s with priority %s\n", jFullName, j.Config.Priority) - StartJail([]string{jFullName}) + jailPri, err := strconv.Atoi(j.Config.Priority) + if err != nil { + panic(fmt.Sprintf("Invalid format for Priority (Jail %s)\n", jFullName)) + } + + if (curThNb >= gMaxThreads || i == 0) { + // FIXME : Use a pool instead of waiting for all threads to run a new one + wg.Wait() + curThNb = 0 + + wg.Add(1) + curThNb++ + curPri = jailPri + go func(jailFullName string) { + defer wg.Done() + StartJail([]string{jailFullName}) + }(jFullName) + } else { + if (curPri == jailPri) { + wg.Add(1) + curThNb++ + go func(jailFullName string) { + defer wg.Done() + StartJail([]string{jailFullName}) + }(jFullName) + } else { + wg.Wait() + curThNb = 0 + + wg.Add(1) + curThNb++ + curPri = jailPri + go func(jailFullName string) { + defer wg.Done() + StartJail([]string{jailFullName}) + }(jFullName) + } + } } + wg.Wait() } diff --git a/cmd/stop.go b/cmd/stop.go index 2733171..ede26b8 100644 --- a/cmd/stop.go +++ b/cmd/stop.go @@ -4,6 +4,7 @@ import ( "os" "fmt" //"log" + "sync" "errors" "regexp" "os/exec" @@ -169,8 +170,13 @@ func stopJail(jail *Jail) error { } // Stop all running jails by reverse priority +// Parallelize up to gMaxThreads +// Only parallelize same priority level jails func StopAllRunningJails() { var stopList []Jail + var wg *sync.WaitGroup + var curThNb int + var curPri int // Get boot enabled jails for _, j := range gJails { @@ -187,12 +193,53 @@ func StopAllRunningJails() { return } JailsOrderedBy(fct.Interface().(jailLessFunc)).Sort(stopList) - - for _, j := range stopList { + + + wg = new(sync.WaitGroup) + curThNb = 0 + for i, j := range stopList { jFullName := fmt.Sprintf("%s/%s", j.Datastore, j.Name) log.Debugf("Stopping %s with priority %s\n", jFullName, j.Config.Priority) - StopJail([]string{jFullName}) + jailPri, err := strconv.Atoi(j.Config.Priority) + if err != nil { + panic(fmt.Sprintf("Invalid format for Priority (Jail %s)\n", jFullName)) + } + + if (curThNb >= gMaxThreads || i == 0) { + // FIXME : Use a pool instead of waiting for all threads to run a new one + wg.Wait() + curThNb = 0 + + wg.Add(1) + curThNb++ + curPri = jailPri + go func(jailFullName string) { + defer wg.Done() + StopJail([]string{jailFullName}) + }(jFullName) + } else { + if (curPri == jailPri) { + wg.Add(1) + curThNb++ + go func(jailFullName string) { + defer wg.Done() + StopJail([]string{jailFullName}) + }(jFullName) + } else { + wg.Wait() + curThNb = 0 + + wg.Add(1) + curThNb++ + curPri = jailPri + go func(jailFullName string) { + defer wg.Done() + StopJail([]string{jailFullName}) + }(jFullName) + } + } } + wg.Wait() } /* @@ -243,8 +290,16 @@ func StopJail(args []string) { return } cvers = strings.TrimRight(cvers, "\n") - fmt.Sprintf(cj.Config.Release, cvers) - cj.ConfigUpdated = true + + //fmt.Sprintf(cj.Config.Release, cvers) + //cj.Config.Release = cvers + //cj.ConfigUpdated = true + + // This is working in this context, but value is not available in WriteConfigToDisk context :/ + setStructFieldValue(cj, "Config.Release", cvers) + fmt.Printf("DEBUG: release was set, now is : %s\n", cj.Config.Release) + + // We need to get the real Config object, not a copy of it out, err := executeCommand(fmt.Sprintf("rctl jail:%s", cj.InternalName)) if err == nil && len(out) > 0 { @@ -410,6 +465,7 @@ func StopJail(args []string) { } } + fmt.Printf("DEBUG: release = %s\n", cj.Config.Release) WriteConfigToDisk(cj.Name, false, true) } diff --git a/cmd/utils.go b/cmd/utils.go index cdb3a1a..fb1db0a 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -21,6 +21,8 @@ import ( const ( ipv4re = `[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}` ifconfigipv4re = `inet[[:space:]](` + ipv4re + `)` + // Maximum thread qty for start/stop + gMaxThreads = 4 ) /*****************************************************************************