From e079d8d8d8cd4f9e4bd85abdf39804075e34517b Mon Sep 17 00:00:00 2001 From: Paolo Angelelli Date: Thu, 3 Aug 2017 11:47:29 +0200 Subject: Remove indexing of offline data from OSM plugin With this patch, offline tiles will be looked up on the fly, thus removing the need to index the offline content at startup. Task-number: QTBUG-59665 Change-Id: I1db62c38363dafe82ee2f2ffc7f493ac5d958fc2 Reviewed-by: Alex Blasche --- .../geoservices/osm/qgeofiletilecacheosm.cpp | 137 ++++++--------------- src/plugins/geoservices/osm/qgeofiletilecacheosm.h | 9 +- 2 files changed, 41 insertions(+), 105 deletions(-) diff --git a/src/plugins/geoservices/osm/qgeofiletilecacheosm.cpp b/src/plugins/geoservices/osm/qgeofiletilecacheosm.cpp index a759edf4..d79702cf 100644 --- a/src/plugins/geoservices/osm/qgeofiletilecacheosm.cpp +++ b/src/plugins/geoservices/osm/qgeofiletilecacheosm.cpp @@ -49,14 +49,17 @@ QGeoFileTileCacheOsm::QGeoFileTileCacheOsm(const QVector const QString &offlineDirectory, const QString &directory, QObject *parent) -: QGeoFileTileCache(directory, parent), m_offlineDirectory(offlineDirectory), m_providers(providers) +: QGeoFileTileCache(directory, parent), m_offlineDirectory(offlineDirectory), m_offlineData(false), m_providers(providers) { m_highDpi.resize(providers.size()); + if (!offlineDirectory.isEmpty()) { + m_offlineDirectory = QDir(offlineDirectory); + if (m_offlineDirectory.exists()) + m_offlineData = true; + } for (int i = 0; i < providers.size(); i++) { providers[i]->setParent(this); m_highDpi[i] = providers[i]->isHighDpi(); - m_mapIdFutures[providers[i]->mapType().mapId()].isFinished(); // To construct a default future for this mapId - m_requestCancel[providers[i]->mapType().mapId()] = 0; connect(providers[i], &QGeoTileProviderOsm::resolutionFinished, this, &QGeoFileTileCacheOsm::onProviderResolutionFinished); connect(providers[i], &QGeoTileProviderOsm::resolutionError, this, &QGeoFileTileCacheOsm::onProviderResolutionFinished); } @@ -64,10 +67,6 @@ QGeoFileTileCacheOsm::QGeoFileTileCacheOsm(const QVector QGeoFileTileCacheOsm::~QGeoFileTileCacheOsm() { - for (const QGeoTileProviderOsm *p : m_providers) { - m_requestCancel[p->mapType().mapId()] = 1; - m_mapIdFutures[p->mapType().mapId()].waitForFinished(); - } } QSharedPointer QGeoFileTileCacheOsm::get(const QGeoTileSpec &spec) @@ -89,21 +88,10 @@ void QGeoFileTileCacheOsm::onProviderResolutionFinished(const QGeoTileProviderOs int mapId = m_providers[i]->mapType().mapId(); m_highDpi[i] = m_providers[i]->isHighDpi(); - // Terminate initOfflineRegistry future for mapId. - if (!m_offlineDirectory.isEmpty()) { - m_requestCancel[mapId] = 1; - m_mapIdFutures[mapId].waitForFinished(); - m_requestCancel[mapId] = 0; - } - // reload cache for mapId i dropTiles(mapId); loadTiles(mapId); - // reload offline registry for mapId i - if (!m_offlineDirectory.isEmpty()) - m_mapIdFutures[mapId] = QtConcurrent::run(this, &QGeoFileTileCacheOsm::initOfflineRegistry, mapId); - // send signal to clear scene in all maps created through this provider that use the reloaded tiles emit mapDataUpdated(mapId); } @@ -152,37 +140,38 @@ void QGeoFileTileCacheOsm::init() // Base class ::init() QGeoFileTileCache::init(); - for (QGeoTileProviderOsm * p: m_providers) { + for (QGeoTileProviderOsm * p: m_providers) clearObsoleteTiles(p); - if (!m_offlineDirectory.isEmpty()) - m_mapIdFutures[p->mapType().mapId()] = QtConcurrent::run(this, &QGeoFileTileCacheOsm::initOfflineRegistry, p->mapType().mapId()); - } } QSharedPointer QGeoFileTileCacheOsm::getFromOfflineStorage(const QGeoTileSpec &spec) { - QMutexLocker locker(&storageLock); - if (m_tilespecToOfflineFilepath.contains(spec)) { - const QString fileName = m_tilespecToOfflineFilepath[spec]; - locker.unlock(); - QFile file(fileName); - file.open(QIODevice::ReadOnly); - QByteArray bytes = file.readAll(); - file.close(); - - QImage image; - if (!image.loadFromData(bytes)) { - handleError(spec, QLatin1String("Problem with tile image")); - return QSharedPointer(0); - } + if (!m_offlineData) + return QSharedPointer(); - addToMemoryCache(spec, bytes, QString()); - QSharedPointer tt = addToTextureCache(spec, image); - if (tt) - return tt; + int providerId = spec.mapId() - 1; + if (providerId < 0 || providerId >= m_providers.size()) + return QSharedPointer(); + + const QString fileName = tileSpecToFilename(spec, QStringLiteral("*"), providerId); + QStringList validTiles = m_offlineDirectory.entryList({fileName}); + if (!validTiles.size()) + return QSharedPointer(); + + QFile file(m_offlineDirectory.absoluteFilePath(validTiles.first())); + if (!file.open(QIODevice::ReadOnly)) + return QSharedPointer(); + QByteArray bytes = file.readAll(); + file.close(); + + QImage image; + if (!image.loadFromData(bytes)) { + handleError(spec, QLatin1String("Problem with tile image")); + return QSharedPointer(0); } - return QSharedPointer(); + addToMemoryCache(spec, bytes, QString()); + return addToTextureCache(spec, image); } void QGeoFileTileCacheOsm::dropTiles(int mapId) @@ -202,11 +191,6 @@ void QGeoFileTileCacheOsm::dropTiles(int mapId) for (const QGeoTileSpec &k : keys) if (k.mapId() == mapId) diskCache_.remove(k); - - keys = m_tilespecToOfflineFilepath.keys(); - for (const QGeoTileSpec &k : keys) - if (k.mapId() == mapId) - m_tilespecToOfflineFilepath.remove(k); } void QGeoFileTileCacheOsm::loadTiles(int mapId) @@ -226,60 +210,18 @@ void QGeoFileTileCacheOsm::loadTiles(int mapId) } } -void QGeoFileTileCacheOsm::initOfflineRegistry(int mapId) -{ - if (mapId < 1) // map ids in osm start from 1 - return; - - // Dealing with duplicates: picking the newest - QMap > fileDates; // key is filename, value is - QDirIterator it(m_offlineDirectory, QStringList() << "*.*", QDir::Files, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks ); - while (it.hasNext()) { - const QString &path = it.next(); - QFileInfo f(path); - if (!fileDates.contains(f.fileName()) || fileDates[f.fileName()].second < f.lastModified()) - fileDates[f.fileName()] = QPair(f.filePath(), f.lastModified()); - if (m_requestCancel[mapId]) - return; - } - - // Clear the content of the index. Entirely (at startup), or selectively (when a provider resolution changes the highDpi status). - QList toRemove; - for (auto i = m_tilespecToOfflineFilepath.constBegin(); i != m_tilespecToOfflineFilepath.constEnd(); ++i) { - if (i.key().mapId() == mapId) - toRemove.append(i.key()); - } - storageLock.lock(); - for (const auto &i : toRemove) - m_tilespecToOfflineFilepath.remove(i); - storageLock.unlock(); - - if (m_requestCancel[mapId]) - return; - - // Fill the index by mapId - int count = 0; - for (auto i= fileDates.constBegin(); i != fileDates.constEnd(); ++i) { - QGeoTileSpec spec = filenameToTileSpec(i.key()); - if (spec.zoom() == -1) - continue; - if (spec.mapId() != mapId) - continue; - count++; - storageLock.lock(); - m_tilespecToOfflineFilepath[spec] = i.value().first; - storageLock.unlock(); - if (m_requestCancel[mapId]) - return; - } - //qInfo() << "OSM plugin has found and is using "<< count <<" offline tiles"; -} - QString QGeoFileTileCacheOsm::tileSpecToFilename(const QGeoTileSpec &spec, const QString &format, const QString &directory) const { int providerId = spec.mapId() - 1; if (providerId < 0 || providerId >= m_providers.size()) return QString(); + + QDir dir = QDir(directory); + return dir.filePath(tileSpecToFilename(spec, format, providerId)); +} + +QString QGeoFileTileCacheOsm::tileSpecToFilename(const QGeoTileSpec &spec, const QString &format, int providerId) const +{ QString filename = spec.plugin(); filename += QLatin1String("-"); filename += (m_providers[providerId]->isHighDpi()) ? QLatin1Char('h') : QLatin1Char('l'); @@ -300,10 +242,7 @@ QString QGeoFileTileCacheOsm::tileSpecToFilename(const QGeoTileSpec &spec, const filename += QLatin1String("."); filename += format; - - QDir dir = QDir(directory); - - return dir.filePath(filename); + return filename; } QGeoTileSpec QGeoFileTileCacheOsm::filenameToTileSpec(const QString &filename) const diff --git a/src/plugins/geoservices/osm/qgeofiletilecacheosm.h b/src/plugins/geoservices/osm/qgeofiletilecacheosm.h index 5f11004c..da1fd0d3 100644 --- a/src/plugins/geoservices/osm/qgeofiletilecacheosm.h +++ b/src/plugins/geoservices/osm/qgeofiletilecacheosm.h @@ -66,20 +66,17 @@ protected Q_SLOTS: protected: void init() override; + inline QString tileSpecToFilename(const QGeoTileSpec &spec, const QString &format, int providerId) const; QString tileSpecToFilename(const QGeoTileSpec &spec, const QString &format, const QString &directory) const override; QGeoTileSpec filenameToTileSpec(const QString &filename) const override; QSharedPointer getFromOfflineStorage(const QGeoTileSpec &spec); void dropTiles(int mapId); void loadTiles(int mapId); - void initOfflineRegistry(int mapId); void clearObsoleteTiles(const QGeoTileProviderOsm *p); - QString m_offlineDirectory; - QHash m_tilespecToOfflineFilepath; - QMap m_requestCancel; - QMap> m_mapIdFutures; - QMutex storageLock; + QDir m_offlineDirectory; + bool m_offlineData; QVector m_providers; QVector m_highDpi; QVector m_maxMapIdTimestamps; -- cgit v1.2.1