Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
[core] make sure tiles are not treated as complete until all worker o…
Browse files Browse the repository at this point in the history
…perations completed

Previously, when we started a worker operation that eventually throws an exception (e.g. due to the tile not being parseable), and then enqueue another worker operation while the first one is processing, we treated the worker as idle once the first operation's error callback fired, even though the second operation was still in progress. Due to our use of coalescing, I was unable to come up with a reliable test since we'd need to reproduce the behavior described above, which is timing dependent.
  • Loading branch information
kkaefer committed Sep 21, 2017
1 parent 6dfb4ec commit 82bdd52
Show file tree
Hide file tree
Showing 11 changed files with 57 additions and 51 deletions.
13 changes: 8 additions & 5 deletions src/mbgl/tile/geometry_tile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,20 +116,21 @@ void GeometryTile::redoLayout() {
worker.invoke(&GeometryTileWorker::setLayers, std::move(copy), correlationID);
}

void GeometryTile::onLayout(LayoutResult result) {
void GeometryTile::onLayout(LayoutResult result, const uint64_t resultCorrelationID) {
loaded = true;
renderable = true;
(void)resultCorrelationID;
nonSymbolBuckets = std::move(result.nonSymbolBuckets);
featureIndex = std::move(result.featureIndex);
data = std::move(result.tileData);
collisionTile.reset();
observer->onTileChanged(*this);
}

void GeometryTile::onPlacement(PlacementResult result) {
void GeometryTile::onPlacement(PlacementResult result, const uint64_t resultCorrelationID) {
loaded = true;
renderable = true;
if (result.correlationID == correlationID) {
if (resultCorrelationID == correlationID) {
pending = false;
}
symbolBuckets = std::move(result.symbolBuckets);
Expand All @@ -140,9 +141,11 @@ void GeometryTile::onPlacement(PlacementResult result) {
observer->onTileChanged(*this);
}

void GeometryTile::onError(std::exception_ptr err) {
void GeometryTile::onError(std::exception_ptr err, const uint64_t resultCorrelationID) {
loaded = true;
pending = false;
if (resultCorrelationID == correlationID) {
pending = false;
}
observer->onTileError(*this, err);
}

Expand Down
8 changes: 3 additions & 5 deletions src/mbgl/tile/geometry_tile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,19 +68,17 @@ class GeometryTile : public Tile, public GlyphRequestor, IconRequestor {
std::unordered_map<std::string, std::shared_ptr<Bucket>> nonSymbolBuckets;
std::unique_ptr<FeatureIndex> featureIndex;
std::unique_ptr<GeometryTileData> tileData;
uint64_t correlationID;
};
void onLayout(LayoutResult);
void onLayout(LayoutResult, uint64_t correlationID);

class PlacementResult {
public:
std::unordered_map<std::string, std::shared_ptr<Bucket>> symbolBuckets;
std::unique_ptr<CollisionTile> collisionTile;
uint64_t correlationID;
};
void onPlacement(PlacementResult);
void onPlacement(PlacementResult, uint64_t correlationID);

void onError(std::exception_ptr);
void onError(std::exception_ptr, uint64_t correlationID);

protected:
const GeometryTileData* getData() {
Expand Down
18 changes: 8 additions & 10 deletions src/mbgl/tile/geometry_tile_worker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ void GeometryTileWorker::setData(std::unique_ptr<const GeometryTileData> data_,
break;
}
} catch (...) {
parent.invoke(&GeometryTile::onError, std::current_exception());
parent.invoke(&GeometryTile::onError, std::current_exception(), correlationID);
}
}

Expand All @@ -112,7 +112,7 @@ void GeometryTileWorker::setLayers(std::vector<std::unique_ptr<Layer>> layers_,
break;
}
} catch (...) {
parent.invoke(&GeometryTile::onError, std::current_exception());
parent.invoke(&GeometryTile::onError, std::current_exception(), correlationID);
}
}

Expand All @@ -136,7 +136,7 @@ void GeometryTileWorker::setPlacementConfig(PlacementConfig placementConfig_, ui
break;
}
} catch (...) {
parent.invoke(&GeometryTile::onError, std::current_exception());
parent.invoke(&GeometryTile::onError, std::current_exception(), correlationID);
}
}

Expand All @@ -161,7 +161,7 @@ void GeometryTileWorker::symbolDependenciesChanged() {
break;
}
} catch (...) {
parent.invoke(&GeometryTile::onError, std::current_exception());
parent.invoke(&GeometryTile::onError, std::current_exception(), correlationID);
}
}

Expand All @@ -187,7 +187,7 @@ void GeometryTileWorker::coalesced() {
break;
}
} catch (...) {
parent.invoke(&GeometryTile::onError, std::current_exception());
parent.invoke(&GeometryTile::onError, std::current_exception(), correlationID);
}
}

