-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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 race condition causing SymbolBucket isEmpty errors #3681
Conversation
Can you describe what the race was? |
@jfirebaugh sure — here's what I gather:
(In all other layer cases, ArrayGroups are created in the bucket's constructor unless already present (here)) I guess the alternate fix here might be something like: create another nested function inside (Also in looking into this I realized that |
What do you mean by The behavior as I understand it is:
So I'm still not clear on how we can wind up with symbol buckets without
|
@lbud @jfirebaugh I hit a similar race/exception a few weeks ago during the WaPo project, but I had thought it was because of our hacky custom source, and so didn't report it here. Possibly unrelated to what's happening here, but I'll describe in case it's helpful. Essentially, the issue I had was inconsistent state in the glyph/icon callbacks. I think was happening for us looked something like:
|
@anandthakker Doesn't mapbox-gl-js/js/source/vector_tile_source.js Lines 71 to 72 in 85097c3
reloadTile being called for a tile that hasn't completed loading yet?
|
@jfirebaugh Ah. Yeah, it does... maybe it was two |
Yeah, looks like two |
@jfirebaugh @anandthakker thanks for the help — I was able to demonstrate that condition where it's reloading a tile before a previous |
…middle of parsing for a given tile
😞 thought I fixed this in 07c9d5a, but upon further interaction with the map (rotating/pitching, so I suspect |
The redoPlacement race I mentioned is unrelated to the above fix (so presumably should be replicable outside of this branch — will verify) and occurs when
meanwhile, in the
At this point,
(Presumably (though I haven't confirmed yet) resetting symbol buckets' arrays while |
Confirmed that the above AssertionError can be nearly replicated in master — the |
Hi guys, are you anywhere near getting this merged and included in a release? I'm experiencing the problems described in #3663 (I'm using |
…es race condition between WorkerTile.parse and WorkerTile.redoPlacement
@bbodien yes, we are actively working on it and will include the fix in the next release. |
I think this is ready — @jfirebaugh could I bother you for a review? 🙏 OP updated to reflect issues/fixes. |
Can you explain this in more detail? Bucket serialization is a synchronous operation, so I'm not clear how it can interleave with |
@jfirebaugh per chat, I was mistaken in my diagnosis of the problem (based on the single worker thread being synchronous) but had inadvertently fixed it by moving |
… to be more localized since it is not needed in featureIndex
@jfirebaugh capturing from voice: I
|
Almost there -- the last thing I see is that the |
… uses the most up-to-date angle and pitch
@jfirebaugh 👍 addressed in dbd4259 (also, looks like we were not updating |
@@ -144,14 +141,9 @@ class WorkerTile { | |||
deps++; | |||
if (deps === 2) { | |||
for (const bucket of this.symbolBuckets) { | |||
// Layers are shared and may have been used by a WorkerTile with a different zoom. |
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.
This needs to happen immediately prior to prepare
as well, since prepare
uses layer properties. (Making this less fragile is tracked in #3479.)
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.
👍
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.
🎉
Fixes #3663 which was introduced after recent optimizations.Unfortunately since was caused by a race condition I don't think we could create a useful regression test…edited to summarize the below discussion + better reflect what this PR does:
Fixes #3663:
VectorTileWorkerSource#reloadTile
would interleave calls toparse
for the same tile, which would cause its SymbolBucket members to reset themselves while assumed to be complete for the purpose of transference. SymbolBucket.prototype.isEmpty throws TypeErrors on startup #3663 then spewed errors because in serializing buckets, some symbol buckets didn't have anarrays
member with its array groups.VectorTileWorkerSource#reloadTile
now checks to see if its WorkerTile is still parsing (using the existingWorkerTile.status
), if so, defers its next parse until it receives a response from the first: vector_tile_worker_source.js#L89-L102WorkerTile.redoPlacement
got deferred if a previousparse
call to the same tile wasn't finished (withWorkerTile.redoPlacementAfterDone
); and then were called inWorkerTile#parse
'sdone
function, after receiving glyph/icon assets and re-parsing symbol buckets but before serializing buckets to return via theparse
callback. This meant the subset of buckets that were re-placed inredoPlacement
— all symbol buckets — were already serialized and tripping assertion errors hereWorkerTile#parse
andWorkerTile#redoPlacement
would be whenWorkerTile#parse
is waiting on glyph/icon assets from the main thread.WorkerTile#parse
only places symbols after this, meaning we'd never need to re-call a deferredredoPlacement
after this as it would return the same result. To fix, I removed theredoPlacementAfterDone
concept altogether here; those interleavedredoPlacement
calls setthis.pitch
and then return.