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

fix: some crashes have come up because of logger injection. the reason seems to be the the binder is being updated every inject #387

Merged
merged 4 commits into from
Feb 23, 2021

Conversation

thomaszurkan-optimizely
Copy link
Contributor

@thomaszurkan-optimizely thomaszurkan-optimizely commented Feb 12, 2021

Summary

There have been a small number of crashes reported and it appears to be the injection of loggers from multiple threads at the same time. This is because the binder was updating the instance variable even when the binder was always suppling new instances (i.e. when not a singleton).

The fix is two fold:

  1. If it is not a singleton just return a new instance via the factory and return.
  2. Convert Binders to structs so there is a copy on read and a copy on write. This way, any changes to the binders are changes to a copy and then the updating of the binder goes through an atomic property so the setter is atomic.

@coveralls
Copy link

coveralls commented Feb 12, 2021

Coverage Status

Coverage decreased (-0.09%) to 98.662% when pulling ab315a7 on binderFix into f1995d5 on master.

@thomaszurkan-optimizely thomaszurkan-optimizely changed the title WIP: first step in fixing binder fix: first step in fixing binder Feb 12, 2021
@thomaszurkan-optimizely thomaszurkan-optimizely changed the title fix: first step in fixing binder fix: some crashes have come up because of logger injection. the reason seems to be the the binder is being updated every inject Feb 12, 2021
Copy link
Collaborator

@jaeopt jaeopt left a comment

Choose a reason for hiding this comment

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

It looks good for fixing the logger issue.
We still have unsafe dictionaries as other possible sync failure sources. Can we fix them all?

@@ -17,6 +17,18 @@
import UIKit
import Optimizely

private final class CustomLogger: OPTLogger {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is redundant with the separate CustomLogger file. I see you changed it to private. Is it required?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, I just wanted to make sure it wasn't a problem if it was private.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Then let's keep it internal and remove this extra copy (or the other one).

Comment on lines +56 to +60
if binders.property?[skLocal] != nil {
binders.property?[skLocal] = b
} else {
binders.property?[skGlobal] = b
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Don't we need synchronization to update binders dictionary?
Let's fix this unsafe dictionaries/arrays in other places as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

the binder set is an atomic property. the binder is a copy and so this is an atomic operation. the get and set are separate. but, the again, since this is only an issue with a singleton that usually provides a instance with creation. it should not be an issue. i don't want to slow everything down by constantly wrapping everything in a dispatch.

@thomaszurkan-optimizely
Copy link
Contributor Author

It looks good for fixing the logger issue.
We still have unsafe dictionaries as other possible sync failure sources. Can we fix them all?

Can you tell me where we are accessing unsafe dictionaries? I would handle that with a synched dictionary not by augment ing the atomic property by the way.

Copy link
Collaborator

@jaeopt jaeopt left a comment

Choose a reason for hiding this comment

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

The test is broken and cannot catch the thread issue here.

}
}
// need to let the main global queue run otherwise some remained queued.
Thread.sleep(forTimeInterval: 0.02)
Copy link
Collaborator

Choose a reason for hiding this comment

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

This sleep delay breaks the test. 1000 async tasks not concurrent any more because this delay.
If we remove the sleep delay and using DispatchGroup for sync, this test fails because concurrency issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This sleep delay breaks the test. 1000 async tasks not concurrent any more because this delay.
If we remove the sleep delay and using DispatchGroup for sync, this test fails because concurrency issue.

Please add a test if you think it would break. The test won't run all the queued in the global queue without the sleep. So.....

@jaeopt jaeopt self-requested a review February 23, 2021 19:23
Copy link
Collaborator

@jaeopt jaeopt left a comment

Choose a reason for hiding this comment

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

Approved for logger bug fix.
The other thread issue I raised can be separated and will be reviewed later instead of blocking this fix.

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.

4 participants