-
Notifications
You must be signed in to change notification settings - Fork 54
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
fix: avoid need to lock state for restart.Pending() #451
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,7 @@ package restart | |
|
||
import ( | ||
"errors" | ||
"sync/atomic" | ||
|
||
"github.com/canonical/pebble/internals/overlord/state" | ||
) | ||
|
@@ -60,7 +61,7 @@ type restartManagerKey struct{} | |
// RestartManager takes care of restart-related state. | ||
type RestartManager struct { | ||
state *state.State | ||
restarting RestartType | ||
restarting atomic.Int32 // really of type RestartType | ||
h Handler | ||
bootID string | ||
} | ||
|
@@ -149,24 +150,20 @@ func Request(st *state.State, t RestartType) { | |
case RestartSystem, RestartSystemNow, RestartSystemHaltNow, RestartSystemPoweroffNow: | ||
st.Set("system-restart-from-boot-id", rm.bootID) | ||
} | ||
rm.restarting = t | ||
rm.restarting.Store(int32(t)) | ||
rm.handleRestart(t) | ||
} | ||
|
||
// Pending returns whether a restart was requested with Request and of which type. | ||
func Pending(st *state.State) (bool, RestartType) { | ||
cached := st.Cached(restartManagerKey{}) | ||
if cached == nil { | ||
return false, RestartUnset | ||
} | ||
rm := cached.(*RestartManager) | ||
return rm.restarting != RestartUnset, rm.restarting | ||
// NOTE: the state does not need to be locked to fetch this information. | ||
func (rm *RestartManager) Pending() (bool, RestartType) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. an "ok" bool is usually the last return value (like error) e.g. Since this is existing functionality, I don't mind. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I was actually tempted to get rid of the bool entirely, because it's just |
||
restarting := RestartType(rm.restarting.Load()) | ||
return restarting != RestartUnset, restarting | ||
} | ||
|
||
func FakePending(st *state.State, restarting RestartType) RestartType { | ||
rm := restartManager(st, "internal error: cannot mock a restart request before RestartManager initialization") | ||
old := rm.restarting | ||
rm.restarting = restarting | ||
func (rm *RestartManager) FakePending(restarting RestartType) RestartType { | ||
old := RestartType(rm.restarting.Load()) | ||
rm.restarting.Store(int32(restarting)) | ||
return old | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In future we could use an
atomic.Pointer[RestartType]
instead, although unnecessary heap allocation for such a small type, keeps the type.