Skip to content
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

feat: port context-aware cond to gobox #325

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open

Conversation

AndrewWinterman
Copy link
Contributor

@AndrewWinterman AndrewWinterman commented Jul 18, 2023

I've been using this for a few months in polaroid (non-generic version), so I figured it's reasonable at this point to port it to GoBox,

What this PR does / why we need it

Jira ID

I didn't make a ticket for this because I'm really just trying to be a good citizen here, this isn't part of feature work or anything.

[XX-XX]

Notes for your reviewers

I've been using this for a few months in polaroid (non-generic version), so I figured it's reasonable at this point to port it to GoBox,
@AndrewWinterman AndrewWinterman requested a review from a team as a code owner July 18, 2023 21:40
Copy link
Contributor

@jkinkead jkinkead left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments / suggestions.

pkg/async/cond.go Outdated Show resolved Hide resolved
pkg/async/cond.go Outdated Show resolved Hide resolved
pkg/async/cond.go Outdated Show resolved Hide resolved
pkg/async/cond.go Outdated Show resolved Hide resolved
pkg/async/cond.go Outdated Show resolved Hide resolved
because Jesse was worried about extra allocations, I aded a couple of benchmarks which also revealed a race that could result in an NPE:

```
BenchmarkCond
BenchmarkCond/one_broadcasts;_one_wait
BenchmarkCond/one_broadcasts;_one_wait-10         	     100	  11171022 ns/op	         1.170 ms_corrected/op	     489 B/op	       9 allocs/op
BenchmarkCond/one_broadcasts;_many_waiters
BenchmarkCond/one_broadcasts;_many_waiters-10     	     100	  11239043 ns/op	         1.230 ms_corrected/op	    2023 B/op	      37 allocs/op
PASS
```
@AndrewWinterman
Copy link
Contributor Author

because Jesse was worried about extra allocations, I aded a couple of benchmarks which also revealed a race that could result in an NPE:

BenchmarkCond
BenchmarkCond/one_broadcasts;_one_wait
BenchmarkCond/one_broadcasts;_one_wait-10         	     100	  11171022 ns/op	         1.170 ms_corrected/op	     489 B/op	       9 allocs/op
BenchmarkCond/one_broadcasts;_many_waiters
BenchmarkCond/one_broadcasts;_many_waiters-10     	     100	  11239043 ns/op	         1.230 ms_corrected/op	    2023 B/op	      37 allocs/op
PASS

pkg/async/cond.go Show resolved Hide resolved
pkg/async/cond.go Show resolved Hide resolved
@AndrewWinterman AndrewWinterman enabled auto-merge (squash) July 21, 2023 23:42
@jaredallard jaredallard requested a review from jkinkead July 24, 2023 16:46
Copy link
Contributor

@jkinkead jkinkead left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly LGTM! One small bug and a couple of comment suggestions.

// a condition, and releasing the lock before waiting for a state change if the condition is not met.
type Cond struct {
pointer atomic.Pointer[chan struct{}]
Mu sync.Mutex
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Document public field?

Comment on lines +31 to +33
t := make(chan struct{})
c.pointer.CompareAndSwap(nil, &t)
return t
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't handle the race where two threads enter this if block at the same time. You should return the value of c.pointer.Load() here (although technically only needed if CompareAndSwap returns false).

Correct verbose version:

Suggested change
t := make(chan struct{})
c.pointer.CompareAndSwap(nil, &t)
return t
t := make(chan struct{})
if c.pointer.CompareAndSwap(nil, &t) {
return t
}
return c.pointer.Load()

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably should close t in my example before line 35.

pkg/async/cond.go Outdated Show resolved Hide resolved
}
}

// WaitForCondition acquires Cond's lock, then checks if the condition is true. If the condition is not true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarify what the lock actually is (and use the receiver name):

Suggested change
// WaitForCondition acquires Cond's lock, then checks if the condition is true. If the condition is not true,
// WaitForCondition acquires c.Mu, then checks if the condition is true. If the condition is not true,

pkg/async/cond.go Outdated Show resolved Hide resolved
// This method encapsulates the instructions in sync.Cond.Wait:
//
// """
// Because c.L is not locked while Wait is waiting, the caller
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update L to Mu throughout the example?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yah, thanks!

AndrewWinterman and others added 2 commits August 7, 2023 14:31
Co-authored-by: Jesse Kinkead <jesse.kinkead@outreach.io>
Co-authored-by: Jesse Kinkead <jesse.kinkead@outreach.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants