Esempio n. 1
0
void TileCache::saveTileAndNotify(const TileDesc& tile, const char *data, const size_t size, const bool priority)
{
    std::unique_lock<std::mutex> lock(_tilesBeingRenderedMutex);

    std::shared_ptr<TileBeingRendered> tileBeingRendered = findTileBeingRendered(tile);
    if (!priority && tileBeingRendered && tileBeingRendered->getVersion() != tile.getVersion())
    {
        Log::trace() << "Skipping unexpected tile ver: " << tile.getVersion()
                     << ", waiting for ver " << tileBeingRendered->getVersion() << Log::end;
        return;
    }

    // Save to disk.
    const auto cachedName = (tileBeingRendered ? tileBeingRendered->getCacheName()
                                               : cacheFileName(tile));
    const auto fileName = _cacheDir + "/" + cachedName;
    Log::trace() << "Saving cache tile: " << fileName << Log::end;
    std::fstream outStream(fileName, std::ios::out);
    outStream.write(data, size);
    outStream.close();

    // Notify subscribers, if any.
    if (tileBeingRendered)
    {
        if (!tileBeingRendered->_subscribers.empty())
        {
            const std::string message = tile.serialize("tile");
            Log::debug("Sending tile message to subscribers: " + message);

            for (const auto& i: tileBeingRendered->_subscribers)
            {
                auto subscriber = i.lock();
                if (subscriber)
                {
                    //FIXME: This is inefficient; should just send directly to each client (although that is risky as well!
                    // Re-emit the tile command in the other thread(s) to re-check and hit
                    // the cache. Construct the message from scratch to contain only the
                    // mandatory parts of the message.
                    subscriber->sendToInputQueue(message);
                }
            }
        }

        // Remove subscriptions.
        if (tileBeingRendered->getVersion() == tile.getVersion())
        {
            Log::debug() << "STATISTICS: tile internal roundtrip "
                         << tileBeingRendered->getElapsedTimeMs() << " ms." << Log::end;
            _tilesBeingRendered.erase(cachedName);
        }
    }
}
Esempio n. 2
0
// FIXME: to be further simplified when we centralize tile messages.
int TileCache::isTileBeingRenderedIfSoSubscribe(const TileDesc& tile, const std::shared_ptr<ClientSession> &subscriber)
{
    std::unique_lock<std::mutex> lock(_tilesBeingRenderedMutex);

    std::shared_ptr<TileBeingRendered> tileBeingRendered = findTileBeingRendered(tile);

    if (tileBeingRendered)
    {
        Log::debug() << "Tile (" << tile.getPart() << ',' << tile.getTilePosX() << ','
                     << tile.getTilePosY() << ") is already being rendered, subscribing." << Log::end;
        assert(subscriber->getKind() == LOOLSession::Kind::ToClient);

        for (const auto &s : tileBeingRendered->_subscribers)
        {
            if (s.lock().get() == subscriber.get())
            {
                Log::debug("Redundant request to re-subscribe on a tile");
                return 0;
            }
        }
        tileBeingRendered->_subscribers.push_back(subscriber);

        const auto duration = (std::chrono::steady_clock::now() - tileBeingRendered->getStartTime());
        if (std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() > COMMAND_TIMEOUT_MS)
        {
            // Tile painting has stalled. Reissue.
            return tileBeingRendered->getVersion();
        }

        return 0;
    }
    else
    {
        Log::debug() << "Tile (" << tile.getPart() << ',' << tile.getTilePosX() << ','
                     << tile.getTilePosY() << ") needs rendering, subscribing for ver: "
                     << tile.getVersion() << "." << Log::end;

        const std::string cachedName = cacheFileName(tile);

        assert(_tilesBeingRendered.find(cachedName) == _tilesBeingRendered.end());

        tileBeingRendered = std::make_shared<TileBeingRendered>(cachedName, tile.getVersion());
        tileBeingRendered->_subscribers.push_back(subscriber);
        _tilesBeingRendered[cachedName] = tileBeingRendered;

        return tileBeingRendered->getVersion();
    }
}