-
-
Notifications
You must be signed in to change notification settings - Fork 640
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: use a sync.Map to prevent "concurrent map read and map write" fa… #1923
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 | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -5,22 +5,23 @@ import ( | |||||||
"fmt" | ||||||||
"io" | ||||||||
"strings" | ||||||||
"sync" | ||||||||
|
||||||||
"github.com/go-task/task/v3/internal/logger" | ||||||||
"github.com/go-task/task/v3/internal/templater" | ||||||||
) | ||||||||
|
||||||||
type Prefixed struct { | ||||||||
logger *logger.Logger | ||||||||
seen map[string]uint | ||||||||
seen *sync.Map | ||||||||
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. Can we simply use a mutex for protecting the
Suggested change
Additionally, 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. From the go docs of
I think that applies here, because potentially a lot of lines get written and only relatively few prefixes will be used. I think speed is important here since task execution blocks waiting for output to be written. But I have no strong opinion about either way, and we would have to benchmark to check which is actually faster. One drawback of |
||||||||
counter *uint | ||||||||
} | ||||||||
|
||||||||
func NewPrefixed(logger *logger.Logger) Prefixed { | ||||||||
var counter uint | ||||||||
|
||||||||
return Prefixed{ | ||||||||
seen: make(map[string]uint), | ||||||||
seen: &sync.Map{}, | ||||||||
counter: &counter, | ||||||||
logger: logger, | ||||||||
} | ||||||||
|
@@ -85,11 +86,11 @@ func (pw *prefixWriter) writeLine(line string) error { | |||||||
line += "\n" | ||||||||
} | ||||||||
|
||||||||
idx, ok := pw.prefixed.seen[pw.prefix] | ||||||||
idx, ok := pw.prefixed.seen.Load(pw.prefix) | ||||||||
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. Perhaps LoadOrStore() is better than Load() and then Store()? 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. You're right, that would be neater. But I will await the below discussion about |
||||||||
|
||||||||
if !ok { | ||||||||
idx = *pw.prefixed.counter | ||||||||
pw.prefixed.seen[pw.prefix] = idx | ||||||||
pw.prefixed.seen.Store(pw.prefix, idx) | ||||||||
|
||||||||
*pw.prefixed.counter++ | ||||||||
} | ||||||||
|
@@ -98,7 +99,7 @@ func (pw *prefixWriter) writeLine(line string) error { | |||||||
return nil | ||||||||
} | ||||||||
|
||||||||
color := PrefixColorSequence[idx%uint(len(PrefixColorSequence))] | ||||||||
color := PrefixColorSequence[idx.(uint)%uint(len(PrefixColorSequence))] | ||||||||
pw.prefixed.logger.FOutf(pw.writer, color, pw.prefix) | ||||||||
|
||||||||
if _, err := fmt.Fprint(pw.writer, "] "); err != nil { | ||||||||
|
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.
Perhaps we need to add a test case to ensure that this PR fixes an issue.
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.
I can try to write one that is deterministic, but since this is a race condition i'm not sure that's possible.