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

[core] don’t use stale collision tile in feature queries #8374

Merged
merged 1 commit into from
Mar 14, 2017

Conversation

ivovandongen
Copy link
Contributor

fixes #8289

We could make this check more granular since the FeatureIndex is still usable in this case, but since it's an edge case, I don't know if it's worth it.

@mention-bot
Copy link

@ivovandongen, thanks for your PR! By analyzing this pull request, we identified @jfirebaugh and @1ec5 to be potential reviewers.

@ivovandongen ivovandongen self-assigned this Mar 13, 2017
@ivovandongen ivovandongen added Core The cross-platform C++ core, aka mbgl release blocker Blocks the next final release labels Mar 13, 2017
@ivovandongen ivovandongen added this to the android-v5.0.0 milestone Mar 13, 2017
@ivovandongen ivovandongen force-pushed the 8289-query-rendered-features-crash branch from 35962d9 to cdd00aa Compare March 13, 2017 15:59
@ivovandongen ivovandongen requested a review from jfirebaugh March 13, 2017 16:00
@ivovandongen
Copy link
Contributor Author

To be able to stub out the FeatureIndex for testing I had to make FeatureIndex#query virtual

@@ -147,7 +147,7 @@ void GeometryTile::queryRenderedFeatures(
const TransformState& transformState,
const RenderedQueryOptions& options) {

if (!featureIndex || !data) return;
if (!featureIndex || !data || availableData != DataAvailability::All) return;
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of returning an empty result set for queries made between layout and placement, I think we could effectively exclude symbol layers from the query by resetting collisionTile in GeometryTile::onLayout. Then checking the collision tile will be skipped, but querying everything else is still possible.

std::unique_ptr<GeometryTileFeature> getFeature(std::size_t i) const override { return std::make_unique<AnnotationTileFeature>(features[i]); }
std::unique_ptr<GeometryTileFeature> getFeature(std::size_t i) const override {
assert(i < features.size());
return std::make_unique<AnnotationTileFeature>(features[i]);
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of adding an assertion, let's change features[i] to features.at(i). The latter has bounds-checking built in, and is what VectorTileLayer::getFeature uses.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Check. I've changed this, but since vector::at throws an exception, which will still crash the app, I'm wondering if we shouldn't catch, log an error and continue in these cases. At least in release builds.

Copy link
Contributor

Choose a reason for hiding this comment

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

For logic errors, it's better to crash -- crashes are picked up by reporting tools, we get a bug report, and can fix the issue. In comparison, logs are mostly ignored.

@@ -35,7 +35,7 @@ class FeatureIndex {

void insert(const GeometryCollection&, std::size_t index, const std::string& sourceLayerName, const std::string& bucketName);

void query(
virtual void query(
Copy link
Contributor

Choose a reason for hiding this comment

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

Here's an alternative way to write the test that uses a real FeatureIndex object. Still requires a lot of setup, but I think using real objects as much as possible is good.

TEST(VectorTile, Issue8289) {
    VectorTileTest test;
    VectorTile tile(OverscaledTileID(0, 0, 0), "source", test.updateParameters, test.tileset);

    auto data = std::make_unique<AnnotationTileData>();
    data->layers.emplace("test", AnnotationTileLayer("test"));
    data->layers.at("test").features.push_back(AnnotationTileFeature(0, FeatureType::Point, GeometryCollection()));

    // Simulate layout and placement of a symbol layer.
    tile.onLayout(GeometryTile::LayoutResult {
        {},
        std::make_unique<FeatureIndex>(),
        std::move(data),
        0
    });

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

    IndexedSubfeature subfeature { 0, "", "", 0 };
    CollisionFeature feature(GeometryCoordinates(), Anchor(0, 0, 0, 0), -5, 5, -5, 5, 1, 0, style::SymbolPlacementType::Point, subfeature, false);
    collisionTile->insertFeature(feature, 0, true);
    collisionTile->placeFeature(feature, false, false);

    tile.onPlacement(GeometryTile::PlacementResult {
        {},
        std::move(collisionTile),
        0
    });

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

    std::unordered_map<std::string, std::vector<Feature>> result;
    GeometryCoordinates queryGeometry {{ Point<int16_t>(0, 0) }};
    TransformState transformState;
    RenderedQueryOptions options;

    tile.queryRenderedFeatures(result, queryGeometry, transformState, options);

    EXPECT_TRUE(result.empty());
}

I verified that in current master, this fails -- not at the same point as in #8289, but enough to show that a data synchronization issue is present, and either of the proposed fixes will solve it.

@ivovandongen ivovandongen force-pushed the 8289-query-rendered-features-crash branch from cdd00aa to 7ac91f5 Compare March 14, 2017 11:20
@ivovandongen
Copy link
Contributor Author

Thanks @jfirebaugh. I've made the requested changes, adding the test in a separate file for clarity.

@ivovandongen ivovandongen changed the title [core] don’t query rendered features until all data is available [core] don’t use stale collision tile in feature queries Mar 14, 2017
@ivovandongen ivovandongen merged commit 96a5315 into master Mar 14, 2017
@ivovandongen ivovandongen deleted the 8289-query-rendered-features-crash branch March 14, 2017 15:28
@boundsj boundsj mentioned this pull request Mar 14, 2017
RomainQuidet pushed a commit to Mappy/mapbox-gl-native that referenced this pull request Mar 15, 2017
@tobrun tobrun mentioned this pull request Mar 17, 2017
10 tasks
RomainQuidet pushed a commit to Mappy/mapbox-gl-native that referenced this pull request Mar 31, 2017
…ashes on stale tiles"

This reverts commit a613b76.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Core The cross-platform C++ core, aka mbgl release blocker Blocks the next final release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Crash with FeatureIndex::addFeature while Map::queryPointAnnotations
3 participants