Waits for all futures to be completed. If the futures are not done,
    wait 100ms and then invoke itself via the ioloop and check again. If
    they are done, set a result on `wait_future` indicating the list of
    futures are done.

    :param wait_future: The future to complete when all `futures` are done
    :type wait_future: tornado.concurrent.Future
    :param list futures: The list of futures to watch for completion

def _futures_wait(wait_future, futures):
    """Waits for all futures to be completed. If the futures are not done,
    wait 100ms and then invoke itself via the ioloop and check again. If
    they are done, set a result on `wait_future` indicating the list of
    futures are done.

    :param wait_future: The future to complete when all `futures` are done
    :type wait_future: tornado.concurrent.Future
    :param list futures: The list of futures to watch for completion

    """
    global _buffer_size, _writing

    remaining = []
    for (future, batch, database, measurements) in futures:

        # If the future hasn't completed, add it to the remaining stack
        if not future.done():
            remaining.append((future, batch, database, measurements))
            continue

        # Get the result of the HTTP request, processing any errors
        error = future.exception()
        if isinstance(error, httpclient.HTTPError):
            if error.code == 400:
                _write_error_batch(batch, database, measurements)
            elif error.code >= 500:
                _on_5xx_error(batch, error, database, measurements)
            else:
                LOGGER.error('Error submitting %s batch %s to InfluxDB (%s): '
                             '%s', database, batch, error.code,
                             error.response.body)
        elif isinstance(error, (TimeoutError, OSError, socket.error,
                                select.error, ssl.socket_error)):
            _on_5xx_error(batch, error, database, measurements)

    # If there are futures that remain, try again in 100ms.
    if remaining:
        return ioloop.IOLoop.current().add_timeout(
            ioloop.IOLoop.current().time() + 0.1,
            _futures_wait, wait_future, remaining)
    else:  # Start the next timeout or trigger the next batch
        _buffer_size = _pending_measurements()
        LOGGER.debug('Batch submitted, %i measurements remain', _buffer_size)
        if _buffer_size >= _trigger_size:
            ioloop.IOLoop.current().add_callback(_trigger_batch_write)
        elif _buffer_size:
            _start_timeout()

    _writing = False
    wait_future.set_result(True)