From 1507bbf6d40252768b4aea397e20001727cc7bcc Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Mon, 22 Sep 2025 09:54:52 +0200 Subject: [PATCH] state: remove mutex Signed-off-by: Kristoffer Dalby --- hscontrol/state/debug.go | 6 ------ hscontrol/state/state.go | 25 ------------------------- 2 files changed, 31 deletions(-) diff --git a/hscontrol/state/debug.go b/hscontrol/state/debug.go index dbe790fa..03d6854f 100644 --- a/hscontrol/state/debug.go +++ b/hscontrol/state/debug.go @@ -60,9 +60,6 @@ type DebugStringInfo struct { // DebugOverview returns a comprehensive overview of the current state for debugging. func (s *State) DebugOverview() string { - s.mu.Lock() - defer s.mu.Unlock() - allNodes := s.nodeStore.ListNodes() users, _ := s.ListAllUsers() @@ -265,9 +262,6 @@ func (s *State) DebugPolicyManager() string { // PolicyDebugString returns a debug representation of the current policy. func (s *State) PolicyDebugString() string { - s.mu.Lock() - defer s.mu.Unlock() - return s.polMan.DebugString() } diff --git a/hscontrol/state/state.go b/hscontrol/state/state.go index 6315d8f2..47f78fd3 100644 --- a/hscontrol/state/state.go +++ b/hscontrol/state/state.go @@ -23,7 +23,6 @@ import ( "github.com/juanfont/headscale/hscontrol/types/change" "github.com/juanfont/headscale/hscontrol/util" "github.com/rs/zerolog/log" - "github.com/sasha-s/go-deadlock" "golang.org/x/sync/errgroup" "gorm.io/gorm" "tailscale.com/net/tsaddr" @@ -48,9 +47,6 @@ var ErrUnsupportedPolicyMode = errors.New("unsupported policy mode") // State manages Headscale's core state, coordinating between database, policy management, // IP allocation, and DERP routing. All methods are thread-safe. type State struct { - // mu protects all in-memory data structures from concurrent access - mu deadlock.RWMutex - // cfg holds the current Headscale configuration cfg *types.Config @@ -202,9 +198,6 @@ func (s *State) DERPMap() tailcfg.DERPMapView { // ReloadPolicy reloads the access control policy and triggers auto-approval if changed. // Returns true if the policy changed. func (s *State) ReloadPolicy() ([]change.ChangeSet, error) { - s.mu.Lock() - defer s.mu.Unlock() - pol, err := policyBytes(s.db, s.cfg) if err != nil { return nil, fmt.Errorf("loading policy: %w", err) @@ -245,9 +238,6 @@ func (s *State) ReloadPolicy() ([]change.ChangeSet, error) { // CreateUser creates a new user and updates the policy manager. // Returns the created user, change set, and any error. func (s *State) CreateUser(user types.User) (*types.User, change.ChangeSet, error) { - s.mu.Lock() - defer s.mu.Unlock() - if err := s.db.DB.Save(&user).Error; err != nil { return nil, change.EmptySet, fmt.Errorf("creating user: %w", err) } @@ -276,9 +266,6 @@ func (s *State) CreateUser(user types.User) (*types.User, change.ChangeSet, erro // UpdateUser modifies an existing user using the provided update function within a transaction. // Returns the updated user, change set, and any error. func (s *State) UpdateUser(userID types.UserID, updateFn func(*types.User) error) (*types.User, change.ChangeSet, error) { - s.mu.Lock() - defer s.mu.Unlock() - user, err := hsdb.Write(s.db.DB, func(tx *gorm.DB) (*types.User, error) { user, err := hsdb.GetUserByID(tx, userID) if err != nil { @@ -355,9 +342,6 @@ func (s *State) ListAllUsers() ([]types.User, error) { // This ensures the NodeStore is the source of truth for the batcher and maintains consistency. // Returns error only; callers should get the updated NodeView from NodeStore to maintain consistency. func (s *State) updateNodeTx(nodeID types.NodeID, updateFn func(tx *gorm.DB) error) error { - s.mu.Lock() - defer s.mu.Unlock() - _, err := hsdb.Write(s.db.DB, func(tx *gorm.DB) (*types.Node, error) { if err := updateFn(tx); err != nil { return nil, err @@ -380,9 +364,6 @@ func (s *State) updateNodeTx(nodeID types.NodeID, updateFn func(tx *gorm.DB) err // persistNodeToDB saves the current state of a node from NodeStore to the database. // CRITICAL: This function MUST get the latest node from NodeStore to ensure consistency. func (s *State) persistNodeToDB(nodeID types.NodeID) (types.NodeView, change.ChangeSet, error) { - s.mu.Lock() - defer s.mu.Unlock() - // CRITICAL: Always get the latest node from NodeStore to ensure we save the current state node, found := s.nodeStore.GetNode(nodeID) if !found { @@ -1068,9 +1049,6 @@ func (s *State) HandleNodeFromAuthPath( expiry *time.Time, registrationMethod string, ) (types.NodeView, change.ChangeSet, error) { - s.mu.Lock() - defer s.mu.Unlock() - // Get the registration entry from cache regEntry, ok := s.GetRegistrationCacheEntry(registrationID) if !ok { @@ -1270,9 +1248,6 @@ func (s *State) HandleNodeFromPreAuthKey( regReq tailcfg.RegisterRequest, machineKey key.MachinePublic, ) (types.NodeView, change.ChangeSet, error) { - s.mu.Lock() - defer s.mu.Unlock() - pak, err := s.GetPreAuthKey(regReq.Auth.AuthKey) if err != nil { return types.NodeView{}, change.EmptySet, err