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

producer/consumer: clean up logging races #108

Merged
merged 1 commit into from
Feb 6, 2015
Merged

producer/consumer: clean up logging races #108

merged 1 commit into from
Feb 6, 2015

Conversation

judwhite
Copy link
Contributor

@judwhite judwhite commented Feb 4, 2015

producer: log method has potential for edge case race condition
(checking nil then using); logger/logLvl could be set anytime, added
Lock in SetLogger, RLock in log and connect methods
producer: remove unnecessary continue in transactionCleanup for select

@mreiferson
Copy link
Member

Hi @judwhite thanks for finding this and the proposed fix. I'd prefer to use atomic.Load/StorePointer rather than locks, feels a bit heavy as written.

@mreiferson mreiferson added the bug label Feb 4, 2015
@judwhite
Copy link
Contributor Author

judwhite commented Feb 5, 2015

@mreiferson if we do that we should include logLvl for the (admittedly edge case) scenario where a partial write could be read from that address. we'll also have to accept that logger and logLvl may be out of sync for a brief moment if in the middle of a call to SetLogger and log is called - the uglier one is if NewConn is called and they're out of sync.

this could also be solved by including the logger/logLvl in the sig of NewProducer, drop SetLogger and not add any locks/atomics - though it's a breaking API change, an annoyance to all for a theoretical issue.

you could also do nothing and add a comment that SetLogger is expected to be called once during initialization. it keeps the code less complicated and documents assumptions.

let me know your thoughts and I'll update.

@mreiferson
Copy link
Member

Ok, you've sold me on this approach. I've got a separate code comment 😁

@@ -201,7 +205,11 @@ func (w *Producer) sendCommandAsync(cmd *Command, doneChan chan *ProducerTransac

func (w *Producer) connect() error {
w.guard.Lock()
defer w.guard.Unlock()
w.logGuard.RLock()
Copy link
Member

Choose a reason for hiding this comment

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

let's wrap logGuard around a smaller critical section (without a defer) and store the w.logger in a local var for passing it along into the new connection instantiation

@mreiferson
Copy link
Member

Do we have the same race condition on Consumer?

@judwhite
Copy link
Contributor Author

judwhite commented Feb 5, 2015

@mreiferson what do you think about this approach? if you like it I'll do the same for Conn and Consumer. the intent is to isolate the scope of the critical sections and provide a safe way to read/write logger/logLvl.

@mreiferson
Copy link
Member

even better, nice work 👍

@judwhite
Copy link
Contributor Author

judwhite commented Feb 6, 2015

@mreiferson ready for review

@mreiferson mreiferson changed the title producer: add log rwmutex; remove extra continue clean up logging races Feb 6, 2015
@mreiferson mreiferson changed the title clean up logging races producer/consumer: clean up logging races Feb 6, 2015
@mreiferson
Copy link
Member

cool LGTM

mind squashing commits down?

@judwhite
Copy link
Contributor Author

judwhite commented Feb 6, 2015

will do

producer/consumer/conn: add getLogger to sync r/w access
remove extra continue
jehiah added a commit that referenced this pull request Feb 6, 2015
producer/consumer: clean up logging races
@jehiah jehiah merged commit e461358 into nsqio:master Feb 6, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants