Each NodeMap has its own NodeFileSource so we should not get multiple
requests of for the same resource anymore, making the coalescing
code path useless.
We still need to keep a list of pending requests indexed by Resources
for the same reason it was introduced before: Resources don't hold
a reference to a uv_loop_t, so it is fine to keep it around, unlike
mbgl::Requests. Otherwise it would cause deadlocks.
The mutex was also kept because the NodeFileSource is accessed by
some arbitrary thread created by mbgl::Map and also by the main
thread coming from the JavaScript engine. More precisely,
NodeFileSource::notify() is called from the main thread while
NodeFileSource::request() and NodeFileSource::cancel() are not,
but they all access the same data structure.
mbgl::Environment was dropped and since most of the errors are being
forwarded to the NodeMap render callback, we can handle them there
and pinpoint exactly what NodeMap object is failing.
- Document Node.js v0.12.x and io.js support
- Document map.release functionality.
- Add notes on garbage collection and request handling.
- Update binary platforms and build instructions.
- Document API token FileSource implementation from
https://github.com/mapbox/mapbox-gl-native/pull/1607
- Update Kind enum values.
On the code path built with node v0.12.4, we are storing
an invalid reference to NodeRequest on the "pending" list. It will
crash when we need to access it like we do when canceling a request.
Ideally we should just have a "std::unordered_map<mbgl::Resource,
v8::UniquePersistent>" but that is not possible because the move
semantics are not fully implemented until V8 v4.3.22. It can be used
on a std::vector but not on a std::map.
See: https://code.google.com/p/v8/issues/detail?id=3669
The solution for keep using C++11 move semantics is to declare the
v8::CopyablePersistentTraits shenanigans and explicitly clear the
v8::Persistent (like we do already for node v0.10).
When Node gets V8 v4.3.22+ we can go back to v8::UniquePersistent
with a more clear implementation.
When requests are made to the FileSource, we now group them by
resource, similarly to what is done on the native implementation. The
file source will reuse the same Response for all the requests on the
observer list.
The NodeRequest no longer holds a reference to the mbgl::Request, so
we can cancel it synchronously. This is needed to avoid a deadlock
when releasing the NodeMap resources with pending requests.
Before:
- Main thread | NodeMap::release()
- Main thread | mbgl::~Map()
- Main thread | Blocks waiting for the Map thread to join
- Map thread | mbgl::Request::cancel()
- Map thread | NodeFileSource posts the "cancel" message to main thread
- *deadlock* | Map thread cannot join because mbgl::Request holds a
reference to the Map thread main loop. Main thread is
blocked, never gets the "cancel" message.
Now:
- Main thread | NodeMap::release()
- Main thread | mbgl::~Map()
- Main thread | Blocks waiting for the Map thread to join
- Map thread | Request::cancel()
- Map thread | NodeFileSource::cancel(), destroys the mbgl::Request
synchronously, mutex guarded access. We also send
a notification to cancel the NodeRequest on the main
thread.
- Map thread | Map thread joins.
- Main thread | NodeMap::release() returns
- Main thread | NodeRequest gets canceled. If NodeRequest replies
before it gets the "cancel" message, nothing happens,
notification gets discarded.