Skip to content

Commit f25870d

Browse files
committed
Use worker pool to make running of smartctl parallel (for issue #197).
Signed-off-by: Póka Balázs <[email protected]>
1 parent 2cc2249 commit f25870d

File tree

2 files changed

+49
-13
lines changed

2 files changed

+49
-13
lines changed

Diff for: main.go

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ func (i *SMARTctlManagerCollector) Describe(ch chan<- *prometheus.Desc) {
5959
func (i *SMARTctlManagerCollector) Collect(ch chan<- prometheus.Metric) {
6060
info := NewSMARTctlInfo(ch)
6161
i.mutex.Lock()
62+
refreshAllDevices(i.logger, i.Devices)
6263
for _, device := range i.Devices {
6364
json := readData(i.logger, device)
6465
if json.Exists() {

Diff for: readjson.go

+48-13
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,17 @@ type JSONCache struct {
3232
LastCollect time.Time
3333
}
3434

35+
type SMARTresult struct {
36+
device Device
37+
JSON gjson.Result
38+
ok bool
39+
}
40+
41+
type SMARTctlWorkerPool struct {
42+
results chan SMARTresult
43+
expected int
44+
}
45+
3546
var (
3647
jsonCache sync.Map
3748
)
@@ -40,6 +51,10 @@ func init() {
4051
jsonCache.Store("", JSONCache{})
4152
}
4253

54+
func createPool() SMARTctlWorkerPool {
55+
return SMARTctlWorkerPool{make(chan SMARTresult), 0}
56+
}
57+
4358
// Parse json to gjson object
4459
func parseJSON(data string) gjson.Result {
4560
if !gjson.Valid(data) {
@@ -62,7 +77,7 @@ func readFakeSMARTctl(logger log.Logger, device Device) gjson.Result {
6277
}
6378

6479
// Get json from smartctl and parse it
65-
func readSMARTctl(logger log.Logger, device Device) (gjson.Result, bool) {
80+
func readSMARTctl(logger log.Logger, device Device, results chan<- SMARTresult) {
6681
start := time.Now()
6782
out, err := exec.Command(*smartctlPath, "--json", "--info", "--health", "--attributes", "--tolerance=verypermissive", "--nocheck=standby", "--format=brief", "--log=error", "--device="+device.Type, device.Name).Output()
6883
if err != nil {
@@ -72,7 +87,7 @@ func readSMARTctl(logger log.Logger, device Device) (gjson.Result, bool) {
7287
rcOk := resultCodeIsOk(logger, device, json.Get("smartctl.exit_status").Int())
7388
jsonOk := jsonIsOk(logger, json)
7489
level.Debug(logger).Log("msg", "Collected S.M.A.R.T. json data", "device", device.Info_Name, "duration", time.Since(start))
75-
return json, rcOk && jsonOk
90+
results <- SMARTresult{device, json, rcOk && jsonOk}
7691
}
7792

7893
func readSMARTctlDevices(logger log.Logger) gjson.Result {
@@ -89,23 +104,43 @@ func readSMARTctlDevices(logger log.Logger) gjson.Result {
89104
return parseJSON(string(out))
90105
}
91106

107+
// Refresh all devices' json
108+
func refreshAllDevices(logger log.Logger, devices []Device) {
109+
if *smartctlFakeData {
110+
return
111+
}
112+
113+
pool := createPool()
114+
for _, device := range devices {
115+
refreshData(logger, device, &pool)
116+
}
117+
for pool.expected > 0 {
118+
result := <-pool.results
119+
if result.ok {
120+
jsonCache.Store(result.device, JSONCache{JSON: result.JSON, LastCollect: time.Now()})
121+
}
122+
pool.expected--
123+
}
124+
close(pool.results)
125+
}
126+
92127
// Select json source and parse
128+
func refreshData(logger log.Logger, device Device, pool *SMARTctlWorkerPool) {
129+
cacheValue, cacheOk := jsonCache.Load(device)
130+
if !cacheOk || time.Now().After(cacheValue.(JSONCache).LastCollect.Add(*smartctlInterval)) {
131+
go readSMARTctl(logger, device, pool.results)
132+
pool.expected++
133+
}
134+
}
135+
93136
func readData(logger log.Logger, device Device) gjson.Result {
94137
if *smartctlFakeData {
95138
return readFakeSMARTctl(logger, device)
96139
}
97140

98-
cacheValue, cacheOk := jsonCache.Load(device)
99-
if !cacheOk || time.Now().After(cacheValue.(JSONCache).LastCollect.Add(*smartctlInterval)) {
100-
json, ok := readSMARTctl(logger, device)
101-
if ok {
102-
jsonCache.Store(device, JSONCache{JSON: json, LastCollect: time.Now()})
103-
j, found := jsonCache.Load(device)
104-
if !found {
105-
level.Warn(logger).Log("msg", "device not found", "device", device.Info_Name)
106-
}
107-
return j.(JSONCache).JSON
108-
}
141+
cacheValue, found := jsonCache.Load(device)
142+
if !found {
143+
level.Warn(logger).Log("msg", "device not found", "device", device.Info_Name)
109144
return gjson.Result{}
110145
}
111146
return cacheValue.(JSONCache).JSON

0 commit comments

Comments
 (0)