diff --git a/autopilot/contractor/alerts.go b/autopilot/contractor/alerts.go index d242bc8f5..661d5393a 100644 --- a/autopilot/contractor/alerts.go +++ b/autopilot/contractor/alerts.go @@ -8,6 +8,13 @@ import ( "go.sia.tech/renterd/api" ) +const ( + // alertLostSectorsThresholdPct defines the the threshold at which we + // register the lost sectors alert. A value of 0.01 means that we register + // the alert if the host lost 1% (or more) of its stored data. + alertLostSectorsThresholdPct = 0.01 +) + var ( alertChurnID = alerts.RandomAlertID() // constant until restarted alertLostSectorsID = alerts.RandomAlertID() // constant until restarted @@ -47,3 +54,7 @@ func newLostSectorsAlert(hk types.PublicKey, lostSectors uint64) alerts.Alert { Timestamp: time.Now(), } } + +func registerLostSectorsAlert(dataLost, dataStored uint64) bool { + return dataLost > 0 && float64(dataLost) >= float64(dataStored)*alertLostSectorsThresholdPct +} diff --git a/autopilot/contractor/alerts_test.go b/autopilot/contractor/alerts_test.go new file mode 100644 index 000000000..489e2c43b --- /dev/null +++ b/autopilot/contractor/alerts_test.go @@ -0,0 +1,26 @@ +package contractor + +import ( + "testing" + + rhpv2 "go.sia.tech/core/rhp/v2" +) + +func TestRegisterLostSectorsAlert(t *testing.T) { + for _, tc := range []struct { + dataLost uint64 + dataStored uint64 + expected bool + }{ + {0, 0, false}, + {0, rhpv2.SectorSize, false}, + {rhpv2.SectorSize, 0, true}, + {rhpv2.SectorSize, 99 * rhpv2.SectorSize, true}, + {rhpv2.SectorSize, 100 * rhpv2.SectorSize, true}, // exactly 1% + {rhpv2.SectorSize, 101 * rhpv2.SectorSize, false}, // just short of 1% + } { + if result := registerLostSectorsAlert(tc.dataLost, tc.dataStored); result != tc.expected { + t.Fatalf("unexpected result for dataLost=%d, dataStored=%d: %v", tc.dataLost, tc.dataStored, result) + } + } +} diff --git a/autopilot/contractor/contractor.go b/autopilot/contractor/contractor.go index a27e741f8..842cdb547 100644 --- a/autopilot/contractor/contractor.go +++ b/autopilot/contractor/contractor.go @@ -298,7 +298,7 @@ func (c *Contractor) performContractMaintenance(ctx *mCtx, w Worker) (bool, erro // check if any used hosts have lost data to warn the user var toDismiss []types.Hash256 for _, h := range hosts { - if h.Interactions.LostSectors > 0 { + if registerLostSectorsAlert(h.Interactions.LostSectors*rhpv2.SectorSize, h.StoredData) { c.alerter.RegisterAlert(ctx, newLostSectorsAlert(h.PublicKey, h.Interactions.LostSectors)) } else { toDismiss = append(toDismiss, alerts.IDForHost(alertLostSectorsID, h.PublicKey))