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

Allow writes and read to not block SpanSinkImpl and only synchronize flush calls #547

Merged
merged 2 commits into from
Mar 12, 2024

Conversation

bidetofevil
Copy link
Collaborator

@bidetofevil bidetofevil commented Mar 12, 2024

Goal

First step to persisting active spans is to sort out the concurrency story and ensuring that we don't lose data if the app crashes in a state where recorded spans are only in memory.

This change stores the flushed spans in a separate list that we can serialize before clearing the completedSpans queue.

Testing

Added test to test race condition caused by concurrent access.

Copy link
Collaborator Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

Join @bidetofevil and the rest of your teammates on Graphite Graphite

Copy link

codecov bot commented Mar 12, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 80.12%. Comparing base (fb350b3) to head (f2bbde3).
Report is 10 commits behind head on master.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #547      +/-   ##
==========================================
+ Coverage   79.73%   80.12%   +0.39%     
==========================================
  Files         409      412       +3     
  Lines       10938    10986      +48     
  Branches     1614     1617       +3     
==========================================
+ Hits         8721     8803      +82     
+ Misses       1569     1538      -31     
+ Partials      648      645       -3     
Files Coverage Δ
.../android/embracesdk/internal/spans/SpanSinkImpl.kt 85.71% <100.00%> (ø)

... and 19 files with indirect coverage changes

@bidetofevil bidetofevil marked this pull request as ready for review March 12, 2024 07:03
@bidetofevil bidetofevil requested a review from a team as a code owner March 12, 2024 07:03
Copy link
Contributor

@lucaslabari lucaslabari left a comment

Choose a reason for hiding this comment

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

LGTM

return completedSpans.toList()
}
val spansToReturn = completedSpans.size
return completedSpans.take(spansToReturn)
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this needed? Instead of just returning completedSpans.toList()

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Because we're not synchronizing this and and write, we can have the completedSpans queue being modified while we are taking a snapshot. Just to be predictable especially for the flush use case, we are doing this so we aren't trying to flush events that were added while the flush was taking place.

Once the flush is triggered, everything that comes after should not be part of what's being flushed.

synchronized(spansToFlush) {
spansToFlush.set(completedSpans())
repeat(spansToFlush.get().size) {
completedSpans.removeAll(spansToFlush.get().toSet())
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this correct? removing all as many times as spans in the list?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

hahaha this is ABSOLUTELY not correct - I will change.

I had a previous implementation that polled N times to remove and add to the flushed spans, but that leaves the the object in a weird state if it crashes in the middle. Doing this atomically works much better even if I have to convert this to a set first.

@lucaslabari lucaslabari self-requested a review March 12, 2024 13:09
Copy link
Contributor

@lucaslabari lucaslabari left a comment

Choose a reason for hiding this comment

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

Left a couple of comments

@bidetofevil bidetofevil force-pushed the hho/improve-spanSink-concurrency branch from a9c0107 to f2bbde3 Compare March 12, 2024 17:17
@bidetofevil bidetofevil merged commit 7d88675 into master Mar 12, 2024
5 checks passed
@bidetofevil bidetofevil deleted the hho/improve-spanSink-concurrency branch March 12, 2024 17:38
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.

None yet

2 participants