Expand Down Expand Up @@ -353,8 +353,7 @@ void GeometryTileWorker::redoLayout() {
std::move(buckets),
std::move(featureIndex),
*data ? (*data)->clone() : nullptr,
correlationID
});
}, correlationID);

attemptPlacement();
}
Expand Down Expand Up @@ -409,9 +408,8 @@ void GeometryTileWorker::attemptPlacement() {

parent.invoke(&GeometryTile::onPlacement, GeometryTile::PlacementResult {
std::move(buckets),
std::move(collisionTile),
correlationID
});
std::move(collisionTile),
}, correlationID);
}

} // namespace mbgl
15 changes: 12 additions & 3 deletions src/mbgl/tile/raster_tile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,27 @@ void RasterTile::setData(std::shared_ptr<const std::string> data,
optional<Timestamp> expires_) {
modified = modified_;
expires = expires_;
worker.invoke(&RasterTileWorker::parse, data);

pending = true;
++correlationID;
worker.invoke(&RasterTileWorker::parse, data, correlationID);
}

void RasterTile::onParsed(std::unique_ptr<Bucket> result) {
void RasterTile::onParsed(std::unique_ptr<Bucket> result, const uint64_t resultCorrelationID) {
bucket = std::move(result);
loaded = true;
if (resultCorrelationID == correlationID) {
pending = false;
}
renderable = bucket ? true : false;
observer->onTileChanged(*this);
}

void RasterTile::onError(std::exception_ptr err) {
void RasterTile::onError(std::exception_ptr err, const uint64_t resultCorrelationID) {
loaded = true;
if (resultCorrelationID == correlationID) {
pending = false;
}
observer->onTileError(*this, err);
}

Expand Down
6 changes: 4 additions & 2 deletions src/mbgl/tile/raster_tile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,17 @@ class RasterTile : public Tile {
void cancel() override;
Bucket* getBucket(const RenderLayer&) const override;

void onParsed(std::unique_ptr<Bucket> result);
void onError(std::exception_ptr);
void onParsed(std::unique_ptr<Bucket> result, uint64_t correlationID);
void onError(std::exception_ptr, uint64_t correlationID);

private:
TileLoader<RasterTile> loader;

std::shared_ptr<Mailbox> mailbox;
Actor<RasterTileWorker> worker;

uint64_t correlationID = 0;

// Contains the Bucket object for the tile. Buckets are render
// objects and they get added by tile parsing operations.
std::unique_ptr<Bucket> bucket;
Expand Down
8 changes: 4 additions & 4 deletions src/mbgl/tile/raster_tile_worker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ RasterTileWorker::RasterTileWorker(ActorRef<RasterTileWorker>, ActorRef<RasterTi
: parent(std::move(parent_)) {
}

void RasterTileWorker::parse(std::shared_ptr<const std::string> data) {
void RasterTileWorker::parse(std::shared_ptr<const std::string> data, uint64_t correlationID) {
if (!data) {
parent.invoke(&RasterTile::onParsed, nullptr); // No data; empty tile.
parent.invoke(&RasterTile::onParsed, nullptr, correlationID); // No data; empty tile.
return;
}

try {
auto bucket = std::make_unique<RasterBucket>(util::unpremultiply(decodeImage(*data)));
parent.invoke(&RasterTile::onParsed, std::move(bucket));
parent.invoke(&RasterTile::onParsed, std::move(bucket), correlationID);
} catch (...) {
parent.invoke(&RasterTile::onError, std::current_exception());
parent.invoke(&RasterTile::onError, std::current_exception(), correlationID);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/mbgl/tile/raster_tile_worker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class RasterTileWorker {
public:
RasterTileWorker(ActorRef<RasterTileWorker>, ActorRef<RasterTile>);

void parse(std::shared_ptr<const std::string> data);
void parse(std::shared_ptr<const std::string> data, uint64_t correlationID);

private:
ActorRef<RasterTile> parent;
Expand Down
9 changes: 3 additions & 6 deletions test/tile/annotation_tile.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@ TEST(AnnotationTile, Issue8289) {
{},
std::make_unique<FeatureIndex>(),
std::move(data),
0
});
}, 0);

auto collisionTile = std::make_unique<CollisionTile>(PlacementConfig());

Expand All @@ -65,16 +64,14 @@ TEST(AnnotationTile, Issue8289) {
tile.onPlacement(GeometryTile::PlacementResult {
{},
std::move(collisionTile),
0
});
}, 0);

// Simulate a second layout with empty data.
tile.onLayout(GeometryTile::LayoutResult {
{},
std::make_unique<FeatureIndex>(),
std::make_unique<AnnotationTileData>(),
0
});
}, 0);

std::unordered_map<std::string, std::vector<Feature>> result;
GeometryCoordinates queryGeometry {{ Point<int16_t>(0, 0) }};
Expand Down
14 changes: 7 additions & 7 deletions test/tile/geojson_tile.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ TEST(GeoJSONTile, Issue7648) {
TEST(GeoJSONTile, Issue9927) {
GeoJSONTileTest test;

CircleLayer layer("circle", "source");
test.style.addLayer(std::make_unique<CircleLayer>("circle", "source"));

mapbox::geometry::feature_collection<int16_t> features;
features.push_back(mapbox::geometry::feature<int16_t> {
Expand All @@ -85,25 +85,25 @@ TEST(GeoJSONTile, Issue9927) {

GeoJSONTile tile(OverscaledTileID(0, 0, 0), "source", test.tileParameters, features);

tile.setLayers({{ layer.baseImpl }});
tile.setPlacementConfig({});

while (!tile.isComplete()) {
test.loop.runOnce();
}

ASSERT_TRUE(tile.isRenderable());
ASSERT_NE(nullptr, tile.getBucket(*layer.baseImpl));
ASSERT_NE(nullptr, tile.getBucket(*test.style.getRenderLayer("circle")));

// Make sure that once we've had a renderable tile and then receive erroneous data, we retain
// the previously rendered data and keep the tile renderable.
tile.setError(std::make_exception_ptr(std::runtime_error("Connection offline")));
ASSERT_TRUE(tile.isRenderable());
ASSERT_NE(nullptr, tile.getBucket(*layer.baseImpl));
ASSERT_NE(nullptr, tile.getBucket(*test.style.getRenderLayer("circle")));

// Then simulate a parsing failure and make sure that we keep it renderable in this situation
// as well.
tile.onError(std::make_exception_ptr(std::runtime_error("Parse error")));
// as well. We're using 3 as a correlationID since we've done two three calls that increment
// this counter (as part of the GeoJSONTile constructor, setLayers, and setPlacementConfig).
tile.onError(std::make_exception_ptr(std::runtime_error("Parse error")), 3);
ASSERT_TRUE(tile.isRenderable());
ASSERT_NE(nullptr, tile.getBucket(*layer.baseImpl));
ASSERT_NE(nullptr, tile.getBucket(*test.style.getRenderLayer("circle")));
}
6 changes: 3 additions & 3 deletions test/tile/raster_tile.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ TEST(RasterTile, setError) {
TEST(RasterTile, onError) {
RasterTileTest test;
RasterTile tile(OverscaledTileID(0, 0, 0), test.tileParameters, test.tileset);
tile.onError(std::make_exception_ptr(std::runtime_error("test")));
tile.onError(std::make_exception_ptr(std::runtime_error("test")), 0);
EXPECT_FALSE(tile.isRenderable());
EXPECT_TRUE(tile.isLoaded());
EXPECT_TRUE(tile.isComplete());
Expand All @@ -56,7 +56,7 @@ TEST(RasterTile, onError) {
TEST(RasterTile, onParsed) {
RasterTileTest test;
RasterTile tile(OverscaledTileID(0, 0, 0), test.tileParameters, test.tileset);
tile.onParsed(std::make_unique<RasterBucket>(UnassociatedImage{}));
tile.onParsed(std::make_unique<RasterBucket>(UnassociatedImage{}), 0);
EXPECT_TRUE(tile.isRenderable());
EXPECT_TRUE(tile.isLoaded());
EXPECT_TRUE(tile.isComplete());
Expand All @@ -79,7 +79,7 @@ TEST(RasterTile, onParsed) {
TEST(RasterTile, onParsedEmpty) {
RasterTileTest test;
RasterTile tile(OverscaledTileID(0, 0, 0), test.tileParameters, test.tileset);
tile.onParsed(nullptr);
tile.onParsed(nullptr, 0);
EXPECT_FALSE(tile.isRenderable());
EXPECT_TRUE(tile.isLoaded());
EXPECT_TRUE(tile.isComplete());
Expand Down
9 changes: 4 additions & 5 deletions test/tile/vector_tile.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ TEST(VectorTile, setError) {
TEST(VectorTile, onError) {
VectorTileTest test;
VectorTile tile(OverscaledTileID(0, 0, 0), "source", test.tileParameters, test.tileset);
tile.onError(std::make_exception_ptr(std::runtime_error("test")));
tile.onError(std::make_exception_ptr(std::runtime_error("test")), 0);

EXPECT_FALSE(tile.isRenderable());
EXPECT_TRUE(tile.isLoaded());
EXPECT_TRUE(tile.isComplete());
Expand All @@ -78,16 +79,14 @@ TEST(VectorTile, Issue7615) {
symbolBucket
}},
nullptr,
0
});
}, 0);

// Subsequent onLayout should not cause the existing symbol bucket to be discarded.
tile.onLayout(GeometryTile::LayoutResult {
{},
nullptr,
nullptr,
0
});
}, 0);

EXPECT_EQ(symbolBucket.get(), tile.getBucket(*symbolLayer.baseImpl->createRenderLayer()));
}
Expand Down

0 comments on commit 82bdd52

Please sign in to comment.