src/mbgl/tile/geometry_tile_worker.cpp
void GeometryTileWorker::setData(std::unique_ptr<const GeometryTileData> data_,
                                 std::set<std::string> availableImages_,
                                 uint64_t correlationID_) {
    try {
        data = std::move(data_);
        correlationID = correlationID_;
        availableImages = std::move(availableImages_);

        switch (state) {
        case Idle:
            parse();
            coalesce();
            break;

        case Coalescing:
        case NeedsParse:
        case NeedsSymbolLayout:
            state = NeedsParse;
            break;
        }
    } catch (...) {
        parent.invoke(&GeometryTile::onError, std::current_exception(), correlationID);
    }
}
/*
   GeometryTileWorker is a state machine. This is its transition diagram.
   States are indicated by [state], lines are transitions triggered by
   messages, (parentheses) are actions taken on transition.

                         [Idle] <-------------------------.
                            |                             |
        set{Data,Layers}, symbolDependenciesChanged,      |
                    setShowCollisionBoxes                 |
                            |                             |
   (do parse and/or symbol layout; self-send "coalesced") |
                            v                             |
                      [Coalescing] --- coalesced ---------.
                         |   |
             .-----------.   .---------------------.
             |                                     |
   .--- set{Data,Layers}                setShowCollisionBoxes,
   |         |                         symbolDependenciesChanged --.
   |         |                                     |               |
   |         v                                     v               |
   .-- [NeedsParse] <-- set{Data,Layers} -- [NeedsSymbolLayout] ---.
             |                                     |
         coalesced                             coalesced
             |                                     |
             v                                     v
   (do parse or symbol layout; self-send "coalesced"; goto [coalescing])

   The idea is that in the [idle] state, parsing happens immediately in response to
   a "set" message, and symbol layout happens once all symbol dependencies are met.
   During this processing, multiple "set" messages might get queued in the mailbox.
   At the end of processing, we self-send "coalesced", read all the queued messages
   until we get to "coalesced", and then re-parse if there were one or more "set"s or
   return to the [idle] state if not.
 
   One important goal of the design is to prevent starvation. Under heavy load new
   requests for tiles should not prevent in progress request from completing.
   It is nevertheless possible to restart an in-progress request:
 
    - [Idle] setData -> parse()
        sends getGlyphs, hasPendingDependencies() is true
        enters [Coalescing], sends coalesced
    - [Coalescing] coalesced -> [Idle]
    - [Idle] setData -> new parse(), interrupts old parse()
        sends getGlyphs, hasPendingDependencies() is true
        enters [Coalescing], sends coalesced
    - [Coalescing] onGlyphsAvailable -> [NeedsSymbolLayout]
           hasPendingDependencies() may or may not be true
    - [NeedsSymbolLayout] coalesced -> finalizeLayout()
           Generates result depending on whether dependencies are met
           -> [Idle]
 
   In this situation, we are counting on the idea that even with rapid changes to
   the tile's data, the set of glyphs/images it requires will not keep growing without
   limit.
 
   Although parsing (which populates all non-symbol buckets and requests dependencies
   for symbol buckets) is internally separate from symbol layout, we only return
   results to the foreground when we have completed both steps. Because we _move_
   the result buckets to the foreground, it is necessary to re-generate all buckets from
   scratch for `setShowCollisionBoxes`, even though it only affects symbol layers.
 
   The GL JS equivalent (in worker_tile.js and vector_tile_worker_source.js)
   is somewhat simpler because it relies on getGlyphs/getImages calls that transfer
   an entire set of glyphs/images on every tile load, while the native logic
   maintains a local state that can be incrementally updated. Because each tile load
   call becomes self-contained, the equivalent of the coalescing logic is handled by
   'reloadTile' queueing a single extra 'reloadTile' callback to run after the next
   completed parse.
*/
GeometryTileWorker is a state machine. This is its transition diagram.
States are indicated by [state], lines are transitions triggered by
messages, (parentheses) are actions taken on transition.



