-
Notifications
You must be signed in to change notification settings - Fork 8
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
Allow concurrent calls for Fake methods. #16
Conversation
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.
Oops, I'm surprised we didn't run into this already...
fake.go
Outdated
) | ||
|
||
// Fake is a fake implementation of Interface | ||
type Fake struct { | ||
nftContext | ||
// lock is used to protect Table and LastTransaction. | ||
// When Table and LastTransaction are accessed directly, it is caller's responsibility | ||
// to ensure there is no data race. |
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.
That's no good... should probably make them private members, and add accessors for them that do proper locking.
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 didn't want to break existing users, but if you think it is ok, I can make them private
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.
later discussed on slack; just adding accessors doesn't work because you'd have to deep-copy Table. So maybe it would make more sense to expose the locking to the caller. Make the sync.Mutex
an embedded field like the nftContext
, and document the fact that you need to .RLock()
it if you are going to look directly at Table
.
Maybe .LastTransaction
should be changed to .GetLastTransaction()
though, with locking. (The transaction itself would be read-only at this point, so you don't have to worry about locking after you access the pointer.)
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.
made lock methods external, added little comments
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.
Not sure I like that idea of GetLastTransaction
because it
- is inconsistent with Table access, which is a bit strange
- will limit potential changes in the future if we ever need to make LastTransaction not-read-only.
wdyt?
fake.go
Outdated
) | ||
|
||
// Fake is a fake implementation of Interface | ||
type Fake struct { | ||
nftContext | ||
// mutex is used to protect Table and LastTransaction. | ||
// When Table and LastTransaction are accessed directly, the caller must acquire Fake.Rlock |
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.
// When Table and LastTransaction are accessed directly, the caller must acquire Fake.Rlock | |
// When Table and LastTransaction are accessed directly, the caller must acquire Fake.RLock |
and below
fake.go
Outdated
// Make sure to acquire Fake.Rlock before accessing Table in a concurrent environment. | ||
LastTransaction *Transaction |
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.
// Make sure to acquire Fake.Rlock before accessing Table in a concurrent environment. | |
LastTransaction *Transaction | |
// Make sure to acquire Fake.Rlock before accessing LastTransaction in a concurrent environment. | |
LastTransaction *Transaction |
But that feels wrong anyway... LastTransaction
is inherently non-concurrency-safe; you can only know that it has the transaction you want if you already know for sure what the most recent Run()
call was. So maybe just add a warning about that. "This is probably not useful if Interface is being used concurrently." ?
And I guess that's an argument against GetLastTransaction()
.
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 think it may be useful for concurrent usage also.
Let's say there is a controller thread running transactions, and test thread checking if it is correct.
On every change I make explicitly in the test, controller is expected to make exactly one transaction, but it may take time to reconcile. I will periodically check from the test thread LastTransaction
until I see expected transaction, but to make it non-racy, I need to make sure I have RLock while reading LastTransaction.
Signed-off-by: Nadia Pinaeva <[email protected]>
/lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: danwinship, npinaeva The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Before, calling
fake.Run
andfake.Dump
from different goroutines caused a data race.