mirror of
https://github.com/minio/minio.git
synced 2025-11-09 05:34:56 -05:00
fix: Avoid more crashes due to concurrent map usage (#5912)
This PR fixes another situation where a crash occurs thanks to @krishnasrinivas for reproducing this Fixes #5897
This commit is contained in:
committed by
Dee Koder
parent
c525424179
commit
4886bfbc72
@@ -56,32 +56,47 @@ func (list *TargetList) Exists(id TargetID) bool {
|
||||
return found
|
||||
}
|
||||
|
||||
// TargetIDErr returns error associated for a targetID
|
||||
type TargetIDErr struct {
|
||||
// ID where the remove or send were initiated.
|
||||
ID TargetID
|
||||
// Stores any error while removing a target or while sending an event.
|
||||
Err error
|
||||
}
|
||||
|
||||
// Remove - closes and removes targets by given target IDs.
|
||||
func (list *TargetList) Remove(ids ...TargetID) map[TargetID]error {
|
||||
func (list *TargetList) Remove(targetids ...TargetID) <-chan TargetIDErr {
|
||||
list.Lock()
|
||||
defer list.Unlock()
|
||||
|
||||
errors := make(map[TargetID]error)
|
||||
errCh := make(chan TargetIDErr)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for _, id := range ids {
|
||||
if target, ok := list.targets[id]; ok {
|
||||
wg.Add(1)
|
||||
go func(id TargetID, target Target) {
|
||||
defer wg.Done()
|
||||
if err := target.Close(); err != nil {
|
||||
errors[id] = err
|
||||
}
|
||||
}(id, target)
|
||||
go func() {
|
||||
defer close(errCh)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for _, id := range targetids {
|
||||
if target, ok := list.targets[id]; ok {
|
||||
wg.Add(1)
|
||||
go func(id TargetID, target Target) {
|
||||
defer wg.Done()
|
||||
if err := target.Close(); err != nil {
|
||||
errCh <- TargetIDErr{
|
||||
ID: id,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
}(id, target)
|
||||
}
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
wg.Wait()
|
||||
|
||||
for _, id := range ids {
|
||||
delete(list.targets, id)
|
||||
}
|
||||
for _, id := range targetids {
|
||||
delete(list.targets, id)
|
||||
}
|
||||
}()
|
||||
|
||||
return errors
|
||||
return errCh
|
||||
}
|
||||
|
||||
// List - returns available target IDs.
|
||||
@@ -98,27 +113,34 @@ func (list *TargetList) List() []TargetID {
|
||||
}
|
||||
|
||||
// Send - sends events to targets identified by target IDs.
|
||||
func (list *TargetList) Send(event Event, targetIDs ...TargetID) map[TargetID]error {
|
||||
func (list *TargetList) Send(event Event, targetIDs ...TargetID) <-chan TargetIDErr {
|
||||
list.Lock()
|
||||
defer list.Unlock()
|
||||
|
||||
errors := make(map[TargetID]error)
|
||||
errCh := make(chan TargetIDErr)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for _, id := range targetIDs {
|
||||
if target, ok := list.targets[id]; ok {
|
||||
wg.Add(1)
|
||||
go func(id TargetID, target Target) {
|
||||
defer wg.Done()
|
||||
if err := target.Send(event); err != nil {
|
||||
errors[id] = err
|
||||
}
|
||||
}(id, target)
|
||||
go func() {
|
||||
defer close(errCh)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for _, id := range targetIDs {
|
||||
if target, ok := list.targets[id]; ok {
|
||||
wg.Add(1)
|
||||
go func(id TargetID, target Target) {
|
||||
defer wg.Done()
|
||||
if err := target.Send(event); err != nil {
|
||||
errCh <- TargetIDErr{
|
||||
ID: id,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
}(id, target)
|
||||
}
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
wg.Wait()
|
||||
}()
|
||||
|
||||
return errors
|
||||
return errCh
|
||||
}
|
||||
|
||||
// NewTargetList - creates TargetList.
|
||||
|
||||
@@ -168,9 +168,9 @@ func TestTargetListRemove(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, testCase := range testCases {
|
||||
errors := testCase.targetList.Remove(testCase.targetID)
|
||||
err := errors[testCase.targetID]
|
||||
expectErr := (err != nil)
|
||||
errCh := testCase.targetList.Remove(testCase.targetID)
|
||||
err := <-errCh
|
||||
expectErr := (err.Err != nil)
|
||||
|
||||
if expectErr != testCase.expectErr {
|
||||
t.Fatalf("test %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr)
|
||||
@@ -255,9 +255,9 @@ func TestTargetListSend(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, testCase := range testCases {
|
||||
errors := testCase.targetList.Send(Event{}, testCase.targetID)
|
||||
err := errors[testCase.targetID]
|
||||
expectErr := (err != nil)
|
||||
errCh := testCase.targetList.Send(Event{}, testCase.targetID)
|
||||
err := <-errCh
|
||||
expectErr := (err.Err != nil)
|
||||
|
||||
if expectErr != testCase.expectErr {
|
||||
t.Fatalf("test %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr)
|
||||
|
||||
Reference in New Issue
Block a user