The idea is that in the [idle] state, parsing happens immediately in response to
a "set" message, and symbol layout happens once all symbol dependencies are met.
During this processing, multiple "set" messages might get queued in the mailbox.

One important goal of the design is to prevent starvation. Under heavy load new
requests for tiles should not prevent in progress request from completing.
It is nevertheless possible to restart an in-progress request.



In this situation, we are counting on the idea that even with rapid changes to
the tile's data, the set of glyphs/images it requires will not keep growing without
limit.

Although parsing (which populates all non-symbol buckets and requests dependencies
for symbol buckets) is internally separate from symbol layout, we only return
results to the foreground when we have completed both steps. Because we _move_
the result buckets to the foreground, it is necessary to re-generate all buckets from
scratch for `setShowCollisionBoxes`, even though it only affects symbol layers.

The GL JS equivalent (in worker_tile.js and vector_tile_worker_source.js)
is somewhat simpler because it relies on getGlyphs/getImages calls that transfer
an entire set of glyphs/images on every tile load, while the native logic
maintains a local state that can be incrementally updated. Because each tile load
call becomes self-contained, the equivalent of the coalescing logic is handled by
'reloadTile' queueing a single extra 'reloadTile' callback to run after the next
completed parse.
GeometryTileWorker is a state machine . This is its transition diagram . States are indicated by [ state ] lines are transitions triggered by messages ( parentheses ) are actions taken on transition . The idea is that in the [ idle ] state parsing happens immediately in response to a " set " message and symbol layout happens once all symbol dependencies are met . During this processing multiple " set " messages might get queued in the mailbox . One important goal of the design is to prevent starvation . Under heavy load new requests for tiles should not prevent in progress request from completing . It is nevertheless possible to restart an in - progress request . In this situation we are counting on the idea that even with rapid changes to the tile ' s data the set of glyphs / images it requires will not keep growing without limit . Although parsing ( which populates all non - symbol buckets and requests dependencies for symbol buckets ) is internally separate from symbol layout we only return results to the foreground when we have completed both steps . Because we _move_ the result buckets to the foreground it is necessary to re - generate all buckets from scratch for ` setShowCollisionBoxes ` even though it only affects symbol layers . The GL JS equivalent ( in worker_tile . js and vector_tile_worker_source . js ) is somewhat simpler because it relies on getGlyphs / getImages calls that transfer an entire set of glyphs / images on every tile load while the native logic maintains a local state that can be incrementally updated . Because each tile load call becomes self - contained the equivalent of the coalescing logic is handled by ' reloadTile ' queueing a single extra ' reloadTile ' callback to run after the next completed parse .
void GeometryTileWorker::setData(std::unique_ptr<const GeometryTileData> data_,
                                 std::set<std::string> availableImages_,
                                 uint64_t correlationID_) {
    try {
        data = std::move(data_);
        correlationID = correlationID_;
        availableImages = std::move(availableImages_);
        switch (state) {
        case Idle:
            parse();
            coalesce();
            break;
        case Coalescing:
        case NeedsParse:
        case NeedsSymbolLayout:
            state = NeedsParse;
            break;
        }
    } catch (...) {
        parent.invoke(&GeometryTile::onError, std::current_exception(), correlationID);
    }
}
void GeometryTileWorker :: setData ( std :: unique_ptr < const GeometryTileData > data_ , std :: set < std :: string > availableImages_ , uint64_t correlationID_ ) { try { data = std :: move ( data_ ) ; correlationID = correlationID_ ; availableImages = std :: move ( availableImages_ ) ; switch ( state ) { case Idle : parse ( ) ; coalesce ( ) ; break ; case Coalescing : case NeedsParse : case NeedsSymbolLayout : state = NeedsParse ; break ; } } catch ( ... ) { parent . invoke ( & GeometryTile :: onError , std :: current_exception ( ) , correlationID ) ; } }
GeometryTileWorker is a state machine.
GeometryTileWorker is a state machine .