-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Request again when obtained data expires #2617
Conversation
A few notes on the current code: Requests are now monitoring until they're explicitly cancelled. We're also returning expired content (a big part of what #896 is about!). However, none of the stale content, or updating requests are used in code yet, since we immediately
|
3769781
to
f522765
Compare
Here's a script to try this out: Start the server with: git clone git@gist.github.com:d74ed2b193bbd1a9507f.git tileserver
cd tileserver
npm install
node index.js Apply this patch to diff --git a/macosx/Info.plist b/macosx/Info.plist
index 514db11..f0e5c7f 100644
--- a/macosx/Info.plist
+++ b/macosx/Info.plist
@@ -32,6 +32,11 @@
<string>0.0.1</string>
<key>NSHighResolutionCapable</key>
<true/>
+ <key>NSAppTransportSecurity</key>
+ <dict>
+ <key>NSAllowsArbitraryLoads</key>
+ <true/>
+ </dict>
<key>CFBundleURLTypes</key>
<array>
<dict>
diff --git a/platform/default/default_styles.cpp b/platform/default/default_styles.cpp
index 9ee5414..2382e5c 100644
--- a/platform/default/default_styles.cpp
+++ b/platform/default/default_styles.cpp
@@ -4,6 +4,7 @@ namespace mbgl {
namespace util {
const std::vector<std::pair<std::string, std::string>> defaultStyles = {
+ { "http://localhost:3000/style.json", "Test" },
{ "asset://styles/streets-v8.json", "Mapbox Streets" },
{ "asset://styles/emerald-v8.json", "Emerald" },
{ "asset://styles/light-v8.json", "Light" },
Then, start the The server sends out tiles with a |
f522765
to
eeebca7
Compare
/cc @jfirebaugh |
eeebca7
to
b43b1e8
Compare
|
||
class Request; | ||
|
||
class RequestHolder { |
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.
What's the reason for a separate RequestHolder
class, rather than the usual pattern of returning a std::unique_ptr<Request>
and having ~Request
auto-cancel?
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 implemented this at first, but backtracked because the pull request grew too big due to too many changes necessary for the unit tests. I'll try again.
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.
Feel free to ticket and queue up for a later PR if you want.
1c3b1b5
to
c0de7cd
Compare
@kkaefer Did a quick test on Android. No problems found. And MapView is correctly GC'd. 👍 |
Looks good @kkaefer |
@@ -87,21 +113,15 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr | |||
return; | |||
} | |||
|
|||
// This is a singular layer. Check if this bucket already exists. | |||
if (getBucket(layer)) |
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.
What's happening here? I believe this check is what makes the layer ref
mechanism efficient, by avoiding creating duplicate buckets for the referent layers.
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 used to be the case, but the parsing is now split up into two distinct step: The initial bucket creation, and the actual parsing. We're no longer creating a new bucket just to throw away that object if we realize we don't have the resources yet. Instead, we're creating all bucket objects just once, then try to parse. If that doesn't work just yet, we're saving the bucket for later. All later "parse" steps will call parsePendingLayers
, which just processes the buckets we saved for later.
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.
Where does ref
deduping happen, exactly? I'm still not seeing that.
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 you're right. Will add that back.
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 is now done before even calling parseLayer()
.
c0de7cd
to
4ca70c9
Compare
4ca70c9
to
2067b4b
Compare
if (angle == currentAngle && pitch == currentPitch && collisionDebug == currentCollisionDebug) | ||
return; | ||
|
||
if (workRequest) { |
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.
Shouldn't this check should go after the assignments to lastAngle
, etc, so that when the callback calls redoPlacement
again it uses the most recent values?
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.
Yup, cleaned this up.
By not automatically destroying Request objects after the result has been delivered, we are making sure that we can potentially fire the callback multiple times without adverse effects. This means that you have to hold on to the result of fs->request(), can explicitly cancel it if you don't want to be notified of data changes anymore. Not doing so will monitor the request indefinitely and will prevent the app from exiting.
We're now returning stale responses from cache. Those responses will have the `stale` flag set to true. Currently, all requesters in the core code discard stale responses, and cancel the request immediately after they got a non-stale response.
When we get a request with an explicit expiration time, we're now starting a timer, and will trigger a refresh once the data expires. This gives requesters a chance to update their data.
It's not implemented in GCC 4.9.2's stdlib (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57250). Instead, we're now always using a mutex to protect access; we previously created a mutex only on cancelation, but since we're always canceling now, it makes sense to allocate it right away.
We're now reparsing tiles when they expire. We're also swapping out buckets atomically to avoid flickering data; i.e. we're displaying the old data as long as we don't have a new parsed bucket for that layer yet. The parsed buckets now live in the *TileData objects rather than in the TileWorker; only partially parsed == pending buckets will remain in the TileWorker. Once they're parsed, they're moved to the *TileData object.
2067b4b
to
a3a9478
Compare
Fixes an issue where updates to stale tiles would remove labels altogether until the map was rotated.
a3a9478
to
75dec6f
Compare
// the layer ordering needs to be respected when calculating text | ||
// collisions. Although, at this point, we requested all the resources | ||
// needed by this tile. | ||
if (partialParse) { |
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.
Does this change how partial parsing works? Previously, because partialParse
was a member variable, if any symbol bucket needed dependencies, all subsequent symbol buckets would be treated as partial. Now it looks like only a bucket that needsDependencies
is treated as partial. From my reading of the above comment, the previous behavior was intentional.
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.
We can create new buckets in an arbitrary order; the only place where order matters is when calling SymbolBucket::placeFeatures
. In the current scenario it's indeed possible that we're placing buckets in the wrong order. Will create a pull request that fixes this.
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.
See #2820
We're currently treating a request as a one-time thing. We should change this to have "Request" mean "monitor this resource and send me updates about it". This means that the file source needs to keep track of when the resource expires, and issue a new request once it expires. This solves the following cases: