[#1700] gc: Fix deadlock

`HandleExpiredLocks` gets read lock, then `shard.Close` tries to acquire
write lock, but `HandleExpiredLocks` calls `inhumeUnlockedIfExpired` or
`selectExpired`, that try to acquire read lock again.

Change-Id: Ib2ed015e859328045b5a542a4f569e5e0ff8b05b
Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
This commit is contained in:
Dmitrii Stepanov 2025-04-15 10:06:05 +03:00
parent 48930ec452
commit 0712c113de
Signed by: dstepanov-yadro
GPG key ID: 237AF1A763293BC0

View file

@ -391,6 +391,16 @@ func (s *Shard) handleExpiredObjects(ctx context.Context, expired []oid.Address)
return
}
s.handleExpiredObjectsUnsafe(ctx, expired)
}
func (s *Shard) handleExpiredObjectsUnsafe(ctx context.Context, expired []oid.Address) {
select {
case <-ctx.Done():
return
default:
}
expired, err := s.getExpiredWithLinked(ctx, expired)
if err != nil {
s.log.Warn(ctx, logs.ShardGCFailedToGetExpiredWithLinked, zap.Error(err))
@ -611,13 +621,6 @@ func (s *Shard) getExpiredObjects(ctx context.Context, epoch uint64, onExpiredFo
}
func (s *Shard) selectExpired(ctx context.Context, epoch uint64, addresses []oid.Address) ([]oid.Address, error) {
s.m.RLock()
defer s.m.RUnlock()
if s.info.Mode.NoMetabase() {
return nil, ErrDegradedMode
}
release, err := s.opsLimiter.ReadRequest(ctx)
if err != nil {
return nil, err
@ -728,7 +731,7 @@ func (s *Shard) inhumeUnlockedIfExpired(ctx context.Context, epoch uint64, unloc
return
}
s.handleExpiredObjects(ctx, expiredUnlocked)
s.handleExpiredObjectsUnsafe(ctx, expiredUnlocked)
}
// HandleDeletedLocks unlocks all objects which were locked by lockers.