From 3c4514aabf3d90718fb35763f053823b7cea914a Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Tue, 15 Jun 2021 17:26:24 +0200 Subject: [PATCH 1/4] Do not expire tiles from source tile caches that are still used by render tiles --- src/ol/source/VectorTile.js | 15 +++++++++++++-- src/ol/tilecoord.js | 13 +++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/ol/source/VectorTile.js b/src/ol/source/VectorTile.js index 957ca34f34..d75e268570 100644 --- a/src/ol/source/VectorTile.js +++ b/src/ol/source/VectorTile.js @@ -18,7 +18,7 @@ import { createXYZ, extentFromProjection, } from '../tilegrid.js'; -import {fromKey, getKeyZXY} from '../tilecoord.js'; +import {fromKey, getCacheKeyForTileKey, getKeyZXY} from '../tilecoord.js'; import {isEmpty} from '../obj.js'; import {loadFeaturesXhr} from '../featureloader.js'; import {toSize} from '../size.js'; @@ -237,8 +237,19 @@ class VectorTile extends UrlTile { * @param {!Object} usedTiles Used tiles. */ expireCache(projection, usedTiles) { + const tileCache = this.getTileCacheForProjection(projection); + const usedSourceTiles = Object.keys(usedTiles).reduce((acc, key) => { + const cacheKey = getCacheKeyForTileKey(key); + if (tileCache.containsKey(cacheKey)) { + const sourceTiles = tileCache.get(cacheKey).sourceTiles; + for (let i = 0, ii = sourceTiles.length; i < ii; ++i) { + acc[sourceTiles[i].getKey()] = true; + } + } + return acc; + }, {}); super.expireCache(projection, usedTiles); - this.sourceTileCache.expireCache({}); + this.sourceTileCache.expireCache(usedSourceTiles); } /** diff --git a/src/ol/tilecoord.js b/src/ol/tilecoord.js index fbd65e6db5..5552774df7 100644 --- a/src/ol/tilecoord.js +++ b/src/ol/tilecoord.js @@ -46,6 +46,19 @@ export function getKey(tileCoord) { return getKeyZXY(tileCoord[0], tileCoord[1], tileCoord[2]); } +/** + * Get the tile cache key for a tile key obtained through `tile.getKey()`. + * @param {string} tileKey The tile key. + * @return {string} The cache key. + */ +export function getCacheKeyForTileKey(tileKey) { + const [z, x, y] = tileKey + .substring(tileKey.lastIndexOf('/') + 1, tileKey.length) + .split(',') + .map(Number); + return getKeyZXY(z, x, y); +} + /** * Get a tile coord given a key. * @param {string} key The tile coord key. From ad4ff9f69541a72f5edff65b2a3bf9858eadc790 Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Tue, 15 Jun 2021 18:52:36 +0200 Subject: [PATCH 2/4] Keep track of loading source tiles when reused --- src/ol/source/VectorTile.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/ol/source/VectorTile.js b/src/ol/source/VectorTile.js index d75e268570..acc23ca846 100644 --- a/src/ol/source/VectorTile.js +++ b/src/ol/source/VectorTile.js @@ -292,15 +292,7 @@ class VectorTile extends UrlTile { ); tile.sourceTiles.push(sourceTile); const sourceTileState = sourceTile.getState(); - if (sourceTileState === TileState.IDLE) { - sourceTile.extent = sourceTileGrid.getTileCoordExtent( - sourceTileCoord - ); - sourceTile.projection = projection; - sourceTile.resolution = sourceTileGrid.getResolution( - sourceTileCoord[0] - ); - this.sourceTileCache.set(tileUrl, sourceTile); + if (sourceTileState < TileState.LOADED) { const listenChange = (event) => { this.handleTileChange(event); const state = sourceTile.getState(); @@ -329,6 +321,16 @@ class VectorTile extends UrlTile { }; sourceTile.addEventListener(EventType.CHANGE, listenChange); tile.loadingSourceTiles++; + } + if (sourceTileState === TileState.IDLE) { + sourceTile.extent = sourceTileGrid.getTileCoordExtent( + sourceTileCoord + ); + sourceTile.projection = projection; + sourceTile.resolution = sourceTileGrid.getResolution( + sourceTileCoord[0] + ); + this.sourceTileCache.set(tileUrl, sourceTile); sourceTile.load(); } }); From 23611508141afd84182b2bd46a54001c6beb4692 Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Tue, 15 Jun 2021 20:01:55 +0200 Subject: [PATCH 3/4] Add regression test --- .../browser/spec/ol/source/vectortile.test.js | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/test/browser/spec/ol/source/vectortile.test.js b/test/browser/spec/ol/source/vectortile.test.js index 290938c3bb..cc80dbf9dc 100644 --- a/test/browser/spec/ol/source/vectortile.test.js +++ b/test/browser/spec/ol/source/vectortile.test.js @@ -183,6 +183,48 @@ describe('ol.source.VectorTile', function () { }); tile.load(); }); + it('triggers events and loads source tile properly for wrapX counterpart', function (done) { + const tile1 = source.getTile( + 14, + 8938, + 5680, + 1, + getProjection('EPSG:3857') + ); + const tile2 = source.getTile( + 14, + 8938 + Math.pow(2, 14), + 5680, + 1, + getProjection('EPSG:3857') + ); + expect(tile2.wrappedTileCoord).to.eql([14, 8938, 5680]); + let loadstart = 0; + source.on('tileloadstart', function () { + ++loadstart; + }); + let loadend = 0; + source.on('tileloadend', function (e) { + ++loadend; + }); + let loaded = 0; + [tile1, tile2].forEach((tile) => { + tile.addEventListener('change', (e) => { + if (e.target.getState() === TileState.LOADED) { + const sourceTiles = e.target.getSourceTiles(); + expect(sourceTiles.length).to.be(1); + expect(sourceTiles[0].getState()).to.be(TileState.LOADED); + ++loaded; + if (loaded === 2) { + expect(loadstart).to.be(1); + expect(loadend).to.be(1); + done(); + } + } + }); + tile.load(); + }); + }); }); describe('different source and render tile grids', function () { From cd719ffb3455e2ab3220b37c8de51a87b86bd2cd Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Tue, 15 Jun 2021 20:30:43 +0200 Subject: [PATCH 4/4] Avoid infinite source tile cache size --- src/ol/source/VectorTile.js | 3 +++ test/browser/spec/ol/source/vectortile.test.js | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/ol/source/VectorTile.js b/src/ol/source/VectorTile.js index acc23ca846..fc3ee620c7 100644 --- a/src/ol/source/VectorTile.js +++ b/src/ol/source/VectorTile.js @@ -471,6 +471,9 @@ class VectorTile extends UrlTile { */ updateCacheSize(tileCount, projection) { super.updateCacheSize(tileCount * 2, projection); + this.sourceTileCache.highWaterMark = this.getTileCacheForProjection( + projection + ).highWaterMark; } } diff --git a/test/browser/spec/ol/source/vectortile.test.js b/test/browser/spec/ol/source/vectortile.test.js index cc80dbf9dc..949c1f0e59 100644 --- a/test/browser/spec/ol/source/vectortile.test.js +++ b/test/browser/spec/ol/source/vectortile.test.js @@ -309,6 +309,18 @@ describe('ol.source.VectorTile', function () { done(); }, 0); }); + + it('adjusts the tile cache size', function (done) { + map.renderSync(); + setTimeout(function () { + expect( + source.getTileCacheForProjection(map.getView().getProjection()) + .highWaterMark + ).to.be(2); + expect(source.sourceTileCache.highWaterMark).to.be(2); + done(); + }, 0); + }); }); it('does not fill up the tile queue', function (done) {